Ver código fonte

Merge branch 'master' into painless_more_whitelisting

Robert Muir 9 anos atrás
pai
commit
0a9c036c3e
76 arquivos alterados com 2495 adições e 1965 exclusões
  1. 4 4
      TESTING.asciidoc
  2. 2 6
      buildSrc/src/main/groovy/org/elasticsearch/gradle/test/NodeInfo.groovy
  3. 11 3
      modules/lang-painless/ant.xml
  4. 17 5
      modules/lang-painless/src/main/antlr/PainlessLexer.g4
  5. 137 0
      modules/lang-painless/src/main/antlr/PainlessLexer.tokens
  6. 102 79
      modules/lang-painless/src/main/antlr/PainlessParser.g4
  7. 137 0
      modules/lang-painless/src/main/antlr/PainlessParser.tokens
  8. 2 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/Analyzer.java
  9. 11 11
      modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java
  10. 28 0
      modules/lang-painless/src/main/java/org/elasticsearch/painless/CompilerSettings.java
  11. 35 17
      modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java
  12. 6 0
      modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java
  13. 23 39
      modules/lang-painless/src/main/java/org/elasticsearch/painless/Variables.java
  14. 199 174
      modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessLexer.java
  15. 247 404
      modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java
  16. 35 35
      modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParserBaseVisitor.java
  17. 79 70
      modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParserVisitor.java
  18. 418 377
      modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java
  19. 9 9
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java
  20. 5 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ALink.java
  21. 13 7
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java
  22. 3 3
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AStatement.java
  23. 35 35
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java
  24. 31 31
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java
  25. 2 2
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java
  26. 6 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java
  27. 47 47
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EChain.java
  28. 65 65
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java
  29. 11 11
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java
  30. 16 16
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java
  31. 5 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java
  32. 4 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java
  33. 4 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java
  34. 9 9
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java
  35. 29 29
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java
  36. 6 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LArrayLength.java
  37. 12 12
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LBrace.java
  38. 18 17
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCall.java
  39. 8 8
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCast.java
  40. 10 11
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java
  41. 10 12
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java
  42. 9 9
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java
  43. 26 25
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LField.java
  44. 12 12
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LListShortcut.java
  45. 12 12
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LMapShortcut.java
  46. 13 13
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewArray.java
  47. 14 14
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewObj.java
  48. 17 12
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LShortcut.java
  49. 69 0
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LStatic.java
  50. 7 7
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LString.java
  51. 14 29
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LVariable.java
  52. 8 4
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java
  53. 6 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java
  54. 26 15
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java
  55. 6 5
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java
  56. 6 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java
  57. 32 27
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java
  58. 21 16
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java
  59. 8 7
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java
  60. 25 27
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java
  61. 84 0
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java
  62. 40 35
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java
  63. 7 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SReturn.java
  64. 12 8
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java
  65. 7 6
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java
  66. 37 32
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java
  67. 19 20
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java
  68. 3 1
      modules/lang-painless/src/main/java/org/elasticsearch/painless/node/package-info.java
  69. 1 1
      modules/lang-painless/src/test/java/org/elasticsearch/painless/NoSemiColonTests.java
  70. 4 1
      modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptTestCase.java
  71. 3 3
      modules/lang-painless/src/test/java/org/elasticsearch/painless/WhenThingsGoWrongTests.java
  72. 81 0
      modules/lang-painless/src/test/java/org/elasticsearch/painless/antlr/ParserTests.java
  73. 1 1
      modules/reindex/src/test/java/org/elasticsearch/index/reindex/CancelTests.java
  74. 5 15
      test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
  75. 7 8
      test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java
  76. 2 2
      test/framework/src/main/java/org/elasticsearch/test/junit/listeners/ReproduceInfoPrinter.java

+ 4 - 4
TESTING.asciidoc

@@ -18,18 +18,18 @@ gradle assemble
 
 == Other test options
 
-To disable and enable network transport, set the `Des.node.mode`.
+To disable and enable network transport, set the `tests.es.node.mode` system property.
 
 Use network transport:
 
 ------------------------------------
--Des.node.mode=network
+-Dtests.es.node.mode=network
 ------------------------------------
 
 Use local transport (default since 1.3):
 
 -------------------------------------
--Des.node.mode=local
+-Dtests.es.node.mode=local
 -------------------------------------
 
 === Running Elasticsearch from a checkout
@@ -195,7 +195,7 @@ gradle test -Dtests.timeoutSuite=5000! ...
 Change the logging level of ES (not gradle)
 
 --------------------------------
-gradle test -Dtests.logger.level=DEBUG
+gradle test -Dtests.es.logger.level=DEBUG
 --------------------------------
 
 Print all the logging output from the test runs to the commandline

+ 2 - 6
buildSrc/src/main/groovy/org/elasticsearch/gradle/test/NodeInfo.groovy

@@ -130,17 +130,13 @@ class NodeInfo {
 
         env = [ 'JAVA_HOME' : project.javaHome ]
         args.addAll("-E", "node.portsfile=true")
-        String loggerLevel = System.getProperty("tests.logger.level")
-        if (loggerLevel != null) {
-            args.addAll("-E", "logger.level=${loggerLevel}")
-        }
         String collectedSystemProperties = config.systemProperties.collect { key, value -> "-D${key}=${value}" }.join(" ")
         String esJavaOpts = config.jvmArgs.isEmpty() ? collectedSystemProperties : collectedSystemProperties + " " + config.jvmArgs
         env.put('ES_JAVA_OPTS', esJavaOpts)
         for (Map.Entry<String, String> property : System.properties.entrySet()) {
-            if (property.getKey().startsWith('es.')) {
+            if (property.key.startsWith('tests.es.')) {
                 args.add("-E")
-                args.add("${property.getKey()}=${property.getValue()}")
+                args.add("${property.key.substring('tests.es.'.size())}=${property.value}")
             }
         }
         env.put('ES_JVM_OPTIONS', new File(confDir, 'jvm.options'))

+ 11 - 3
modules/lang-painless/ant.xml

@@ -42,10 +42,16 @@
   <macrodef name="regen-delete">
     <attribute name="grammar" />
     <sequential>
+      <local name="grammar.path"/>
+      <property name="grammar.path" location="src/main/antlr"/>
+      <!-- delete token files so files will be generated -->
+      <delete dir="${grammar.path}" includes="@{grammar}*.tokens"/>
       <local name="output.path"/>
       <patternset id="grammar.@{grammar}.patternset">
         <include name="@{grammar}Lexer.java" />
         <include name="@{grammar}Parser.java" />
+        <include name="@{grammar}Lexer.tokens" />
+        <include name="@{grammar}Parser.tokens" />
         <include name="@{grammar}ParserVisitor.java" />
         <include name="@{grammar}ParserBaseVisitor.java" />
       </patternset>
@@ -70,6 +76,7 @@
         <sysproperty key="user.language" value="en"/>
         <sysproperty key="user.country" value="US"/>
         <sysproperty key="user.variant" value=""/>
+        <arg value="-Werror"/>
         <arg value="-package"/>
         <arg value="org.elasticsearch.painless.antlr"/>
         <arg value="-o"/>
@@ -92,6 +99,7 @@
         <sysproperty key="user.language" value="en"/>
         <sysproperty key="user.country" value="US"/>
         <sysproperty key="user.variant" value=""/>
+        <arg value="-Werror"/>
         <arg value="-package"/>
         <arg value="org.elasticsearch.painless.antlr"/>
         <arg value="-no-listener"/>
@@ -121,9 +129,9 @@
       <fileset id="grammar.fileset" dir="${output.path}">
         <patternset refid="grammar.@{grammar}.patternset"/>
       </fileset>
-      <!-- remove files that are not needed to compile or at runtime -->
-      <delete dir="${grammar.path}" includes="@{grammar}*.tokens"/>
-      <delete dir="${output.path}" includes="@{grammar}*.tokens"/>
+      <!-- moves token files to grammar directory for use with IDE's -->
+      <move file="${output.path}/@{grammar}Lexer.tokens" todir="${grammar.path}"/>
+      <move file="${output.path}/@{grammar}Parser.tokens" todir="${grammar.path}"/>
       <!-- make the generated classes package private -->
       <replaceregexp match="public ((interface|class) \Q@{grammar}\E\w+)" replace="\1" encoding="UTF-8">
         <fileset refid="grammar.fileset"/>

+ 17 - 5
modules/lang-painless/src/main/antlr/PainlessLexer.g4

@@ -19,6 +19,10 @@
 
 lexer grammar PainlessLexer;
 
+@header {
+import org.elasticsearch.painless.Definition;
+}
+
 WS: [ \t\n\r]+ -> skip;
 COMMENT: ( '//' .*? [\n\r] | '/*' .*? '*/' ) -> skip;
 
@@ -28,7 +32,7 @@ LBRACE:    '[';
 RBRACE:    ']';
 LP:        '(';
 RP:        ')';
-DOT:       '.' -> mode(EXT);
+DOT:       '.' -> mode(AFTER_DOT);
 COMMA:     ',';
 SEMICOLON: ';';
 IF:        'if';
@@ -88,7 +92,7 @@ AUSH:   '>>>=';
 OCTAL: '0' [0-7]+ [lL]?;
 HEX: '0' [xX] [0-9a-fA-F]+ [lL]?;
 INTEGER: ( '0' | [1-9] [0-9]* ) [lLfFdD]?;
-DECIMAL: ( '0' | [1-9] [0-9]* ) DOT [0-9]* ( [eE] [+\-]? [0-9]+ )? [fF]?;
+DECIMAL: ( '0' | [1-9] [0-9]* ) (DOT [0-9]+)? ( [eE] [+\-]? [0-9]+ )? [fF]?;
 
 STRING: ( '"' ( '\\"' | '\\\\' | ~[\\"] )*? '"' ) | ( '\'' ( '\\\'' | '\\\\' | ~[\\"] )*? '\'' );
 
@@ -97,8 +101,16 @@ FALSE: 'false';
 
 NULL: 'null';
 
+// The predicate here allows us to remove ambiguities when
+// dealing with types versus identifiers.  We check against
+// the current whitelist to determine whether a token is a type
+// or not.  Note this works by processing one character at a time
+// and the rule is added or removed as this happens.  This is also known
+// as "the lexer hack."  See (https://en.wikipedia.org/wiki/The_lexer_hack).
+TYPE: ID ( DOT ID )* { Definition.isSimpleType(getText()) }?;
 ID: [_a-zA-Z] [_a-zA-Z0-9]*;
 
-mode EXT;
-EXTINTEGER: ( '0' | [1-9] [0-9]* ) -> mode(DEFAULT_MODE);
-EXTID: [_a-zA-Z] [_a-zA-Z0-9]* -> mode(DEFAULT_MODE);
+mode AFTER_DOT;
+
+DOTINTEGER: ( '0' | [1-9] [0-9]* )                        -> mode(DEFAULT_MODE);
+DOTID: [_a-z] [_a-zA-Z0-9]*                               -> mode(DEFAULT_MODE);

+ 137 - 0
modules/lang-painless/src/main/antlr/PainlessLexer.tokens

@@ -0,0 +1,137 @@
+WS=1
+COMMENT=2
+LBRACK=3
+RBRACK=4
+LBRACE=5
+RBRACE=6
+LP=7
+RP=8
+DOT=9
+COMMA=10
+SEMICOLON=11
+IF=12
+ELSE=13
+WHILE=14
+DO=15
+FOR=16
+CONTINUE=17
+BREAK=18
+RETURN=19
+NEW=20
+TRY=21
+CATCH=22
+THROW=23
+BOOLNOT=24
+BWNOT=25
+MUL=26
+DIV=27
+REM=28
+ADD=29
+SUB=30
+LSH=31
+RSH=32
+USH=33
+LT=34
+LTE=35
+GT=36
+GTE=37
+EQ=38
+EQR=39
+NE=40
+NER=41
+BWAND=42
+XOR=43
+BWOR=44
+BOOLAND=45
+BOOLOR=46
+COND=47
+COLON=48
+INCR=49
+DECR=50
+ASSIGN=51
+AADD=52
+ASUB=53
+AMUL=54
+ADIV=55
+AREM=56
+AAND=57
+AXOR=58
+AOR=59
+ALSH=60
+ARSH=61
+AUSH=62
+OCTAL=63
+HEX=64
+INTEGER=65
+DECIMAL=66
+STRING=67
+TRUE=68
+FALSE=69
+NULL=70
+TYPE=71
+ID=72
+DOTINTEGER=73
+DOTID=74
+'{'=3
+'}'=4
+'['=5
+']'=6
+'('=7
+')'=8
+'.'=9
+','=10
+';'=11
+'if'=12
+'else'=13
+'while'=14
+'do'=15
+'for'=16
+'continue'=17
+'break'=18
+'return'=19
+'new'=20
+'try'=21
+'catch'=22
+'throw'=23
+'!'=24
+'~'=25
+'*'=26
+'/'=27
+'%'=28
+'+'=29
+'-'=30
+'<<'=31
+'>>'=32
+'>>>'=33
+'<'=34
+'<='=35
+'>'=36
+'>='=37
+'=='=38
+'==='=39
+'!='=40
+'!=='=41
+'&'=42
+'^'=43
+'|'=44
+'&&'=45
+'||'=46
+'?'=47
+':'=48
+'++'=49
+'--'=50
+'='=51
+'+='=52
+'-='=53
+'*='=54
+'/='=55
+'%='=56
+'&='=57
+'^='=58
+'|='=59
+'<<='=60
+'>>='=61
+'>>>='=62
+'true'=68
+'false'=69
+'null'=70

+ 102 - 79
modules/lang-painless/src/main/antlr/PainlessParser.g4

@@ -22,35 +22,37 @@ parser grammar PainlessParser;
 options { tokenVocab=PainlessLexer; }
 
 source
-    : statement+ EOF
+    : statement* EOF
     ;
 
+// Note we use a predicate on the if/else case here to prevent the
+// "dangling-else" ambiguity by forcing the 'else' token to be consumed
+// as soon as one is found.  See (https://en.wikipedia.org/wiki/Dangling_else).
 statement
-    : IF LP expression RP block ( ELSE block )?                                              # if
-    | WHILE LP expression RP ( block | empty )                                               # while
-    | DO block WHILE LP expression RP ( SEMICOLON | EOF )                                    # do
-    | FOR LP initializer? SEMICOLON expression? SEMICOLON afterthought? RP ( block | empty ) # for
-    | declaration ( SEMICOLON | EOF )                                                        # decl
-    | CONTINUE ( SEMICOLON | EOF )                                                           # continue
-    | BREAK ( SEMICOLON | EOF )                                                              # break
-    | RETURN expression ( SEMICOLON | EOF )                                                  # return
-    | TRY block trap+                                                                        # try
-    | THROW expression ( SEMICOLON | EOF )                                                   # throw
-    | expression ( SEMICOLON | EOF )                                                         # expr
+    : IF LP expression RP trailer ( ELSE trailer | { _input.LA(1) != ELSE }? )                 # if
+    | WHILE LP expression RP ( trailer | empty )                                               # while
+    | DO block WHILE LP expression RP delimiter                                                # do
+    | FOR LP initializer? SEMICOLON expression? SEMICOLON afterthought? RP ( trailer | empty ) # for
+    | declaration delimiter                                                                    # decl
+    | CONTINUE delimiter                                                                       # continue
+    | BREAK delimiter                                                                          # break
+    | RETURN expression delimiter                                                              # return
+    | TRY block trap+                                                                          # try
+    | THROW expression delimiter                                                               # throw
+    | expression delimiter                                                                     # expr
     ;
 
-block
-    : LBRACK statement+ RBRACK # multiple
-    | statement                # single
+trailer
+    : block
+    | statement
     ;
 
-empty
-    : emptyscope
-    | SEMICOLON
+block
+    : LBRACK statement* RBRACK
     ;
 
-emptyscope
-    : LBRACK RBRACK
+empty
+    : SEMICOLON
     ;
 
 initializer
@@ -63,75 +65,96 @@ afterthought
     ;
 
 declaration
-    : decltype declvar ( COMMA declvar )*
+    : decltype declvar (COMMA declvar)*
     ;
 
 decltype
-    : identifier (LBRACE RBRACE)*
+    : TYPE (LBRACE RBRACE)*
     ;
 
 declvar
-    : identifier ( ASSIGN expression )?
+    : ID ( ASSIGN expression )?
     ;
 
 trap
-    : CATCH LP ( identifier identifier ) RP ( block | emptyscope )
-    ;
-
-identifier
-    : ID generic?
-    ;
-
-generic
-    : LT identifier ( COMMA identifier )* GT
-    ;
-
-expression
-    :               LP expression RP                                    # precedence
-    |               ( OCTAL | HEX | INTEGER | DECIMAL )                 # numeric
-    |               TRUE                                                # true
-    |               FALSE                                               # false
-    |               NULL                                                # null
-    | <assoc=right> chain ( INCR | DECR )                               # postinc
-    | <assoc=right> ( INCR | DECR ) chain                               # preinc
-    |               chain                                               # read
-    | <assoc=right> ( BOOLNOT | BWNOT | ADD | SUB ) expression          # unary
-    | <assoc=right> LP decltype RP expression                           # cast
-    |               expression ( MUL | DIV | REM ) expression           # binary
-    |               expression ( ADD | SUB ) expression                 # binary
-    |               expression ( LSH | RSH | USH ) expression           # binary
-    |               expression ( LT | LTE | GT | GTE ) expression       # comp
-    |               expression ( EQ | EQR | NE | NER ) expression       # comp
-    |               expression BWAND expression                         # binary
-    |               expression XOR expression                           # binary
-    |               expression BWOR expression                          # binary
-    |               expression BOOLAND expression                       # bool
-    |               expression BOOLOR expression                        # bool
-    | <assoc=right> expression COND expression COLON expression         # conditional
-    | <assoc=right> chain ( ASSIGN | AADD | ASUB | AMUL | ADIV
-                                      | AREM | AAND | AXOR | AOR
-                                      | ALSH | ARSH | AUSH ) expression # assignment
-    ;
-
-chain
-    : linkprec
-    | linkcast
-    | linkvar
-    | linknew
-    | linkstring
-    ;
-
-linkprec:   LP ( linkprec | linkcast | linkvar | linknew | linkstring ) RP ( linkdot | linkbrace )?;
-linkcast:   LP decltype RP ( linkprec | linkcast | linkvar | linknew | linkstring );
-linkbrace:  LBRACE expression RBRACE ( linkdot | linkbrace )?;
-linkdot:    DOT ( linkcall | linkfield );
-linkcall:   EXTID arguments ( linkdot | linkbrace )?;
-linkvar:    identifier ( linkdot | linkbrace )?;
-linkfield:  ( EXTID | EXTINTEGER ) ( linkdot | linkbrace )?;
-linknew:    NEW identifier ( ( arguments linkdot? ) | ( ( LBRACE expression RBRACE )+ linkdot? ) );
-linkstring: STRING (linkdot | linkbrace )?;
+    : CATCH LP TYPE ID RP block
+    ;
+
+delimiter
+    : SEMICOLON
+    | EOF
+    ;
+
+// Note we return the boolean s.  This is returned as true
+// if secondaries (postfixes) are allowed, otherwise, false.
+// This prevents illegal secondaries from being appended to
+// expressions using precedence that aren't variable/method chains.
+expression returns [boolean s = true]
+    :               u = unary[false]                                       { $s = $u.s; }           # single
+    |               expression ( MUL | DIV | REM ) expression              { $s = false; }          # binary
+    |               expression ( ADD | SUB ) expression                    { $s = false; }          # binary
+    |               expression ( LSH | RSH | USH ) expression              { $s = false; }          # binary
+    |               expression ( LT | LTE | GT | GTE ) expression          { $s = false; }          # comp
+    |               expression ( EQ | EQR | NE | NER ) expression          { $s = false; }          # comp
+    |               expression BWAND expression                            { $s = false; }          # binary
+    |               expression XOR expression                              { $s = false; }          # binary
+    |               expression BWOR expression                             { $s = false; }          # binary
+    |               expression BOOLAND expression                          { $s = false; }          # bool
+    |               expression BOOLOR expression                           { $s = false; }          # bool
+    | <assoc=right> expression COND e0 = expression COLON e1 = expression  { $s = $e0.s && $e1.s; } # conditional
+    // TODO: Should we allow crazy syntax like (x = 5).call()?
+    //       Other crazy syntaxes work, but this one requires
+    //       a complete restructure of the rules as EChain isn't
+    //       designed to handle more postfixes after an assignment.
+    | <assoc=right> chain[true] ( ASSIGN | AADD | ASUB | AMUL |
+                                  ADIV   | AREM | AAND | AXOR |
+                                  AOR    | ALSH | ARSH | AUSH ) expression { $s = false; }         # assignment
+    ;
+
+// Note we take in the boolean c.  This is used to indicate
+// whether or not this rule was called when we are already
+// processing a variable/method chain.  This prevents the chain
+// from being applied to rules where it wouldn't be allowed.
+unary[boolean c] returns [boolean s = true]
+    : { !$c }? ( INCR | DECR ) chain[true]                                  # pre
+    | { !$c }? chain[true] (INCR | DECR )                                   # post
+    | { !$c }? chain[false]                                                 # read
+    | { !$c }? ( OCTAL | HEX | INTEGER | DECIMAL )          { $s = false; } # numeric
+    | { !$c }? TRUE                                         { $s = false; } # true
+    | { !$c }? FALSE                                        { $s = false; } # false
+    | { !$c }? NULL                                         { $s = false; } # null
+    | { !$c }? ( BOOLNOT | BWNOT | ADD | SUB ) unary[false]                 # operator
+    |          LP decltype RP unary[$c]                                     # cast
+    ;
+
+chain[boolean c]
+    : p = primary[$c] secondary[$p.s]*                             # dynamic
+    | decltype dot secondary[true]*                                # static
+    | NEW TYPE (LBRACE expression RBRACE)+ (dot secondary[true]*)? # newarray
+    ;
+
+primary[boolean c] returns [boolean s = true]
+    : { !$c }? LP e = expression RP { $s = $e.s; } # exprprec
+    | { $c }?  LP unary[true] RP                   # chainprec
+    |          STRING                              # string
+    |          ID                                  # variable
+    |          NEW TYPE arguments                  # newobject
+    ;
+
+secondary[boolean s]
+    : { $s }? dot
+    | { $s }? brace
+    ;
+
+dot
+    : DOT DOTID arguments        # callinvoke
+    | DOT ( DOTID | DOTINTEGER ) # fieldaccess
+    ;
+
+brace
+    : LBRACE expression RBRACE # braceaccess
+    ;
 
 arguments
     : ( LP ( expression ( COMMA expression )* )? RP )
     ;
-

+ 137 - 0
modules/lang-painless/src/main/antlr/PainlessParser.tokens

@@ -0,0 +1,137 @@
+WS=1
+COMMENT=2
+LBRACK=3
+RBRACK=4
+LBRACE=5
+RBRACE=6
+LP=7
+RP=8
+DOT=9
+COMMA=10
+SEMICOLON=11
+IF=12
+ELSE=13
+WHILE=14
+DO=15
+FOR=16
+CONTINUE=17
+BREAK=18
+RETURN=19
+NEW=20
+TRY=21
+CATCH=22
+THROW=23
+BOOLNOT=24
+BWNOT=25
+MUL=26
+DIV=27
+REM=28
+ADD=29
+SUB=30
+LSH=31
+RSH=32
+USH=33
+LT=34
+LTE=35
+GT=36
+GTE=37
+EQ=38
+EQR=39
+NE=40
+NER=41
+BWAND=42
+XOR=43
+BWOR=44
+BOOLAND=45
+BOOLOR=46
+COND=47
+COLON=48
+INCR=49
+DECR=50
+ASSIGN=51
+AADD=52
+ASUB=53
+AMUL=54
+ADIV=55
+AREM=56
+AAND=57
+AXOR=58
+AOR=59
+ALSH=60
+ARSH=61
+AUSH=62
+OCTAL=63
+HEX=64
+INTEGER=65
+DECIMAL=66
+STRING=67
+TRUE=68
+FALSE=69
+NULL=70
+TYPE=71
+ID=72
+DOTINTEGER=73
+DOTID=74
+'{'=3
+'}'=4
+'['=5
+']'=6
+'('=7
+')'=8
+'.'=9
+','=10
+';'=11
+'if'=12
+'else'=13
+'while'=14
+'do'=15
+'for'=16
+'continue'=17
+'break'=18
+'return'=19
+'new'=20
+'try'=21
+'catch'=22
+'throw'=23
+'!'=24
+'~'=25
+'*'=26
+'/'=27
+'%'=28
+'+'=29
+'-'=30
+'<<'=31
+'>>'=32
+'>>>'=33
+'<'=34
+'<='=35
+'>'=36
+'>='=37
+'=='=38
+'==='=39
+'!='=40
+'!=='=41
+'&'=42
+'^'=43
+'|'=44
+'&&'=45
+'||'=46
+'?'=47
+':'=48
+'++'=49
+'--'=50
+'='=51
+'+='=52
+'-='=53
+'*='=54
+'/='=55
+'%='=56
+'&='=57
+'^='=58
+'|='=59
+'<<='=60
+'>>='=61
+'>>>='=62
+'true'=68
+'false'=69
+'null'=70

+ 2 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/Analyzer.java

@@ -26,9 +26,8 @@ import org.elasticsearch.painless.node.SSource;
  * Runs the analysis phase of compilation using the Painless AST.
  */
 final class Analyzer {
-    static Variables analyze(final CompilerSettings settings,
-                                    final Reserved shortcut, final SSource root) {
-        final Variables variables = new Variables(settings, shortcut);
+    static Variables analyze(Reserved shortcut, SSource root) {
+        Variables variables = new Variables(shortcut);
         root.analyze(variables);
 
         return variables;

+ 11 - 11
modules/lang-painless/src/main/java/org/elasticsearch/painless/Compiler.java

@@ -57,7 +57,7 @@ final class Compiler {
         try {
             // Setup the code privileges.
             CODESOURCE = new CodeSource(new URL("file:" + BootstrapInfo.UNTRUSTED_CODEBASE), (Certificate[]) null);
-        } catch (final MalformedURLException impossible) {
+        } catch (MalformedURLException impossible) {
             throw new RuntimeException(impossible);
         }
     }
@@ -69,7 +69,7 @@ final class Compiler {
         /**
          * @param parent The parent ClassLoader.
          */
-        Loader(final ClassLoader parent) {
+        Loader(ClassLoader parent) {
             super(parent);
         }
 
@@ -79,7 +79,7 @@ final class Compiler {
          * @param bytes The generated byte code.
          * @return A Class object extending {@link Executable}.
          */
-        Class<? extends Executable> define(final String name, final byte[] bytes) {
+        Class<? extends Executable> define(String name, byte[] bytes) {
             return defineClass(name, bytes, 0, bytes.length, CODESOURCE).asSubclass(Executable.class);
         }
     }
@@ -92,7 +92,7 @@ final class Compiler {
      * @param settings The CompilerSettings to be used during the compilation.
      * @return An {@link Executable} Painless script.
      */
-    static Executable compile(final Loader loader, final String name, final String source, final CompilerSettings settings) {
+    static Executable compile(Loader loader, String name, String source, CompilerSettings settings) {
         byte[] bytes = compile(name, source, settings);
 
         return createExecutable(loader, name, source, bytes);
@@ -111,9 +111,9 @@ final class Compiler {
                 " plugin if a script longer than this length is a requirement.");
         }
 
-        final Reserved reserved = new Reserved();
-        final SSource root = Walker.buildPainlessTree(source, reserved, settings);
-        final Variables variables = Analyzer.analyze(settings, reserved, root);
+        Reserved reserved = new Reserved();
+        SSource root = Walker.buildPainlessTree(source, reserved, settings);
+        Variables variables = Analyzer.analyze(reserved, root);
 
         return Writer.write(settings, name, source, variables, root);
     }
@@ -126,13 +126,13 @@ final class Compiler {
      * @param bytes The ASM generated byte code to define the class with.
      * @return A Painless {@link Executable} script.
      */
-    private static Executable createExecutable(final Loader loader, final String name, final String source, final byte[] bytes) {
+    private static Executable createExecutable(Loader loader, String name, String source, byte[] bytes) {
         try {
-            final Class<? extends Executable> clazz = loader.define(CLASS_NAME, bytes);
-            final java.lang.reflect.Constructor<? extends Executable> constructor = clazz.getConstructor(String.class, String.class);
+            Class<? extends Executable> clazz = loader.define(CLASS_NAME, bytes);
+            java.lang.reflect.Constructor<? extends Executable> constructor = clazz.getConstructor(String.class, String.class);
 
             return constructor.newInstance(name, source);
-        } catch (final Exception exception) { // Catch everything to let the user know this is something caused internally.
+        } catch (Exception exception) { // Catch everything to let the user know this is something caused internally.
             throw new IllegalStateException(
                     "An internal error occurred attempting to define the script [" + name + "].", exception);
         }

+ 28 - 0
modules/lang-painless/src/main/java/org/elasticsearch/painless/CompilerSettings.java

@@ -29,11 +29,22 @@ public final class CompilerSettings {
      */
     public static final String MAX_LOOP_COUNTER = "max_loop_counter";
 
+    /**
+     * Constant to be used for enabling additional internal compilation checks (slower).
+     */
+    public static final String PICKY = "picky";
+
     /**
      * The maximum number of statements allowed to be run in a loop.
      */
     private int maxLoopCounter = 10000;
 
+    /**
+     * Whether to throw exception on ambiguity or other internal parsing issues. This option
+     * makes things slower too, it is only for debugging.
+     */
+    private boolean picky = false;
+
     /**
      * Returns the value for the cumulative total number of statements that can be made in all loops
      * in a script before an exception is thrown.  This attempts to prevent infinite loops.  Note if
@@ -50,4 +61,21 @@ public final class CompilerSettings {
     public final void setMaxLoopCounter(int max) {
         this.maxLoopCounter = max;
     }
+
+    /**
+     * Returns true if the compiler should be picky. This means it runs slower and enables additional
+     * runtime checks, throwing an exception if there are ambiguities in the grammar or other low level
+     * parsing problems.
+     */
+    public boolean isPicky() {
+      return picky;
+    }
+
+    /**
+     * Set to true if compilation should be picky.
+     * @see #isPicky
+     */
+    public void setPicky(boolean picky) {
+      this.picky = picky;
+    }
 }

+ 35 - 17
modules/lang-painless/src/main/java/org/elasticsearch/painless/Definition.java

@@ -48,7 +48,7 @@ public final class Definition {
                       "java.util.stream.txt"));
 
     private static final Definition INSTANCE = new Definition();
-    
+
     /** Some native types as constants: */
     public static final Type VOID_TYPE = getType("void");
     public static final Type BOOLEAN_TYPE = getType("boolean");
@@ -295,7 +295,7 @@ public final class Definition {
             staticMembers = new HashMap<>();
             members = new HashMap<>();
         }
-        
+
         private Struct(final Struct struct) {
             name = struct.name;
             clazz = struct.clazz;
@@ -379,6 +379,22 @@ public final class Definition {
         }
     }
 
+    /** Returns whether or not a non-array type exists. */
+    public static boolean isSimpleType(final String name) {
+        return INSTANCE.structsMap.containsKey(name);
+    }
+
+    /** Returns whether or not a type exists without an exception. */
+    public static boolean isType(final String name) {
+        try {
+            INSTANCE.getTypeInternal(name);
+
+            return true;
+        } catch (IllegalArgumentException exception) {
+            return false;
+        }
+    }
+
     /** Gets the type given by its name */
     public static Type getType(final String name) {
         return INSTANCE.getTypeInternal(name);
@@ -388,13 +404,13 @@ public final class Definition {
     public static Type getType(final Struct struct, final int dimensions) {
         return INSTANCE.getTypeInternal(struct, dimensions);
     }
-    
+
     public static RuntimeClass getRuntimeClass(Class<?> clazz) {
         return INSTANCE.runtimeMap.get(clazz);
     }
-    
+
     // INTERNAL IMPLEMENTATION:
-    
+
     private final Map<Class<?>, RuntimeClass> runtimeMap;
     private final Map<String, Struct> structsMap;
     private final Map<String, Type> simpleTypesMap;
@@ -864,15 +880,17 @@ public final class Definition {
         runtimeMap.put(struct.clazz, new RuntimeClass(methods, getters, setters));
     }
 
-    private Type getTypeInternal(final String name) {
+    private Type getTypeInternal(String name) {
         // simple types (e.g. 0 array dimensions) are a simple hash lookup for speed
         Type simple = simpleTypesMap.get(name);
+
         if (simple != null) {
             return simple;
         }
-        final int dimensions = getDimensions(name);
-        final String structstr = dimensions == 0 ? name : name.substring(0, name.indexOf('['));
-        final Struct struct = structsMap.get(structstr);
+
+        int dimensions = getDimensions(name);
+        String structstr = dimensions == 0 ? name : name.substring(0, name.indexOf('['));
+        Struct struct = structsMap.get(structstr);
 
         if (struct == null) {
             throw new IllegalArgumentException("The struct with name [" + name + "] has not been defined.");
@@ -881,29 +899,29 @@ public final class Definition {
         return getTypeInternal(struct, dimensions);
     }
 
-    private Type getTypeInternal(final Struct struct, final int dimensions) {
+    private Type getTypeInternal(Struct struct, int dimensions) {
         String name = struct.name;
         org.objectweb.asm.Type type = struct.type;
         Class<?> clazz = struct.clazz;
         Sort sort;
 
         if (dimensions > 0) {
-            final StringBuilder builder = new StringBuilder(name);
-            final char[] brackets = new char[dimensions];
+            StringBuilder builder = new StringBuilder(name);
+            char[] brackets = new char[dimensions];
 
             for (int count = 0; count < dimensions; ++count) {
                 builder.append("[]");
                 brackets[count] = '[';
             }
 
-            final String descriptor = new String(brackets) + struct.type.getDescriptor();
+            String descriptor = new String(brackets) + struct.type.getDescriptor();
 
             name = builder.toString();
             type = org.objectweb.asm.Type.getType(descriptor);
 
             try {
                 clazz = Class.forName(type.getInternalName().replace('/', '.'));
-            } catch (final ClassNotFoundException exception) {
+            } catch (ClassNotFoundException exception) {
                 throw new IllegalArgumentException("The class [" + type.getInternalName() + "]" +
                     " could not be found to create type [" + name + "].");
             }
@@ -914,7 +932,7 @@ public final class Definition {
         } else {
             sort = Sort.OBJECT;
 
-            for (final Sort value : Sort.values()) {
+            for (Sort value : Sort.values()) {
                 if (value.clazz == null) {
                     continue;
                 }
@@ -930,12 +948,12 @@ public final class Definition {
         return new Type(name, dimensions, struct, clazz, type, sort);
     }
 
-    private int getDimensions(final String name) {
+    private int getDimensions(String name) {
         int dimensions = 0;
         int index = name.indexOf('[');
 
         if (index != -1) {
-            final int length = name.length();
+            int length = name.length();
 
             while (index < length) {
                 if (name.charAt(index) == '[' && ++index < length && name.charAt(index++) == ']') {

+ 6 - 0
modules/lang-painless/src/main/java/org/elasticsearch/painless/PainlessScriptEngineService.java

@@ -121,6 +121,12 @@ public final class PainlessScriptEngineService extends AbstractComponent impleme
                 compilerSettings.setMaxLoopCounter(Integer.parseInt(value));
             }
 
+            value = copy.remove(CompilerSettings.PICKY);
+
+            if (value != null) {
+                compilerSettings.setPicky(Boolean.parseBoolean(value));
+            }
+
             if (!copy.isEmpty()) {
                 throw new IllegalArgumentException("Unrecognized compile-time parameter(s): " + copy);
             }

+ 23 - 39
modules/lang-painless/src/main/java/org/elasticsearch/painless/Variables.java

@@ -50,7 +50,7 @@ public final class Variables {
         boolean ctx = false;
         boolean loop = false;
 
-        public void markReserved(final String name) {
+        public void markReserved(String name) {
             if (SCORE.equals(name)) {
                 score = true;
             } else if (CTX.equals(name)) {
@@ -58,7 +58,7 @@ public final class Variables {
             }
         }
 
-        public boolean isReserved(final String name) {
+        public boolean isReserved(String name) {
             return name.equals(THIS) || name.equals(PARAMS) || name.equals(SCORER) || name.equals(DOC) ||
                 name.equals(VALUE) || name.equals(SCORE) || name.equals(CTX) || name.equals(LOOP);
          }
@@ -77,7 +77,7 @@ public final class Variables {
 
         public boolean read = false;
 
-        private Variable(final String location, final String name, final Type type, final int slot, final boolean readonly) {
+        private Variable(String location, String name, Type type, int slot, boolean readonly) {
             this.location = location;
             this.name = name;
             this.type = type;
@@ -91,7 +91,7 @@ public final class Variables {
     private final Deque<Integer> scopes = new ArrayDeque<>();
     private final Deque<Variable> variables = new ArrayDeque<>();
 
-    public Variables(final CompilerSettings settings, final Reserved reserved) {
+    public Variables(Reserved reserved) {
         this.reserved = reserved;
 
         incrementScope();
@@ -99,35 +99,35 @@ public final class Variables {
         // Method variables.
 
         // This reference.  Internal use only.
-        addVariable("[" + Reserved.THIS + "]"  , "Executable", Reserved.THIS  , true, true);
+        addVariable("[" + Reserved.THIS + "]", Definition.getType("Executable"), Reserved.THIS, true, true);
 
-        // Input map of variables passed to the script.  TODO: Rename to 'params' since that will be its use.
-        addVariable("[" + Reserved.PARAMS + "]", "Map", Reserved.PARAMS, true, true);
+        // Input map of variables passed to the script.
+        addVariable("[" + Reserved.PARAMS + "]", Definition.getType("Map"), Reserved.PARAMS, true, true);
 
         // Scorer parameter passed to the script.  Internal use only.
-        addVariable("[" + Reserved.SCORER + "]", "def", Reserved.SCORER, true, true);
+        addVariable("[" + Reserved.SCORER + "]", Definition.DEF_TYPE, Reserved.SCORER, true, true);
 
         // Doc parameter passed to the script. TODO: Currently working as a Map, we can do better?
-        addVariable("[" + Reserved.DOC + "]"   , "Map", Reserved.DOC   , true, true);
+        addVariable("[" + Reserved.DOC + "]", Definition.getType("Map"), Reserved.DOC, true, true);
 
         // Aggregation _value parameter passed to the script.
-        addVariable("[" + Reserved.VALUE + "]" , "def", Reserved.VALUE , true, true);
+        addVariable("[" + Reserved.VALUE + "]", Definition.DEF_TYPE, Reserved.VALUE, true, true);
 
         // Shortcut variables.
 
         // Document's score as a read-only double.
         if (reserved.score) {
-            addVariable("[" + Reserved.SCORE + "]", "double", Reserved.SCORE, true, true);
+            addVariable("[" + Reserved.SCORE + "]", Definition.DOUBLE_TYPE, Reserved.SCORE, true, true);
         }
 
         // The ctx map set by executable scripts as a read-only map.
         if (reserved.ctx) {
-            addVariable("[" + Reserved.CTX + "]", "Map", Reserved.CTX, true, true);
+            addVariable("[" + Reserved.CTX + "]", Definition.getType("Map"), Reserved.CTX, true, true);
         }
 
         // Loop counter to catch infinite loops.  Internal use only.
-        if (reserved.loop && settings.getMaxLoopCounter() > 0) {
-            addVariable("[" + Reserved.LOOP + "]", "int", Reserved.LOOP, true, true);
+        if (reserved.loop) {
+            addVariable("[" + Reserved.LOOP + "]", Definition.INT_TYPE, Reserved.LOOP, true, true);
         }
     }
 
@@ -139,7 +139,7 @@ public final class Variables {
         int remove = scopes.pop();
 
         while (remove > 0) {
-            final Variable variable = variables.pop();
+             Variable variable = variables.pop();
 
             if (variable.read) {
                 throw new IllegalArgumentException("Error [" + variable.location + "]: Variable [" + variable.name + "] never used.");
@@ -149,11 +149,11 @@ public final class Variables {
         }
     }
 
-    public Variable getVariable(final String location, final String name) {
-        final Iterator<Variable> itr = variables.iterator();
+    public Variable getVariable(String location, String name) {
+         Iterator<Variable> itr = variables.iterator();
 
         while (itr.hasNext()) {
-            final Variable variable = itr.next();
+             Variable variable = itr.next();
 
             if (variable.name.equals(name)) {
                 return variable;
@@ -167,8 +167,7 @@ public final class Variables {
         return null;
     }
 
-    public Variable addVariable(final String location, final String typestr, final String name,
-                                final boolean readonly, final boolean reserved) {
+    public Variable addVariable(String location, Type type, String name, boolean readonly, boolean reserved) {
         if (!reserved && this.reserved.isReserved(name)) {
             throw new IllegalArgumentException("Error " + location + ": Variable name [" + name + "] is reserved.");
         }
@@ -177,38 +176,23 @@ public final class Variables {
             throw new IllegalArgumentException("Error " + location + ": Variable name [" + name + "] already defined.");
         }
 
-        final Type type;
-
-        try {
-            type = Definition.getType(typestr);
-        } catch (final IllegalArgumentException exception) {
-            throw new IllegalArgumentException("Error " + location + ": Not a type [" + typestr + "].");
-        }
-
-        boolean legal = !name.contains("<");
-
         try {
             Definition.getType(name);
-            legal = false;
-        } catch (final IllegalArgumentException exception) {
+        } catch (IllegalArgumentException exception) {
             // Do nothing.
         }
 
-        if (!legal) {
-            throw new IllegalArgumentException("Error " + location + ": Variable name [" + name + "] cannot be a type.");
-        }
-
-        final Variable previous = variables.peekFirst();
+        Variable previous = variables.peekFirst();
         int slot = 0;
 
         if (previous != null) {
             slot = previous.slot + previous.type.type.getSize();
         }
 
-        final Variable variable = new Variable(location, name, type, slot, readonly);
+        Variable variable = new Variable(location, name, type, slot, readonly);
         variables.push(variable);
 
-        final int update = scopes.pop() + 1;
+        int update = scopes.pop() + 1;
         scopes.push(update);
 
         return variable;

+ 199 - 174
modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessLexer.java

@@ -1,5 +1,8 @@
 // ANTLR GENERATED CODE: DO NOT EDIT
 package org.elasticsearch.painless.antlr;
+
+import org.elasticsearch.painless.Definition;
+
 import org.antlr.v4.runtime.Lexer;
 import org.antlr.v4.runtime.CharStream;
 import org.antlr.v4.runtime.Token;
@@ -25,10 +28,10 @@ class PainlessLexer extends Lexer {
     BWOR=44, BOOLAND=45, BOOLOR=46, COND=47, COLON=48, INCR=49, DECR=50, ASSIGN=51, 
     AADD=52, ASUB=53, AMUL=54, ADIV=55, AREM=56, AAND=57, AXOR=58, AOR=59, 
     ALSH=60, ARSH=61, AUSH=62, OCTAL=63, HEX=64, INTEGER=65, DECIMAL=66, STRING=67, 
-    TRUE=68, FALSE=69, NULL=70, ID=71, EXTINTEGER=72, EXTID=73;
-  public static final int EXT = 1;
+    TRUE=68, FALSE=69, NULL=70, TYPE=71, ID=72, DOTINTEGER=73, DOTID=74;
+  public static final int AFTER_DOT = 1;
   public static String[] modeNames = {
-    "DEFAULT_MODE", "EXT"
+    "DEFAULT_MODE", "AFTER_DOT"
   };
 
   public static final String[] ruleNames = {
@@ -39,8 +42,8 @@ class PainlessLexer extends Lexer {
     "GTE", "EQ", "EQR", "NE", "NER", "BWAND", "XOR", "BWOR", "BOOLAND", "BOOLOR", 
     "COND", "COLON", "INCR", "DECR", "ASSIGN", "AADD", "ASUB", "AMUL", "ADIV", 
     "AREM", "AAND", "AXOR", "AOR", "ALSH", "ARSH", "AUSH", "OCTAL", "HEX", 
-    "INTEGER", "DECIMAL", "STRING", "TRUE", "FALSE", "NULL", "ID", "EXTINTEGER", 
-    "EXTID"
+    "INTEGER", "DECIMAL", "STRING", "TRUE", "FALSE", "NULL", "TYPE", "ID", 
+    "DOTINTEGER", "DOTID"
   };
 
   private static final String[] _LITERAL_NAMES = {
@@ -61,8 +64,8 @@ class PainlessLexer extends Lexer {
     "GTE", "EQ", "EQR", "NE", "NER", "BWAND", "XOR", "BWOR", "BOOLAND", "BOOLOR", 
     "COND", "COLON", "INCR", "DECR", "ASSIGN", "AADD", "ASUB", "AMUL", "ADIV", 
     "AREM", "AAND", "AXOR", "AOR", "ALSH", "ARSH", "AUSH", "OCTAL", "HEX", 
-    "INTEGER", "DECIMAL", "STRING", "TRUE", "FALSE", "NULL", "ID", "EXTINTEGER", 
-    "EXTID"
+    "INTEGER", "DECIMAL", "STRING", "TRUE", "FALSE", "NULL", "TYPE", "ID", 
+    "DOTINTEGER", "DOTID"
   };
   public static final Vocabulary VOCABULARY = new VocabularyImpl(_LITERAL_NAMES, _SYMBOLIC_NAMES);
 
@@ -118,8 +121,24 @@ class PainlessLexer extends Lexer {
   @Override
   public ATN getATN() { return _ATN; }
 
+  @Override
+  public boolean sempred(RuleContext _localctx, int ruleIndex, int predIndex) {
+    switch (ruleIndex) {
+    case 70:
+      return TYPE_sempred((RuleContext)_localctx, predIndex);
+    }
+    return true;
+  }
+  private boolean TYPE_sempred(RuleContext _localctx, int predIndex) {
+    switch (predIndex) {
+    case 0:
+      return  Definition.isSimpleType(getText()) ;
+    }
+    return true;
+  }
+
   public static final String _serializedATN =
-    "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2K\u01fb\b\1\b\1\4"+
+    "\3\u0430\ud6d1\u8206\uad2d\u4417\uaef1\u8d80\uaadd\2L\u0209\b\1\b\1\4"+
     "\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n"+
     "\4\13\t\13\4\f\t\f\4\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22"+
     "\t\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30\t\30\4\31"+
@@ -128,172 +147,178 @@ class PainlessLexer extends Lexer {
     "+\4,\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63\t\63\4\64"+
     "\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\49\t9\4:\t:\4;\t;\4<\t<\4=\t"+
     "=\4>\t>\4?\t?\4@\t@\4A\tA\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4"+
-    "I\tI\4J\tJ\3\2\6\2\u0098\n\2\r\2\16\2\u0099\3\2\3\2\3\3\3\3\3\3\3\3\7"+
-    "\3\u00a2\n\3\f\3\16\3\u00a5\13\3\3\3\3\3\3\3\3\3\3\3\7\3\u00ac\n\3\f\3"+
-    "\16\3\u00af\13\3\3\3\3\3\5\3\u00b3\n\3\3\3\3\3\3\4\3\4\3\5\3\5\3\6\3\6"+
-    "\3\7\3\7\3\b\3\b\3\t\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\f\3\f\3\r\3\r\3\r"+
-    "\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\17\3\20\3\20\3\20"+
-    "\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\23"+
-    "\3\23\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\25\3\25"+
-    "\3\25\3\25\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3\27\3\27\3\27\3\30\3\30"+
-    "\3\30\3\30\3\30\3\30\3\31\3\31\3\32\3\32\3\33\3\33\3\34\3\34\3\35\3\35"+
-    "\3\36\3\36\3\37\3\37\3 \3 \3 \3!\3!\3!\3\"\3\"\3\"\3\"\3#\3#\3$\3$\3$"+
-    "\3%\3%\3&\3&\3&\3\'\3\'\3\'\3(\3(\3(\3(\3)\3)\3)\3*\3*\3*\3*\3+\3+\3,"+
-    "\3,\3-\3-\3.\3.\3.\3/\3/\3/\3\60\3\60\3\61\3\61\3\62\3\62\3\62\3\63\3"+
-    "\63\3\63\3\64\3\64\3\65\3\65\3\65\3\66\3\66\3\66\3\67\3\67\3\67\38\38"+
-    "\38\39\39\39\3:\3:\3:\3;\3;\3;\3<\3<\3<\3=\3=\3=\3=\3>\3>\3>\3>\3?\3?"+
-    "\3?\3?\3?\3@\3@\6@\u0179\n@\r@\16@\u017a\3@\5@\u017e\n@\3A\3A\3A\6A\u0183"+
-    "\nA\rA\16A\u0184\3A\5A\u0188\nA\3B\3B\3B\7B\u018d\nB\fB\16B\u0190\13B"+
-    "\5B\u0192\nB\3B\5B\u0195\nB\3C\3C\3C\7C\u019a\nC\fC\16C\u019d\13C\5C\u019f"+
-    "\nC\3C\3C\7C\u01a3\nC\fC\16C\u01a6\13C\3C\3C\5C\u01aa\nC\3C\6C\u01ad\n"+
-    "C\rC\16C\u01ae\5C\u01b1\nC\3C\5C\u01b4\nC\3D\3D\3D\3D\3D\3D\7D\u01bc\n"+
-    "D\fD\16D\u01bf\13D\3D\3D\3D\3D\3D\3D\3D\7D\u01c8\nD\fD\16D\u01cb\13D\3"+
-    "D\5D\u01ce\nD\3E\3E\3E\3E\3E\3F\3F\3F\3F\3F\3F\3G\3G\3G\3G\3G\3H\3H\7"+
-    "H\u01e2\nH\fH\16H\u01e5\13H\3I\3I\3I\7I\u01ea\nI\fI\16I\u01ed\13I\5I\u01ef"+
-    "\nI\3I\3I\3J\3J\7J\u01f5\nJ\fJ\16J\u01f8\13J\3J\3J\6\u00a3\u00ad\u01bd"+
-    "\u01c9\2K\4\3\6\4\b\5\n\6\f\7\16\b\20\t\22\n\24\13\26\f\30\r\32\16\34"+
-    "\17\36\20 \21\"\22$\23&\24(\25*\26,\27.\30\60\31\62\32\64\33\66\348\35"+
-    ":\36<\37> @!B\"D#F$H%J&L\'N(P)R*T+V,X-Z.\\/^\60`\61b\62d\63f\64h\65j\66"+
-    "l\67n8p9r:t;v<x=z>|?~@\u0080A\u0082B\u0084C\u0086D\u0088E\u008aF\u008c"+
-    "G\u008eH\u0090I\u0092J\u0094K\4\2\3\21\5\2\13\f\17\17\"\"\4\2\f\f\17\17"+
-    "\3\2\629\4\2NNnn\4\2ZZzz\5\2\62;CHch\3\2\63;\3\2\62;\b\2FFHHNNffhhnn\4"+
-    "\2GGgg\4\2--//\4\2HHhh\4\2$$^^\5\2C\\aac|\6\2\62;C\\aac|\u0216\2\4\3\2"+
-    "\2\2\2\6\3\2\2\2\2\b\3\2\2\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16\3\2\2\2\2\20"+
-    "\3\2\2\2\2\22\3\2\2\2\2\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32\3\2"+
-    "\2\2\2\34\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2\2\2\2$\3\2\2\2\2&\3"+
-    "\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2\62\3"+
-    "\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\28\3\2\2\2\2:\3\2\2\2\2<\3\2\2\2\2>\3"+
-    "\2\2\2\2@\3\2\2\2\2B\3\2\2\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3\2\2"+
-    "\2\2L\3\2\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2\2\2\2V\3\2\2\2\2"+
-    "X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2\2^\3\2\2\2\2`\3\2\2\2\2b\3\2\2\2\2d\3"+
-    "\2\2\2\2f\3\2\2\2\2h\3\2\2\2\2j\3\2\2\2\2l\3\2\2\2\2n\3\2\2\2\2p\3\2\2"+
-    "\2\2r\3\2\2\2\2t\3\2\2\2\2v\3\2\2\2\2x\3\2\2\2\2z\3\2\2\2\2|\3\2\2\2\2"+
-    "~\3\2\2\2\2\u0080\3\2\2\2\2\u0082\3\2\2\2\2\u0084\3\2\2\2\2\u0086\3\2"+
-    "\2\2\2\u0088\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2\2\u008e\3\2\2\2\2"+
-    "\u0090\3\2\2\2\3\u0092\3\2\2\2\3\u0094\3\2\2\2\4\u0097\3\2\2\2\6\u00b2"+
-    "\3\2\2\2\b\u00b6\3\2\2\2\n\u00b8\3\2\2\2\f\u00ba\3\2\2\2\16\u00bc\3\2"+
-    "\2\2\20\u00be\3\2\2\2\22\u00c0\3\2\2\2\24\u00c2\3\2\2\2\26\u00c6\3\2\2"+
-    "\2\30\u00c8\3\2\2\2\32\u00ca\3\2\2\2\34\u00cd\3\2\2\2\36\u00d2\3\2\2\2"+
-    " \u00d8\3\2\2\2\"\u00db\3\2\2\2$\u00df\3\2\2\2&\u00e8\3\2\2\2(\u00ee\3"+
-    "\2\2\2*\u00f5\3\2\2\2,\u00f9\3\2\2\2.\u00fd\3\2\2\2\60\u0103\3\2\2\2\62"+
-    "\u0109\3\2\2\2\64\u010b\3\2\2\2\66\u010d\3\2\2\28\u010f\3\2\2\2:\u0111"+
-    "\3\2\2\2<\u0113\3\2\2\2>\u0115\3\2\2\2@\u0117\3\2\2\2B\u011a\3\2\2\2D"+
-    "\u011d\3\2\2\2F\u0121\3\2\2\2H\u0123\3\2\2\2J\u0126\3\2\2\2L\u0128\3\2"+
-    "\2\2N\u012b\3\2\2\2P\u012e\3\2\2\2R\u0132\3\2\2\2T\u0135\3\2\2\2V\u0139"+
-    "\3\2\2\2X\u013b\3\2\2\2Z\u013d\3\2\2\2\\\u013f\3\2\2\2^\u0142\3\2\2\2"+
-    "`\u0145\3\2\2\2b\u0147\3\2\2\2d\u0149\3\2\2\2f\u014c\3\2\2\2h\u014f\3"+
-    "\2\2\2j\u0151\3\2\2\2l\u0154\3\2\2\2n\u0157\3\2\2\2p\u015a\3\2\2\2r\u015d"+
-    "\3\2\2\2t\u0160\3\2\2\2v\u0163\3\2\2\2x\u0166\3\2\2\2z\u0169\3\2\2\2|"+
-    "\u016d\3\2\2\2~\u0171\3\2\2\2\u0080\u0176\3\2\2\2\u0082\u017f\3\2\2\2"+
-    "\u0084\u0191\3\2\2\2\u0086\u019e\3\2\2\2\u0088\u01cd\3\2\2\2\u008a\u01cf"+
-    "\3\2\2\2\u008c\u01d4\3\2\2\2\u008e\u01da\3\2\2\2\u0090\u01df\3\2\2\2\u0092"+
-    "\u01ee\3\2\2\2\u0094\u01f2\3\2\2\2\u0096\u0098\t\2\2\2\u0097\u0096\3\2"+
-    "\2\2\u0098\u0099\3\2\2\2\u0099\u0097\3\2\2\2\u0099\u009a\3\2\2\2\u009a"+
-    "\u009b\3\2\2\2\u009b\u009c\b\2\2\2\u009c\5\3\2\2\2\u009d\u009e\7\61\2"+
-    "\2\u009e\u009f\7\61\2\2\u009f\u00a3\3\2\2\2\u00a0\u00a2\13\2\2\2\u00a1"+
-    "\u00a0\3\2\2\2\u00a2\u00a5\3\2\2\2\u00a3\u00a4\3\2\2\2\u00a3\u00a1\3\2"+
-    "\2\2\u00a4\u00a6\3\2\2\2\u00a5\u00a3\3\2\2\2\u00a6\u00b3\t\3\2\2\u00a7"+
-    "\u00a8\7\61\2\2\u00a8\u00a9\7,\2\2\u00a9\u00ad\3\2\2\2\u00aa\u00ac\13"+
-    "\2\2\2\u00ab\u00aa\3\2\2\2\u00ac\u00af\3\2\2\2\u00ad\u00ae\3\2\2\2\u00ad"+
-    "\u00ab\3\2\2\2\u00ae\u00b0\3\2\2\2\u00af\u00ad\3\2\2\2\u00b0\u00b1\7,"+
-    "\2\2\u00b1\u00b3\7\61\2\2\u00b2\u009d\3\2\2\2\u00b2\u00a7\3\2\2\2\u00b3"+
-    "\u00b4\3\2\2\2\u00b4\u00b5\b\3\2\2\u00b5\7\3\2\2\2\u00b6\u00b7\7}\2\2"+
-    "\u00b7\t\3\2\2\2\u00b8\u00b9\7\177\2\2\u00b9\13\3\2\2\2\u00ba\u00bb\7"+
-    "]\2\2\u00bb\r\3\2\2\2\u00bc\u00bd\7_\2\2\u00bd\17\3\2\2\2\u00be\u00bf"+
-    "\7*\2\2\u00bf\21\3\2\2\2\u00c0\u00c1\7+\2\2\u00c1\23\3\2\2\2\u00c2\u00c3"+
-    "\7\60\2\2\u00c3\u00c4\3\2\2\2\u00c4\u00c5\b\n\3\2\u00c5\25\3\2\2\2\u00c6"+
-    "\u00c7\7.\2\2\u00c7\27\3\2\2\2\u00c8\u00c9\7=\2\2\u00c9\31\3\2\2\2\u00ca"+
-    "\u00cb\7k\2\2\u00cb\u00cc\7h\2\2\u00cc\33\3\2\2\2\u00cd\u00ce\7g\2\2\u00ce"+
-    "\u00cf\7n\2\2\u00cf\u00d0\7u\2\2\u00d0\u00d1\7g\2\2\u00d1\35\3\2\2\2\u00d2"+
-    "\u00d3\7y\2\2\u00d3\u00d4\7j\2\2\u00d4\u00d5\7k\2\2\u00d5\u00d6\7n\2\2"+
-    "\u00d6\u00d7\7g\2\2\u00d7\37\3\2\2\2\u00d8\u00d9\7f\2\2\u00d9\u00da\7"+
-    "q\2\2\u00da!\3\2\2\2\u00db\u00dc\7h\2\2\u00dc\u00dd\7q\2\2\u00dd\u00de"+
-    "\7t\2\2\u00de#\3\2\2\2\u00df\u00e0\7e\2\2\u00e0\u00e1\7q\2\2\u00e1\u00e2"+
-    "\7p\2\2\u00e2\u00e3\7v\2\2\u00e3\u00e4\7k\2\2\u00e4\u00e5\7p\2\2\u00e5"+
-    "\u00e6\7w\2\2\u00e6\u00e7\7g\2\2\u00e7%\3\2\2\2\u00e8\u00e9\7d\2\2\u00e9"+
-    "\u00ea\7t\2\2\u00ea\u00eb\7g\2\2\u00eb\u00ec\7c\2\2\u00ec\u00ed\7m\2\2"+
-    "\u00ed\'\3\2\2\2\u00ee\u00ef\7t\2\2\u00ef\u00f0\7g\2\2\u00f0\u00f1\7v"+
-    "\2\2\u00f1\u00f2\7w\2\2\u00f2\u00f3\7t\2\2\u00f3\u00f4\7p\2\2\u00f4)\3"+
-    "\2\2\2\u00f5\u00f6\7p\2\2\u00f6\u00f7\7g\2\2\u00f7\u00f8\7y\2\2\u00f8"+
-    "+\3\2\2\2\u00f9\u00fa\7v\2\2\u00fa\u00fb\7t\2\2\u00fb\u00fc\7{\2\2\u00fc"+
-    "-\3\2\2\2\u00fd\u00fe\7e\2\2\u00fe\u00ff\7c\2\2\u00ff\u0100\7v\2\2\u0100"+
-    "\u0101\7e\2\2\u0101\u0102\7j\2\2\u0102/\3\2\2\2\u0103\u0104\7v\2\2\u0104"+
-    "\u0105\7j\2\2\u0105\u0106\7t\2\2\u0106\u0107\7q\2\2\u0107\u0108\7y\2\2"+
-    "\u0108\61\3\2\2\2\u0109\u010a\7#\2\2\u010a\63\3\2\2\2\u010b\u010c\7\u0080"+
-    "\2\2\u010c\65\3\2\2\2\u010d\u010e\7,\2\2\u010e\67\3\2\2\2\u010f\u0110"+
-    "\7\61\2\2\u01109\3\2\2\2\u0111\u0112\7\'\2\2\u0112;\3\2\2\2\u0113\u0114"+
-    "\7-\2\2\u0114=\3\2\2\2\u0115\u0116\7/\2\2\u0116?\3\2\2\2\u0117\u0118\7"+
-    ">\2\2\u0118\u0119\7>\2\2\u0119A\3\2\2\2\u011a\u011b\7@\2\2\u011b\u011c"+
-    "\7@\2\2\u011cC\3\2\2\2\u011d\u011e\7@\2\2\u011e\u011f\7@\2\2\u011f\u0120"+
-    "\7@\2\2\u0120E\3\2\2\2\u0121\u0122\7>\2\2\u0122G\3\2\2\2\u0123\u0124\7"+
-    ">\2\2\u0124\u0125\7?\2\2\u0125I\3\2\2\2\u0126\u0127\7@\2\2\u0127K\3\2"+
-    "\2\2\u0128\u0129\7@\2\2\u0129\u012a\7?\2\2\u012aM\3\2\2\2\u012b\u012c"+
-    "\7?\2\2\u012c\u012d\7?\2\2\u012dO\3\2\2\2\u012e\u012f\7?\2\2\u012f\u0130"+
-    "\7?\2\2\u0130\u0131\7?\2\2\u0131Q\3\2\2\2\u0132\u0133\7#\2\2\u0133\u0134"+
-    "\7?\2\2\u0134S\3\2\2\2\u0135\u0136\7#\2\2\u0136\u0137\7?\2\2\u0137\u0138"+
-    "\7?\2\2\u0138U\3\2\2\2\u0139\u013a\7(\2\2\u013aW\3\2\2\2\u013b\u013c\7"+
-    "`\2\2\u013cY\3\2\2\2\u013d\u013e\7~\2\2\u013e[\3\2\2\2\u013f\u0140\7("+
-    "\2\2\u0140\u0141\7(\2\2\u0141]\3\2\2\2\u0142\u0143\7~\2\2\u0143\u0144"+
-    "\7~\2\2\u0144_\3\2\2\2\u0145\u0146\7A\2\2\u0146a\3\2\2\2\u0147\u0148\7"+
-    "<\2\2\u0148c\3\2\2\2\u0149\u014a\7-\2\2\u014a\u014b\7-\2\2\u014be\3\2"+
-    "\2\2\u014c\u014d\7/\2\2\u014d\u014e\7/\2\2\u014eg\3\2\2\2\u014f\u0150"+
-    "\7?\2\2\u0150i\3\2\2\2\u0151\u0152\7-\2\2\u0152\u0153\7?\2\2\u0153k\3"+
-    "\2\2\2\u0154\u0155\7/\2\2\u0155\u0156\7?\2\2\u0156m\3\2\2\2\u0157\u0158"+
-    "\7,\2\2\u0158\u0159\7?\2\2\u0159o\3\2\2\2\u015a\u015b\7\61\2\2\u015b\u015c"+
-    "\7?\2\2\u015cq\3\2\2\2\u015d\u015e\7\'\2\2\u015e\u015f\7?\2\2\u015fs\3"+
-    "\2\2\2\u0160\u0161\7(\2\2\u0161\u0162\7?\2\2\u0162u\3\2\2\2\u0163\u0164"+
-    "\7`\2\2\u0164\u0165\7?\2\2\u0165w\3\2\2\2\u0166\u0167\7~\2\2\u0167\u0168"+
-    "\7?\2\2\u0168y\3\2\2\2\u0169\u016a\7>\2\2\u016a\u016b\7>\2\2\u016b\u016c"+
-    "\7?\2\2\u016c{\3\2\2\2\u016d\u016e\7@\2\2\u016e\u016f\7@\2\2\u016f\u0170"+
-    "\7?\2\2\u0170}\3\2\2\2\u0171\u0172\7@\2\2\u0172\u0173\7@\2\2\u0173\u0174"+
-    "\7@\2\2\u0174\u0175\7?\2\2\u0175\177\3\2\2\2\u0176\u0178\7\62\2\2\u0177"+
-    "\u0179\t\4\2\2\u0178\u0177\3\2\2\2\u0179\u017a\3\2\2\2\u017a\u0178\3\2"+
-    "\2\2\u017a\u017b\3\2\2\2\u017b\u017d\3\2\2\2\u017c\u017e\t\5\2\2\u017d"+
-    "\u017c\3\2\2\2\u017d\u017e\3\2\2\2\u017e\u0081\3\2\2\2\u017f\u0180\7\62"+
-    "\2\2\u0180\u0182\t\6\2\2\u0181\u0183\t\7\2\2\u0182\u0181\3\2\2\2\u0183"+
-    "\u0184\3\2\2\2\u0184\u0182\3\2\2\2\u0184\u0185\3\2\2\2\u0185\u0187\3\2"+
-    "\2\2\u0186\u0188\t\5\2\2\u0187\u0186\3\2\2\2\u0187\u0188\3\2\2\2\u0188"+
-    "\u0083\3\2\2\2\u0189\u0192\7\62\2\2\u018a\u018e\t\b\2\2\u018b\u018d\t"+
-    "\t\2\2\u018c\u018b\3\2\2\2\u018d\u0190\3\2\2\2\u018e\u018c\3\2\2\2\u018e"+
-    "\u018f\3\2\2\2\u018f\u0192\3\2\2\2\u0190\u018e\3\2\2\2\u0191\u0189\3\2"+
-    "\2\2\u0191\u018a\3\2\2\2\u0192\u0194\3\2\2\2\u0193\u0195\t\n\2\2\u0194"+
-    "\u0193\3\2\2\2\u0194\u0195\3\2\2\2\u0195\u0085\3\2\2\2\u0196\u019f\7\62"+
-    "\2\2\u0197\u019b\t\b\2\2\u0198\u019a\t\t\2\2\u0199\u0198\3\2\2\2\u019a"+
-    "\u019d\3\2\2\2\u019b\u0199\3\2\2\2\u019b\u019c\3\2\2\2\u019c\u019f\3\2"+
-    "\2\2\u019d\u019b\3\2\2\2\u019e\u0196\3\2\2\2\u019e\u0197\3\2\2\2\u019f"+
-    "\u01a0\3\2\2\2\u01a0\u01a4\5\24\n\2\u01a1\u01a3\t\t\2\2\u01a2\u01a1\3"+
-    "\2\2\2\u01a3\u01a6\3\2\2\2\u01a4\u01a2\3\2\2\2\u01a4\u01a5\3\2\2\2\u01a5"+
-    "\u01b0\3\2\2\2\u01a6\u01a4\3\2\2\2\u01a7\u01a9\t\13\2\2\u01a8\u01aa\t"+
-    "\f\2\2\u01a9\u01a8\3\2\2\2\u01a9\u01aa\3\2\2\2\u01aa\u01ac\3\2\2\2\u01ab"+
-    "\u01ad\t\t\2\2\u01ac\u01ab\3\2\2\2\u01ad\u01ae\3\2\2\2\u01ae\u01ac\3\2"+
-    "\2\2\u01ae\u01af\3\2\2\2\u01af\u01b1\3\2\2\2\u01b0\u01a7\3\2\2\2\u01b0"+
-    "\u01b1\3\2\2\2\u01b1\u01b3\3\2\2\2\u01b2\u01b4\t\r\2\2\u01b3\u01b2\3\2"+
-    "\2\2\u01b3\u01b4\3\2\2\2\u01b4\u0087\3\2\2\2\u01b5\u01bd\7$\2\2\u01b6"+
-    "\u01b7\7^\2\2\u01b7\u01bc\7$\2\2\u01b8\u01b9\7^\2\2\u01b9\u01bc\7^\2\2"+
-    "\u01ba\u01bc\n\16\2\2\u01bb\u01b6\3\2\2\2\u01bb\u01b8\3\2\2\2\u01bb\u01ba"+
-    "\3\2\2\2\u01bc\u01bf\3\2\2\2\u01bd\u01be\3\2\2\2\u01bd\u01bb\3\2\2\2\u01be"+
-    "\u01c0\3\2\2\2\u01bf\u01bd\3\2\2\2\u01c0\u01ce\7$\2\2\u01c1\u01c9\7)\2"+
-    "\2\u01c2\u01c3\7^\2\2\u01c3\u01c8\7)\2\2\u01c4\u01c5\7^\2\2\u01c5\u01c8"+
-    "\7^\2\2\u01c6\u01c8\n\16\2\2\u01c7\u01c2\3\2\2\2\u01c7\u01c4\3\2\2\2\u01c7"+
-    "\u01c6\3\2\2\2\u01c8\u01cb\3\2\2\2\u01c9\u01ca\3\2\2\2\u01c9\u01c7\3\2"+
-    "\2\2\u01ca\u01cc\3\2\2\2\u01cb\u01c9\3\2\2\2\u01cc\u01ce\7)\2\2\u01cd"+
-    "\u01b5\3\2\2\2\u01cd\u01c1\3\2\2\2\u01ce\u0089\3\2\2\2\u01cf\u01d0\7v"+
-    "\2\2\u01d0\u01d1\7t\2\2\u01d1\u01d2\7w\2\2\u01d2\u01d3\7g\2\2\u01d3\u008b"+
-    "\3\2\2\2\u01d4\u01d5\7h\2\2\u01d5\u01d6\7c\2\2\u01d6\u01d7\7n\2\2\u01d7"+
-    "\u01d8\7u\2\2\u01d8\u01d9\7g\2\2\u01d9\u008d\3\2\2\2\u01da\u01db\7p\2"+
-    "\2\u01db\u01dc\7w\2\2\u01dc\u01dd\7n\2\2\u01dd\u01de\7n\2\2\u01de\u008f"+
-    "\3\2\2\2\u01df\u01e3\t\17\2\2\u01e0\u01e2\t\20\2\2\u01e1\u01e0\3\2\2\2"+
-    "\u01e2\u01e5\3\2\2\2\u01e3\u01e1\3\2\2\2\u01e3\u01e4\3\2\2\2\u01e4\u0091"+
-    "\3\2\2\2\u01e5\u01e3\3\2\2\2\u01e6\u01ef\7\62\2\2\u01e7\u01eb\t\b\2\2"+
-    "\u01e8\u01ea\t\t\2\2\u01e9\u01e8\3\2\2\2\u01ea\u01ed\3\2\2\2\u01eb\u01e9"+
-    "\3\2\2\2\u01eb\u01ec\3\2\2\2\u01ec\u01ef\3\2\2\2\u01ed\u01eb\3\2\2\2\u01ee"+
-    "\u01e6\3\2\2\2\u01ee\u01e7\3\2\2\2\u01ef\u01f0\3\2\2\2\u01f0\u01f1\bI"+
-    "\4\2\u01f1\u0093\3\2\2\2\u01f2\u01f6\t\17\2\2\u01f3\u01f5\t\20\2\2\u01f4"+
-    "\u01f3\3\2\2\2\u01f5\u01f8\3\2\2\2\u01f6\u01f4\3\2\2\2\u01f6\u01f7\3\2"+
-    "\2\2\u01f7\u01f9\3\2\2\2\u01f8\u01f6\3\2\2\2\u01f9\u01fa\bJ\4\2\u01fa"+
-    "\u0095\3\2\2\2\37\2\3\u0099\u00a3\u00ad\u00b2\u017a\u017d\u0184\u0187"+
-    "\u018e\u0191\u0194\u019b\u019e\u01a4\u01a9\u01ae\u01b0\u01b3\u01bb\u01bd"+
-    "\u01c7\u01c9\u01cd\u01e3\u01eb\u01ee\u01f6\5\b\2\2\4\3\2\4\2\2";
+    "I\tI\4J\tJ\4K\tK\3\2\6\2\u009a\n\2\r\2\16\2\u009b\3\2\3\2\3\3\3\3\3\3"+
+    "\3\3\7\3\u00a4\n\3\f\3\16\3\u00a7\13\3\3\3\3\3\3\3\3\3\3\3\7\3\u00ae\n"+
+    "\3\f\3\16\3\u00b1\13\3\3\3\3\3\5\3\u00b5\n\3\3\3\3\3\3\4\3\4\3\5\3\5\3"+
+    "\6\3\6\3\7\3\7\3\b\3\b\3\t\3\t\3\n\3\n\3\n\3\n\3\13\3\13\3\f\3\f\3\r\3"+
+    "\r\3\r\3\16\3\16\3\16\3\16\3\16\3\17\3\17\3\17\3\17\3\17\3\17\3\20\3\20"+
+    "\3\20\3\21\3\21\3\21\3\21\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22\3\22"+
+    "\3\23\3\23\3\23\3\23\3\23\3\23\3\24\3\24\3\24\3\24\3\24\3\24\3\24\3\25"+
+    "\3\25\3\25\3\25\3\26\3\26\3\26\3\26\3\27\3\27\3\27\3\27\3\27\3\27\3\30"+
+    "\3\30\3\30\3\30\3\30\3\30\3\31\3\31\3\32\3\32\3\33\3\33\3\34\3\34\3\35"+
+    "\3\35\3\36\3\36\3\37\3\37\3 \3 \3 \3!\3!\3!\3\"\3\"\3\"\3\"\3#\3#\3$\3"+
+    "$\3$\3%\3%\3&\3&\3&\3\'\3\'\3\'\3(\3(\3(\3(\3)\3)\3)\3*\3*\3*\3*\3+\3"+
+    "+\3,\3,\3-\3-\3.\3.\3.\3/\3/\3/\3\60\3\60\3\61\3\61\3\62\3\62\3\62\3\63"+
+    "\3\63\3\63\3\64\3\64\3\65\3\65\3\65\3\66\3\66\3\66\3\67\3\67\3\67\38\3"+
+    "8\38\39\39\39\3:\3:\3:\3;\3;\3;\3<\3<\3<\3=\3=\3=\3=\3>\3>\3>\3>\3?\3"+
+    "?\3?\3?\3?\3@\3@\6@\u017b\n@\r@\16@\u017c\3@\5@\u0180\n@\3A\3A\3A\6A\u0185"+
+    "\nA\rA\16A\u0186\3A\5A\u018a\nA\3B\3B\3B\7B\u018f\nB\fB\16B\u0192\13B"+
+    "\5B\u0194\nB\3B\5B\u0197\nB\3C\3C\3C\7C\u019c\nC\fC\16C\u019f\13C\5C\u01a1"+
+    "\nC\3C\3C\6C\u01a5\nC\rC\16C\u01a6\5C\u01a9\nC\3C\3C\5C\u01ad\nC\3C\6"+
+    "C\u01b0\nC\rC\16C\u01b1\5C\u01b4\nC\3C\5C\u01b7\nC\3D\3D\3D\3D\3D\3D\7"+
+    "D\u01bf\nD\fD\16D\u01c2\13D\3D\3D\3D\3D\3D\3D\3D\7D\u01cb\nD\fD\16D\u01ce"+
+    "\13D\3D\5D\u01d1\nD\3E\3E\3E\3E\3E\3F\3F\3F\3F\3F\3F\3G\3G\3G\3G\3G\3"+
+    "H\3H\3H\3H\7H\u01e7\nH\fH\16H\u01ea\13H\3H\3H\3I\3I\7I\u01f0\nI\fI\16"+
+    "I\u01f3\13I\3J\3J\3J\7J\u01f8\nJ\fJ\16J\u01fb\13J\5J\u01fd\nJ\3J\3J\3"+
+    "K\3K\7K\u0203\nK\fK\16K\u0206\13K\3K\3K\6\u00a5\u00af\u01c0\u01cc\2L\4"+
+    "\3\6\4\b\5\n\6\f\7\16\b\20\t\22\n\24\13\26\f\30\r\32\16\34\17\36\20 \21"+
+    "\"\22$\23&\24(\25*\26,\27.\30\60\31\62\32\64\33\66\348\35:\36<\37> @!"+
+    "B\"D#F$H%J&L\'N(P)R*T+V,X-Z.\\/^\60`\61b\62d\63f\64h\65j\66l\67n8p9r:"+
+    "t;v<x=z>|?~@\u0080A\u0082B\u0084C\u0086D\u0088E\u008aF\u008cG\u008eH\u0090"+
+    "I\u0092J\u0094K\u0096L\4\2\3\22\5\2\13\f\17\17\"\"\4\2\f\f\17\17\3\2\62"+
+    "9\4\2NNnn\4\2ZZzz\5\2\62;CHch\3\2\63;\3\2\62;\b\2FFHHNNffhhnn\4\2GGgg"+
+    "\4\2--//\4\2HHhh\4\2$$^^\5\2C\\aac|\6\2\62;C\\aac|\4\2aac|\u0226\2\4\3"+
+    "\2\2\2\2\6\3\2\2\2\2\b\3\2\2\2\2\n\3\2\2\2\2\f\3\2\2\2\2\16\3\2\2\2\2"+
+    "\20\3\2\2\2\2\22\3\2\2\2\2\24\3\2\2\2\2\26\3\2\2\2\2\30\3\2\2\2\2\32\3"+
+    "\2\2\2\2\34\3\2\2\2\2\36\3\2\2\2\2 \3\2\2\2\2\"\3\2\2\2\2$\3\2\2\2\2&"+
+    "\3\2\2\2\2(\3\2\2\2\2*\3\2\2\2\2,\3\2\2\2\2.\3\2\2\2\2\60\3\2\2\2\2\62"+
+    "\3\2\2\2\2\64\3\2\2\2\2\66\3\2\2\2\28\3\2\2\2\2:\3\2\2\2\2<\3\2\2\2\2"+
+    ">\3\2\2\2\2@\3\2\2\2\2B\3\2\2\2\2D\3\2\2\2\2F\3\2\2\2\2H\3\2\2\2\2J\3"+
+    "\2\2\2\2L\3\2\2\2\2N\3\2\2\2\2P\3\2\2\2\2R\3\2\2\2\2T\3\2\2\2\2V\3\2\2"+
+    "\2\2X\3\2\2\2\2Z\3\2\2\2\2\\\3\2\2\2\2^\3\2\2\2\2`\3\2\2\2\2b\3\2\2\2"+
+    "\2d\3\2\2\2\2f\3\2\2\2\2h\3\2\2\2\2j\3\2\2\2\2l\3\2\2\2\2n\3\2\2\2\2p"+
+    "\3\2\2\2\2r\3\2\2\2\2t\3\2\2\2\2v\3\2\2\2\2x\3\2\2\2\2z\3\2\2\2\2|\3\2"+
+    "\2\2\2~\3\2\2\2\2\u0080\3\2\2\2\2\u0082\3\2\2\2\2\u0084\3\2\2\2\2\u0086"+
+    "\3\2\2\2\2\u0088\3\2\2\2\2\u008a\3\2\2\2\2\u008c\3\2\2\2\2\u008e\3\2\2"+
+    "\2\2\u0090\3\2\2\2\2\u0092\3\2\2\2\3\u0094\3\2\2\2\3\u0096\3\2\2\2\4\u0099"+
+    "\3\2\2\2\6\u00b4\3\2\2\2\b\u00b8\3\2\2\2\n\u00ba\3\2\2\2\f\u00bc\3\2\2"+
+    "\2\16\u00be\3\2\2\2\20\u00c0\3\2\2\2\22\u00c2\3\2\2\2\24\u00c4\3\2\2\2"+
+    "\26\u00c8\3\2\2\2\30\u00ca\3\2\2\2\32\u00cc\3\2\2\2\34\u00cf\3\2\2\2\36"+
+    "\u00d4\3\2\2\2 \u00da\3\2\2\2\"\u00dd\3\2\2\2$\u00e1\3\2\2\2&\u00ea\3"+
+    "\2\2\2(\u00f0\3\2\2\2*\u00f7\3\2\2\2,\u00fb\3\2\2\2.\u00ff\3\2\2\2\60"+
+    "\u0105\3\2\2\2\62\u010b\3\2\2\2\64\u010d\3\2\2\2\66\u010f\3\2\2\28\u0111"+
+    "\3\2\2\2:\u0113\3\2\2\2<\u0115\3\2\2\2>\u0117\3\2\2\2@\u0119\3\2\2\2B"+
+    "\u011c\3\2\2\2D\u011f\3\2\2\2F\u0123\3\2\2\2H\u0125\3\2\2\2J\u0128\3\2"+
+    "\2\2L\u012a\3\2\2\2N\u012d\3\2\2\2P\u0130\3\2\2\2R\u0134\3\2\2\2T\u0137"+
+    "\3\2\2\2V\u013b\3\2\2\2X\u013d\3\2\2\2Z\u013f\3\2\2\2\\\u0141\3\2\2\2"+
+    "^\u0144\3\2\2\2`\u0147\3\2\2\2b\u0149\3\2\2\2d\u014b\3\2\2\2f\u014e\3"+
+    "\2\2\2h\u0151\3\2\2\2j\u0153\3\2\2\2l\u0156\3\2\2\2n\u0159\3\2\2\2p\u015c"+
+    "\3\2\2\2r\u015f\3\2\2\2t\u0162\3\2\2\2v\u0165\3\2\2\2x\u0168\3\2\2\2z"+
+    "\u016b\3\2\2\2|\u016f\3\2\2\2~\u0173\3\2\2\2\u0080\u0178\3\2\2\2\u0082"+
+    "\u0181\3\2\2\2\u0084\u0193\3\2\2\2\u0086\u01a0\3\2\2\2\u0088\u01d0\3\2"+
+    "\2\2\u008a\u01d2\3\2\2\2\u008c\u01d7\3\2\2\2\u008e\u01dd\3\2\2\2\u0090"+
+    "\u01e2\3\2\2\2\u0092\u01ed\3\2\2\2\u0094\u01fc\3\2\2\2\u0096\u0200\3\2"+
+    "\2\2\u0098\u009a\t\2\2\2\u0099\u0098\3\2\2\2\u009a\u009b\3\2\2\2\u009b"+
+    "\u0099\3\2\2\2\u009b\u009c\3\2\2\2\u009c\u009d\3\2\2\2\u009d\u009e\b\2"+
+    "\2\2\u009e\5\3\2\2\2\u009f\u00a0\7\61\2\2\u00a0\u00a1\7\61\2\2\u00a1\u00a5"+
+    "\3\2\2\2\u00a2\u00a4\13\2\2\2\u00a3\u00a2\3\2\2\2\u00a4\u00a7\3\2\2\2"+
+    "\u00a5\u00a6\3\2\2\2\u00a5\u00a3\3\2\2\2\u00a6\u00a8\3\2\2\2\u00a7\u00a5"+
+    "\3\2\2\2\u00a8\u00b5\t\3\2\2\u00a9\u00aa\7\61\2\2\u00aa\u00ab\7,\2\2\u00ab"+
+    "\u00af\3\2\2\2\u00ac\u00ae\13\2\2\2\u00ad\u00ac\3\2\2\2\u00ae\u00b1\3"+
+    "\2\2\2\u00af\u00b0\3\2\2\2\u00af\u00ad\3\2\2\2\u00b0\u00b2\3\2\2\2\u00b1"+
+    "\u00af\3\2\2\2\u00b2\u00b3\7,\2\2\u00b3\u00b5\7\61\2\2\u00b4\u009f\3\2"+
+    "\2\2\u00b4\u00a9\3\2\2\2\u00b5\u00b6\3\2\2\2\u00b6\u00b7\b\3\2\2\u00b7"+
+    "\7\3\2\2\2\u00b8\u00b9\7}\2\2\u00b9\t\3\2\2\2\u00ba\u00bb\7\177\2\2\u00bb"+
+    "\13\3\2\2\2\u00bc\u00bd\7]\2\2\u00bd\r\3\2\2\2\u00be\u00bf\7_\2\2\u00bf"+
+    "\17\3\2\2\2\u00c0\u00c1\7*\2\2\u00c1\21\3\2\2\2\u00c2\u00c3\7+\2\2\u00c3"+
+    "\23\3\2\2\2\u00c4\u00c5\7\60\2\2\u00c5\u00c6\3\2\2\2\u00c6\u00c7\b\n\3"+
+    "\2\u00c7\25\3\2\2\2\u00c8\u00c9\7.\2\2\u00c9\27\3\2\2\2\u00ca\u00cb\7"+
+    "=\2\2\u00cb\31\3\2\2\2\u00cc\u00cd\7k\2\2\u00cd\u00ce\7h\2\2\u00ce\33"+
+    "\3\2\2\2\u00cf\u00d0\7g\2\2\u00d0\u00d1\7n\2\2\u00d1\u00d2\7u\2\2\u00d2"+
+    "\u00d3\7g\2\2\u00d3\35\3\2\2\2\u00d4\u00d5\7y\2\2\u00d5\u00d6\7j\2\2\u00d6"+
+    "\u00d7\7k\2\2\u00d7\u00d8\7n\2\2\u00d8\u00d9\7g\2\2\u00d9\37\3\2\2\2\u00da"+
+    "\u00db\7f\2\2\u00db\u00dc\7q\2\2\u00dc!\3\2\2\2\u00dd\u00de\7h\2\2\u00de"+
+    "\u00df\7q\2\2\u00df\u00e0\7t\2\2\u00e0#\3\2\2\2\u00e1\u00e2\7e\2\2\u00e2"+
+    "\u00e3\7q\2\2\u00e3\u00e4\7p\2\2\u00e4\u00e5\7v\2\2\u00e5\u00e6\7k\2\2"+
+    "\u00e6\u00e7\7p\2\2\u00e7\u00e8\7w\2\2\u00e8\u00e9\7g\2\2\u00e9%\3\2\2"+
+    "\2\u00ea\u00eb\7d\2\2\u00eb\u00ec\7t\2\2\u00ec\u00ed\7g\2\2\u00ed\u00ee"+
+    "\7c\2\2\u00ee\u00ef\7m\2\2\u00ef\'\3\2\2\2\u00f0\u00f1\7t\2\2\u00f1\u00f2"+
+    "\7g\2\2\u00f2\u00f3\7v\2\2\u00f3\u00f4\7w\2\2\u00f4\u00f5\7t\2\2\u00f5"+
+    "\u00f6\7p\2\2\u00f6)\3\2\2\2\u00f7\u00f8\7p\2\2\u00f8\u00f9\7g\2\2\u00f9"+
+    "\u00fa\7y\2\2\u00fa+\3\2\2\2\u00fb\u00fc\7v\2\2\u00fc\u00fd\7t\2\2\u00fd"+
+    "\u00fe\7{\2\2\u00fe-\3\2\2\2\u00ff\u0100\7e\2\2\u0100\u0101\7c\2\2\u0101"+
+    "\u0102\7v\2\2\u0102\u0103\7e\2\2\u0103\u0104\7j\2\2\u0104/\3\2\2\2\u0105"+
+    "\u0106\7v\2\2\u0106\u0107\7j\2\2\u0107\u0108\7t\2\2\u0108\u0109\7q\2\2"+
+    "\u0109\u010a\7y\2\2\u010a\61\3\2\2\2\u010b\u010c\7#\2\2\u010c\63\3\2\2"+
+    "\2\u010d\u010e\7\u0080\2\2\u010e\65\3\2\2\2\u010f\u0110\7,\2\2\u0110\67"+
+    "\3\2\2\2\u0111\u0112\7\61\2\2\u01129\3\2\2\2\u0113\u0114\7\'\2\2\u0114"+
+    ";\3\2\2\2\u0115\u0116\7-\2\2\u0116=\3\2\2\2\u0117\u0118\7/\2\2\u0118?"+
+    "\3\2\2\2\u0119\u011a\7>\2\2\u011a\u011b\7>\2\2\u011bA\3\2\2\2\u011c\u011d"+
+    "\7@\2\2\u011d\u011e\7@\2\2\u011eC\3\2\2\2\u011f\u0120\7@\2\2\u0120\u0121"+
+    "\7@\2\2\u0121\u0122\7@\2\2\u0122E\3\2\2\2\u0123\u0124\7>\2\2\u0124G\3"+
+    "\2\2\2\u0125\u0126\7>\2\2\u0126\u0127\7?\2\2\u0127I\3\2\2\2\u0128\u0129"+
+    "\7@\2\2\u0129K\3\2\2\2\u012a\u012b\7@\2\2\u012b\u012c\7?\2\2\u012cM\3"+
+    "\2\2\2\u012d\u012e\7?\2\2\u012e\u012f\7?\2\2\u012fO\3\2\2\2\u0130\u0131"+
+    "\7?\2\2\u0131\u0132\7?\2\2\u0132\u0133\7?\2\2\u0133Q\3\2\2\2\u0134\u0135"+
+    "\7#\2\2\u0135\u0136\7?\2\2\u0136S\3\2\2\2\u0137\u0138\7#\2\2\u0138\u0139"+
+    "\7?\2\2\u0139\u013a\7?\2\2\u013aU\3\2\2\2\u013b\u013c\7(\2\2\u013cW\3"+
+    "\2\2\2\u013d\u013e\7`\2\2\u013eY\3\2\2\2\u013f\u0140\7~\2\2\u0140[\3\2"+
+    "\2\2\u0141\u0142\7(\2\2\u0142\u0143\7(\2\2\u0143]\3\2\2\2\u0144\u0145"+
+    "\7~\2\2\u0145\u0146\7~\2\2\u0146_\3\2\2\2\u0147\u0148\7A\2\2\u0148a\3"+
+    "\2\2\2\u0149\u014a\7<\2\2\u014ac\3\2\2\2\u014b\u014c\7-\2\2\u014c\u014d"+
+    "\7-\2\2\u014de\3\2\2\2\u014e\u014f\7/\2\2\u014f\u0150\7/\2\2\u0150g\3"+
+    "\2\2\2\u0151\u0152\7?\2\2\u0152i\3\2\2\2\u0153\u0154\7-\2\2\u0154\u0155"+
+    "\7?\2\2\u0155k\3\2\2\2\u0156\u0157\7/\2\2\u0157\u0158\7?\2\2\u0158m\3"+
+    "\2\2\2\u0159\u015a\7,\2\2\u015a\u015b\7?\2\2\u015bo\3\2\2\2\u015c\u015d"+
+    "\7\61\2\2\u015d\u015e\7?\2\2\u015eq\3\2\2\2\u015f\u0160\7\'\2\2\u0160"+
+    "\u0161\7?\2\2\u0161s\3\2\2\2\u0162\u0163\7(\2\2\u0163\u0164\7?\2\2\u0164"+
+    "u\3\2\2\2\u0165\u0166\7`\2\2\u0166\u0167\7?\2\2\u0167w\3\2\2\2\u0168\u0169"+
+    "\7~\2\2\u0169\u016a\7?\2\2\u016ay\3\2\2\2\u016b\u016c\7>\2\2\u016c\u016d"+
+    "\7>\2\2\u016d\u016e\7?\2\2\u016e{\3\2\2\2\u016f\u0170\7@\2\2\u0170\u0171"+
+    "\7@\2\2\u0171\u0172\7?\2\2\u0172}\3\2\2\2\u0173\u0174\7@\2\2\u0174\u0175"+
+    "\7@\2\2\u0175\u0176\7@\2\2\u0176\u0177\7?\2\2\u0177\177\3\2\2\2\u0178"+
+    "\u017a\7\62\2\2\u0179\u017b\t\4\2\2\u017a\u0179\3\2\2\2\u017b\u017c\3"+
+    "\2\2\2\u017c\u017a\3\2\2\2\u017c\u017d\3\2\2\2\u017d\u017f\3\2\2\2\u017e"+
+    "\u0180\t\5\2\2\u017f\u017e\3\2\2\2\u017f\u0180\3\2\2\2\u0180\u0081\3\2"+
+    "\2\2\u0181\u0182\7\62\2\2\u0182\u0184\t\6\2\2\u0183\u0185\t\7\2\2\u0184"+
+    "\u0183\3\2\2\2\u0185\u0186\3\2\2\2\u0186\u0184\3\2\2\2\u0186\u0187\3\2"+
+    "\2\2\u0187\u0189\3\2\2\2\u0188\u018a\t\5\2\2\u0189\u0188\3\2\2\2\u0189"+
+    "\u018a\3\2\2\2\u018a\u0083\3\2\2\2\u018b\u0194\7\62\2\2\u018c\u0190\t"+
+    "\b\2\2\u018d\u018f\t\t\2\2\u018e\u018d\3\2\2\2\u018f\u0192\3\2\2\2\u0190"+
+    "\u018e\3\2\2\2\u0190\u0191\3\2\2\2\u0191\u0194\3\2\2\2\u0192\u0190\3\2"+
+    "\2\2\u0193\u018b\3\2\2\2\u0193\u018c\3\2\2\2\u0194\u0196\3\2\2\2\u0195"+
+    "\u0197\t\n\2\2\u0196\u0195\3\2\2\2\u0196\u0197\3\2\2\2\u0197\u0085\3\2"+
+    "\2\2\u0198\u01a1\7\62\2\2\u0199\u019d\t\b\2\2\u019a\u019c\t\t\2\2\u019b"+
+    "\u019a\3\2\2\2\u019c\u019f\3\2\2\2\u019d\u019b\3\2\2\2\u019d\u019e\3\2"+
+    "\2\2\u019e\u01a1\3\2\2\2\u019f\u019d\3\2\2\2\u01a0\u0198\3\2\2\2\u01a0"+
+    "\u0199\3\2\2\2\u01a1\u01a8\3\2\2\2\u01a2\u01a4\5\24\n\2\u01a3\u01a5\t"+
+    "\t\2\2\u01a4\u01a3\3\2\2\2\u01a5\u01a6\3\2\2\2\u01a6\u01a4\3\2\2\2\u01a6"+
+    "\u01a7\3\2\2\2\u01a7\u01a9\3\2\2\2\u01a8\u01a2\3\2\2\2\u01a8\u01a9\3\2"+
+    "\2\2\u01a9\u01b3\3\2\2\2\u01aa\u01ac\t\13\2\2\u01ab\u01ad\t\f\2\2\u01ac"+
+    "\u01ab\3\2\2\2\u01ac\u01ad\3\2\2\2\u01ad\u01af\3\2\2\2\u01ae\u01b0\t\t"+
+    "\2\2\u01af\u01ae\3\2\2\2\u01b0\u01b1\3\2\2\2\u01b1\u01af\3\2\2\2\u01b1"+
+    "\u01b2\3\2\2\2\u01b2\u01b4\3\2\2\2\u01b3\u01aa\3\2\2\2\u01b3\u01b4\3\2"+
+    "\2\2\u01b4\u01b6\3\2\2\2\u01b5\u01b7\t\r\2\2\u01b6\u01b5\3\2\2\2\u01b6"+
+    "\u01b7\3\2\2\2\u01b7\u0087\3\2\2\2\u01b8\u01c0\7$\2\2\u01b9\u01ba\7^\2"+
+    "\2\u01ba\u01bf\7$\2\2\u01bb\u01bc\7^\2\2\u01bc\u01bf\7^\2\2\u01bd\u01bf"+
+    "\n\16\2\2\u01be\u01b9\3\2\2\2\u01be\u01bb\3\2\2\2\u01be\u01bd\3\2\2\2"+
+    "\u01bf\u01c2\3\2\2\2\u01c0\u01c1\3\2\2\2\u01c0\u01be\3\2\2\2\u01c1\u01c3"+
+    "\3\2\2\2\u01c2\u01c0\3\2\2\2\u01c3\u01d1\7$\2\2\u01c4\u01cc\7)\2\2\u01c5"+
+    "\u01c6\7^\2\2\u01c6\u01cb\7)\2\2\u01c7\u01c8\7^\2\2\u01c8\u01cb\7^\2\2"+
+    "\u01c9\u01cb\n\16\2\2\u01ca\u01c5\3\2\2\2\u01ca\u01c7\3\2\2\2\u01ca\u01c9"+
+    "\3\2\2\2\u01cb\u01ce\3\2\2\2\u01cc\u01cd\3\2\2\2\u01cc\u01ca\3\2\2\2\u01cd"+
+    "\u01cf\3\2\2\2\u01ce\u01cc\3\2\2\2\u01cf\u01d1\7)\2\2\u01d0\u01b8\3\2"+
+    "\2\2\u01d0\u01c4\3\2\2\2\u01d1\u0089\3\2\2\2\u01d2\u01d3\7v\2\2\u01d3"+
+    "\u01d4\7t\2\2\u01d4\u01d5\7w\2\2\u01d5\u01d6\7g\2\2\u01d6\u008b\3\2\2"+
+    "\2\u01d7\u01d8\7h\2\2\u01d8\u01d9\7c\2\2\u01d9\u01da\7n\2\2\u01da\u01db"+
+    "\7u\2\2\u01db\u01dc\7g\2\2\u01dc\u008d\3\2\2\2\u01dd\u01de\7p\2\2\u01de"+
+    "\u01df\7w\2\2\u01df\u01e0\7n\2\2\u01e0\u01e1\7n\2\2\u01e1\u008f\3\2\2"+
+    "\2\u01e2\u01e8\5\u0092I\2\u01e3\u01e4\5\24\n\2\u01e4\u01e5\5\u0092I\2"+
+    "\u01e5\u01e7\3\2\2\2\u01e6\u01e3\3\2\2\2\u01e7\u01ea\3\2\2\2\u01e8\u01e6"+
+    "\3\2\2\2\u01e8\u01e9\3\2\2\2\u01e9\u01eb\3\2\2\2\u01ea\u01e8\3\2\2\2\u01eb"+
+    "\u01ec\6H\2\2\u01ec\u0091\3\2\2\2\u01ed\u01f1\t\17\2\2\u01ee\u01f0\t\20"+
+    "\2\2\u01ef\u01ee\3\2\2\2\u01f0\u01f3\3\2\2\2\u01f1\u01ef\3\2\2\2\u01f1"+
+    "\u01f2\3\2\2\2\u01f2\u0093\3\2\2\2\u01f3\u01f1\3\2\2\2\u01f4\u01fd\7\62"+
+    "\2\2\u01f5\u01f9\t\b\2\2\u01f6\u01f8\t\t\2\2\u01f7\u01f6\3\2\2\2\u01f8"+
+    "\u01fb\3\2\2\2\u01f9\u01f7\3\2\2\2\u01f9\u01fa\3\2\2\2\u01fa\u01fd\3\2"+
+    "\2\2\u01fb\u01f9\3\2\2\2\u01fc\u01f4\3\2\2\2\u01fc\u01f5\3\2\2\2\u01fd"+
+    "\u01fe\3\2\2\2\u01fe\u01ff\bJ\4\2\u01ff\u0095\3\2\2\2\u0200\u0204\t\21"+
+    "\2\2\u0201\u0203\t\20\2\2\u0202\u0201\3\2\2\2\u0203\u0206\3\2\2\2\u0204"+
+    "\u0202\3\2\2\2\u0204\u0205\3\2\2\2\u0205\u0207\3\2\2\2\u0206\u0204\3\2"+
+    "\2\2\u0207\u0208\bK\4\2\u0208\u0097\3\2\2\2!\2\3\u009b\u00a5\u00af\u00b4"+
+    "\u017c\u017f\u0186\u0189\u0190\u0193\u0196\u019d\u01a0\u01a6\u01a8\u01ac"+
+    "\u01b1\u01b3\u01b6\u01be\u01c0\u01ca\u01cc\u01d0\u01e8\u01f1\u01f9\u01fc"+
+    "\u0204\5\b\2\2\4\3\2\4\2\2";
   public static final ATN _ATN =
     new ATNDeserializer().deserialize(_serializedATN.toCharArray());
   static {

Diferenças do arquivo suprimidas por serem muito extensas
+ 247 - 404
modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParser.java


+ 35 - 35
modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParserBaseVisitor.java

@@ -101,14 +101,14 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitMultiple(PainlessParser.MultipleContext ctx) { return visitChildren(ctx); }
+  @Override public T visitTrailer(PainlessParser.TrailerContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitSingle(PainlessParser.SingleContext ctx) { return visitChildren(ctx); }
+  @Override public T visitBlock(PainlessParser.BlockContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
@@ -116,13 +116,6 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
    * {@link #visitChildren} on {@code ctx}.</p>
    */
   @Override public T visitEmpty(PainlessParser.EmptyContext ctx) { return visitChildren(ctx); }
-  /**
-   * {@inheritDoc}
-   *
-   * <p>The default implementation returns the result of calling
-   * {@link #visitChildren} on {@code ctx}.</p>
-   */
-  @Override public T visitEmptyscope(PainlessParser.EmptyscopeContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
@@ -171,14 +164,14 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitIdentifier(PainlessParser.IdentifierContext ctx) { return visitChildren(ctx); }
+  @Override public T visitDelimiter(PainlessParser.DelimiterContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitGeneric(PainlessParser.GenericContext ctx) { return visitChildren(ctx); }
+  @Override public T visitSingle(PainlessParser.SingleContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
@@ -192,168 +185,175 @@ class PainlessParserBaseVisitor<T> extends AbstractParseTreeVisitor<T> implement
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitRead(PainlessParser.ReadContext ctx) { return visitChildren(ctx); }
+  @Override public T visitBool(PainlessParser.BoolContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitBool(PainlessParser.BoolContext ctx) { return visitChildren(ctx); }
+  @Override public T visitConditional(PainlessParser.ConditionalContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitConditional(PainlessParser.ConditionalContext ctx) { return visitChildren(ctx); }
+  @Override public T visitAssignment(PainlessParser.AssignmentContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitAssignment(PainlessParser.AssignmentContext ctx) { return visitChildren(ctx); }
+  @Override public T visitBinary(PainlessParser.BinaryContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitFalse(PainlessParser.FalseContext ctx) { return visitChildren(ctx); }
+  @Override public T visitPre(PainlessParser.PreContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitNumeric(PainlessParser.NumericContext ctx) { return visitChildren(ctx); }
+  @Override public T visitPost(PainlessParser.PostContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitUnary(PainlessParser.UnaryContext ctx) { return visitChildren(ctx); }
+  @Override public T visitRead(PainlessParser.ReadContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitPrecedence(PainlessParser.PrecedenceContext ctx) { return visitChildren(ctx); }
+  @Override public T visitNumeric(PainlessParser.NumericContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitPreinc(PainlessParser.PreincContext ctx) { return visitChildren(ctx); }
+  @Override public T visitTrue(PainlessParser.TrueContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitPostinc(PainlessParser.PostincContext ctx) { return visitChildren(ctx); }
+  @Override public T visitFalse(PainlessParser.FalseContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitCast(PainlessParser.CastContext ctx) { return visitChildren(ctx); }
+  @Override public T visitNull(PainlessParser.NullContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitNull(PainlessParser.NullContext ctx) { return visitChildren(ctx); }
+  @Override public T visitOperator(PainlessParser.OperatorContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitBinary(PainlessParser.BinaryContext ctx) { return visitChildren(ctx); }
+  @Override public T visitCast(PainlessParser.CastContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitTrue(PainlessParser.TrueContext ctx) { return visitChildren(ctx); }
+  @Override public T visitDynamic(PainlessParser.DynamicContext ctx) { return visitChildren(ctx); }
+  /**
+   * {@inheritDoc}
+   *
+   * <p>The default implementation returns the result of calling
+   * {@link #visitChildren} on {@code ctx}.</p>
+   */
+  @Override public T visitStatic(PainlessParser.StaticContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitChain(PainlessParser.ChainContext ctx) { return visitChildren(ctx); }
+  @Override public T visitNewarray(PainlessParser.NewarrayContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitLinkprec(PainlessParser.LinkprecContext ctx) { return visitChildren(ctx); }
+  @Override public T visitExprprec(PainlessParser.ExprprecContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitLinkcast(PainlessParser.LinkcastContext ctx) { return visitChildren(ctx); }
+  @Override public T visitChainprec(PainlessParser.ChainprecContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitLinkbrace(PainlessParser.LinkbraceContext ctx) { return visitChildren(ctx); }
+  @Override public T visitString(PainlessParser.StringContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitLinkdot(PainlessParser.LinkdotContext ctx) { return visitChildren(ctx); }
+  @Override public T visitVariable(PainlessParser.VariableContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitLinkcall(PainlessParser.LinkcallContext ctx) { return visitChildren(ctx); }
+  @Override public T visitNewobject(PainlessParser.NewobjectContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitLinkvar(PainlessParser.LinkvarContext ctx) { return visitChildren(ctx); }
+  @Override public T visitSecondary(PainlessParser.SecondaryContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitLinkfield(PainlessParser.LinkfieldContext ctx) { return visitChildren(ctx); }
+  @Override public T visitCallinvoke(PainlessParser.CallinvokeContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitLinknew(PainlessParser.LinknewContext ctx) { return visitChildren(ctx); }
+  @Override public T visitFieldaccess(PainlessParser.FieldaccessContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *
    * <p>The default implementation returns the result of calling
    * {@link #visitChildren} on {@code ctx}.</p>
    */
-  @Override public T visitLinkstring(PainlessParser.LinkstringContext ctx) { return visitChildren(ctx); }
+  @Override public T visitBraceaccess(PainlessParser.BraceaccessContext ctx) { return visitChildren(ctx); }
   /**
    * {@inheritDoc}
    *

+ 79 - 70
modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/PainlessParserVisitor.java

@@ -94,31 +94,23 @@ interface PainlessParserVisitor<T> extends ParseTreeVisitor<T> {
    */
   T visitExpr(PainlessParser.ExprContext ctx);
   /**
-   * Visit a parse tree produced by the {@code multiple}
-   * labeled alternative in {@link PainlessParser#block}.
+   * Visit a parse tree produced by {@link PainlessParser#trailer}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitMultiple(PainlessParser.MultipleContext ctx);
+  T visitTrailer(PainlessParser.TrailerContext ctx);
   /**
-   * Visit a parse tree produced by the {@code single}
-   * labeled alternative in {@link PainlessParser#block}.
+   * Visit a parse tree produced by {@link PainlessParser#block}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitSingle(PainlessParser.SingleContext ctx);
+  T visitBlock(PainlessParser.BlockContext ctx);
   /**
    * Visit a parse tree produced by {@link PainlessParser#empty}.
    * @param ctx the parse tree
    * @return the visitor result
    */
   T visitEmpty(PainlessParser.EmptyContext ctx);
-  /**
-   * Visit a parse tree produced by {@link PainlessParser#emptyscope}.
-   * @param ctx the parse tree
-   * @return the visitor result
-   */
-  T visitEmptyscope(PainlessParser.EmptyscopeContext ctx);
   /**
    * Visit a parse tree produced by {@link PainlessParser#initializer}.
    * @param ctx the parse tree
@@ -156,17 +148,18 @@ interface PainlessParserVisitor<T> extends ParseTreeVisitor<T> {
    */
   T visitTrap(PainlessParser.TrapContext ctx);
   /**
-   * Visit a parse tree produced by {@link PainlessParser#identifier}.
+   * Visit a parse tree produced by {@link PainlessParser#delimiter}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitIdentifier(PainlessParser.IdentifierContext ctx);
+  T visitDelimiter(PainlessParser.DelimiterContext ctx);
   /**
-   * Visit a parse tree produced by {@link PainlessParser#generic}.
+   * Visit a parse tree produced by the {@code single}
+   * labeled alternative in {@link PainlessParser#expression}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitGeneric(PainlessParser.GenericContext ctx);
+  T visitSingle(PainlessParser.SingleContext ctx);
   /**
    * Visit a parse tree produced by the {@code comp}
    * labeled alternative in {@link PainlessParser#expression}.
@@ -174,13 +167,6 @@ interface PainlessParserVisitor<T> extends ParseTreeVisitor<T> {
    * @return the visitor result
    */
   T visitComp(PainlessParser.CompContext ctx);
-  /**
-   * Visit a parse tree produced by the {@code read}
-   * labeled alternative in {@link PainlessParser#expression}.
-   * @param ctx the parse tree
-   * @return the visitor result
-   */
-  T visitRead(PainlessParser.ReadContext ctx);
   /**
    * Visit a parse tree produced by the {@code bool}
    * labeled alternative in {@link PainlessParser#expression}.
@@ -203,135 +189,158 @@ interface PainlessParserVisitor<T> extends ParseTreeVisitor<T> {
    */
   T visitAssignment(PainlessParser.AssignmentContext ctx);
   /**
-   * Visit a parse tree produced by the {@code false}
+   * Visit a parse tree produced by the {@code binary}
    * labeled alternative in {@link PainlessParser#expression}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitFalse(PainlessParser.FalseContext ctx);
+  T visitBinary(PainlessParser.BinaryContext ctx);
   /**
-   * Visit a parse tree produced by the {@code numeric}
-   * labeled alternative in {@link PainlessParser#expression}.
+   * Visit a parse tree produced by the {@code pre}
+   * labeled alternative in {@link PainlessParser#unary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitNumeric(PainlessParser.NumericContext ctx);
+  T visitPre(PainlessParser.PreContext ctx);
   /**
-   * Visit a parse tree produced by the {@code unary}
-   * labeled alternative in {@link PainlessParser#expression}.
+   * Visit a parse tree produced by the {@code post}
+   * labeled alternative in {@link PainlessParser#unary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitUnary(PainlessParser.UnaryContext ctx);
+  T visitPost(PainlessParser.PostContext ctx);
   /**
-   * Visit a parse tree produced by the {@code precedence}
-   * labeled alternative in {@link PainlessParser#expression}.
+   * Visit a parse tree produced by the {@code read}
+   * labeled alternative in {@link PainlessParser#unary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitPrecedence(PainlessParser.PrecedenceContext ctx);
+  T visitRead(PainlessParser.ReadContext ctx);
   /**
-   * Visit a parse tree produced by the {@code preinc}
-   * labeled alternative in {@link PainlessParser#expression}.
+   * Visit a parse tree produced by the {@code numeric}
+   * labeled alternative in {@link PainlessParser#unary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitPreinc(PainlessParser.PreincContext ctx);
+  T visitNumeric(PainlessParser.NumericContext ctx);
   /**
-   * Visit a parse tree produced by the {@code postinc}
-   * labeled alternative in {@link PainlessParser#expression}.
+   * Visit a parse tree produced by the {@code true}
+   * labeled alternative in {@link PainlessParser#unary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitPostinc(PainlessParser.PostincContext ctx);
+  T visitTrue(PainlessParser.TrueContext ctx);
   /**
-   * Visit a parse tree produced by the {@code cast}
-   * labeled alternative in {@link PainlessParser#expression}.
+   * Visit a parse tree produced by the {@code false}
+   * labeled alternative in {@link PainlessParser#unary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitCast(PainlessParser.CastContext ctx);
+  T visitFalse(PainlessParser.FalseContext ctx);
   /**
    * Visit a parse tree produced by the {@code null}
-   * labeled alternative in {@link PainlessParser#expression}.
+   * labeled alternative in {@link PainlessParser#unary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
   T visitNull(PainlessParser.NullContext ctx);
   /**
-   * Visit a parse tree produced by the {@code binary}
-   * labeled alternative in {@link PainlessParser#expression}.
+   * Visit a parse tree produced by the {@code operator}
+   * labeled alternative in {@link PainlessParser#unary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitBinary(PainlessParser.BinaryContext ctx);
+  T visitOperator(PainlessParser.OperatorContext ctx);
   /**
-   * Visit a parse tree produced by the {@code true}
-   * labeled alternative in {@link PainlessParser#expression}.
+   * Visit a parse tree produced by the {@code cast}
+   * labeled alternative in {@link PainlessParser#unary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitTrue(PainlessParser.TrueContext ctx);
+  T visitCast(PainlessParser.CastContext ctx);
+  /**
+   * Visit a parse tree produced by the {@code dynamic}
+   * labeled alternative in {@link PainlessParser#chain}.
+   * @param ctx the parse tree
+   * @return the visitor result
+   */
+  T visitDynamic(PainlessParser.DynamicContext ctx);
+  /**
+   * Visit a parse tree produced by the {@code static}
+   * labeled alternative in {@link PainlessParser#chain}.
+   * @param ctx the parse tree
+   * @return the visitor result
+   */
+  T visitStatic(PainlessParser.StaticContext ctx);
   /**
-   * Visit a parse tree produced by {@link PainlessParser#chain}.
+   * Visit a parse tree produced by the {@code newarray}
+   * labeled alternative in {@link PainlessParser#chain}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitChain(PainlessParser.ChainContext ctx);
+  T visitNewarray(PainlessParser.NewarrayContext ctx);
   /**
-   * Visit a parse tree produced by {@link PainlessParser#linkprec}.
+   * Visit a parse tree produced by the {@code exprprec}
+   * labeled alternative in {@link PainlessParser#primary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitLinkprec(PainlessParser.LinkprecContext ctx);
+  T visitExprprec(PainlessParser.ExprprecContext ctx);
   /**
-   * Visit a parse tree produced by {@link PainlessParser#linkcast}.
+   * Visit a parse tree produced by the {@code chainprec}
+   * labeled alternative in {@link PainlessParser#primary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitLinkcast(PainlessParser.LinkcastContext ctx);
+  T visitChainprec(PainlessParser.ChainprecContext ctx);
   /**
-   * Visit a parse tree produced by {@link PainlessParser#linkbrace}.
+   * Visit a parse tree produced by the {@code string}
+   * labeled alternative in {@link PainlessParser#primary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitLinkbrace(PainlessParser.LinkbraceContext ctx);
+  T visitString(PainlessParser.StringContext ctx);
   /**
-   * Visit a parse tree produced by {@link PainlessParser#linkdot}.
+   * Visit a parse tree produced by the {@code variable}
+   * labeled alternative in {@link PainlessParser#primary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitLinkdot(PainlessParser.LinkdotContext ctx);
+  T visitVariable(PainlessParser.VariableContext ctx);
   /**
-   * Visit a parse tree produced by {@link PainlessParser#linkcall}.
+   * Visit a parse tree produced by the {@code newobject}
+   * labeled alternative in {@link PainlessParser#primary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitLinkcall(PainlessParser.LinkcallContext ctx);
+  T visitNewobject(PainlessParser.NewobjectContext ctx);
   /**
-   * Visit a parse tree produced by {@link PainlessParser#linkvar}.
+   * Visit a parse tree produced by {@link PainlessParser#secondary}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitLinkvar(PainlessParser.LinkvarContext ctx);
+  T visitSecondary(PainlessParser.SecondaryContext ctx);
   /**
-   * Visit a parse tree produced by {@link PainlessParser#linkfield}.
+   * Visit a parse tree produced by the {@code callinvoke}
+   * labeled alternative in {@link PainlessParser#dot}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitLinkfield(PainlessParser.LinkfieldContext ctx);
+  T visitCallinvoke(PainlessParser.CallinvokeContext ctx);
   /**
-   * Visit a parse tree produced by {@link PainlessParser#linknew}.
+   * Visit a parse tree produced by the {@code fieldaccess}
+   * labeled alternative in {@link PainlessParser#dot}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitLinknew(PainlessParser.LinknewContext ctx);
+  T visitFieldaccess(PainlessParser.FieldaccessContext ctx);
   /**
-   * Visit a parse tree produced by {@link PainlessParser#linkstring}.
+   * Visit a parse tree produced by the {@code braceaccess}
+   * labeled alternative in {@link PainlessParser#brace}.
    * @param ctx the parse tree
    * @return the visitor result
    */
-  T visitLinkstring(PainlessParser.LinkstringContext ctx);
+  T visitBraceaccess(PainlessParser.BraceaccessContext ctx);
   /**
    * Visit a parse tree produced by {@link PainlessParser#arguments}.
    * @param ctx the parse tree

+ 418 - 377
modules/lang-painless/src/main/java/org/elasticsearch/painless/antlr/Walker.java

@@ -20,8 +20,13 @@
 package org.elasticsearch.painless.antlr;
 
 import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.BaseErrorListener;
 import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.DiagnosticErrorListener;
 import org.antlr.v4.runtime.ParserRuleContext;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.atn.PredictionMode;
 import org.elasticsearch.painless.CompilerSettings;
 import org.elasticsearch.painless.Operation;
 import org.elasticsearch.painless.Variables.Reserved;
@@ -29,51 +34,54 @@ import org.elasticsearch.painless.antlr.PainlessParser.AfterthoughtContext;
 import org.elasticsearch.painless.antlr.PainlessParser.ArgumentsContext;
 import org.elasticsearch.painless.antlr.PainlessParser.AssignmentContext;
 import org.elasticsearch.painless.antlr.PainlessParser.BinaryContext;
+import org.elasticsearch.painless.antlr.PainlessParser.BlockContext;
+import org.elasticsearch.painless.antlr.PainlessParser.BoolContext;
+import org.elasticsearch.painless.antlr.PainlessParser.BraceaccessContext;
 import org.elasticsearch.painless.antlr.PainlessParser.BreakContext;
+import org.elasticsearch.painless.antlr.PainlessParser.CallinvokeContext;
 import org.elasticsearch.painless.antlr.PainlessParser.CastContext;
+import org.elasticsearch.painless.antlr.PainlessParser.ChainprecContext;
+import org.elasticsearch.painless.antlr.PainlessParser.CompContext;
 import org.elasticsearch.painless.antlr.PainlessParser.ConditionalContext;
 import org.elasticsearch.painless.antlr.PainlessParser.ContinueContext;
 import org.elasticsearch.painless.antlr.PainlessParser.DeclContext;
 import org.elasticsearch.painless.antlr.PainlessParser.DeclarationContext;
 import org.elasticsearch.painless.antlr.PainlessParser.DecltypeContext;
 import org.elasticsearch.painless.antlr.PainlessParser.DeclvarContext;
+import org.elasticsearch.painless.antlr.PainlessParser.DelimiterContext;
 import org.elasticsearch.painless.antlr.PainlessParser.DoContext;
+import org.elasticsearch.painless.antlr.PainlessParser.DynamicContext;
 import org.elasticsearch.painless.antlr.PainlessParser.EmptyContext;
-import org.elasticsearch.painless.antlr.PainlessParser.EmptyscopeContext;
 import org.elasticsearch.painless.antlr.PainlessParser.ExprContext;
 import org.elasticsearch.painless.antlr.PainlessParser.ExpressionContext;
-import org.elasticsearch.painless.antlr.PainlessParser.LinkbraceContext;
-import org.elasticsearch.painless.antlr.PainlessParser.LinkcallContext;
-import org.elasticsearch.painless.antlr.PainlessParser.LinkcastContext;
-import org.elasticsearch.painless.antlr.PainlessParser.LinkdotContext;
-import org.elasticsearch.painless.antlr.PainlessParser.ReadContext;
-import org.elasticsearch.painless.antlr.PainlessParser.LinkfieldContext;
-import org.elasticsearch.painless.antlr.PainlessParser.LinknewContext;
-import org.elasticsearch.painless.antlr.PainlessParser.LinkprecContext;
-import org.elasticsearch.painless.antlr.PainlessParser.ChainContext;
-import org.elasticsearch.painless.antlr.PainlessParser.LinkstringContext;
-import org.elasticsearch.painless.antlr.PainlessParser.LinkvarContext;
+import org.elasticsearch.painless.antlr.PainlessParser.ExprprecContext;
 import org.elasticsearch.painless.antlr.PainlessParser.FalseContext;
+import org.elasticsearch.painless.antlr.PainlessParser.FieldaccessContext;
 import org.elasticsearch.painless.antlr.PainlessParser.ForContext;
-import org.elasticsearch.painless.antlr.PainlessParser.GenericContext;
-import org.elasticsearch.painless.antlr.PainlessParser.IdentifierContext;
 import org.elasticsearch.painless.antlr.PainlessParser.IfContext;
 import org.elasticsearch.painless.antlr.PainlessParser.InitializerContext;
-import org.elasticsearch.painless.antlr.PainlessParser.MultipleContext;
+import org.elasticsearch.painless.antlr.PainlessParser.NewarrayContext;
+import org.elasticsearch.painless.antlr.PainlessParser.NewobjectContext;
 import org.elasticsearch.painless.antlr.PainlessParser.NullContext;
 import org.elasticsearch.painless.antlr.PainlessParser.NumericContext;
-import org.elasticsearch.painless.antlr.PainlessParser.PostincContext;
-import org.elasticsearch.painless.antlr.PainlessParser.PrecedenceContext;
-import org.elasticsearch.painless.antlr.PainlessParser.PreincContext;
+import org.elasticsearch.painless.antlr.PainlessParser.OperatorContext;
+import org.elasticsearch.painless.antlr.PainlessParser.PostContext;
+import org.elasticsearch.painless.antlr.PainlessParser.PreContext;
+import org.elasticsearch.painless.antlr.PainlessParser.ReadContext;
 import org.elasticsearch.painless.antlr.PainlessParser.ReturnContext;
+import org.elasticsearch.painless.antlr.PainlessParser.SecondaryContext;
 import org.elasticsearch.painless.antlr.PainlessParser.SingleContext;
 import org.elasticsearch.painless.antlr.PainlessParser.SourceContext;
 import org.elasticsearch.painless.antlr.PainlessParser.StatementContext;
+import org.elasticsearch.painless.antlr.PainlessParser.StaticContext;
+import org.elasticsearch.painless.antlr.PainlessParser.StringContext;
 import org.elasticsearch.painless.antlr.PainlessParser.ThrowContext;
+import org.elasticsearch.painless.antlr.PainlessParser.TrailerContext;
 import org.elasticsearch.painless.antlr.PainlessParser.TrapContext;
 import org.elasticsearch.painless.antlr.PainlessParser.TrueContext;
 import org.elasticsearch.painless.antlr.PainlessParser.TryContext;
 import org.elasticsearch.painless.antlr.PainlessParser.UnaryContext;
+import org.elasticsearch.painless.antlr.PainlessParser.VariableContext;
 import org.elasticsearch.painless.antlr.PainlessParser.WhileContext;
 import org.elasticsearch.painless.node.AExpression;
 import org.elasticsearch.painless.node.ALink;
@@ -82,11 +90,11 @@ import org.elasticsearch.painless.node.AStatement;
 import org.elasticsearch.painless.node.EBinary;
 import org.elasticsearch.painless.node.EBool;
 import org.elasticsearch.painless.node.EBoolean;
-import org.elasticsearch.painless.node.EExplicit;
 import org.elasticsearch.painless.node.EChain;
 import org.elasticsearch.painless.node.EComp;
 import org.elasticsearch.painless.node.EConditional;
 import org.elasticsearch.painless.node.EDecimal;
+import org.elasticsearch.painless.node.EExplicit;
 import org.elasticsearch.painless.node.ENull;
 import org.elasticsearch.painless.node.ENumeric;
 import org.elasticsearch.painless.node.EUnary;
@@ -96,21 +104,23 @@ import org.elasticsearch.painless.node.LCast;
 import org.elasticsearch.painless.node.LField;
 import org.elasticsearch.painless.node.LNewArray;
 import org.elasticsearch.painless.node.LNewObj;
+import org.elasticsearch.painless.node.LStatic;
 import org.elasticsearch.painless.node.LString;
 import org.elasticsearch.painless.node.LVariable;
 import org.elasticsearch.painless.node.SBlock;
 import org.elasticsearch.painless.node.SBreak;
+import org.elasticsearch.painless.node.SCatch;
 import org.elasticsearch.painless.node.SContinue;
 import org.elasticsearch.painless.node.SDeclBlock;
 import org.elasticsearch.painless.node.SDeclaration;
 import org.elasticsearch.painless.node.SDo;
 import org.elasticsearch.painless.node.SExpression;
 import org.elasticsearch.painless.node.SFor;
+import org.elasticsearch.painless.node.SIf;
 import org.elasticsearch.painless.node.SIfElse;
 import org.elasticsearch.painless.node.SReturn;
 import org.elasticsearch.painless.node.SSource;
 import org.elasticsearch.painless.node.SThrow;
-import org.elasticsearch.painless.node.STrap;
 import org.elasticsearch.painless.node.STry;
 import org.elasticsearch.painless.node.SWhile;
 
@@ -120,7 +130,7 @@ import java.util.List;
 /**
  * Converts the ANTLR tree to a Painless tree.
  */
-public final class Walker extends PainlessParserBaseVisitor<ANode> {
+public final class Walker extends PainlessParserBaseVisitor<Object> {
 
     public static SSource buildPainlessTree(String source, Reserved reserved, CompilerSettings settings) {
         return new Walker(source, reserved, settings).source;
@@ -136,329 +146,292 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
         this.source = (SSource)visit(buildAntlrTree(source));
     }
 
-    private SourceContext buildAntlrTree(final String source) {
-        final ANTLRInputStream stream = new ANTLRInputStream(source);
-        final PainlessLexer lexer = new ErrorHandlingLexer(stream);
-        final PainlessParser parser = new PainlessParser(new CommonTokenStream(lexer));
-        final ParserErrorStrategy strategy = new ParserErrorStrategy();
+    private SourceContext buildAntlrTree(String source) {
+        ANTLRInputStream stream = new ANTLRInputStream(source);
+        PainlessLexer lexer = new ErrorHandlingLexer(stream);
+        PainlessParser parser = new PainlessParser(new CommonTokenStream(lexer));
+        ParserErrorStrategy strategy = new ParserErrorStrategy();
 
         lexer.removeErrorListeners();
         parser.removeErrorListeners();
+
+        if (settings.isPicky()) {
+            setupPicky(parser);
+        }
+
         parser.setErrorHandler(strategy);
 
         return parser.source();
     }
 
-    private int line(final ParserRuleContext ctx) {
+    private void setupPicky(PainlessParser parser) {
+        // Diagnostic listener invokes syntaxError on other listeners for ambiguity issues,
+        parser.addErrorListener(new DiagnosticErrorListener(true));
+        // a second listener to fail the test when the above happens.
+        parser.addErrorListener(new BaseErrorListener() {
+            @Override
+            public void syntaxError(final Recognizer<?,?> recognizer, final Object offendingSymbol, final int line,
+                                    final int charPositionInLine, final String msg, final RecognitionException e) {
+                throw new AssertionError("line: " + line + ", offset: " + charPositionInLine +
+                    ", symbol:" + offendingSymbol + " " + msg);
+            }
+        });
+
+        // Enable exact ambiguity detection (costly). we enable exact since its the default for
+        // DiagnosticErrorListener, life is too short to think about what 'inexact ambiguity' might mean.
+        parser.getInterpreter().setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);
+    }
+
+    private int line(ParserRuleContext ctx) {
         return ctx.getStart().getLine();
     }
 
-    private String location(final ParserRuleContext ctx) {
+    private int offset(ParserRuleContext ctx) {
+        return ctx.getStart().getStartIndex();
+    }
+
+    private String location(ParserRuleContext ctx) {
         return "[ " + ctx.getStart().getLine() + " : " + ctx.getStart().getCharPositionInLine() + " ]";
     }
 
     @Override
-    public ANode visitSource(final SourceContext ctx) {
-        final List<AStatement> statements = new ArrayList<>();
+    public Object visitSource(SourceContext ctx) {
+        List<AStatement> statements = new ArrayList<>();
 
-        for (final StatementContext statement : ctx.statement()) {
+        for (StatementContext statement : ctx.statement()) {
             statements.add((AStatement)visit(statement));
         }
 
-        return new SSource(line(ctx), location(ctx), statements);
+        return new SSource(line(ctx), offset(ctx), location(ctx), statements);
     }
 
     @Override
-    public ANode visitIf(final IfContext ctx) {
-        final AExpression condition = (AExpression)visit(ctx.expression());
-        final AStatement ifblock = (AStatement)visit(ctx.block(0));
-        final AStatement elseblock = ctx.block(1) == null ? null : (AStatement)visit(ctx.block(1));
+    public Object visitIf(IfContext ctx) {
+        AExpression expression = (AExpression)visitExpression(ctx.expression());
+        SBlock ifblock = (SBlock)visit(ctx.trailer(0));
 
-        return new SIfElse(line(ctx), location(ctx), condition, ifblock, elseblock);
+        if (ctx.trailer().size() > 1) {
+            SBlock elseblock = (SBlock)visit(ctx.trailer(1));
+
+            return new SIfElse(line(ctx), offset(ctx), location(ctx), expression, ifblock, elseblock);
+        } else {
+            return new SIf(line(ctx), offset(ctx), location(ctx), expression, ifblock);
+        }
     }
 
     @Override
-    public ANode visitWhile(final WhileContext ctx) {
-        final AExpression condition = (AExpression)visit(ctx.expression());
-        final AStatement block = ctx.block() == null ? null : (AStatement)visit(ctx.block());
+    public Object visitWhile(WhileContext ctx) {
+        if (settings.getMaxLoopCounter() > 0) {
+            reserved.usesLoop();
+        }
 
-        reserved.usesLoop();
+        AExpression expression = (AExpression)visitExpression(ctx.expression());
 
-        return new SWhile(line(ctx), location(ctx), condition, block, settings.getMaxLoopCounter());
+        if (ctx.trailer() != null) {
+            SBlock block = (SBlock)visit(ctx.trailer());
+
+            return new SWhile(line(ctx), offset(ctx), location(ctx), settings.getMaxLoopCounter(), expression, block);
+        } else if (ctx.empty() != null) {
+            return new SWhile(line(ctx), offset(ctx), location(ctx), settings.getMaxLoopCounter(), expression, null);
+        } else {
+            throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
+        }
     }
 
     @Override
-    public ANode visitDo(final DoContext ctx) {
-        final AStatement block = ctx.block() == null ? null : (AStatement)visit(ctx.block());
-        final AExpression condition = (AExpression)visit(ctx.expression());
+    public Object visitDo(DoContext ctx) {
+        if (settings.getMaxLoopCounter() > 0) {
+            reserved.usesLoop();
+        }
 
-        reserved.usesLoop();
+        AExpression expression = (AExpression)visitExpression(ctx.expression());
+        SBlock block = (SBlock)visit(ctx.block());
 
-        return new SDo(line(ctx), location(ctx), block, condition, settings.getMaxLoopCounter());
+        return new SDo(line(ctx), offset(ctx), location(ctx), settings.getMaxLoopCounter(), block, expression);
     }
 
     @Override
-    public ANode visitFor(final ForContext ctx) {
-        final ANode intializer = ctx.initializer() == null ? null : visit(ctx.initializer());
-        final AExpression condition = ctx.expression() == null ? null : (AExpression)visit(ctx.expression());
-        final AExpression afterthought = ctx.afterthought() == null ? null : (AExpression)visit(ctx.afterthought());
-        final AStatement block = ctx.block() == null ? null : (AStatement)visit(ctx.block());
+    public Object visitFor(ForContext ctx) {
+        if (settings.getMaxLoopCounter() > 0) {
+            reserved.usesLoop();
+        }
+
+        ANode initializer = ctx.initializer() == null ? null : (ANode)visit(ctx.initializer());
+        AExpression expression = ctx.expression() == null ? null : (AExpression)visitExpression(ctx.expression());
+        AExpression afterthought = ctx.afterthought() == null ? null : (AExpression)visit(ctx.afterthought());
 
-        reserved.usesLoop();
+        if (ctx.trailer() != null) {
+            SBlock block = (SBlock)visit(ctx.trailer());
 
-        return new SFor(line(ctx), location(ctx), intializer, condition, afterthought, block, settings.getMaxLoopCounter());
+            return new SFor(line(ctx), offset(ctx), location(ctx),
+                settings.getMaxLoopCounter(), initializer, expression, afterthought, block);
+        } else if (ctx.empty() != null) {
+            return new SFor(line(ctx), offset(ctx), location(ctx),
+                settings.getMaxLoopCounter(), initializer, expression, afterthought, null);
+        } else {
+            throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
+        }
     }
 
     @Override
-    public ANode visitDecl(final DeclContext ctx) {
+    public Object visitDecl(DeclContext ctx) {
         return visit(ctx.declaration());
     }
 
     @Override
-    public ANode visitContinue(final ContinueContext ctx) {
-        return new SContinue(line(ctx), location(ctx));
+    public Object visitContinue(ContinueContext ctx) {
+        return new SContinue(line(ctx), offset(ctx), location(ctx));
     }
 
     @Override
-    public ANode visitBreak(final BreakContext ctx) {
-        return new SBreak(line(ctx), location(ctx));
+    public Object visitBreak(BreakContext ctx) {
+        return new SBreak(line(ctx), offset(ctx), location(ctx));
     }
 
     @Override
-    public ANode visitReturn(final ReturnContext ctx) {
-        final AExpression expression = (AExpression)visit(ctx.expression());
+    public Object visitReturn(ReturnContext ctx) {
+        AExpression expression = (AExpression)visitExpression(ctx.expression());
 
-        return new SReturn(line(ctx), location(ctx), expression);
+        return new SReturn(line(ctx), offset(ctx), location(ctx), expression);
     }
 
     @Override
-    public ANode visitTry(final TryContext ctx) {
-        final AStatement block = (AStatement)visit(ctx.block());
-        final List<STrap> traps = new ArrayList<>();
+    public Object visitTry(TryContext ctx) {
+        SBlock block = (SBlock)visit(ctx.block());
+        List<SCatch> catches = new ArrayList<>();
 
-        for (final TrapContext trap : ctx.trap()) {
-            traps.add((STrap)visit(trap));
+        for (TrapContext trap : ctx.trap()) {
+            catches.add((SCatch)visit(trap));
         }
 
-        return new STry(line(ctx), location(ctx), block, traps);
+        return new STry(line(ctx), offset(ctx), location(ctx), block, catches);
     }
 
     @Override
-    public ANode visitThrow(final ThrowContext ctx) {
-        final AExpression expression = (AExpression)visit(ctx.expression());
+    public Object visitThrow(ThrowContext ctx) {
+        AExpression expression = (AExpression)visitExpression(ctx.expression());
 
-        return new SThrow(line(ctx), location(ctx), expression);
+        return new SThrow(line(ctx), offset(ctx), location(ctx), expression);
     }
 
     @Override
-    public ANode visitExpr(final ExprContext ctx) {
-        final AExpression expression = (AExpression)visit(ctx.expression());
+    public Object visitExpr(ExprContext ctx) {
+        AExpression expression = (AExpression)visitExpression(ctx.expression());
 
-        return new SExpression(line(ctx), location(ctx), expression);
+        return new SExpression(line(ctx), offset(ctx), location(ctx), expression);
     }
 
     @Override
-    public ANode visitMultiple(final MultipleContext ctx) {
-        final List<AStatement> statements = new ArrayList<>();
+    public Object visitTrailer(TrailerContext ctx) {
+        if (ctx.block() != null) {
+            return visit(ctx.block());
+        } else if (ctx.statement() != null) {
+            List<AStatement> statements = new ArrayList<>();
+            statements.add((AStatement)visit(ctx.statement()));
 
-        for (final StatementContext statement : ctx.statement()) {
-            statements.add((AStatement)visit(statement));
+            return new SBlock(line(ctx), offset(ctx), location(ctx), statements);
+        } else {
+            throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
         }
-
-        return new SBlock(line(ctx), location(ctx), statements);
     }
 
     @Override
-    public ANode visitSingle(final SingleContext ctx) {
-        final List<AStatement> statements = new ArrayList<>();
-        statements.add((AStatement)visit(ctx.statement()));
+    public Object visitBlock(BlockContext ctx) {
+        if (ctx.statement().isEmpty()) {
+            return null;
+        } else {
+            List<AStatement> statements = new ArrayList<>();
 
-        return new SBlock(line(ctx), location(ctx), statements);
-    }
+            for (StatementContext statement : ctx.statement()) {
+                statements.add((AStatement)visit(statement));
+            }
 
-    @Override
-    public ANode visitEmpty(final EmptyContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+            return new SBlock(line(ctx), offset(ctx), location(ctx), statements);
+        }
     }
 
     @Override
-    public ANode visitEmptyscope(final EmptyscopeContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+    public Object visitEmpty(EmptyContext ctx) {
+        throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
     }
 
     @Override
-    public ANode visitInitializer(final InitializerContext ctx) {
+    public Object visitInitializer(InitializerContext ctx) {
         if (ctx.declaration() != null) {
             return visit(ctx.declaration());
         } else if (ctx.expression() != null) {
-            return visit(ctx.expression());
-        }
-
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
-    }
-
-    @Override
-    public ANode visitAfterthought(final AfterthoughtContext ctx) {
-        return visit(ctx.expression());
-    }
-
-    @Override
-    public ANode visitDeclaration(final DeclarationContext ctx) {
-        final String type = ctx.decltype().getText();
-        final List<SDeclaration> declarations = new ArrayList<>();
-
-        for (final DeclvarContext declvar : ctx.declvar()) {
-            final String name = declvar.identifier().getText();
-            final AExpression expression = declvar.expression() == null ? null : (AExpression)visit(declvar.expression());
-            declarations.add(new SDeclaration(line(ctx), location(ctx), type, name, expression));
+            return visitExpression(ctx.expression());
+        } else {
+            throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
         }
-
-        return new SDeclBlock(line(ctx), location(ctx), declarations);
     }
 
     @Override
-    public ANode visitDecltype(final DecltypeContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+    public Object visitAfterthought(AfterthoughtContext ctx) {
+        return visitExpression(ctx.expression());
     }
 
     @Override
-    public ANode visitDeclvar(final DeclvarContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
-    }
-
-    @Override
-    public ANode visitTrap(final TrapContext ctx) {
-        final String type = ctx.identifier(0).getText();
-        final String name = ctx.identifier(1).getText();
-        final AStatement block = ctx.block() == null ? null : (AStatement)visit(ctx.block());
+    public Object visitDeclaration(DeclarationContext ctx) {
+        String type = ctx.decltype().getText();
+        List<SDeclaration> declarations = new ArrayList<>();
 
-        return new STrap(line(ctx), location(ctx), type, name, block);
-    }
+        for (DeclvarContext declvar : ctx.declvar()) {
+            String name = declvar.ID().getText();
+            AExpression expression = declvar.expression() == null ? null : (AExpression)visitExpression(declvar.expression());
 
-    @Override
-    public ANode visitIdentifier(final IdentifierContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
-    }
-
-    @Override
-    public ANode visitGeneric(final GenericContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
-    }
-
-    @Override
-    public ANode visitPrecedence(final PrecedenceContext ctx) {
-        return visit(ctx.expression());
-    }
-
-    @Override
-    public ANode visitNumeric(final NumericContext ctx) {
-        final boolean negate = ctx.parent instanceof UnaryContext && ((UnaryContext)ctx.parent).SUB() != null;
-
-        if (ctx.DECIMAL() != null) {
-            return new EDecimal(line(ctx), location(ctx), (negate ? "-" : "") + ctx.DECIMAL().getText());
-        } else if (ctx.HEX() != null) {
-            return new ENumeric(line(ctx), location(ctx), (negate ? "-" : "") + ctx.HEX().getText().substring(2), 16);
-        } else if (ctx.INTEGER() != null) {
-            return new ENumeric(line(ctx), location(ctx), (negate ? "-" : "") + ctx.INTEGER().getText(), 10);
-        } else if (ctx.OCTAL() != null) {
-            return new ENumeric(line(ctx), location(ctx), (negate ? "-" : "") + ctx.OCTAL().getText().substring(1), 8);
-        } else {
-            throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+            declarations.add(new SDeclaration(line(ctx), offset(ctx), location(ctx), type, name, expression));
         }
-    }
 
-    @Override
-    public ANode visitTrue(final TrueContext ctx) {
-        return new EBoolean(line(ctx), location(ctx), true);
+        return new SDeclBlock(line(ctx), offset(ctx), location(ctx), declarations);
     }
 
     @Override
-    public ANode visitFalse(FalseContext ctx) {
-        return new EBoolean(line(ctx), location(ctx), false);
+    public Object visitDecltype(DecltypeContext ctx) {
+        throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
     }
 
     @Override
-    public ANode visitNull(final NullContext ctx) {
-        return new ENull(line(ctx), location(ctx));
+    public Object visitDeclvar(DeclvarContext ctx) {
+        throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
     }
 
     @Override
-    public ANode visitPostinc(final PostincContext ctx) {
-        final List<ALink> links = new ArrayList<>();
-        final Operation operation;
-
-        visitChain(ctx.chain(), links);
-
-        if (ctx.INCR() != null) {
-            operation = Operation.INCR;
-        } else if (ctx.DECR() != null) {
-            operation = Operation.DECR;
-        } else {
-            throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
-        }
+    public Object visitTrap(TrapContext ctx) {
+        String type = ctx.TYPE().getText();
+        String name = ctx.ID().getText();
+        SBlock block = (SBlock)visit(ctx.block());
 
-        return new EChain(line(ctx), location(ctx), links, false, true, operation, null);
+        return new SCatch(line(ctx), offset(ctx), location(ctx), type, name, block);
     }
 
     @Override
-    public ANode visitPreinc(final PreincContext ctx) {
-        final List<ALink> links = new ArrayList<>();
-        final Operation operation;
-
-        visitChain(ctx.chain(), links);
-
-        if (ctx.INCR() != null) {
-            operation = Operation.INCR;
-        } else if (ctx.DECR() != null) {
-            operation = Operation.DECR;
-        } else {
-            throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
-        }
-
-        return new EChain(line(ctx), location(ctx), links, true, false, operation, null);
+    public Object visitDelimiter(DelimiterContext ctx) {
+        throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
     }
 
-    @Override
-    public ANode visitRead(final ReadContext ctx) {
-        final List<ALink> links = new ArrayList<>();
-
-        visitChain(ctx.chain(), links);
+    private Object visitExpression(ExpressionContext ctx) {
+        Object expression = visit(ctx);
 
-        return new EChain(line(ctx), location(ctx), links, false, false, null, null);
-    }
+        if (expression instanceof List) {
+            @SuppressWarnings("unchecked")
+            List<ALink> links = (List<ALink>)expression;
 
-    @Override
-    public ANode visitUnary(final UnaryContext ctx) {
-        if (ctx.SUB() != null && ctx.expression() instanceof NumericContext) {
-            return visit(ctx.expression());
+            return new EChain(line(ctx), offset(ctx), location(ctx), links, false, false, null, null);
         } else {
-            final Operation operation;
-
-            if (ctx.BOOLNOT() != null) {
-                operation = Operation.NOT;
-            } else if (ctx.BWNOT() != null) {
-                operation = Operation.BWNOT;
-            } else if (ctx.ADD() != null) {
-                operation = Operation.ADD;
-            } else if (ctx.SUB() != null) {
-                operation = Operation.SUB;
-            } else {
-                throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
-            }
-
-            return new EUnary(line(ctx), location(ctx), operation, (AExpression)visit(ctx.expression()));
+            return expression;
         }
     }
 
     @Override
-    public ANode visitCast(final CastContext ctx) {
-        return new EExplicit(line(ctx), location(ctx), ctx.decltype().getText(), (AExpression)visit(ctx.expression()));
+    public Object visitSingle(SingleContext ctx) {
+        return visit(ctx.unary());
     }
 
     @Override
-    public ANode visitBinary(final BinaryContext ctx) {
-        final AExpression left = (AExpression)visit(ctx.expression(0));
-        final AExpression right = (AExpression)visit(ctx.expression(1));
+    public Object visitBinary(BinaryContext ctx) {
+        AExpression left = (AExpression)visitExpression(ctx.expression(0));
+        AExpression right = (AExpression)visitExpression(ctx.expression(1));
         final Operation operation;
 
         if (ctx.MUL() != null) {
@@ -487,13 +460,13 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
             throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
         }
 
-        return new EBinary(line(ctx), location(ctx), operation, left, right);
+        return new EBinary(line(ctx), offset(ctx), location(ctx), operation, left, right);
     }
 
     @Override
-    public ANode visitComp(PainlessParser.CompContext ctx) {
-        final AExpression left = (AExpression)visit(ctx.expression(0));
-        final AExpression right = (AExpression)visit(ctx.expression(1));
+    public Object visitComp(CompContext ctx) {
+        AExpression left = (AExpression)visitExpression(ctx.expression(0));
+        AExpression right = (AExpression)visitExpression(ctx.expression(1));
         final Operation operation;
 
         if (ctx.LT() != null) {
@@ -516,13 +489,13 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
             throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
         }
 
-        return new EComp(line(ctx), location(ctx), operation, left, right);
+        return new EComp(line(ctx), offset(ctx), location(ctx), operation, left, right);
     }
 
     @Override
-    public ANode visitBool(PainlessParser.BoolContext ctx) {
-        final AExpression left = (AExpression)visit(ctx.expression(0));
-        final AExpression right = (AExpression)visit(ctx.expression(1));
+    public Object visitBool(BoolContext ctx) {
+        AExpression left = (AExpression)visitExpression(ctx.expression(0));
+        AExpression right = (AExpression)visitExpression(ctx.expression(1));
         final Operation operation;
 
         if (ctx.BOOLAND() != null) {
@@ -533,27 +506,27 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
             throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
         }
 
-        return new EBool(line(ctx), location(ctx), operation, left, right);
+        return new EBool(line(ctx), offset(ctx), location(ctx), operation, left, right);
     }
 
-
     @Override
-    public ANode visitConditional(final ConditionalContext ctx) {
-        final AExpression condition = (AExpression)visit(ctx.expression(0));
-        final AExpression left = (AExpression)visit(ctx.expression(1));
-        final AExpression right = (AExpression)visit(ctx.expression(2));
+    public Object visitConditional(ConditionalContext ctx) {
+        AExpression condition = (AExpression)visitExpression(ctx.expression(0));
+        AExpression left = (AExpression)visitExpression(ctx.expression(1));
+        AExpression right = (AExpression)visitExpression(ctx.expression(2));
 
-        return new EConditional(line(ctx), location(ctx), condition, left, right);
+        return new EConditional(line(ctx), offset(ctx), location(ctx), condition, left, right);
     }
 
     @Override
-    public ANode visitAssignment(final AssignmentContext ctx) {
-        final List<ALink> links = new ArrayList<>();
+    public Object visitAssignment(AssignmentContext ctx) {
+        @SuppressWarnings("unchecked")
+        List<ALink> links = (List<ALink>)visit(ctx.chain());
         final Operation operation;
 
-        visitChain(ctx.chain(), links);
-
-        if (ctx.AMUL() != null) {
+        if (ctx.ASSIGN() != null) {
+            operation = null;
+        } else if (ctx.AMUL() != null) {
             operation = Operation.MUL;
         } else if (ctx.ADIV() != null) {
             operation = Operation.DIV;
@@ -576,222 +549,290 @@ public final class Walker extends PainlessParserBaseVisitor<ANode> {
         } else if (ctx.AOR() != null) {
             operation = Operation.BWOR;
         } else {
-            operation = null;
+            throw new IllegalStateException("Error " + location(ctx) + ": Illegal tree structure.");
         }
 
-        return new EChain(line(ctx), location(ctx), links, false, false, operation, (AExpression)visit(ctx.expression()));
+        AExpression expression = (AExpression)visitExpression(ctx.expression());
+
+        return new EChain(line(ctx), offset(ctx), location(ctx), links, false, false, operation, expression);
     }
 
-    private void visitChain(final ChainContext ctx, final List<ALink> links) {
-        if (ctx.linkprec() != null) {
-            visitLinkprec(ctx.linkprec(), links);
-        } else if (ctx.linkcast() != null) {
-            visitLinkcast(ctx.linkcast(), links);
-        } else if (ctx.linkvar() != null) {
-            visitLinkvar(ctx.linkvar(), links);
-        } else if (ctx.linknew() != null) {
-            visitLinknew(ctx.linknew(), links);
-        } else if (ctx.linkstring() != null) {
-            visitLinkstring(ctx.linkstring(), links);
+    private Object visitUnary(UnaryContext ctx) {
+        Object expression = visit(ctx);
+
+        if (expression instanceof List) {
+            @SuppressWarnings("unchecked")
+            List<ALink> links = (List<ALink>)expression;
+
+            return new EChain(line(ctx), offset(ctx), location(ctx), links, false, false, null, null);
         } else {
-            throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+            return expression;
         }
     }
 
     @Override
-    public ANode visitChain(final ChainContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
-    }
+    public Object visitPre(PreContext ctx) {
+        @SuppressWarnings("unchecked")
+        List<ALink> links = (List<ALink>)visit(ctx.chain());
+        final Operation operation;
 
-    private void visitLinkprec(final LinkprecContext ctx, final List<ALink> links) {
-        if (ctx.linkprec() != null) {
-            visitLinkprec(ctx.linkprec(), links);
-        } else if (ctx.linkcast() != null) {
-            visitLinkcast(ctx.linkcast(), links);
-        } else if (ctx.linkvar() != null) {
-            visitLinkvar(ctx.linkvar(), links);
-        } else if (ctx.linknew() != null) {
-            visitLinknew(ctx.linknew(), links);
-        } else if (ctx.linkstring() != null) {
-            visitLinkstring(ctx.linkstring(), links);
+        if (ctx.INCR() != null) {
+            operation = Operation.INCR;
+        } else if (ctx.DECR() != null) {
+            operation = Operation.DECR;
         } else {
-            throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+            throw new IllegalStateException("Error " + location(ctx) + ": Illegal tree structure.");
         }
 
-        if (ctx.linkbrace() != null) {
-            visitLinkbrace(ctx.linkbrace(), links);
-        } else if (ctx.linkdot() != null) {
-            visitLinkdot(ctx.linkdot(), links);
-        }
+        return new EChain(line(ctx), offset(ctx), location(ctx), links, true, false, operation, null);
     }
 
     @Override
-    public ANode visitLinkprec(final LinkprecContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
-    }
+    public Object visitPost(PostContext ctx) {
+        @SuppressWarnings("unchecked")
+        List<ALink> links = (List<ALink>)visit(ctx.chain());
+        final Operation operation;
 
-    private void visitLinkcast(final LinkcastContext ctx, final List<ALink> links) {
-        if (ctx.linkprec() != null) {
-            visitLinkprec(ctx.linkprec(), links);
-        } else if (ctx.linkcast() != null) {
-            visitLinkcast(ctx.linkcast(), links);
-        } else if (ctx.linkvar() != null) {
-            visitLinkvar(ctx.linkvar(), links);
-        } else if (ctx.linknew() != null) {
-            visitLinknew(ctx.linknew(), links);
-        } else if (ctx.linkstring() != null) {
-            visitLinkstring(ctx.linkstring(), links);
+        if (ctx.INCR() != null) {
+            operation = Operation.INCR;
+        } else if (ctx.DECR() != null) {
+            operation = Operation.DECR;
         } else {
-            throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+            throw new IllegalStateException("Error " + location(ctx) + ": Illegal tree structure.");
         }
 
-        links.add(new LCast(line(ctx), location(ctx), ctx.decltype().getText()));
+        return new EChain(line(ctx), offset(ctx), location(ctx), links, false, true, operation, null);
     }
 
     @Override
-    public ANode visitLinkcast(final LinkcastContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+    public Object visitRead(ReadContext ctx) {
+        return visit(ctx.chain());
     }
 
-    private void visitLinkbrace(final LinkbraceContext ctx, final List<ALink> links) {
-        links.add(new LBrace(line(ctx), location(ctx), (AExpression)visit(ctx.expression())));
+    @Override
+    public Object visitNumeric(NumericContext ctx) {
+        final boolean negate = ctx.parent instanceof OperatorContext && ((OperatorContext)ctx.parent).SUB() != null;
 
-        if (ctx.linkbrace() != null) {
-            visitLinkbrace(ctx.linkbrace(), links);
-        } else if (ctx.linkdot() != null) {
-            visitLinkdot(ctx.linkdot(), links);
+        if (ctx.DECIMAL() != null) {
+            return new EDecimal(line(ctx), offset(ctx), location(ctx), (negate ? "-" : "") + ctx.DECIMAL().getText());
+        } else if (ctx.HEX() != null) {
+            return new ENumeric(line(ctx), offset(ctx), location(ctx), (negate ? "-" : "") + ctx.HEX().getText().substring(2), 16);
+        } else if (ctx.INTEGER() != null) {
+            return new ENumeric(line(ctx), offset(ctx), location(ctx), (negate ? "-" : "") + ctx.INTEGER().getText(), 10);
+        } else if (ctx.OCTAL() != null) {
+            return new ENumeric(line(ctx), offset(ctx), location(ctx), (negate ? "-" : "") + ctx.OCTAL().getText().substring(1), 8);
+        } else {
+            throw new IllegalStateException("Error " + location(ctx) + ": Illegal tree structure.");
         }
     }
 
     @Override
-    public ANode visitLinkbrace(final LinkbraceContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+    public Object visitTrue(TrueContext ctx) {
+        return new EBoolean(line(ctx), offset(ctx), location(ctx), true);
     }
 
-    private void visitLinkdot(final LinkdotContext ctx, final List<ALink> links) {
-        if (ctx.linkcall() != null) {
-            visitLinkcall(ctx.linkcall(), links);
-        } else if (ctx.linkfield() != null) {
-            visitLinkfield(ctx.linkfield(), links);
-        }
+    @Override
+    public Object visitFalse(FalseContext ctx) {
+        return new EBoolean(line(ctx), offset(ctx), location(ctx), false);
     }
 
     @Override
-    public ANode visitLinkdot(final LinkdotContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+    public Object visitNull(NullContext ctx) {
+        return new ENull(line(ctx), offset(ctx), location(ctx));
     }
 
-    private void visitLinkcall(final LinkcallContext ctx, final List<ALink> links) {
-        final List<AExpression> arguments = new ArrayList<>();
-
-        for (final ExpressionContext expression : ctx.arguments().expression()) {
-            arguments.add((AExpression)visit(expression));
-        }
+    @Override
+    public Object visitOperator(OperatorContext ctx) {
+        if (ctx.SUB() != null && ctx.unary() instanceof NumericContext) {
+            return visit(ctx.unary());
+        } else {
+            AExpression expression = (AExpression)visitUnary(ctx.unary());
+            final Operation operation;
 
-        links.add(new LCall(line(ctx), location(ctx), ctx.EXTID().getText(), arguments));
+            if (ctx.BOOLNOT() != null) {
+                operation = Operation.NOT;
+            } else if (ctx.BWNOT() != null) {
+                operation = Operation.BWNOT;
+            } else if (ctx.ADD() != null) {
+                operation = Operation.ADD;
+            } else if (ctx.SUB() != null) {
+                operation = Operation.SUB;
+            } else {
+                throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
+            }
 
-        if (ctx.linkbrace() != null) {
-            visitLinkbrace(ctx.linkbrace(), links);
-        } else if (ctx.linkdot() != null) {
-            visitLinkdot(ctx.linkdot(), links);
+            return new EUnary(line(ctx), offset(ctx), location(ctx), operation, expression);
         }
     }
 
     @Override
-    public ANode visitLinkcall(final LinkcallContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+    public Object visitCast(CastContext ctx) {
+        String type = ctx.decltype().getText();
+        Object child = visit(ctx.unary());
+
+        if (child instanceof List) {
+            @SuppressWarnings("unchecked")
+            List<ALink> links = (List<ALink>)child;
+            links.add(new LCast(line(ctx), offset(ctx), location(ctx), type));
+
+            return links;
+        } else {
+            return new EExplicit(line(ctx), offset(ctx), location(ctx), type, (AExpression)child);
+        }
     }
 
-    private void visitLinkvar(final LinkvarContext ctx, final List<ALink> links) {
-        final String name = ctx.identifier().getText();
+    @Override
+    public Object visitDynamic(DynamicContext ctx) {
+        Object child = visit(ctx.primary());
 
-        reserved.markReserved(name);
+        if (child instanceof List) {
+            @SuppressWarnings("unchecked")
+            List<ALink> links = (List<ALink>)child;
 
-        links.add(new LVariable(line(ctx), location(ctx), name));
+            for (SecondaryContext secondary : ctx.secondary()) {
+                links.add((ALink)visit(secondary));
+            }
 
-        if (ctx.linkbrace() != null) {
-            visitLinkbrace(ctx.linkbrace(), links);
-        } else if (ctx.linkdot() != null) {
-            visitLinkdot(ctx.linkdot(), links);
+            return links;
+        } else if (!ctx.secondary().isEmpty()) {
+            throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
+        } else {
+            return child;
         }
     }
 
     @Override
-    public ANode visitLinkvar(final LinkvarContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+    public Object visitStatic(StaticContext ctx) {
+        String type = ctx.decltype().getText();
+        List<ALink> links = new ArrayList<>();
+
+        links.add(new LStatic(line(ctx), offset(ctx), location(ctx), type));
+        links.add((ALink)visit(ctx.dot()));
+
+        for (SecondaryContext secondary : ctx.secondary()) {
+            links.add((ALink)visit(secondary));
+        }
+
+        return links;
     }
 
-    private void visitLinkfield(final LinkfieldContext ctx, final List<ALink> links) {
-        final String value;
+    @Override
+    public Object visitNewarray(NewarrayContext ctx) {
+        String type = ctx.TYPE().getText();
+        List<AExpression> expressions = new ArrayList<>();
 
-        if (ctx.EXTID() != null) {
-            value = ctx.EXTID().getText();
-        } else if (ctx.EXTINTEGER() != null) {
-            value = ctx.EXTINTEGER().getText();
-        } else {
-            throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+        for (ExpressionContext expression : ctx.expression()) {
+            expressions.add((AExpression)visitExpression(expression));
         }
 
-        links.add(new LField(line(ctx), location(ctx), value));
+        List<ALink> links = new ArrayList<>();
+        links.add(new LNewArray(line(ctx), offset(ctx), location(ctx), type, expressions));
+
+        if (ctx.dot() != null) {
+            links.add((ALink)visit(ctx.dot()));
 
-        if (ctx.linkbrace() != null) {
-            visitLinkbrace(ctx.linkbrace(), links);
-        } else if (ctx.linkdot() != null) {
-            visitLinkdot(ctx.linkdot(), links);
+            for (SecondaryContext secondary : ctx.secondary()) {
+                links.add((ALink)visit(secondary));
+            }
+        } else if (!ctx.secondary().isEmpty()) {
+            throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
         }
+
+        return links;
     }
 
     @Override
-    public ANode visitLinkfield(final LinkfieldContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+    public Object visitExprprec(ExprprecContext ctx) {
+        return visit(ctx.expression());
     }
 
-    private void visitLinknew(final LinknewContext ctx, final List<ALink> links) {
-        final List<AExpression> arguments = new ArrayList<>();
+    @Override
+    public Object visitChainprec(ChainprecContext ctx) {
+        return visit(ctx.unary());
+    }
 
-        if (ctx.arguments() != null) {
-            for (final ExpressionContext expression : ctx.arguments().expression()) {
-                arguments.add((AExpression)visit(expression));
-            }
+    @Override
+    public Object visitString(StringContext ctx) {
+        String string = ctx.STRING().getText().substring(1, ctx.STRING().getText().length() - 1);
+        List<ALink> links = new ArrayList<>();
+        links.add(new LString(line(ctx), offset(ctx), location(ctx), string));
 
-            links.add(new LNewObj(line(ctx), location(ctx), ctx.identifier().getText(), arguments));
-        } else if (ctx.expression().size() > 0) {
-            for (final ExpressionContext expression : ctx.expression()) {
-                arguments.add((AExpression)visit(expression));
-            }
+        return links;
+    }
 
-            links.add(new LNewArray(line(ctx), location(ctx), ctx.identifier().getText(), arguments));
-        } else {
-            throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+    @Override
+    public Object visitVariable(VariableContext ctx) {
+        String name = ctx.ID().getText();
+        List<ALink> links = new ArrayList<>();
+        links.add(new LVariable(line(ctx), offset(ctx), location(ctx), name));
+
+        reserved.markReserved(name);
+
+        return links;
+    }
+
+    @Override
+    public Object visitNewobject(NewobjectContext ctx) {
+        String type = ctx.TYPE().getText();
+        List<AExpression> arguments = new ArrayList<>();
+
+        for (ExpressionContext expression : ctx.arguments().expression()) {
+            arguments.add((AExpression)visitExpression(expression));
         }
 
-        if (ctx.linkdot() != null) {
-            visitLinkdot(ctx.linkdot(), links);
+        List<ALink> links = new ArrayList<>();
+        links.add(new LNewObj(line(ctx), offset(ctx), location(ctx), type, arguments));
+
+        return links;
+    }
+
+    @Override
+    public Object visitSecondary(SecondaryContext ctx) {
+        if (ctx.dot() != null) {
+            return visit(ctx.dot());
+        } else if (ctx.brace() != null) {
+            return visit(ctx.brace());
+        } else {
+            throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
         }
     }
 
     @Override
-    public ANode visitLinknew(final LinknewContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+    public Object visitCallinvoke(CallinvokeContext ctx) {
+        String name = ctx.DOTID().getText();
+        List<AExpression> arguments = new ArrayList<>();
+
+        for (ExpressionContext expression : ctx.arguments().expression()) {
+            arguments.add((AExpression)visitExpression(expression));
+        }
+
+        return new LCall(line(ctx), offset(ctx), location(ctx), name, arguments);
     }
 
-    private void visitLinkstring(final LinkstringContext ctx, final List<ALink> links) {
-        links.add(new LString(line(ctx), location(ctx), ctx.STRING().getText().substring(1, ctx.STRING().getText().length() - 1)));
+    @Override
+    public Object visitFieldaccess(FieldaccessContext ctx) {
+        final String value;
 
-        if (ctx.linkbrace() != null) {
-            visitLinkbrace(ctx.linkbrace(), links);
-        } else if (ctx.linkdot() != null) {
-            visitLinkdot(ctx.linkdot(), links);
+        if (ctx.DOTID() != null) {
+            value = ctx.DOTID().getText();
+        } else if (ctx.DOTINTEGER() != null) {
+            value = ctx.DOTINTEGER().getText();
+        } else {
+            throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
         }
+
+        return new LField(line(ctx), offset(ctx), location(ctx), value);
     }
 
     @Override
-    public ANode visitLinkstring(final LinkstringContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+    public Object visitBraceaccess(BraceaccessContext ctx) {
+        AExpression expression = (AExpression)visitExpression(ctx.expression());
+
+        return new LBrace(line(ctx), offset(ctx), location(ctx), expression);
     }
 
     @Override
-    public ANode visitArguments(final ArgumentsContext ctx) {
-        throw new IllegalStateException("Error " + location(ctx) + ": Unexpected state.");
+    public Object visitArguments(ArgumentsContext ctx) {
+        throw new IllegalStateException("Error " + location(ctx) + " Illegal tree structure.");
     }
 }

+ 9 - 9
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AExpression.java

@@ -98,8 +98,8 @@ public abstract class AExpression extends ANode {
      */
     protected Label fals = null;
 
-    public AExpression(final int line, final String location) {
-        super(line, location);
+    public AExpression(int line, int offset, String location) {
+        super(line, offset, location);
     }
 
     /**
@@ -110,7 +110,7 @@ public abstract class AExpression extends ANode {
     /**
      * Writes ASM based on the data collected during the analysis phase.
      */
-    abstract void write(MethodWriter adapter);
+    abstract void write(MethodWriter writer);
 
     /**
      * Inserts {@link ECast} nodes into the tree for implicit casts.  Also replaces
@@ -124,7 +124,7 @@ public abstract class AExpression extends ANode {
             if (constant == null || this instanceof EConstant) {
                 return this;
             } else {
-                final EConstant econstant = new EConstant(line, location, constant);
+                final EConstant econstant = new EConstant(line, offset, location, constant);
                 econstant.analyze(variables);
 
                 if (!expected.equals(econstant.actual)) {
@@ -135,7 +135,7 @@ public abstract class AExpression extends ANode {
             }
         } else {
             if (constant == null) {
-                final ECast ecast = new ECast(line, location, this, cast);
+                final ECast ecast = new ECast(line, offset, location, this, cast);
                 ecast.statement = statement;
                 ecast.actual = expected;
                 ecast.isNull = isNull;
@@ -145,7 +145,7 @@ public abstract class AExpression extends ANode {
                 if (expected.sort.constant) {
                     constant = AnalyzerCaster.constCast(location, constant, cast);
 
-                    final EConstant econstant = new EConstant(line, location, constant);
+                    final EConstant econstant = new EConstant(line, offset, location, constant);
                     econstant.analyze(variables);
 
                     if (!expected.equals(econstant.actual)) {
@@ -154,19 +154,19 @@ public abstract class AExpression extends ANode {
 
                     return econstant;
                 } else if (this instanceof EConstant) {
-                    final ECast ecast = new ECast(line, location, this, cast);
+                    final ECast ecast = new ECast(line, offset, location, this, cast);
                     ecast.actual = expected;
 
                     return ecast;
                 } else {
-                    final EConstant econstant = new EConstant(line, location, constant);
+                    final EConstant econstant = new EConstant(line, offset, location, constant);
                     econstant.analyze(variables);
 
                     if (!actual.equals(econstant.actual)) {
                         throw new IllegalStateException(error("Illegal tree structure."));
                     }
 
-                    final ECast ecast = new ECast(line, location, econstant, cast);
+                    final ECast ecast = new ECast(line, offset, location, econstant, cast);
                     ecast.actual = expected;
 
                     return ecast;

+ 5 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ALink.java

@@ -73,8 +73,8 @@ public abstract class ALink extends ANode {
      */
     String string = null;
 
-    ALink(int line, String location, int size) {
-        super(line, location);
+    ALink(int line, int offset, String location, int size) {
+        super(line, offset, location);
 
         this.size = size;
     }
@@ -90,17 +90,17 @@ public abstract class ALink extends ANode {
     /**
      * Write values before a load/store occurs such as an array index.
      */
-    abstract void write(MethodWriter adapter);
+    abstract void write(MethodWriter writer);
 
     /**
      * Write a load for the specific link type.
      */
-    abstract void load(MethodWriter adapter);
+    abstract void load(MethodWriter writer);
 
     /**
      * Write a store for the specific link type.
      */
-    abstract void store(MethodWriter adapter);
+    abstract void store(MethodWriter writer);
 
     /**
      * Used to copy link data from one to another during analysis in the case of replacement.

+ 13 - 7
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ANode.java

@@ -28,32 +28,38 @@ import org.objectweb.asm.Label;
 public abstract class ANode {
 
     /**
-     * The line number in the original source used for debug messages.
+     * The line number in the original source used for debugging and errors.
      */
     final int line;
 
+    /**
+     * The character offset in the original source used for debugging and errors.
+     */
+    final int offset;
+
     /**
      * The location in the original source to be printed in error messages.
      */
     final String location;
 
-    ANode(final int line, final String location) {
+    ANode(int line, int offset, String location) {
         this.line = line;
+        this.offset = offset;
         this.location = location;
     }
 
     public String error(final String message) {
         return "Error " + location  + ": " + message;
     }
-    
-    /** 
+
+    /**
      * Writes line number information
      * <p>
      * Currently we emit line number data for for leaf S-nodes
      */
-    void writeDebugInfo(MethodWriter adapter) {
+    void writeDebugInfo(MethodWriter writer) {
         Label label = new Label();
-        adapter.visitLabel(label);
-        adapter.visitLineNumber(line, label);
+        writer.visitLabel(label);
+        writer.visitLineNumber(line, label);
     }
 }

+ 3 - 3
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/AStatement.java

@@ -107,8 +107,8 @@ public abstract class AStatement extends ANode {
      */
     Label brake = null;
 
-    AStatement(int line, String location) {
-        super(line, location);
+    AStatement(int line, int offset, String location) {
+        super(line, offset, location);
     }
 
     /**
@@ -119,5 +119,5 @@ public abstract class AStatement extends ANode {
     /**
      * Writes ASM based on the data collected during the analysis phase.
      */
-    abstract void write(MethodWriter adapter);
+    abstract void write(MethodWriter writer);
 }

+ 35 - 35
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBinary.java

@@ -38,8 +38,8 @@ public final class EBinary extends AExpression {
 
     boolean cat = false;
 
-    public EBinary(int line, String location, Operation operation, AExpression left, AExpression right) {
-        super(line, location);
+    public EBinary(int line, int offset, String location, Operation operation, AExpression left, AExpression right) {
+        super(line, offset, location);
 
         this.operation = operation;
         this.left = left;
@@ -79,7 +79,7 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply multiply [*] to types " +
@@ -93,7 +93,7 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant * (int)right.constant;
@@ -115,7 +115,7 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply divide [/] to types " +
@@ -129,7 +129,7 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant / (int)right.constant;
@@ -151,7 +151,7 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply remainder [%] to types " +
@@ -165,7 +165,7 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant % (int)right.constant;
@@ -187,14 +187,14 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteAdd(left.actual, right.actual);
+        Type promote = AnalyzerCaster.promoteAdd(left.actual, right.actual);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply add [+] to types " +
                 "[" + left.actual.name + "] and [" + right.actual.name + "]."));
         }
 
-        final Sort sort = promote.sort;
+        Sort sort = promote.sort;
 
         if (sort == Sort.STRING) {
             left.expected = left.actual;
@@ -239,7 +239,7 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply subtract [-] to types " +
@@ -253,7 +253,7 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant - (int)right.constant;
@@ -275,7 +275,7 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply left shift [<<] to types " +
@@ -290,7 +290,7 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant << (int)right.constant;
@@ -308,7 +308,7 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply right shift [>>] to types " +
@@ -323,7 +323,7 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant >> (int)right.constant;
@@ -341,7 +341,7 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, false);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply unsigned shift [>>>] to types " +
@@ -356,7 +356,7 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant >>> (int)right.constant;
@@ -374,7 +374,7 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply and [&] to types " +
@@ -388,7 +388,7 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant & (int)right.constant;
@@ -406,7 +406,7 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteXor(left.actual, right.actual);
+        Type promote = AnalyzerCaster.promoteXor(left.actual, right.actual);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply xor [^] to types " +
@@ -420,7 +420,7 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.BOOL) {
                 constant = (boolean)left.constant ^ (boolean)right.constant;
@@ -440,7 +440,7 @@ public final class EBinary extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, false);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply or [|] to types " +
@@ -454,7 +454,7 @@ public final class EBinary extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant | (int)right.constant;
@@ -469,34 +469,34 @@ public final class EBinary extends AExpression {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         if (actual.sort == Sort.STRING && operation == Operation.ADD) {
             if (!cat) {
-                adapter.writeNewStrings();
+                writer.writeNewStrings();
             }
 
-            left.write(adapter);
+            left.write(writer);
 
             if (!(left instanceof EBinary) || ((EBinary)left).operation != Operation.ADD || left.actual.sort != Sort.STRING) {
-                adapter.writeAppendStrings(left.actual);
+                writer.writeAppendStrings(left.actual);
             }
 
-            right.write(adapter);
+            right.write(writer);
 
             if (!(right instanceof EBinary) || ((EBinary)right).operation != Operation.ADD || right.actual.sort != Sort.STRING) {
-                adapter.writeAppendStrings(right.actual);
+                writer.writeAppendStrings(right.actual);
             }
 
             if (!cat) {
-                adapter.writeToStrings();
+                writer.writeToStrings();
             }
         } else {
-            left.write(adapter);
-            right.write(adapter);
+            left.write(writer);
+            right.write(writer);
 
-            adapter.writeBinaryInstruction(location, actual, operation);
+            writer.writeBinaryInstruction(location, actual, operation);
         }
 
-        adapter.writeBranch(tru, fals);
+        writer.writeBranch(tru, fals);
     }
 }

+ 31 - 31
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBool.java

@@ -34,8 +34,8 @@ public final class EBool extends AExpression {
     AExpression left;
     AExpression right;
 
-    public EBool(int line, String location, Operation operation, AExpression left, AExpression right) {
-        super(line, location);
+    public EBool(int line, int offset, String location, Operation operation, AExpression left, AExpression right) {
+        super(line, offset, location);
 
         this.operation = operation;
         this.left = left;
@@ -66,70 +66,70 @@ public final class EBool extends AExpression {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         if (tru != null || fals != null) {
             if (operation == Operation.AND) {
-                final Label localfals = fals == null ? new Label() : fals;
+                Label localfals = fals == null ? new Label() : fals;
 
                 left.fals = localfals;
                 right.tru = tru;
                 right.fals = fals;
 
-                left.write(adapter);
-                right.write(adapter);
+                left.write(writer);
+                right.write(writer);
 
                 if (fals == null) {
-                    adapter.mark(localfals);
+                    writer.mark(localfals);
                 }
             } else if (operation == Operation.OR) {
-                final Label localtru = tru == null ? new Label() : tru;
+                Label localtru = tru == null ? new Label() : tru;
 
                 left.tru = localtru;
                 right.tru = tru;
                 right.fals = fals;
 
-                left.write(adapter);
-                right.write(adapter);
+                left.write(writer);
+                right.write(writer);
 
                 if (tru == null) {
-                    adapter.mark(localtru);
+                    writer.mark(localtru);
                 }
             } else {
                 throw new IllegalStateException(error("Illegal tree structure."));
             }
         } else {
             if (operation == Operation.AND) {
-                final Label localfals = new Label();
-                final Label end = new Label();
+                Label localfals = new Label();
+                Label end = new Label();
 
                 left.fals = localfals;
                 right.fals = localfals;
 
-                left.write(adapter);
-                right.write(adapter);
+                left.write(writer);
+                right.write(writer);
 
-                adapter.push(true);
-                adapter.goTo(end);
-                adapter.mark(localfals);
-                adapter.push(false);
-                adapter.mark(end);
+                writer.push(true);
+                writer.goTo(end);
+                writer.mark(localfals);
+                writer.push(false);
+                writer.mark(end);
             } else if (operation == Operation.OR) {
-                final Label localtru = new Label();
-                final Label localfals = new Label();
-                final Label end = new Label();
+                Label localtru = new Label();
+                Label localfals = new Label();
+                Label end = new Label();
 
                 left.tru = localtru;
                 right.fals = localfals;
 
-                left.write(adapter);
-                right.write(adapter);
+                left.write(writer);
+                right.write(writer);
 
-                adapter.mark(localtru);
-                adapter.push(true);
-                adapter.goTo(end);
-                adapter.mark(localfals);
-                adapter.push(false);
-                adapter.mark(end);
+                writer.mark(localtru);
+                writer.push(true);
+                writer.goTo(end);
+                writer.mark(localfals);
+                writer.push(false);
+                writer.mark(end);
             } else {
                 throw new IllegalStateException(error("Illegal tree structure."));
             }

+ 2 - 2
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EBoolean.java

@@ -28,8 +28,8 @@ import org.elasticsearch.painless.MethodWriter;
  */
 public final class EBoolean extends AExpression {
 
-    public EBoolean(int line, String location, boolean constant) {
-        super(line, location);
+    public EBoolean(int line, int offset, String location, boolean constant) {
+        super(line, offset, location);
 
         this.constant = constant;
     }

+ 6 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ECast.java

@@ -34,8 +34,8 @@ final class ECast extends AExpression {
 
     Cast cast = null;
 
-    ECast(int line, String location, AExpression child, Cast cast) {
-        super(line, location);
+    ECast(int line, int offset, String location, AExpression child, Cast cast) {
+        super(line, offset, location);
 
         this.type = null;
         this.child = child;
@@ -49,9 +49,9 @@ final class ECast extends AExpression {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        child.write(adapter);
-        adapter.writeCast(cast);
-        adapter.writeBranch(tru, fals);
+    void write(MethodWriter writer) {
+        child.write(writer);
+        writer.writeCast(cast);
+        writer.writeBranch(tru, fals);
     }
 }

+ 47 - 47
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EChain.java

@@ -46,9 +46,9 @@ public final class EChain extends AExpression {
     Cast there = null;
     Cast back = null;
 
-    public EChain(int line, String location, List<ALink> links,
+    public EChain(int line, int offset, String location, List<ALink> links,
                   boolean pre, boolean post, Operation operation, AExpression expression) {
-        super(line, location);
+        super(line, offset, location);
 
         this.links = links;
         this.pre = pre;
@@ -76,7 +76,7 @@ public final class EChain extends AExpression {
         int index = 0;
 
         while (index < links.size()) {
-            final ALink current = links.get(index);
+            ALink current = links.get(index);
 
             if (previous != null) {
                 current.before = previous.after;
@@ -91,7 +91,7 @@ public final class EChain extends AExpression {
                 current.store = expression != null || pre || post;
             }
 
-            final ALink analyzed = current.analyze(variables);
+            ALink analyzed = current.analyze(variables);
 
             if (analyzed == null) {
                 links.remove(index);
@@ -111,7 +111,7 @@ public final class EChain extends AExpression {
     }
 
     private void analyzeIncrDecr() {
-        final ALink last = links.get(links.size() - 1);
+        ALink last = links.get(links.size() - 1);
 
         if (pre && post) {
             throw new IllegalStateException(error("Illegal tree structure."));
@@ -120,29 +120,29 @@ public final class EChain extends AExpression {
                 throw new IllegalStateException(error("Illegal tree structure."));
             }
 
-            final Sort sort = last.after.sort;
+            Sort sort = last.after.sort;
 
             if (operation == Operation.INCR) {
                 if (sort == Sort.DOUBLE) {
-                    expression = new EConstant(line, location, 1D);
+                    expression = new EConstant(line, offset, location, 1D);
                 } else if (sort == Sort.FLOAT) {
-                    expression = new EConstant(line, location, 1F);
+                    expression = new EConstant(line, offset, location, 1F);
                 } else if (sort == Sort.LONG) {
-                    expression = new EConstant(line, location, 1L);
+                    expression = new EConstant(line, offset, location, 1L);
                 } else {
-                    expression = new EConstant(line, location, 1);
+                    expression = new EConstant(line, offset, location, 1);
                 }
 
                 operation = Operation.ADD;
             } else if (operation == Operation.DECR) {
                 if (sort == Sort.DOUBLE) {
-                    expression = new EConstant(line, location, 1D);
+                    expression = new EConstant(line, offset, location, 1D);
                 } else if (sort == Sort.FLOAT) {
-                    expression = new EConstant(line, location, 1F);
+                    expression = new EConstant(line, offset, location, 1F);
                 } else if (sort == Sort.LONG) {
-                    expression = new EConstant(line, location, 1L);
+                    expression = new EConstant(line, offset, location, 1L);
                 } else {
-                    expression = new EConstant(line, location, 1);
+                    expression = new EConstant(line, offset, location, 1);
                 }
 
                 operation = Operation.SUB;
@@ -153,7 +153,7 @@ public final class EChain extends AExpression {
     }
 
     private void analyzeCompound(Variables variables) {
-        final ALink last = links.get(links.size() - 1);
+        ALink last = links.get(links.size() - 1);
 
         expression.analyze(variables);
 
@@ -214,9 +214,9 @@ public final class EChain extends AExpression {
     }
 
     private void analyzeWrite(Variables variables) {
-        final ALink last = links.get(links.size() - 1);
+        ALink last = links.get(links.size() - 1);
 
-        // If the store node is a DEF node, we remove the cast to DEF from the expression
+        // If the store node is a def node, we remove the cast to def from the expression
         // and promote the real type to it:
         if (last instanceof IDefLink) {
             expression.analyze(variables);
@@ -234,9 +234,9 @@ public final class EChain extends AExpression {
     }
 
     private void analyzeRead() {
-        final ALink last = links.get(links.size() - 1);
+        ALink last = links.get(links.size() - 1);
 
-        // If the load node is a DEF node, we adapt its after type to use _this_ expected output type:
+        // If the load node is a def node, we adapt its after type to use _this_ expected output type:
         if (last instanceof IDefLink && this.expected != null) {
             last.after = this.expected;
         }
@@ -247,70 +247,70 @@ public final class EChain extends AExpression {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         if (cat) {
-            adapter.writeNewStrings();
+            writer.writeNewStrings();
         }
 
-        final ALink last = links.get(links.size() - 1);
+        ALink last = links.get(links.size() - 1);
 
-        for (final ALink link : links) {
-            link.write(adapter);
+        for (ALink link : links) {
+            link.write(writer);
 
             if (link == last && link.store) {
                 if (cat) {
-                    adapter.writeDup(link.size, 1);
-                    link.load(adapter);
-                    adapter.writeAppendStrings(link.after);
+                    writer.writeDup(link.size, 1);
+                    link.load(writer);
+                    writer.writeAppendStrings(link.after);
 
-                    expression.write(adapter);
+                    expression.write(writer);
 
                     if (!(expression instanceof EBinary) ||
                         ((EBinary)expression).operation != Operation.ADD || expression.actual.sort != Sort.STRING) {
-                        adapter.writeAppendStrings(expression.actual);
+                        writer.writeAppendStrings(expression.actual);
                     }
 
-                    adapter.writeToStrings();
-                    adapter.writeCast(back);
+                    writer.writeToStrings();
+                    writer.writeCast(back);
 
                     if (link.load) {
-                        adapter.writeDup(link.after.sort.size, link.size);
+                        writer.writeDup(link.after.sort.size, link.size);
                     }
 
-                    link.store(adapter);
+                    link.store(writer);
                 } else if (operation != null) {
-                    adapter.writeDup(link.size, 0);
-                    link.load(adapter);
+                    writer.writeDup(link.size, 0);
+                    link.load(writer);
 
                     if (link.load && post) {
-                        adapter.writeDup(link.after.sort.size, link.size);
+                        writer.writeDup(link.after.sort.size, link.size);
                     }
 
-                    adapter.writeCast(there);
-                    expression.write(adapter);
-                    adapter.writeBinaryInstruction(location, promote, operation);
+                    writer.writeCast(there);
+                    expression.write(writer);
+                    writer.writeBinaryInstruction(location, promote, operation);
 
-                    adapter.writeCast(back);
+                    writer.writeCast(back);
 
                     if (link.load && !post) {
-                        adapter.writeDup(link.after.sort.size, link.size);
+                        writer.writeDup(link.after.sort.size, link.size);
                     }
 
-                    link.store(adapter);
+                    link.store(writer);
                 } else {
-                    expression.write(adapter);
+                    expression.write(writer);
 
                     if (link.load) {
-                        adapter.writeDup(link.after.sort.size, link.size);
+                        writer.writeDup(link.after.sort.size, link.size);
                     }
 
-                    link.store(adapter);
+                    link.store(writer);
                 }
             } else {
-                link.load(adapter);
+                link.load(writer);
             }
         }
 
-        adapter.writeBranch(tru, fals);
+        writer.writeBranch(tru, fals);
     }
 }

+ 65 - 65
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EComp.java

@@ -46,8 +46,8 @@ public final class EComp extends AExpression {
     AExpression left;
     AExpression right;
 
-    public EComp(int line, String location, Operation operation, AExpression left, AExpression right) {
-        super(line, location);
+    public EComp(int line, int offset, String location, Operation operation, AExpression left, AExpression right) {
+        super(line, offset, location);
 
         this.operation = operation;
         this.left = left;
@@ -81,7 +81,7 @@ public final class EComp extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
+        Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply equals [==] to types " +
@@ -99,7 +99,7 @@ public final class EComp extends AExpression {
         }
 
         if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.BOOL) {
                 constant = (boolean)left.constant == (boolean)right.constant;
@@ -127,7 +127,7 @@ public final class EComp extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
+        Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply reference equals [===] to types " +
@@ -145,7 +145,7 @@ public final class EComp extends AExpression {
         }
 
         if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.BOOL) {
                 constant = (boolean)left.constant == (boolean)right.constant;
@@ -169,7 +169,7 @@ public final class EComp extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
+        Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply not equals [!=] to types " +
@@ -187,7 +187,7 @@ public final class EComp extends AExpression {
         }
 
         if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.BOOL) {
                 constant = (boolean)left.constant != (boolean)right.constant;
@@ -215,7 +215,7 @@ public final class EComp extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
+        Type promote = AnalyzerCaster.promoteEquality(left.actual, right.actual);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply reference not equals [!==] to types " +
@@ -233,7 +233,7 @@ public final class EComp extends AExpression {
         }
 
         if ((left.constant != null || left.isNull) && (right.constant != null || right.isNull)) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.BOOL) {
                 constant = (boolean)left.constant != (boolean)right.constant;
@@ -257,7 +257,7 @@ public final class EComp extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply greater than or equals [>=] to types " +
@@ -271,7 +271,7 @@ public final class EComp extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant >= (int)right.constant;
@@ -293,7 +293,7 @@ public final class EComp extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply greater than [>] to types " +
@@ -307,7 +307,7 @@ public final class EComp extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant > (int)right.constant;
@@ -329,7 +329,7 @@ public final class EComp extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply less than or equals [<=] to types " +
@@ -343,7 +343,7 @@ public final class EComp extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant <= (int)right.constant;
@@ -365,7 +365,7 @@ public final class EComp extends AExpression {
         left.analyze(variables);
         right.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
+        Type promote = AnalyzerCaster.promoteNumeric(left.actual, right.actual, true);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply less than [>=] to types " +
@@ -379,7 +379,7 @@ public final class EComp extends AExpression {
         right = right.cast(variables);
 
         if (left.constant != null && right.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = (int)left.constant < (int)right.constant;
@@ -398,28 +398,28 @@ public final class EComp extends AExpression {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        final boolean branch = tru != null || fals != null;
-        final org.objectweb.asm.Type rtype = right.actual.type;
-        final Sort rsort = right.actual.sort;
+    void write(MethodWriter writer) {
+        boolean branch = tru != null || fals != null;
+        org.objectweb.asm.Type rtype = right.actual.type;
+        Sort rsort = right.actual.sort;
 
-        left.write(adapter);
+        left.write(writer);
 
         if (!right.isNull) {
-            right.write(adapter);
+            right.write(writer);
         }
 
-        final Label jump = tru != null ? tru : fals != null ? fals : new Label();
-        final Label end = new Label();
+        Label jump = tru != null ? tru : fals != null ? fals : new Label();
+        Label end = new Label();
 
-        final boolean eq = (operation == Operation.EQ || operation == Operation.EQR) && (tru != null || fals == null) ||
+        boolean eq = (operation == Operation.EQ || operation == Operation.EQR) && (tru != null || fals == null) ||
             (operation == Operation.NE || operation == Operation.NER) && fals != null;
-        final boolean ne = (operation == Operation.NE || operation == Operation.NER) && (tru != null || fals == null) ||
+        boolean ne = (operation == Operation.NE || operation == Operation.NER) && (tru != null || fals == null) ||
             (operation == Operation.EQ || operation == Operation.EQR) && fals != null;
-        final boolean lt  = operation == Operation.LT  && (tru != null || fals == null) || operation == Operation.GTE && fals != null;
-        final boolean lte = operation == Operation.LTE && (tru != null || fals == null) || operation == Operation.GT  && fals != null;
-        final boolean gt  = operation == Operation.GT  && (tru != null || fals == null) || operation == Operation.LTE && fals != null;
-        final boolean gte = operation == Operation.GTE && (tru != null || fals == null) || operation == Operation.LT  && fals != null;
+        boolean lt  = operation == Operation.LT  && (tru != null || fals == null) || operation == Operation.GTE && fals != null;
+        boolean lte = operation == Operation.LTE && (tru != null || fals == null) || operation == Operation.GT  && fals != null;
+        boolean gt  = operation == Operation.GT  && (tru != null || fals == null) || operation == Operation.LTE && fals != null;
+        boolean gte = operation == Operation.GTE && (tru != null || fals == null) || operation == Operation.LT  && fals != null;
 
         boolean writejump = true;
 
@@ -430,8 +430,8 @@ public final class EComp extends AExpression {
             case CHAR:
                 throw new IllegalStateException(error("Illegal tree structure."));
             case BOOL:
-                if      (eq) adapter.ifZCmp(MethodWriter.EQ, jump);
-                else if (ne) adapter.ifZCmp(MethodWriter.NE, jump);
+                if      (eq) writer.ifZCmp(MethodWriter.EQ, jump);
+                else if (ne) writer.ifZCmp(MethodWriter.NE, jump);
                 else {
                     throw new IllegalStateException(error("Illegal tree structure."));
                 }
@@ -441,12 +441,12 @@ public final class EComp extends AExpression {
             case LONG:
             case FLOAT:
             case DOUBLE:
-                if      (eq)  adapter.ifCmp(rtype, MethodWriter.EQ, jump);
-                else if (ne)  adapter.ifCmp(rtype, MethodWriter.NE, jump);
-                else if (lt)  adapter.ifCmp(rtype, MethodWriter.LT, jump);
-                else if (lte) adapter.ifCmp(rtype, MethodWriter.LE, jump);
-                else if (gt)  adapter.ifCmp(rtype, MethodWriter.GT, jump);
-                else if (gte) adapter.ifCmp(rtype, MethodWriter.GE, jump);
+                if      (eq)  writer.ifCmp(rtype, MethodWriter.EQ, jump);
+                else if (ne)  writer.ifCmp(rtype, MethodWriter.NE, jump);
+                else if (lt)  writer.ifCmp(rtype, MethodWriter.LT, jump);
+                else if (lte) writer.ifCmp(rtype, MethodWriter.LE, jump);
+                else if (gt)  writer.ifCmp(rtype, MethodWriter.GT, jump);
+                else if (gte) writer.ifCmp(rtype, MethodWriter.GE, jump);
                 else {
                     throw new IllegalStateException(error("Illegal tree structure."));
                 }
@@ -455,66 +455,66 @@ public final class EComp extends AExpression {
             case DEF:
                 if (eq) {
                     if (right.isNull) {
-                        adapter.ifNull(jump);
+                        writer.ifNull(jump);
                     } else if (!left.isNull && (operation == Operation.EQ || operation == Operation.NE)) {
-                        adapter.invokeStatic(DEF_UTIL_TYPE, DEF_EQ_CALL);
+                        writer.invokeStatic(DEF_UTIL_TYPE, DEF_EQ_CALL);
                         writejump = false;
                     } else {
-                        adapter.ifCmp(rtype, MethodWriter.EQ, jump);
+                        writer.ifCmp(rtype, MethodWriter.EQ, jump);
                     }
                 } else if (ne) {
                     if (right.isNull) {
-                        adapter.ifNonNull(jump);
+                        writer.ifNonNull(jump);
                     } else if (!left.isNull && (operation == Operation.EQ || operation == Operation.NE)) {
-                        adapter.invokeStatic(DEF_UTIL_TYPE, DEF_EQ_CALL);
-                        adapter.ifZCmp(MethodWriter.EQ, jump);
+                        writer.invokeStatic(DEF_UTIL_TYPE, DEF_EQ_CALL);
+                        writer.ifZCmp(MethodWriter.EQ, jump);
                     } else {
-                        adapter.ifCmp(rtype, MethodWriter.NE, jump);
+                        writer.ifCmp(rtype, MethodWriter.NE, jump);
                     }
                 } else if (lt) {
-                    adapter.invokeStatic(DEF_UTIL_TYPE, DEF_LT_CALL);
+                    writer.invokeStatic(DEF_UTIL_TYPE, DEF_LT_CALL);
                     writejump = false;
                 } else if (lte) {
-                    adapter.invokeStatic(DEF_UTIL_TYPE, DEF_LTE_CALL);
+                    writer.invokeStatic(DEF_UTIL_TYPE, DEF_LTE_CALL);
                     writejump = false;
                 } else if (gt) {
-                    adapter.invokeStatic(DEF_UTIL_TYPE, DEF_GT_CALL);
+                    writer.invokeStatic(DEF_UTIL_TYPE, DEF_GT_CALL);
                     writejump = false;
                 } else if (gte) {
-                    adapter.invokeStatic(DEF_UTIL_TYPE, DEF_GTE_CALL);
+                    writer.invokeStatic(DEF_UTIL_TYPE, DEF_GTE_CALL);
                     writejump = false;
                 } else {
                     throw new IllegalStateException(error("Illegal tree structure."));
                 }
 
                 if (branch && !writejump) {
-                    adapter.ifZCmp(MethodWriter.NE, jump);
+                    writer.ifZCmp(MethodWriter.NE, jump);
                 }
 
                 break;
             default:
                 if (eq) {
                     if (right.isNull) {
-                        adapter.ifNull(jump);
+                        writer.ifNull(jump);
                     } else if (operation == Operation.EQ || operation == Operation.NE) {
-                        adapter.invokeStatic(UTILITY_TYPE, CHECKEQUALS);
+                        writer.invokeStatic(UTILITY_TYPE, CHECKEQUALS);
 
                         if (branch) {
-                            adapter.ifZCmp(MethodWriter.NE, jump);
+                            writer.ifZCmp(MethodWriter.NE, jump);
                         }
 
                         writejump = false;
                     } else {
-                        adapter.ifCmp(rtype, MethodWriter.EQ, jump);
+                        writer.ifCmp(rtype, MethodWriter.EQ, jump);
                     }
                 } else if (ne) {
                     if (right.isNull) {
-                        adapter.ifNonNull(jump);
+                        writer.ifNonNull(jump);
                     } else if (operation == Operation.EQ || operation == Operation.NE) {
-                        adapter.invokeStatic(UTILITY_TYPE, CHECKEQUALS);
-                        adapter.ifZCmp(MethodWriter.EQ, jump);
+                        writer.invokeStatic(UTILITY_TYPE, CHECKEQUALS);
+                        writer.ifZCmp(MethodWriter.EQ, jump);
                     } else {
-                        adapter.ifCmp(rtype, MethodWriter.NE, jump);
+                        writer.ifCmp(rtype, MethodWriter.NE, jump);
                     }
                 } else {
                     throw new IllegalStateException(error("Illegal tree structure."));
@@ -522,11 +522,11 @@ public final class EComp extends AExpression {
         }
 
         if (!branch && writejump) {
-            adapter.push(false);
-            adapter.goTo(end);
-            adapter.mark(jump);
-            adapter.push(true);
-            adapter.mark(end);
+            writer.push(false);
+            writer.goTo(end);
+            writer.mark(jump);
+            writer.push(true);
+            writer.mark(end);
         }
     }
 }

+ 11 - 11
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConditional.java

@@ -35,8 +35,8 @@ public final class EConditional extends AExpression {
     AExpression left;
     AExpression right;
 
-    public EConditional(int line, String location, AExpression condition, AExpression left, AExpression right) {
-        super(line, location);
+    public EConditional(int line, int offset, String location, AExpression condition, AExpression left, AExpression right) {
+        super(line, offset, location);
 
         this.condition = condition;
         this.left = left;
@@ -77,19 +77,19 @@ public final class EConditional extends AExpression {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        final Label localfals = new Label();
-        final Label end = new Label();
+    void write(MethodWriter writer) {
+        Label localfals = new Label();
+        Label end = new Label();
 
         condition.fals = localfals;
         left.tru = right.tru = tru;
         left.fals = right.fals = fals;
 
-        condition.write(adapter);
-        left.write(adapter);
-        adapter.goTo(end);
-        adapter.mark(localfals);
-        right.write(adapter);
-        adapter.mark(end);
+        condition.write(writer);
+        left.write(writer);
+        writer.goTo(end);
+        writer.mark(localfals);
+        right.write(writer);
+        writer.mark(end);
     }
 }

+ 16 - 16
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EConstant.java

@@ -30,8 +30,8 @@ import org.elasticsearch.painless.MethodWriter;
  */
 final class EConstant extends AExpression {
 
-    EConstant(int line, String location, Object constant) {
-        super(line, location);
+    EConstant(int line, int offset, String location, Object constant) {
+        super(line, offset, location);
 
         this.constant = constant;
     }
@@ -62,25 +62,25 @@ final class EConstant extends AExpression {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        final Sort sort = actual.sort;
+    void write(MethodWriter writer) {
+        Sort sort = actual.sort;
 
         switch (sort) {
-            case STRING: adapter.push((String)constant);  break;
-            case DOUBLE: adapter.push((double)constant);  break;
-            case FLOAT:  adapter.push((float)constant);   break;
-            case LONG:   adapter.push((long)constant);    break;
-            case INT:    adapter.push((int)constant);     break;
-            case CHAR:   adapter.push((char)constant);    break;
-            case SHORT:  adapter.push((short)constant);   break;
-            case BYTE:   adapter.push((byte)constant);    break;
+            case STRING: writer.push((String)constant);  break;
+            case DOUBLE: writer.push((double)constant);  break;
+            case FLOAT:  writer.push((float)constant);   break;
+            case LONG:   writer.push((long)constant);    break;
+            case INT:    writer.push((int)constant);     break;
+            case CHAR:   writer.push((char)constant);    break;
+            case SHORT:  writer.push((short)constant);   break;
+            case BYTE:   writer.push((byte)constant);    break;
             case BOOL:
                 if (tru != null && (boolean)constant) {
-                    adapter.goTo(tru);
+                    writer.goTo(tru);
                 } else if (fals != null && !(boolean)constant) {
-                    adapter.goTo(fals);
+                    writer.goTo(fals);
                 } else if (tru == null && fals == null) {
-                    adapter.push((boolean)constant);
+                    writer.push((boolean)constant);
                 }
 
                 break;
@@ -89,7 +89,7 @@ final class EConstant extends AExpression {
         }
 
         if (sort != Sort.BOOL) {
-            adapter.writeBranch(tru, fals);
+            writer.writeBranch(tru, fals);
         }
     }
 }

+ 5 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EDecimal.java

@@ -30,8 +30,8 @@ public final class EDecimal extends AExpression {
 
     final String value;
 
-    public EDecimal(int line, String location, String value) {
-        super(line, location);
+    public EDecimal(int line, int offset, String location, String value) {
+        super(line, offset, location);
 
         this.value = value;
     }
@@ -42,21 +42,21 @@ public final class EDecimal extends AExpression {
             try {
                 constant = Float.parseFloat(value.substring(0, value.length() - 1));
                 actual = Definition.FLOAT_TYPE;
-            } catch (final NumberFormatException exception) {
+            } catch (NumberFormatException exception) {
                 throw new IllegalArgumentException(error("Invalid float constant [" + value + "]."));
             }
         } else {
             try {
                 constant = Double.parseDouble(value);
                 actual = Definition.DOUBLE_TYPE;
-            } catch (final NumberFormatException exception) {
+            } catch (NumberFormatException exception) {
                 throw new IllegalArgumentException(error("Invalid double constant [" + value + "]."));
             }
         }
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         throw new IllegalArgumentException(error("Illegal tree structure."));
     }
 }

+ 4 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EExplicit.java

@@ -31,8 +31,8 @@ public final class EExplicit extends AExpression {
     final String type;
     AExpression child;
 
-    public EExplicit(int line, String location, String type, AExpression child) {
-        super(line, location);
+    public EExplicit(int line, int offset, String location, String type, AExpression child) {
+        super(line, offset, location);
 
         this.type = type;
         this.child = child;
@@ -42,7 +42,7 @@ public final class EExplicit extends AExpression {
     void analyze(Variables variables) {
         try {
             actual = Definition.getType(this.type);
-        } catch (final IllegalArgumentException exception) {
+        } catch (IllegalArgumentException exception) {
             throw new IllegalArgumentException(error("Not a type [" + this.type + "]."));
         }
 
@@ -53,7 +53,7 @@ public final class EExplicit extends AExpression {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         throw new IllegalArgumentException(error("Illegal tree structure."));
     }
 

+ 4 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENull.java

@@ -29,8 +29,8 @@ import org.elasticsearch.painless.MethodWriter;
  */
 public final class ENull extends AExpression {
 
-    public ENull(int line, String location) {
-        super(line, location);
+    public ENull(int line, int offset, String location) {
+        super(line, offset, location);
     }
 
     @Override
@@ -49,7 +49,7 @@ public final class ENull extends AExpression {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        adapter.visitInsn(Opcodes.ACONST_NULL);
+    void write(MethodWriter writer) {
+        writer.visitInsn(Opcodes.ACONST_NULL);
     }
 }

+ 9 - 9
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/ENumeric.java

@@ -32,8 +32,8 @@ public final class ENumeric extends AExpression {
     final String value;
     int radix;
 
-    public ENumeric(int line, String location, String value, int radix) {
-        super(line, location);
+    public ENumeric(int line, int offset, String location, String value, int radix) {
+        super(line, offset, location);
 
         this.value = value;
         this.radix = radix;
@@ -49,7 +49,7 @@ public final class ENumeric extends AExpression {
             try {
                 constant = Double.parseDouble(value.substring(0, value.length() - 1));
                 actual = Definition.DOUBLE_TYPE;
-            } catch (final NumberFormatException exception) {
+            } catch (NumberFormatException exception) {
                 throw new IllegalArgumentException(error("Invalid double constant [" + value + "]."));
             }
         } else if (value.endsWith("f") || value.endsWith("F")) {
@@ -60,20 +60,20 @@ public final class ENumeric extends AExpression {
             try {
                 constant = Float.parseFloat(value.substring(0, value.length() - 1));
                 actual = Definition.FLOAT_TYPE;
-            } catch (final NumberFormatException exception) {
+            } catch (NumberFormatException exception) {
                 throw new IllegalArgumentException(error("Invalid float constant [" + value + "]."));
             }
         } else if (value.endsWith("l") || value.endsWith("L")) {
             try {
                 constant = Long.parseLong(value.substring(0, value.length() - 1), radix);
                 actual = Definition.LONG_TYPE;
-            } catch (final NumberFormatException exception) {
+            } catch (NumberFormatException exception) {
                 throw new IllegalArgumentException(error("Invalid long constant [" + value + "]."));
             }
         } else {
             try {
-                final Sort sort = expected == null ? Sort.INT : expected.sort;
-                final int integer = Integer.parseInt(value, radix);
+                Sort sort = expected == null ? Sort.INT : expected.sort;
+                int integer = Integer.parseInt(value, radix);
 
                 if (sort == Sort.BYTE && integer >= Byte.MIN_VALUE && integer <= Byte.MAX_VALUE) {
                     constant = (byte)integer;
@@ -88,14 +88,14 @@ public final class ENumeric extends AExpression {
                     constant = integer;
                     actual = Definition.INT_TYPE;
                 }
-            } catch (final NumberFormatException exception) {
+            } catch (NumberFormatException exception) {
                 throw new IllegalArgumentException(error("Invalid int constant [" + value + "]."));
             }
         }
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         throw new IllegalArgumentException(error("Illegal tree structure."));
     }
 }

+ 29 - 29
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/EUnary.java

@@ -37,11 +37,11 @@ import static org.elasticsearch.painless.WriterConstants.DEF_UTIL_TYPE;
  */
 public final class EUnary extends AExpression {
 
-    Operation operation;
+    final Operation operation;
     AExpression child;
 
-    public EUnary(int line, String location, Operation operation, AExpression child) {
-        super(line, location);
+    public EUnary(int line, int offset, String location, Operation operation, AExpression child) {
+        super(line, offset, location);
 
         this.operation = operation;
         this.child = child;
@@ -77,7 +77,7 @@ public final class EUnary extends AExpression {
     void analyzeBWNot(Variables variables) {
         child.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(child.actual, false);
+        Type promote = AnalyzerCaster.promoteNumeric(child.actual, false);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply not [~] to type [" + child.actual.name + "]."));
@@ -87,7 +87,7 @@ public final class EUnary extends AExpression {
         child = child.cast(variables);
 
         if (child.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = ~(int)child.constant;
@@ -104,7 +104,7 @@ public final class EUnary extends AExpression {
     void analyzerAdd(Variables variables) {
         child.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(child.actual, true);
+        Type promote = AnalyzerCaster.promoteNumeric(child.actual, true);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply positive [+] to type [" + child.actual.name + "]."));
@@ -114,7 +114,7 @@ public final class EUnary extends AExpression {
         child = child.cast(variables);
 
         if (child.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = +(int)child.constant;
@@ -135,7 +135,7 @@ public final class EUnary extends AExpression {
     void analyzerSub(Variables variables) {
         child.analyze(variables);
 
-        final Type promote = AnalyzerCaster.promoteNumeric(child.actual, true);
+        Type promote = AnalyzerCaster.promoteNumeric(child.actual, true);
 
         if (promote == null) {
             throw new ClassCastException(error("Cannot apply negative [-] to type [" + child.actual.name + "]."));
@@ -145,7 +145,7 @@ public final class EUnary extends AExpression {
         child = child.cast(variables);
 
         if (child.constant != null) {
-            final Sort sort = promote.sort;
+            Sort sort = promote.sort;
 
             if (sort == Sort.INT) {
                 constant = -(int)child.constant;
@@ -164,56 +164,56 @@ public final class EUnary extends AExpression {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         if (operation == Operation.NOT) {
             if (tru == null && fals == null) {
-                final Label localfals = new Label();
-                final Label end = new Label();
+                Label localfals = new Label();
+                Label end = new Label();
 
                 child.fals = localfals;
-                child.write(adapter);
+                child.write(writer);
 
-                adapter.push(false);
-                adapter.goTo(end);
-                adapter.mark(localfals);
-                adapter.push(true);
-                adapter.mark(end);
+                writer.push(false);
+                writer.goTo(end);
+                writer.mark(localfals);
+                writer.push(true);
+                writer.mark(end);
             } else {
                 child.tru = fals;
                 child.fals = tru;
-                child.write(adapter);
+                child.write(writer);
             }
         } else {
-            final org.objectweb.asm.Type type = actual.type;
-            final Sort sort = actual.sort;
+            org.objectweb.asm.Type type = actual.type;
+            Sort sort = actual.sort;
 
-            child.write(adapter);
+            child.write(writer);
 
             if (operation == Operation.BWNOT) {
                 if (sort == Sort.DEF) {
-                    adapter.invokeStatic(DEF_UTIL_TYPE, DEF_NOT_CALL);
+                    writer.invokeStatic(DEF_UTIL_TYPE, DEF_NOT_CALL);
                 } else {
                     if (sort == Sort.INT) {
-                        adapter.push(-1);
+                        writer.push(-1);
                     } else if (sort == Sort.LONG) {
-                        adapter.push(-1L);
+                        writer.push(-1L);
                     } else {
                         throw new IllegalStateException(error("Illegal tree structure."));
                     }
 
-                    adapter.math(MethodWriter.XOR, type);
+                    writer.math(MethodWriter.XOR, type);
                 }
             } else if (operation == Operation.SUB) {
                 if (sort == Sort.DEF) {
-                    adapter.invokeStatic(DEF_UTIL_TYPE, DEF_NEG_CALL);
+                    writer.invokeStatic(DEF_UTIL_TYPE, DEF_NEG_CALL);
                 } else {
-                    adapter.math(MethodWriter.NEG, type);
+                    writer.math(MethodWriter.NEG, type);
                 }
             } else if (operation != Operation.ADD) {
                 throw new IllegalStateException(error("Illegal tree structure."));
             }
 
-            adapter.writeBranch(tru, fals);
+            writer.writeBranch(tru, fals);
         }
     }
 }

+ 6 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LArrayLength.java

@@ -30,8 +30,8 @@ public final class LArrayLength extends ALink {
 
     final String value;
 
-    LArrayLength(int line, String location, String value) {
-        super(line, location, -1);
+    LArrayLength(int line, int offset, String location, String value) {
+        super(line, offset, location, -1);
 
         this.value = value;
     }
@@ -54,17 +54,17 @@ public final class LArrayLength extends ALink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         // Do nothing.
     }
 
     @Override
-    void load(MethodWriter adapter) {
-        adapter.arrayLength();
+    void load(MethodWriter writer) {
+        writer.arrayLength();
     }
 
     @Override
-    void store(MethodWriter adapter) {
+    void store(MethodWriter writer) {
         throw new IllegalStateException(error("Illegal tree structure."));
     }
 }

+ 12 - 12
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LBrace.java

@@ -34,8 +34,8 @@ public final class LBrace extends ALink {
 
     AExpression index;
 
-    public LBrace(int line, String location, AExpression index) {
-        super(line, location, 2);
+    public LBrace(int line, int offset, String location, AExpression index) {
+        super(line, offset, location, 2);
 
         this.index = index;
     }
@@ -43,7 +43,7 @@ public final class LBrace extends ALink {
     @Override
     ALink analyze(Variables variables) {
         if (before == null) {
-            throw new IllegalStateException(error("Illegal tree structure."));
+            throw new IllegalArgumentException(error("Illegal array access made without target."));
         }
 
         final Sort sort = before.sort;
@@ -57,29 +57,29 @@ public final class LBrace extends ALink {
 
             return this;
         } else if (sort == Sort.DEF) {
-            return new LDefArray(line, location, index).copy(this).analyze(variables);
+            return new LDefArray(line, offset, location, index).copy(this).analyze(variables);
         } else if (Map.class.isAssignableFrom(before.clazz)) {
-            return new LMapShortcut(line, location, index).copy(this).analyze(variables);
+            return new LMapShortcut(line, offset, location, index).copy(this).analyze(variables);
         } else if (List.class.isAssignableFrom(before.clazz)) {
-            return new LListShortcut(line, location, index).copy(this).analyze(variables);
+            return new LListShortcut(line, offset, location, index).copy(this).analyze(variables);
         }
 
         throw new IllegalArgumentException(error("Illegal array access on type [" + before.name + "]."));
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        index.write(adapter);
+    void write(MethodWriter writer) {
+        index.write(writer);
     }
 
     @Override
-    void load(MethodWriter adapter) {
-        adapter.arrayLoad(after.type);
+    void load(MethodWriter writer) {
+        writer.arrayLoad(after.type);
     }
 
     @Override
-    void store(MethodWriter adapter) {
-        adapter.arrayStore(after.type);
+    void store(MethodWriter writer) {
+        writer.arrayStore(after.type);
     }
 
 }

+ 18 - 17
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCall.java

@@ -21,6 +21,7 @@ package org.elasticsearch.painless.node;
 
 import org.elasticsearch.painless.Definition;
 import org.elasticsearch.painless.Definition.Method;
+import org.elasticsearch.painless.Definition.Sort;
 import org.elasticsearch.painless.Definition.Struct;
 import org.elasticsearch.painless.Variables;
 import org.elasticsearch.painless.MethodWriter;
@@ -37,8 +38,8 @@ public final class LCall extends ALink {
 
     Method method = null;
 
-    public LCall(int line, String location, String name, List<AExpression> arguments) {
-        super(line, location, -1);
+    public LCall(int line, int offset, String location, String name, List<AExpression> arguments) {
+        super(line, offset, location, -1);
 
         this.name = name;
         this.arguments = arguments;
@@ -47,20 +48,20 @@ public final class LCall extends ALink {
     @Override
     ALink analyze(Variables variables) {
         if (before == null) {
-            throw new IllegalStateException(error("Illegal tree structure."));
-        } else if (before.sort == Definition.Sort.ARRAY) {
+            throw new IllegalArgumentException(error("Illegal call [" + name + "] made without target."));
+        } else if (before.sort == Sort.ARRAY) {
             throw new IllegalArgumentException(error("Illegal call [" + name + "] on array type."));
         } else if (store) {
             throw new IllegalArgumentException(error("Cannot assign a value to a call [" + name + "]."));
         }
 
         Definition.MethodKey methodKey = new Definition.MethodKey(name, arguments.size());
-        final Struct struct = before.struct;
+        Struct struct = before.struct;
         method = statik ? struct.staticMethods.get(methodKey) : struct.methods.get(methodKey);
 
         if (method != null) {
             for (int argument = 0; argument < arguments.size(); ++argument) {
-                final AExpression expression = arguments.get(argument);
+                AExpression expression = arguments.get(argument);
 
                 expression.expected = method.arguments.get(argument);
                 expression.internal = true;
@@ -72,8 +73,8 @@ public final class LCall extends ALink {
             after = method.rtn;
 
             return this;
-        } else if (before.sort == Definition.Sort.DEF) {
-            final ALink link = new LDefCall(line, location, name, arguments);
+        } else if (before.sort == Sort.DEF) {
+            ALink link = new LDefCall(line, offset, location, name, arguments);
             link.copy(this);
 
             return link.analyze(variables);
@@ -84,31 +85,31 @@ public final class LCall extends ALink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         // Do nothing.
     }
 
     @Override
-    void load(MethodWriter adapter) {
-        for (final AExpression argument : arguments) {
-            argument.write(adapter);
+    void load(MethodWriter writer) {
+        for (AExpression argument : arguments) {
+            argument.write(writer);
         }
 
         if (java.lang.reflect.Modifier.isStatic(method.modifiers)) {
-            adapter.invokeStatic(method.owner.type, method.method);
+            writer.invokeStatic(method.owner.type, method.method);
         } else if (java.lang.reflect.Modifier.isInterface(method.owner.clazz.getModifiers())) {
-            adapter.invokeInterface(method.owner.type, method.method);
+            writer.invokeInterface(method.owner.type, method.method);
         } else {
-            adapter.invokeVirtual(method.owner.type, method.method);
+            writer.invokeVirtual(method.owner.type, method.method);
         }
 
         if (!method.rtn.clazz.equals(method.handle.type().returnType())) {
-            adapter.checkCast(method.rtn.type);
+            writer.checkCast(method.rtn.type);
         }
     }
 
     @Override
-    void store(MethodWriter adapter) {
+    void store(MethodWriter writer) {
         throw new IllegalStateException(error("Illegal tree structure."));
     }
 }

+ 8 - 8
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LCast.java

@@ -34,8 +34,8 @@ public final class LCast extends ALink {
 
     Cast cast = null;
 
-    public LCast(int line, String location, String type) {
-        super(line, location, -1);
+    public LCast(int line, int offset, String location, String type) {
+        super(line, offset, location, -1);
 
         this.type = type;
     }
@@ -43,14 +43,14 @@ public final class LCast extends ALink {
     @Override
     ALink analyze(Variables variables) {
         if (before == null) {
-            throw new IllegalStateException(error("Illegal tree structure."));
+            throw new IllegalStateException(error("Illegal cast without a target."));
         } else if (store) {
             throw new IllegalArgumentException(error("Cannot assign a value to a cast."));
         }
 
         try {
             after = Definition.getType(type);
-        } catch (final IllegalArgumentException exception) {
+        } catch (IllegalArgumentException exception) {
             throw new IllegalArgumentException(error("Not a type [" + type + "]."));
         }
 
@@ -60,17 +60,17 @@ public final class LCast extends ALink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        adapter.writeCast(cast);
+    void write(MethodWriter writer) {
+        writer.writeCast(cast);
     }
 
     @Override
-    void load(MethodWriter adapter) {
+    void load(MethodWriter writer) {
         // Do nothing.
     }
 
     @Override
-    void store(MethodWriter adapter) {
+    void store(MethodWriter writer) {
         throw new IllegalStateException(error("Illegal tree structure."));
     }
 }

+ 10 - 11
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefArray.java

@@ -34,8 +34,8 @@ final class LDefArray extends ALink implements IDefLink {
 
     AExpression index;
 
-    LDefArray(int line, String location, AExpression index) {
-        super(line, location, 2);
+    LDefArray(int line, int offset, String location, AExpression index) {
+        super(line, offset, location, 2);
 
         this.index = index;
     }
@@ -52,20 +52,19 @@ final class LDefArray extends ALink implements IDefLink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        index.write(adapter);
+    void write(MethodWriter writer) {
+        index.write(writer);
     }
 
     @Override
-    void load(MethodWriter adapter) {
-        final String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type, index.actual.type);
-        adapter.invokeDynamic("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.ARRAY_LOAD);
+    void load(MethodWriter writer) {
+        String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type, index.actual.type);
+        writer.invokeDynamic("arrayLoad", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_LOAD);
     }
 
     @Override
-    void store(MethodWriter adapter) {
-        final String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type,
-            index.actual.type, after.type);
-        adapter.invokeDynamic("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.ARRAY_STORE);
+    void store(MethodWriter writer) {
+        String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, index.actual.type, after.type);
+        writer.invokeDynamic("arrayStore", desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.ARRAY_STORE);
     }
 }

+ 10 - 12
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefCall.java

@@ -36,8 +36,8 @@ final class LDefCall extends ALink implements IDefLink {
     final String name;
     final List<AExpression> arguments;
 
-    LDefCall(int line, String location, String name, List<AExpression> arguments) {
-        super(line, location, -1);
+    LDefCall(int line, int offset, String location, String name, List<AExpression> arguments) {
+        super(line, offset, location, -1);
 
         this.name = name;
         this.arguments = arguments;
@@ -46,7 +46,7 @@ final class LDefCall extends ALink implements IDefLink {
     @Override
     ALink analyze(Variables variables) {
         for (int argument = 0; argument < arguments.size(); ++argument) {
-            final AExpression expression = arguments.get(argument);
+            AExpression expression = arguments.get(argument);
 
             expression.internal = true;
             expression.analyze(variables);
@@ -61,34 +61,32 @@ final class LDefCall extends ALink implements IDefLink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         // Do nothing.
     }
 
     @Override
-    void load(MethodWriter adapter) {
-        final StringBuilder signature = new StringBuilder();
+    void load(MethodWriter writer) {
+        StringBuilder signature = new StringBuilder();
 
         signature.append('(');
         // first parameter is the receiver, we never know its type: always Object
         signature.append(Definition.DEF_TYPE.type.getDescriptor());
 
-        // TODO: remove our explicit conversions and feed more type information for return value,
-        // it can avoid some unnecessary boxing etc.
-        for (final AExpression argument : arguments) {
+        for (AExpression argument : arguments) {
             signature.append(argument.actual.type.getDescriptor());
-            argument.write(adapter);
+            argument.write(writer);
         }
 
         signature.append(')');
         // return value
         signature.append(after.type.getDescriptor());
 
-        adapter.invokeDynamic(name, signature.toString(), DEF_BOOTSTRAP_HANDLE, DefBootstrap.METHOD_CALL);
+        writer.invokeDynamic(name, signature.toString(), DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.METHOD_CALL);
     }
 
     @Override
-    void store(MethodWriter adapter) {
+    void store(MethodWriter writer) {
         throw new IllegalStateException(error("Illegal tree structure."));
     }
 }

+ 9 - 9
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LDefField.java

@@ -34,8 +34,8 @@ final class LDefField extends ALink implements IDefLink {
 
     final String value;
 
-    LDefField(int line, String location, String value) {
-        super(line, location, 1);
+    LDefField(int line, int offset, String location, String value) {
+        super(line, offset, location, 1);
 
         this.value = value;
     }
@@ -49,19 +49,19 @@ final class LDefField extends ALink implements IDefLink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         // Do nothing.
     }
 
     @Override
-    void load(MethodWriter adapter) {
-        final String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type);
-        adapter.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.LOAD);
+    void load(MethodWriter writer) {
+        String desc = Type.getMethodDescriptor(after.type, Definition.DEF_TYPE.type);
+        writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.LOAD);
     }
 
     @Override
-    void store(MethodWriter adapter) {
-        final String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, after.type);
-        adapter.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, DefBootstrap.STORE);
+    void store(MethodWriter writer) {
+        String desc = Type.getMethodDescriptor(Definition.VOID_TYPE.type, Definition.DEF_TYPE.type, after.type);
+        writer.invokeDynamic(value, desc, DEF_BOOTSTRAP_HANDLE, (Object)DefBootstrap.STORE);
     }
 }

+ 26 - 25
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LField.java

@@ -38,8 +38,8 @@ public final class LField extends ALink {
 
     Field field;
 
-    public LField(int line, String location, String value) {
-        super(line, location, 1);
+    public LField(int line, int offset, String location, String value) {
+        super(line, offset, location, 1);
 
         this.value = value;
     }
@@ -47,18 +47,18 @@ public final class LField extends ALink {
     @Override
     ALink analyze(Variables variables) {
         if (before == null) {
-            throw new IllegalStateException(error("Illegal tree structure."));
+            throw new IllegalArgumentException(error("Illegal field [" + value + "] access made without target."));
         }
 
-        final Sort sort = before.sort;
+        Sort sort = before.sort;
 
         if (sort == Sort.ARRAY) {
-            return new LArrayLength(line, location, value).copy(this).analyze(variables);
+            return new LArrayLength(line, offset, location, value).copy(this).analyze(variables);
         } else if (sort == Sort.DEF) {
-            return new LDefField(line, location, value).copy(this).analyze(variables);
+            return new LDefField(line, offset, location, value).copy(this).analyze(variables);
         }
 
-        final Struct struct = before.struct;
+        Struct struct = before.struct;
         field = statik ? struct.staticMembers.get(value) : struct.members.get(value);
 
         if (field != null) {
@@ -71,25 +71,26 @@ public final class LField extends ALink {
 
             return this;
         } else {
-            // TODO: improve this: the isXXX case seems missing???
-            final boolean shortcut =
-                struct.methods.containsKey(new Definition.MethodKey("get" + 
-                        Character.toUpperCase(value.charAt(0)) + value.substring(1), 0)) ||
-                struct.methods.containsKey(new Definition.MethodKey("set" + 
-                        Character.toUpperCase(value.charAt(0)) + value.substring(1), 1));
+            boolean shortcut =
+                struct.methods.containsKey(new Definition.MethodKey("get" +
+                    Character.toUpperCase(value.charAt(0)) + value.substring(1), 0)) ||
+                struct.methods.containsKey(new Definition.MethodKey("is" +
+                    Character.toUpperCase(value.charAt(0)) + value.substring(1), 0)) ||
+                struct.methods.containsKey(new Definition.MethodKey("set" +
+                    Character.toUpperCase(value.charAt(0)) + value.substring(1), 1));
 
             if (shortcut) {
-                return new LShortcut(line, location, value).copy(this).analyze(variables);
+                return new LShortcut(line, offset, location, value).copy(this).analyze(variables);
             } else {
-                final EConstant index = new EConstant(line, location, value);
+                EConstant index = new EConstant(line, offset, location, value);
                 index.analyze(variables);
 
                 if (Map.class.isAssignableFrom(before.clazz)) {
-                    return new LMapShortcut(line, location, index).copy(this).analyze(variables);
+                    return new LMapShortcut(line, offset, location, index).copy(this).analyze(variables);
                 }
-                
+
                 if (List.class.isAssignableFrom(before.clazz)) {
-                    return new LListShortcut(line, location, index).copy(this).analyze(variables);
+                    return new LListShortcut(line, offset, location, index).copy(this).analyze(variables);
                 }
             }
         }
@@ -98,25 +99,25 @@ public final class LField extends ALink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         // Do nothing.
     }
 
     @Override
-    void load(MethodWriter adapter) {
+    void load(MethodWriter writer) {
         if (java.lang.reflect.Modifier.isStatic(field.modifiers)) {
-            adapter.getStatic(field.owner.type, field.javaName, field.type.type);
+            writer.getStatic(field.owner.type, field.javaName, field.type.type);
         } else {
-            adapter.getField(field.owner.type, field.javaName, field.type.type);
+            writer.getField(field.owner.type, field.javaName, field.type.type);
         }
     }
 
     @Override
-    void store(MethodWriter adapter) {
+    void store(MethodWriter writer) {
         if (java.lang.reflect.Modifier.isStatic(field.modifiers)) {
-            adapter.putStatic(field.owner.type, field.javaName, field.type.type);
+            writer.putStatic(field.owner.type, field.javaName, field.type.type);
         } else {
-            adapter.putField(field.owner.type, field.javaName, field.type.type);
+            writer.putField(field.owner.type, field.javaName, field.type.type);
         }
     }
 }

+ 12 - 12
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LListShortcut.java

@@ -34,8 +34,8 @@ final class LListShortcut extends ALink {
     Method getter;
     Method setter;
 
-    LListShortcut(int line, String location, AExpression index) {
-        super(line, location, 2);
+    LListShortcut(int line, int offset, String location, AExpression index) {
+        super(line, offset, location, 2);
 
         this.index = index;
     }
@@ -73,31 +73,31 @@ final class LListShortcut extends ALink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        index.write(adapter);
+    void write(MethodWriter writer) {
+        index.write(writer);
     }
 
     @Override
-    void load(MethodWriter adapter) {
+    void load(MethodWriter writer) {
         if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
-            adapter.invokeInterface(getter.owner.type, getter.method);
+            writer.invokeInterface(getter.owner.type, getter.method);
         } else {
-            adapter.invokeVirtual(getter.owner.type, getter.method);
+            writer.invokeVirtual(getter.owner.type, getter.method);
         }
 
         if (!getter.rtn.clazz.equals(getter.handle.type().returnType())) {
-            adapter.checkCast(getter.rtn.type);
+            writer.checkCast(getter.rtn.type);
         }
     }
 
     @Override
-    void store(MethodWriter adapter) {
+    void store(MethodWriter writer) {
         if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
-            adapter.invokeInterface(setter.owner.type, setter.method);
+            writer.invokeInterface(setter.owner.type, setter.method);
         } else {
-            adapter.invokeVirtual(setter.owner.type, setter.method);
+            writer.invokeVirtual(setter.owner.type, setter.method);
         }
 
-        adapter.writePop(setter.rtn.sort.size);
+        writer.writePop(setter.rtn.sort.size);
     }
 }

+ 12 - 12
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LMapShortcut.java

@@ -34,8 +34,8 @@ final class LMapShortcut extends ALink {
     Method getter;
     Method setter;
 
-    LMapShortcut(int line, String location, AExpression index) {
-        super(line, location, 2);
+    LMapShortcut(int line, int offset, String location, AExpression index) {
+        super(line, offset, location, 2);
 
         this.index = index;
     }
@@ -72,31 +72,31 @@ final class LMapShortcut extends ALink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        index.write(adapter);
+    void write(MethodWriter writer) {
+        index.write(writer);
     }
 
     @Override
-    void load(MethodWriter adapter) {
+    void load(MethodWriter writer) {
         if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
-            adapter.invokeInterface(getter.owner.type, getter.method);
+            writer.invokeInterface(getter.owner.type, getter.method);
         } else {
-            adapter.invokeVirtual(getter.owner.type, getter.method);
+            writer.invokeVirtual(getter.owner.type, getter.method);
         }
 
         if (!getter.rtn.clazz.equals(getter.handle.type().returnType())) {
-            adapter.checkCast(getter.rtn.type);
+            writer.checkCast(getter.rtn.type);
         }
     }
 
     @Override
-    void store(MethodWriter adapter) {
+    void store(MethodWriter writer) {
         if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
-            adapter.invokeInterface(setter.owner.type, setter.method);
+            writer.invokeInterface(setter.owner.type, setter.method);
         } else {
-            adapter.invokeVirtual(setter.owner.type, setter.method);
+            writer.invokeVirtual(setter.owner.type, setter.method);
         }
 
-        adapter.writePop(setter.rtn.sort.size);
+        writer.writePop(setter.rtn.sort.size);
     }
 }

+ 13 - 13
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewArray.java

@@ -34,8 +34,8 @@ public final class LNewArray extends ALink {
     final String type;
     final List<AExpression> arguments;
 
-    public LNewArray(int line, String location, String type, List<AExpression> arguments) {
-        super(line, location, -1);
+    public LNewArray(int line, int offset, String location, String type, List<AExpression> arguments) {
+        super(line, offset, location, -1);
 
         this.type = type;
         this.arguments = arguments;
@@ -44,23 +44,23 @@ public final class LNewArray extends ALink {
     @Override
     ALink analyze(Variables variables) {
         if (before != null) {
-            throw new IllegalStateException(error("Illegal tree structure."));
+            throw new IllegalArgumentException(error("Cannot create a new array with a target already defined."));
         } else if (store) {
             throw new IllegalArgumentException(error("Cannot assign a value to a new array."));
         } else if (!load) {
-            throw new IllegalArgumentException(error("A newly created array must be assigned."));
+            throw new IllegalArgumentException(error("A newly created array must be read."));
         }
 
         final Type type;
 
         try {
             type = Definition.getType(this.type);
-        } catch (final IllegalArgumentException exception) {
+        } catch (IllegalArgumentException exception) {
             throw new IllegalArgumentException(error("Not a type [" + this.type + "]."));
         }
 
         for (int argument = 0; argument < arguments.size(); ++argument) {
-            final AExpression expression = arguments.get(argument);
+            AExpression expression = arguments.get(argument);
 
             expression.expected = Definition.INT_TYPE;
             expression.analyze(variables);
@@ -73,25 +73,25 @@ public final class LNewArray extends ALink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         // Do nothing.
     }
 
     @Override
-    void load(MethodWriter adapter) {
-        for (final AExpression argument : arguments) {
-            argument.write(adapter);
+    void load(MethodWriter writer) {
+        for (AExpression argument : arguments) {
+            argument.write(writer);
         }
 
         if (arguments.size() > 1) {
-            adapter.visitMultiANewArrayInsn(after.type.getDescriptor(), after.type.getDimensions());
+            writer.visitMultiANewArrayInsn(after.type.getDescriptor(), after.type.getDimensions());
         } else {
-            adapter.newArray(Definition.getType(after.struct, 0).type);
+            writer.newArray(Definition.getType(after.struct, 0).type);
         }
     }
 
     @Override
-    void store(MethodWriter adapter) {
+    void store(MethodWriter writer) {
         throw new IllegalStateException(error("Illegal tree structure."));
     }
 }

+ 14 - 14
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LNewObj.java

@@ -38,8 +38,8 @@ public final class LNewObj extends ALink {
 
     Constructor constructor;
 
-    public LNewObj(int line, String location, String type, List<AExpression> arguments) {
-        super(line, location, -1);
+    public LNewObj(int line, int offset, String location, String type, List<AExpression> arguments) {
+        super(line, offset, location, -1);
 
         this.type = type;
         this.arguments = arguments;
@@ -48,7 +48,7 @@ public final class LNewObj extends ALink {
     @Override
     ALink analyze(Variables variables) {
         if (before != null) {
-            throw new IllegalStateException(error("Illegal tree structure"));
+            throw new IllegalArgumentException(error("Illegal new call with a target already defined."));
         } else if (store) {
             throw new IllegalArgumentException(error("Cannot assign a value to a new call."));
         }
@@ -57,15 +57,15 @@ public final class LNewObj extends ALink {
 
         try {
             type = Definition.getType(this.type);
-        } catch (final IllegalArgumentException exception) {
+        } catch (IllegalArgumentException exception) {
             throw new IllegalArgumentException(error("Not a type [" + this.type + "]."));
         }
 
-        final Struct struct = type.struct;
+        Struct struct = type.struct;
         constructor = struct.constructors.get(new Definition.MethodKey("new", arguments.size()));
 
         if (constructor != null) {
-            final Type[] types = new Type[constructor.arguments.size()];
+            Type[] types = new Type[constructor.arguments.size()];
             constructor.arguments.toArray(types);
 
             if (constructor.arguments.size() != arguments.size()) {
@@ -74,7 +74,7 @@ public final class LNewObj extends ALink {
             }
 
             for (int argument = 0; argument < arguments.size(); ++argument) {
-                final AExpression expression = arguments.get(argument);
+                AExpression expression = arguments.get(argument);
 
                 expression.expected = types[argument];
                 expression.internal = true;
@@ -92,27 +92,27 @@ public final class LNewObj extends ALink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         // Do nothing.
     }
 
     @Override
-    void load(MethodWriter adapter) {
-        adapter.newInstance(after.type);
+    void load(MethodWriter writer) {
+        writer.newInstance(after.type);
 
         if (load) {
-            adapter.dup();
+            writer.dup();
         }
 
         for (AExpression argument : arguments) {
-            argument.write(adapter);
+            argument.write(writer);
         }
 
-        adapter.invokeConstructor(constructor.owner.type, constructor.method);
+        writer.invokeConstructor(constructor.owner.type, constructor.method);
     }
 
     @Override
-    void store(MethodWriter adapter) {
+    void store(MethodWriter writer) {
         throw new IllegalStateException(error("Illegal tree structure."));
     }
 }

+ 17 - 12
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LShortcut.java

@@ -36,17 +36,22 @@ final class LShortcut extends ALink {
     Method getter = null;
     Method setter = null;
 
-    LShortcut(int line, String location, String value) {
-        super(line, location, 1);
+    LShortcut(int line, int offset, String location, String value) {
+        super(line, offset, location, 1);
 
         this.value = value;
     }
 
     @Override
     ALink analyze(Variables variables) {
-        final Struct struct = before.struct;
+        Struct struct = before.struct;
 
         getter = struct.methods.get(new Definition.MethodKey("get" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 0));
+
+        if (getter == null) {
+            getter = struct.methods.get(new Definition.MethodKey("is" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 0));
+        }
+
         setter = struct.methods.get(new Definition.MethodKey("set" + Character.toUpperCase(value.charAt(0)) + value.substring(1), 1));
 
         if (getter != null && (getter.rtn.sort == Sort.VOID || !getter.arguments.isEmpty())) {
@@ -73,31 +78,31 @@ final class LShortcut extends ALink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         // Do nothing.
     }
 
     @Override
-    void load(MethodWriter adapter) {
+    void load(MethodWriter writer) {
         if (java.lang.reflect.Modifier.isInterface(getter.owner.clazz.getModifiers())) {
-            adapter.invokeInterface(getter.owner.type, getter.method);
+            writer.invokeInterface(getter.owner.type, getter.method);
         } else {
-            adapter.invokeVirtual(getter.owner.type, getter.method);
+            writer.invokeVirtual(getter.owner.type, getter.method);
         }
 
         if (!getter.rtn.clazz.equals(getter.handle.type().returnType())) {
-            adapter.checkCast(getter.rtn.type);
+            writer.checkCast(getter.rtn.type);
         }
     }
 
     @Override
-    void store(MethodWriter adapter) {
+    void store(MethodWriter writer) {
         if (java.lang.reflect.Modifier.isInterface(setter.owner.clazz.getModifiers())) {
-            adapter.invokeInterface(setter.owner.type, setter.method);
+            writer.invokeInterface(setter.owner.type, setter.method);
         } else {
-            adapter.invokeVirtual(setter.owner.type, setter.method);
+            writer.invokeVirtual(setter.owner.type, setter.method);
         }
 
-        adapter.writePop(setter.rtn.sort.size);
+        writer.writePop(setter.rtn.sort.size);
     }
 }

+ 69 - 0
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LStatic.java

@@ -0,0 +1,69 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.painless.node;
+
+import org.elasticsearch.painless.Definition;
+import org.elasticsearch.painless.MethodWriter;
+import org.elasticsearch.painless.Variables;
+
+/**
+ * Represents a static type target.
+ */
+public final class LStatic extends ALink {
+
+    final String type;
+
+    public LStatic(int line, int offset, String location, String type) {
+        super(line, offset, location, 0);
+
+        this.type = type;
+    }
+
+    @Override
+    ALink analyze(Variables variables) {
+        if (before != null) {
+            throw new IllegalArgumentException(error("Illegal static type [" + type + "] after target already defined."));
+        }
+
+        try {
+            after = Definition.getType(type);
+            statik = true;
+        } catch (IllegalArgumentException exception) {
+            throw new IllegalArgumentException(error("Not a type [" + type + "]."));
+        }
+
+        return this;
+    }
+
+    @Override
+    void write(MethodWriter writer) {
+        throw new IllegalStateException(error("Illegal tree structure."));
+    }
+
+    @Override
+    void load(MethodWriter writer) {
+        throw new IllegalStateException(error("Illegal tree structure."));
+    }
+
+    @Override
+    void store(MethodWriter writer) {
+        throw new IllegalStateException(error("Illegal tree structure."));
+    }
+}

+ 7 - 7
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LString.java

@@ -28,8 +28,8 @@ import org.elasticsearch.painless.MethodWriter;
  */
 public final class LString extends ALink {
 
-    public LString(int line, String location, String string) {
-        super(line, location, -1);
+    public LString(int line, int offset, String location, String string) {
+        super(line, offset, location, -1);
 
         this.string = string;
     }
@@ -37,7 +37,7 @@ public final class LString extends ALink {
     @Override
     ALink analyze(Variables variables) {
         if (before != null) {
-            throw new IllegalStateException("Illegal tree structure.");
+            throw new IllegalArgumentException(error("Illegal String constant [" + string + "]."));
         } else if (store) {
             throw new IllegalArgumentException(error("Cannot write to read-only String constant [" + string + "]."));
         } else if (!load) {
@@ -50,17 +50,17 @@ public final class LString extends ALink {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         // Do nothing.
     }
 
     @Override
-    void load(MethodWriter adapter) {
-        adapter.push(string);
+    void load(MethodWriter writer) {
+        writer.push(string);
     }
 
     @Override
-    void store(MethodWriter adapter) {
+    void store(MethodWriter writer) {
         throw new IllegalStateException(error("Illegal tree structure."));
     }
 }

+ 14 - 29
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/LVariable.java

@@ -19,12 +19,10 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition;
-import org.elasticsearch.painless.Definition.Type;
+import org.elasticsearch.painless.MethodWriter;
 import org.elasticsearch.painless.Variables;
 import org.elasticsearch.painless.Variables.Variable;
 import org.objectweb.asm.Opcodes;
-import org.elasticsearch.painless.MethodWriter;
 
 /**
  * Represents a variable load/store.
@@ -35,8 +33,8 @@ public final class LVariable extends ALink {
 
     int slot;
 
-    public LVariable(int line, String location, String name) {
-        super(line, location, 0);
+    public LVariable(int line, int offset, String location, String name) {
+        super(line, offset, location, 0);
 
         this.name = name;
     }
@@ -44,46 +42,33 @@ public final class LVariable extends ALink {
     @Override
     ALink analyze(Variables variables) {
         if (before != null) {
-            throw new IllegalStateException(error("Illegal tree structure."));
+            throw new IllegalArgumentException(error("Illegal variable [" + name + "] access with target already defined."));
         }
 
-        Type type = null;
+        Variable variable = variables.getVariable(location, name);
 
-        try {
-            type = Definition.getType(name);
-        } catch (final IllegalArgumentException exception) {
-            // Do nothing.
+        if (store && variable.readonly) {
+            throw new IllegalArgumentException(error("Variable [" + variable.name + "] is read-only."));
         }
 
-        if (type != null) {
-            statik = true;
-            after = type;
-        } else {
-            final Variable variable = variables.getVariable(location, name);
-
-            if (store && variable.readonly) {
-                throw new IllegalArgumentException(error("Variable [" + variable.name + "] is read-only."));
-            }
-
-            slot = variable.slot;
-            after = variable.type;
-        }
+        slot = variable.slot;
+        after = variable.type;
 
         return this;
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         // Do nothing.
     }
 
     @Override
-    void load(MethodWriter adapter) {
-        adapter.visitVarInsn(after.type.getOpcode(Opcodes.ILOAD), slot);
+    void load(MethodWriter writer) {
+        writer.visitVarInsn(after.type.getOpcode(Opcodes.ILOAD), slot);
     }
 
     @Override
-    void store(MethodWriter adapter) {
-        adapter.visitVarInsn(after.type.getOpcode(Opcodes.ISTORE), slot);
+    void store(MethodWriter writer) {
+        writer.visitVarInsn(after.type.getOpcode(Opcodes.ISTORE), slot);
     }
 }

+ 8 - 4
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBlock.java

@@ -32,14 +32,18 @@ public final class SBlock extends AStatement {
 
     final List<AStatement> statements;
 
-    public SBlock(int line, String location, List<AStatement> statements) {
-        super(line, location);
+    public SBlock(int line, int offset, String location, List<AStatement> statements) {
+        super(line, offset, location);
 
         this.statements = Collections.unmodifiableList(statements);
     }
 
     @Override
     void analyze(Variables variables) {
+        if (statements == null || statements.isEmpty()) {
+            throw new IllegalArgumentException(error("A block must contain at least one statement."));
+        }
+
         final AStatement last = statements.get(statements.size() - 1);
 
         for (AStatement statement : statements) {
@@ -63,11 +67,11 @@ public final class SBlock extends AStatement {
     }
 
     @Override
-    void write(MethodWriter adapter) {
+    void write(MethodWriter writer) {
         for (AStatement statement : statements) {
             statement.continu = continu;
             statement.brake = brake;
-            statement.write(adapter);
+            statement.write(writer);
         }
     }
 }

+ 6 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SBreak.java

@@ -27,8 +27,8 @@ import org.elasticsearch.painless.MethodWriter;
  */
 public final class SBreak extends AStatement {
 
-    public SBreak(int line, String location) {
-        super(line, location);
+    public SBreak(int line, int offset, String location) {
+        super(line, offset, location);
     }
 
     @Override
@@ -44,8 +44,9 @@ public final class SBreak extends AStatement {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        writeDebugInfo(adapter);
-        adapter.goTo(brake);
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
+
+        writer.goTo(brake);
     }
 }

+ 26 - 15
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STrap.java → modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SCatch.java

@@ -19,6 +19,8 @@
 
 package org.elasticsearch.painless.node;
 
+import org.elasticsearch.painless.Definition;
+import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Variables;
 import org.elasticsearch.painless.Variables.Variable;
 import org.objectweb.asm.Label;
@@ -28,11 +30,11 @@ import org.elasticsearch.painless.MethodWriter;
 /**
  * Represents a catch block as part of a try-catch block.
  */
-public final class STrap extends AStatement {
+public final class SCatch extends AStatement {
 
     final String type;
     final String name;
-    final AStatement block;
+    final SBlock block;
 
     Variable variable;
 
@@ -40,8 +42,8 @@ public final class STrap extends AStatement {
     Label end;
     Label exception;
 
-    public STrap(int line, String location, String type, String name, AStatement block) {
-        super(line, location);
+    public SCatch(int line, int offset, String location, String type, String name, SBlock block) {
+        super(line, offset, location);
 
         this.type = type;
         this.name = name;
@@ -50,12 +52,20 @@ public final class STrap extends AStatement {
 
     @Override
     void analyze(Variables variables) {
-        variable = variables.addVariable(location, type, name, true, false);
+        final Type type;
+
+        try {
+            type = Definition.getType(this.type);
+        } catch (IllegalArgumentException exception) {
+            throw new IllegalArgumentException(error("Not a type [" + this.type + "]."));
+        }
 
-        if (!Exception.class.isAssignableFrom(variable.type.clazz)) {
-            throw new ClassCastException(error("Not an exception type [" + variable.type.name + "]."));
+        if (!Exception.class.isAssignableFrom(type.clazz)) {
+            throw new ClassCastException(error("Not an exception type [" + this.type + "]."));
         }
 
+        variable = variables.addVariable(location, type, name, true, false);
+
         if (block != null) {
             block.lastSource = lastSource;
             block.inLoop = inLoop;
@@ -73,23 +83,24 @@ public final class STrap extends AStatement {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        writeDebugInfo(adapter);
-        final Label jump = new Label();
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
+
+        Label jump = new Label();
 
-        adapter.mark(jump);
-        adapter.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.slot);
+        writer.mark(jump);
+        writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.slot);
 
         if (block != null) {
             block.continu = continu;
             block.brake = brake;
-            block.write(adapter);
+            block.write(writer);
         }
 
-        adapter.visitTryCatchBlock(begin, end, jump, variable.type.type.getInternalName());
+        writer.visitTryCatchBlock(begin, end, jump, variable.type.type.getInternalName());
 
         if (exception != null && !block.allEscape) {
-            adapter.goTo(exception);
+            writer.goTo(exception);
         }
     }
 }

+ 6 - 5
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SContinue.java

@@ -27,8 +27,8 @@ import org.elasticsearch.painless.MethodWriter;
  */
 public final class SContinue extends AStatement {
 
-    public SContinue(int line, String location) {
-        super(line, location);
+    public SContinue(int line, int offset, String location) {
+        super(line, offset, location);
     }
 
     @Override
@@ -47,8 +47,9 @@ public final class SContinue extends AStatement {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        writeDebugInfo(adapter);
-        adapter.goTo(continu);
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
+
+        writer.goTo(continu);
     }
 }

+ 6 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclBlock.java

@@ -32,15 +32,15 @@ public final class SDeclBlock extends AStatement {
 
     final List<SDeclaration> declarations;
 
-    public SDeclBlock(int line, String location, List<SDeclaration> declarations) {
-        super(line, location);
+    public SDeclBlock(int line, int offset, String location, List<SDeclaration> declarations) {
+        super(line, offset, location);
 
         this.declarations = Collections.unmodifiableList(declarations);
     }
 
     @Override
     void analyze(Variables variables) {
-        for (final SDeclaration declaration : declarations) {
+        for (SDeclaration declaration : declarations) {
             declaration.analyze(variables);
         }
 
@@ -48,9 +48,9 @@ public final class SDeclBlock extends AStatement {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        for (final SDeclaration declaration : declarations) {
-            declaration.write(adapter);
+    void write(MethodWriter writer) {
+        for (SDeclaration declaration : declarations) {
+            declaration.write(writer);
         }
     }
 }

+ 32 - 27
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDeclaration.java

@@ -19,7 +19,8 @@
 
 package org.elasticsearch.painless.node;
 
-import org.elasticsearch.painless.Definition.Sort;
+import org.elasticsearch.painless.Definition;
+import org.elasticsearch.painless.Definition.Type;
 import org.elasticsearch.painless.Variables;
 import org.elasticsearch.painless.Variables.Variable;
 import org.objectweb.asm.Opcodes;
@@ -36,8 +37,8 @@ public final class SDeclaration extends AStatement {
 
     Variable variable;
 
-    public SDeclaration(int line, String location, String type, String name, AExpression expression) {
-        super(line, location);
+    public SDeclaration(int line, int offset, String location, String type, String name, AExpression expression) {
+        super(line, offset, location);
 
         this.type = type;
         this.name = name;
@@ -46,40 +47,44 @@ public final class SDeclaration extends AStatement {
 
     @Override
     void analyze(Variables variables) {
-        variable = variables.addVariable(location, type, name, false, false);
+        final Type type;
+
+        try {
+            type = Definition.getType(this.type);
+        } catch (IllegalArgumentException exception) {
+            throw new IllegalArgumentException(error("Not a type [" + this.type + "]."));
+        }
 
         if (expression != null) {
-            expression.expected = variable.type;
+            expression.expected = type;
             expression.analyze(variables);
             expression = expression.cast(variables);
         }
+
+        variable = variables.addVariable(location, type, name, false, false);
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        writeDebugInfo(adapter);
-        final org.objectweb.asm.Type type = variable.type.type;
-        final Sort sort = variable.type.sort;
-
-        final boolean initialize = expression == null;
-
-        if (!initialize) {
-            expression.write(adapter);
-        }
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
 
-        switch (sort) {
-            case VOID:   throw new IllegalStateException(error("Illegal tree structure."));
-            case BOOL:
-            case BYTE:
-            case SHORT:
-            case CHAR:
-            case INT:    if (initialize) adapter.push(0);    break;
-            case LONG:   if (initialize) adapter.push(0L);   break;
-            case FLOAT:  if (initialize) adapter.push(0.0F); break;
-            case DOUBLE: if (initialize) adapter.push(0.0);  break;
-            default:     if (initialize) adapter.visitInsn(Opcodes.ACONST_NULL);
+        if (expression == null) {
+            switch (variable.type.sort) {
+                case VOID:   throw new IllegalStateException(error("Illegal tree structure."));
+                case BOOL:
+                case BYTE:
+                case SHORT:
+                case CHAR:
+                case INT:    writer.push(0);    break;
+                case LONG:   writer.push(0L);   break;
+                case FLOAT:  writer.push(0.0F); break;
+                case DOUBLE: writer.push(0.0);  break;
+                default:     writer.visitInsn(Opcodes.ACONST_NULL);
+            }
+        } else {
+            expression.write(writer);
         }
 
-        adapter.visitVarInsn(type.getOpcode(Opcodes.ISTORE), variable.slot);
+        writer.visitVarInsn(variable.type.type.getOpcode(Opcodes.ISTORE), variable.slot);
     }
 }

+ 21 - 16
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SDo.java

@@ -29,12 +29,12 @@ import org.elasticsearch.painless.MethodWriter;
  */
 public final class SDo extends AStatement {
 
-    final AStatement block;
-    AExpression condition;
     final int maxLoopCounter;
+    final SBlock block;
+    AExpression condition;
 
-    public SDo(int line, String location, AStatement block, AExpression condition, int maxLoopCounter) {
-        super(line, location);
+    public SDo(int line, int offset, String location, int maxLoopCounter, SBlock block, AExpression condition) {
+        super(line, offset, location);
 
         this.condition = condition;
         this.block = block;
@@ -45,6 +45,10 @@ public final class SDo extends AStatement {
     void analyze(Variables variables) {
         variables.incrementScope();
 
+        if (block == null) {
+            throw new IllegalArgumentException(error("Extraneous do while loop."));
+        }
+
         block.beginLoop = true;
         block.inLoop = true;
 
@@ -81,26 +85,27 @@ public final class SDo extends AStatement {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        writeDebugInfo(adapter);
-        final Label start = new Label();
-        final Label begin = new Label();
-        final Label end = new Label();
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
+
+        Label start = new Label();
+        Label begin = new Label();
+        Label end = new Label();
 
-        adapter.mark(start);
+        writer.mark(start);
 
         block.continu = begin;
         block.brake = end;
-        block.write(adapter);
+        block.write(writer);
 
-        adapter.mark(begin);
+        writer.mark(begin);
 
         condition.fals = end;
-        condition.write(adapter);
+        condition.write(writer);
 
-        adapter.writeLoopCounter(loopCounterSlot, Math.max(1, block.statementCount));
+        writer.writeLoopCounter(loopCounterSlot, Math.max(1, block.statementCount));
 
-        adapter.goTo(start);
-        adapter.mark(end);
+        writer.goTo(start);
+        writer.mark(end);
     }
 }

+ 8 - 7
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SExpression.java

@@ -31,8 +31,8 @@ public final class SExpression extends AStatement {
 
     AExpression expression;
 
-    public SExpression(int line, String location, AExpression expression) {
-        super(line, location);
+    public SExpression(int line, int offset, String location, AExpression expression) {
+        super(line, offset, location);
 
         this.expression = expression;
     }
@@ -59,14 +59,15 @@ public final class SExpression extends AStatement {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        writeDebugInfo(adapter);
-        expression.write(adapter);
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
+
+        expression.write(writer);
 
         if (methodEscape) {
-            adapter.returnValue();
+            writer.returnValue();
         } else {
-            adapter.writePop(expression.expected.sort.size);
+            writer.writePop(expression.expected.sort.size);
         }
     }
 }

+ 25 - 27
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SFor.java

@@ -29,15 +29,15 @@ import org.elasticsearch.painless.MethodWriter;
  */
 public final class SFor extends AStatement {
 
+    final int maxLoopCounter;
     ANode initializer;
     AExpression condition;
     AExpression afterthought;
-    final AStatement block;
-    final int maxLoopCounter;
+    final SBlock block;
 
-    public SFor(int line, String location,
-                ANode initializer, AExpression condition, AExpression afterthought, AStatement block, int maxLoopCounter) {
-        super(line, location);
+    public SFor(int line, int offset, String location, int maxLoopCounter,
+                ANode initializer, AExpression condition, AExpression afterthought, SBlock block) {
+        super(line, offset, location);
 
         this.initializer = initializer;
         this.condition = condition;
@@ -56,7 +56,7 @@ public final class SFor extends AStatement {
             if (initializer instanceof SDeclBlock) {
                 ((SDeclBlock)initializer).analyze(variables);
             } else if (initializer instanceof AExpression) {
-                final AExpression initializer = (AExpression)this.initializer;
+                AExpression initializer = (AExpression)this.initializer;
 
                 initializer.read = false;
                 initializer.analyze(variables);
@@ -70,7 +70,6 @@ public final class SFor extends AStatement {
         }
 
         if (condition != null) {
-
             condition.expected = Definition.BOOLEAN_TYPE;
             condition.analyze(variables);
             condition = condition.cast(variables);
@@ -99,8 +98,6 @@ public final class SFor extends AStatement {
             }
         }
 
-        int count = 1;
-
         if (block != null) {
             block.beginLoop = true;
             block.inLoop = true;
@@ -116,7 +113,7 @@ public final class SFor extends AStatement {
                 allEscape = true;
             }
 
-            block.statementCount = Math.max(count, block.statementCount);
+            block.statementCount = Math.max(1, block.statementCount);
         }
 
         statementCount = 1;
@@ -129,26 +126,27 @@ public final class SFor extends AStatement {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        writeDebugInfo(adapter);
-        final Label start = new Label();
-        final Label begin = afterthought == null ? start : new Label();
-        final Label end = new Label();
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
+
+        Label start = new Label();
+        Label begin = afterthought == null ? start : new Label();
+        Label end = new Label();
 
         if (initializer instanceof SDeclBlock) {
-            ((SDeclBlock)initializer).write(adapter);
+            ((SDeclBlock)initializer).write(writer);
         } else if (initializer instanceof AExpression) {
             AExpression initializer = (AExpression)this.initializer;
 
-            initializer.write(adapter);
-            adapter.writePop(initializer.expected.sort.size);
+            initializer.write(writer);
+            writer.writePop(initializer.expected.sort.size);
         }
 
-        adapter.mark(start);
+        writer.mark(start);
 
         if (condition != null) {
             condition.fals = end;
-            condition.write(adapter);
+            condition.write(writer);
         }
 
         boolean allEscape = false;
@@ -162,21 +160,21 @@ public final class SFor extends AStatement {
                 ++statementCount;
             }
 
-            adapter.writeLoopCounter(loopCounterSlot, statementCount);
-            block.write(adapter);
+            writer.writeLoopCounter(loopCounterSlot, statementCount);
+            block.write(writer);
         } else {
-            adapter.writeLoopCounter(loopCounterSlot, 1);
+            writer.writeLoopCounter(loopCounterSlot, 1);
         }
 
         if (afterthought != null) {
-            adapter.mark(begin);
-            afterthought.write(adapter);
+            writer.mark(begin);
+            afterthought.write(writer);
         }
 
         if (afterthought != null || !allEscape) {
-            adapter.goTo(start);
+            writer.goTo(start);
         }
 
-        adapter.mark(end);
+        writer.mark(end);
     }
 }

+ 84 - 0
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIf.java

@@ -0,0 +1,84 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.painless.node;
+
+import org.elasticsearch.painless.Definition;
+import org.elasticsearch.painless.Variables;
+import org.objectweb.asm.Label;
+import org.elasticsearch.painless.MethodWriter;
+
+/**
+ * Represents an if block.
+ */
+public final class SIf extends AStatement {
+
+    AExpression condition;
+    final SBlock ifblock;
+
+    public SIf(int line, int offset, String location, AExpression condition, SBlock ifblock) {
+        super(line, offset, location);
+
+        this.condition = condition;
+        this.ifblock = ifblock;
+    }
+
+    @Override
+    void analyze(Variables variables) {
+        condition.expected = Definition.BOOLEAN_TYPE;
+        condition.analyze(variables);
+        condition = condition.cast(variables);
+
+        if (condition.constant != null) {
+            throw new IllegalArgumentException(error("Extraneous if statement."));
+        }
+
+        if (ifblock == null) {
+            throw new IllegalArgumentException(error("Extraneous if statement."));
+        }
+
+        ifblock.lastSource = lastSource;
+        ifblock.inLoop = inLoop;
+        ifblock.lastLoop = lastLoop;
+
+        variables.incrementScope();
+        ifblock.analyze(variables);
+        variables.decrementScope();
+
+        anyContinue = ifblock.anyContinue;
+        anyBreak = ifblock.anyBreak;
+        statementCount = ifblock.statementCount;
+    }
+
+    @Override
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
+
+        Label fals = new Label();
+
+        condition.fals = fals;
+        condition.write(writer);
+
+        ifblock.continu = continu;
+        ifblock.brake = brake;
+        ifblock.write(writer);
+
+        writer.mark(fals);
+    }
+}

+ 40 - 35
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SIfElse.java

@@ -30,11 +30,11 @@ import org.elasticsearch.painless.MethodWriter;
 public final class SIfElse extends AStatement {
 
     AExpression condition;
-    final AStatement ifblock;
-    final AStatement elseblock;
+    final SBlock ifblock;
+    final SBlock elseblock;
 
-    public SIfElse(int line, String location, AExpression condition, AStatement ifblock, AStatement elseblock) {
-        super(line, location);
+    public SIfElse(int line, int offset, String location, AExpression condition, SBlock ifblock, SBlock elseblock) {
+        super(line, offset, location);
 
         this.condition = condition;
         this.ifblock = ifblock;
@@ -51,6 +51,10 @@ public final class SIfElse extends AStatement {
             throw new IllegalArgumentException(error("Extraneous if statement."));
         }
 
+        if (ifblock == null) {
+            throw new IllegalArgumentException(error("Extraneous if statement."));
+        }
+
         ifblock.lastSource = lastSource;
         ifblock.inLoop = inLoop;
         ifblock.lastLoop = lastLoop;
@@ -63,49 +67,50 @@ public final class SIfElse extends AStatement {
         anyBreak = ifblock.anyBreak;
         statementCount = ifblock.statementCount;
 
-        if (elseblock != null) {
-            elseblock.lastSource = lastSource;
-            elseblock.inLoop = inLoop;
-            elseblock.lastLoop = lastLoop;
-
-            variables.incrementScope();
-            elseblock.analyze(variables);
-            variables.decrementScope();
-
-            methodEscape = ifblock.methodEscape && elseblock.methodEscape;
-            loopEscape = ifblock.loopEscape && elseblock.loopEscape;
-            allEscape = ifblock.allEscape && elseblock.allEscape;
-            anyContinue |= elseblock.anyContinue;
-            anyBreak |= elseblock.anyBreak;
-            statementCount = Math.max(ifblock.statementCount, elseblock.statementCount);
+        if (elseblock == null) {
+            throw new IllegalArgumentException(error("Extraneous else statement."));
         }
+
+        elseblock.lastSource = lastSource;
+        elseblock.inLoop = inLoop;
+        elseblock.lastLoop = lastLoop;
+
+        variables.incrementScope();
+        elseblock.analyze(variables);
+        variables.decrementScope();
+
+        methodEscape = ifblock.methodEscape && elseblock.methodEscape;
+        loopEscape = ifblock.loopEscape && elseblock.loopEscape;
+        allEscape = ifblock.allEscape && elseblock.allEscape;
+        anyContinue |= elseblock.anyContinue;
+        anyBreak |= elseblock.anyBreak;
+        statementCount = Math.max(ifblock.statementCount, elseblock.statementCount);
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        writeDebugInfo(adapter);
-        final Label end = new Label();
-        final Label fals = elseblock != null ? new Label() : end;
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
+
+        Label end = new Label();
+        Label fals = elseblock != null ? new Label() : end;
 
         condition.fals = fals;
-        condition.write(adapter);
+        condition.write(writer);
 
         ifblock.continu = continu;
         ifblock.brake = brake;
-        ifblock.write(adapter);
+        ifblock.write(writer);
 
-        if (elseblock != null) {
-            if (!ifblock.allEscape) {
-                adapter.goTo(end);
-            }
+        if (!ifblock.allEscape) {
+            writer.goTo(end);
+        }
 
-            adapter.mark(fals);
+        writer.mark(fals);
 
-            elseblock.continu = continu;
-            elseblock.brake = brake;
-            elseblock.write(adapter);
-        }
+        elseblock.continu = continu;
+        elseblock.brake = brake;
+        elseblock.write(writer);
 
-        adapter.mark(end);
+        writer.mark(end);
     }
 }

+ 7 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SReturn.java

@@ -30,8 +30,8 @@ public final class SReturn extends AStatement {
 
     AExpression expression;
 
-    public SReturn(int line, String location, AExpression expression) {
-        super(line, location);
+    public SReturn(int line, int offset, String location, AExpression expression) {
+        super(line, offset, location);
 
         this.expression = expression;
     }
@@ -51,9 +51,10 @@ public final class SReturn extends AStatement {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        writeDebugInfo(adapter);
-        expression.write(adapter);
-        adapter.returnValue();
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
+
+        expression.write(writer);
+        writer.returnValue();
     }
 }

+ 12 - 8
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SSource.java

@@ -33,19 +33,23 @@ public final class SSource extends AStatement {
 
     final List<AStatement> statements;
 
-    public SSource(int line, String location, List<AStatement> statements) {
-        super(line, location);
+    public SSource(int line, int offset, String location, List<AStatement> statements) {
+        super(line, offset, location);
 
         this.statements = Collections.unmodifiableList(statements);
     }
 
     @Override
     public void analyze(Variables variables) {
+        if (statements == null || statements.isEmpty()) {
+            throw new IllegalArgumentException(error("Cannot generate an empty script."));
+        }
+
         variables.incrementScope();
 
         final AStatement last = statements.get(statements.size() - 1);
 
-        for (final AStatement statement : statements) {
+        for (AStatement statement : statements) {
             if (allEscape) {
                 throw new IllegalArgumentException(error("Unreachable statement."));
             }
@@ -61,14 +65,14 @@ public final class SSource extends AStatement {
     }
 
     @Override
-    public void write(MethodWriter adapter) {
-        for (final AStatement statement : statements) {
-            statement.write(adapter);
+    public void write(MethodWriter writer) {
+        for (AStatement statement : statements) {
+            statement.write(writer);
         }
 
         if (!methodEscape) {
-            adapter.visitInsn(Opcodes.ACONST_NULL);
-            adapter.returnValue();
+            writer.visitInsn(Opcodes.ACONST_NULL);
+            writer.returnValue();
         }
     }
 }

+ 7 - 6
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SThrow.java

@@ -30,8 +30,8 @@ public final class SThrow extends AStatement {
 
     AExpression expression;
 
-    public SThrow(int line, String location, AExpression expression) {
-        super(line, location);
+    public SThrow(int line, int offset, String location, AExpression expression) {
+        super(line, offset, location);
 
         this.expression = expression;
     }
@@ -49,9 +49,10 @@ public final class SThrow extends AStatement {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        writeDebugInfo(adapter);
-        expression.write(adapter);
-        adapter.throwException();
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
+
+        expression.write(writer);
+        writer.throwException();
     }
 }

+ 37 - 32
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/STry.java

@@ -31,18 +31,22 @@ import java.util.List;
  */
 public final class STry extends AStatement {
 
-    final AStatement block;
-    final List<STrap> traps;
+    final SBlock block;
+    final List<SCatch> catches;
 
-    public STry(int line, String location, AStatement block, List<STrap> traps) {
-        super(line, location);
+    public STry(int line, int offset, String location, SBlock block, List<SCatch> traps) {
+        super(line, offset, location);
 
         this.block = block;
-        this.traps = Collections.unmodifiableList(traps);
+        this.catches = Collections.unmodifiableList(traps);
     }
 
     @Override
     void analyze(Variables variables) {
+        if (block == null) {
+            throw new IllegalArgumentException(error("Extraneous try statement."));
+        }
+
         block.lastSource = lastSource;
         block.inLoop = inLoop;
         block.lastLoop = lastLoop;
@@ -59,55 +63,56 @@ public final class STry extends AStatement {
 
         int statementCount = 0;
 
-        for (final STrap trap : traps) {
-            trap.lastSource = lastSource;
-            trap.inLoop = inLoop;
-            trap.lastLoop = lastLoop;
+        for (SCatch catc : catches) {
+            catc.lastSource = lastSource;
+            catc.inLoop = inLoop;
+            catc.lastLoop = lastLoop;
 
             variables.incrementScope();
-            trap.analyze(variables);
+            catc.analyze(variables);
             variables.decrementScope();
 
-            methodEscape &= trap.methodEscape;
-            loopEscape &= trap.loopEscape;
-            allEscape &= trap.allEscape;
-            anyContinue |= trap.anyContinue;
-            anyBreak |= trap.anyBreak;
+            methodEscape &= catc.methodEscape;
+            loopEscape &= catc.loopEscape;
+            allEscape &= catc.allEscape;
+            anyContinue |= catc.anyContinue;
+            anyBreak |= catc.anyBreak;
 
-            statementCount = Math.max(statementCount, trap.statementCount);
+            statementCount = Math.max(statementCount, catc.statementCount);
         }
 
         this.statementCount = block.statementCount + statementCount;
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        writeDebugInfo(adapter);
-        final Label begin = new Label();
-        final Label end = new Label();
-        final Label exception = new Label();
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
+
+        Label begin = new Label();
+        Label end = new Label();
+        Label exception = new Label();
 
-        adapter.mark(begin);
+        writer.mark(begin);
 
         block.continu = continu;
         block.brake = brake;
-        block.write(adapter);
+        block.write(writer);
 
         if (!block.allEscape) {
-            adapter.goTo(exception);
+            writer.goTo(exception);
         }
 
-        adapter.mark(end);
+        writer.mark(end);
 
-        for (final STrap trap : traps) {
-            trap.begin = begin;
-            trap.end = end;
-            trap.exception = traps.size() > 1 ? exception : null;
-            trap.write(adapter);
+        for (SCatch catc : catches) {
+            catc.begin = begin;
+            catc.end = end;
+            catc.exception = catches.size() > 1 ? exception : null;
+            catc.write(writer);
         }
 
-        if (!block.allEscape || traps.size() > 1) {
-            adapter.mark(exception);
+        if (!block.allEscape || catches.size() > 1) {
+            writer.mark(exception);
         }
     }
 }

+ 19 - 20
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/SWhile.java

@@ -29,16 +29,16 @@ import org.elasticsearch.painless.MethodWriter;
  */
 public final class SWhile extends AStatement {
 
-    AExpression condition;
-    final AStatement block;
     final int maxLoopCounter;
+    AExpression condition;
+    final SBlock block;
 
-    public SWhile(int line, String location, AExpression condition, AStatement block, int maxLoopCounter) {
-        super(line, location);
+    public SWhile(int line, int offset, String location, int maxLoopCounter, AExpression condition, SBlock block) {
+        super(line, offset, location);
 
+        this.maxLoopCounter = maxLoopCounter;
         this.condition = condition;
         this.block = block;
-        this.maxLoopCounter = maxLoopCounter;
     }
 
     @Override
@@ -63,8 +63,6 @@ public final class SWhile extends AStatement {
             }
         }
 
-        int count = 1;
-
         if (block != null) {
             block.beginLoop = true;
             block.inLoop = true;
@@ -72,7 +70,7 @@ public final class SWhile extends AStatement {
             block.analyze(variables);
 
             if (block.loopEscape && !block.anyContinue) {
-                throw new IllegalArgumentException(error("Extranous while loop."));
+                throw new IllegalArgumentException(error("Extraneous while loop."));
             }
 
             if (continuous && !block.anyBreak) {
@@ -80,7 +78,7 @@ public final class SWhile extends AStatement {
                 allEscape = true;
             }
 
-            block.statementCount = Math.max(count, block.statementCount);
+            block.statementCount = Math.max(1, block.statementCount);
         }
 
         statementCount = 1;
@@ -93,30 +91,31 @@ public final class SWhile extends AStatement {
     }
 
     @Override
-    void write(MethodWriter adapter) {
-        writeDebugInfo(adapter);
-        final Label begin = new Label();
-        final Label end = new Label();
+    void write(MethodWriter writer) {
+        writeDebugInfo(writer);
+
+        Label begin = new Label();
+        Label end = new Label();
 
-        adapter.mark(begin);
+        writer.mark(begin);
 
         condition.fals = end;
-        condition.write(adapter);
+        condition.write(writer);
 
         if (block != null) {
-            adapter.writeLoopCounter(loopCounterSlot, Math.max(1, block.statementCount));
+            writer.writeLoopCounter(loopCounterSlot, Math.max(1, block.statementCount));
 
             block.continu = begin;
             block.brake = end;
-            block.write(adapter);
+            block.write(writer);
         } else {
-            adapter.writeLoopCounter(loopCounterSlot, 1);
+            writer.writeLoopCounter(loopCounterSlot, 1);
         }
 
         if (block == null || !block.allEscape) {
-            adapter.goTo(begin);
+            writer.goTo(begin);
         }
 
-        adapter.mark(end);
+        writer.mark(end);
     }
 }

+ 3 - 1
modules/lang-painless/src/main/java/org/elasticsearch/painless/node/package-info.java

@@ -59,21 +59,23 @@
  * {@link org.elasticsearch.painless.node.LNewArray} - Represents an array instantiation.
  * {@link org.elasticsearch.painless.node.LNewObj} - Respresents and object instantiation.
  * {@link org.elasticsearch.painless.node.LShortcut} - Represents a field load/store shortcut.  (Internal only.)
+ * {@link org.elasticsearch.painless.node.LStatic} - Represents a static type target.
  * {@link org.elasticsearch.painless.node.LString} - Represents a string constant.
  * {@link org.elasticsearch.painless.node.LVariable} - Represents a variable load/store.
  * {@link org.elasticsearch.painless.node.SBlock} - Represents a set of statements as a branch of control-flow.
  * {@link org.elasticsearch.painless.node.SBreak} - Represents a break statement.
+ * {@link org.elasticsearch.painless.node.SCatch} - Represents a catch block as part of a try-catch block.
  * {@link org.elasticsearch.painless.node.SContinue} - Represents a continue statement.
  * {@link org.elasticsearch.painless.node.SDeclaration} - Represents a single variable declaration.
  * {@link org.elasticsearch.painless.node.SDeclBlock} - Represents a series of declarations.
  * {@link org.elasticsearch.painless.node.SDo} - Represents a do-while loop.
  * {@link org.elasticsearch.painless.node.SExpression} - Represents the top-level node for an expression as a statement.
  * {@link org.elasticsearch.painless.node.SFor} - Represents a for loop.
+ * {@link org.elasticsearch.painless.node.SIf} - Represents an if block.
  * {@link org.elasticsearch.painless.node.SIfElse} - Represents an if/else block.
  * {@link org.elasticsearch.painless.node.SReturn} - Represents a return statement.
  * {@link org.elasticsearch.painless.node.SSource} - The root of all Painless trees.  Contains a series of statements.
  * {@link org.elasticsearch.painless.node.SThrow} - Represents a throw statement.
- * {@link org.elasticsearch.painless.node.STrap} - Represents a catch block as part of a try-catch block.
  * {@link org.elasticsearch.painless.node.STry} - Represents the try block as part of a try-catch block.
  * {@link org.elasticsearch.painless.node.SWhile} - Represents a while loop.
  * <p>

+ 1 - 1
modules/lang-painless/src/test/java/org/elasticsearch/painless/NoSemiColonTests.java

@@ -59,7 +59,7 @@ public class NoSemiColonTests extends ScriptTestCase {
         assertEquals(String[][].class, exec("String[][] a = new String[1][2]; return a").getClass());
         assertEquals(Map[][][].class, exec("Map[][][] a = new Map[1][2][3]; return a").getClass());
     }
-    
+
     public void testExpression() {
         assertEquals(10, exec("10"));
         assertEquals(10, exec("5 + 5"));

+ 4 - 1
modules/lang-painless/src/test/java/org/elasticsearch/painless/ScriptTestCase.java

@@ -26,6 +26,7 @@ import org.elasticsearch.test.ESTestCase;
 import org.junit.Before;
 
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 
 /**
@@ -48,7 +49,9 @@ public abstract class ScriptTestCase extends ESTestCase {
 
     /** Compiles and returns the result of {@code script} with access to {@code vars} */
     public Object exec(String script, Map<String, Object> vars) {
-        return exec(script, vars, Collections.emptyMap());
+        Map<String,String> compilerSettings = new HashMap<>();
+        compilerSettings.put(CompilerSettings.PICKY, "true");
+        return exec(script, vars, compilerSettings);
     }
 
     /** Compiles and returns the result of {@code script} with access to {@code vars} and compile-time parameters */

+ 3 - 3
modules/lang-painless/src/test/java/org/elasticsearch/painless/WhenThingsGoWrongTests.java

@@ -52,13 +52,13 @@ public class WhenThingsGoWrongTests extends ScriptTestCase {
                  "return y.isEmpty();");
         });
         assertEquals(3, exception.getStackTrace()[0].getLineNumber());
-        
+
         // trigger NPE at line 4 in script (inside conditional)
         exception = expectThrows(NullPointerException.class, () -> {
             exec("String x = null;\n" +
                  "boolean y = false;\n" +
                  "if (!y) {\n" +
-                 "  y = x.isEmpty();\n" + 
+                 "  y = x.isEmpty();\n" +
                  "}\n" +
                  "return y;");
         });
@@ -133,7 +133,7 @@ public class WhenThingsGoWrongTests extends ScriptTestCase {
             exec("try { int x; } catch (PainlessError error) {}");
             fail("should have hit ParseException");
         });
-        assertTrue(parseException.getMessage().contains("Not a type [PainlessError]."));
+        assertTrue(parseException.getMessage().contains("unexpected token ['PainlessError']"));
     }
 
     public void testLoopLimits() {

+ 81 - 0
modules/lang-painless/src/test/java/org/elasticsearch/painless/antlr/ParserTests.java

@@ -0,0 +1,81 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.painless.antlr;
+
+import org.antlr.v4.runtime.ANTLRInputStream;
+import org.antlr.v4.runtime.BaseErrorListener;
+import org.antlr.v4.runtime.CommonTokenStream;
+import org.antlr.v4.runtime.DiagnosticErrorListener;
+import org.antlr.v4.runtime.RecognitionException;
+import org.antlr.v4.runtime.Recognizer;
+import org.antlr.v4.runtime.atn.PredictionMode;
+import org.elasticsearch.painless.antlr.PainlessParser.SourceContext;
+import org.elasticsearch.painless.ScriptTestCase;
+
+import java.text.ParseException;
+
+public class ParserTests extends ScriptTestCase {
+    private static class TestException extends RuntimeException {
+        TestException(String msg) {
+            super(msg);
+        }
+    }
+
+    private SourceContext buildAntlrTree(String source) {
+        ANTLRInputStream stream = new ANTLRInputStream(source);
+        PainlessLexer lexer = new ErrorHandlingLexer(stream);
+        PainlessParser parser = new PainlessParser(new CommonTokenStream(lexer));
+        ParserErrorStrategy strategy = new ParserErrorStrategy();
+
+        lexer.removeErrorListeners();
+        parser.removeErrorListeners();
+
+        // Diagnostic listener invokes syntaxError on other listeners for ambiguity issues,
+        parser.addErrorListener(new DiagnosticErrorListener(true));
+        // a second listener to fail the test when the above happens.
+        parser.addErrorListener(new BaseErrorListener() {
+            @Override
+            public void syntaxError(final Recognizer<?, ?> recognizer, final Object offendingSymbol, final int line,
+                                    final int charPositionInLine, final String msg, final RecognitionException e) {
+                throw new TestException("line: " + line + ", offset: " + charPositionInLine +
+                    ", symbol:" + offendingSymbol + " " + msg);
+            }
+        });
+
+        // Enable exact ambiguity detection (costly). we enable exact since its the default for
+        // DiagnosticErrorListener, life is too short to think about what 'inexact ambiguity' might mean.
+        parser.getInterpreter().setPredictionMode(PredictionMode.LL_EXACT_AMBIG_DETECTION);
+        parser.setErrorHandler(strategy);
+
+        return parser.source();
+    }
+
+    public void testIllegalSecondary() {
+        //TODO: Need way more corner case tests.
+        Exception exception = expectThrows(TestException.class, () -> buildAntlrTree("(x = 5).y"));
+        assertTrue(exception.getMessage().contains("no viable alternative"));
+        exception = expectThrows(TestException.class, () -> buildAntlrTree("((x = 5).y = 2).z;"));
+        assertTrue(exception.getMessage().contains("no viable alternative"));
+        exception = expectThrows(TestException.class, () -> buildAntlrTree("(2 + 2).z"));
+        assertTrue(exception.getMessage().contains("no viable alternative"));
+        exception = expectThrows(RuntimeException.class, () -> buildAntlrTree("((Map)x.-x)"));
+        assertTrue(exception.getMessage().contains("unexpected character"));
+    }
+}

+ 1 - 1
modules/reindex/src/test/java/org/elasticsearch/index/reindex/CancelTests.java

@@ -137,7 +137,7 @@ public class CancelTests extends ReindexTestCase {
         ALLOWED_OPERATIONS.release(BLOCKING_OPERATIONS);
 
         // Checks that no more operations are executed
-        assertBusy(() -> ALLOWED_OPERATIONS.availablePermits() == 0 && ALLOWED_OPERATIONS.getQueueLength() == 0);
+        assertBusy(() -> assertTrue(ALLOWED_OPERATIONS.availablePermits() == 0 && ALLOWED_OPERATIONS.getQueueLength() == 0));
 
         // And check the status of the response
         BulkIndexByScrollResponse response = future.get();

+ 5 - 15
test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java

@@ -443,24 +443,13 @@ public abstract class ESTestCase extends LuceneTestCase {
      * Runs the code block for 10 seconds waiting for no assertion to trip.
      */
     public static void assertBusy(Runnable codeBlock) throws Exception {
-        assertBusy(Executors.callable(codeBlock), 10, TimeUnit.SECONDS);
-    }
-
-    public static void assertBusy(Runnable codeBlock, long maxWaitTime, TimeUnit unit) throws Exception {
-        assertBusy(Executors.callable(codeBlock), maxWaitTime, unit);
-    }
-
-    /**
-     * Runs the code block for 10 seconds waiting for no assertion to trip.
-     */
-    public static <V> V assertBusy(Callable<V> codeBlock) throws Exception {
-        return assertBusy(codeBlock, 10, TimeUnit.SECONDS);
+        assertBusy(codeBlock, 10, TimeUnit.SECONDS);
     }
 
     /**
      * Runs the code block for the provided interval, waiting for no assertions to trip.
      */
-    public static <V> V assertBusy(Callable<V> codeBlock, long maxWaitTime, TimeUnit unit) throws Exception {
+    public static void assertBusy(Runnable codeBlock, long maxWaitTime, TimeUnit unit) throws Exception {
         long maxTimeInMillis = TimeUnit.MILLISECONDS.convert(maxWaitTime, unit);
         long iterations = Math.max(Math.round(Math.log10(maxTimeInMillis) / Math.log10(2)), 1);
         long timeInMillis = 1;
@@ -468,7 +457,8 @@ public abstract class ESTestCase extends LuceneTestCase {
         List<AssertionError> failures = new ArrayList<>();
         for (int i = 0; i < iterations; i++) {
             try {
-                return codeBlock.call();
+                codeBlock.run();
+                return;
             } catch (AssertionError e) {
                 failures.add(e);
             }
@@ -479,7 +469,7 @@ public abstract class ESTestCase extends LuceneTestCase {
         timeInMillis = maxTimeInMillis - sum;
         Thread.sleep(Math.max(timeInMillis, 0));
         try {
-            return codeBlock.call();
+            codeBlock.run();
         } catch (AssertionError e) {
             for (AssertionError failure : failures) {
                 e.addSuppressed(failure);

+ 7 - 8
test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java

@@ -80,7 +80,6 @@ import org.elasticsearch.indices.fielddata.cache.IndicesFieldDataCache;
 import org.elasticsearch.indices.recovery.RecoverySettings;
 import org.elasticsearch.node.MockNode;
 import org.elasticsearch.node.Node;
-import org.elasticsearch.node.internal.InternalSettingsPreparer;
 import org.elasticsearch.node.service.NodeService;
 import org.elasticsearch.plugins.Plugin;
 import org.elasticsearch.script.ScriptService;
@@ -293,8 +292,8 @@ public final class InternalTestCluster extends TestCluster {
         builder.put("http.port", HTTP_BASE_PORT + "-" + (HTTP_BASE_PORT + PORTS_PER_CLUSTER));
         builder.put(Node.NODE_MODE_SETTING.getKey(), nodeMode);
         builder.put("http.pipelining", enableHttpPipelining);
-        if (Strings.hasLength(System.getProperty("tests.logger.level"))) {
-            builder.put("logger.level", System.getProperty("tests.logger.level"));
+        if (Strings.hasLength(System.getProperty("tests.es.logger.level"))) {
+            builder.put("logger.level", System.getProperty("tests.es.logger.level"));
         }
         if (Strings.hasLength(System.getProperty("es.logger.prefix"))) {
             builder.put("logger.prefix", System.getProperty("es.logger.prefix"));
@@ -318,14 +317,14 @@ public final class InternalTestCluster extends TestCluster {
 
     public static String configuredNodeMode() {
         Builder builder = Settings.builder();
-        if (Strings.isEmpty(System.getProperty("node.mode")) && Strings.isEmpty(System.getProperty("node.local"))) {
+        if (Strings.isEmpty(System.getProperty("tests.es.node.mode")) && Strings.isEmpty(System.getProperty("tests.node.local"))) {
             return "local"; // default if nothing is specified
         }
-        if (Strings.hasLength(System.getProperty("node.mode"))) {
-            builder.put(Node.NODE_MODE_SETTING.getKey(), System.getProperty("node.mode"));
+        if (Strings.hasLength(System.getProperty("tests.es.node.mode"))) {
+            builder.put(Node.NODE_MODE_SETTING.getKey(), System.getProperty("tests.es.node.mode"));
         }
-        if (Strings.hasLength(System.getProperty("node.local"))) {
-            builder.put(Node.NODE_LOCAL_SETTING.getKey(), System.getProperty("node.local"));
+        if (Strings.hasLength(System.getProperty("tests.es.node.local"))) {
+            builder.put(Node.NODE_LOCAL_SETTING.getKey(), System.getProperty("tests.es.node.local"));
         }
         if (DiscoveryNode.isLocalNode(builder.build())) {
             return "local";

+ 2 - 2
test/framework/src/main/java/org/elasticsearch/test/junit/listeners/ReproduceInfoPrinter.java

@@ -137,10 +137,10 @@ public class ReproduceInfoPrinter extends RunListener {
         }
 
         public ReproduceErrorMessageBuilder appendESProperties() {
-            appendProperties("tests.logger.level");
+            appendProperties("tests.es.logger.level");
             if (inVerifyPhase()) {
                 // these properties only make sense for integration tests
-                appendProperties("node.mode", "node.local", TESTS_CLUSTER,
+                appendProperties("tests.es.node.mode", "tests.es.node.local", TESTS_CLUSTER,
                     ESIntegTestCase.TESTS_ENABLE_MOCK_MODULES);
             }
             appendProperties("tests.assertion.disabled", "tests.security.manager", "tests.nightly", "tests.jvms",

Alguns arquivos não foram mostrados porque muitos arquivos mudaram nesse diff