@@ -173,6 +173,9 @@ typedef struct
173173 // The 1-based line number of [currentChar].
174174 int currentLine ;
175175
176+ // The upcoming token.
177+ Token next ;
178+
176179 // The most recently lexed token.
177180 Token current ;
178181
@@ -639,13 +642,13 @@ static bool matchChar(Parser* parser, char c)
639642// range.
640643static void makeToken (Parser * parser , TokenType type )
641644{
642- parser -> current .type = type ;
643- parser -> current .start = parser -> tokenStart ;
644- parser -> current .length = (int )(parser -> currentChar - parser -> tokenStart );
645- parser -> current .line = parser -> currentLine ;
645+ parser -> next .type = type ;
646+ parser -> next .start = parser -> tokenStart ;
647+ parser -> next .length = (int )(parser -> currentChar - parser -> tokenStart );
648+ parser -> next .line = parser -> currentLine ;
646649
647650 // Make line tokens appear on the line containing the "\n".
648- if (type == TOKEN_LINE ) parser -> current .line -- ;
651+ if (type == TOKEN_LINE ) parser -> next .line -- ;
649652}
650653
651654// If the current character is [c], then consumes it and makes a token of type
@@ -719,17 +722,17 @@ static void makeNumber(Parser* parser, bool isHex)
719722
720723 if (isHex )
721724 {
722- parser -> current .value = NUM_VAL ((double )strtoll (parser -> tokenStart , NULL , 16 ));
725+ parser -> next .value = NUM_VAL ((double )strtoll (parser -> tokenStart , NULL , 16 ));
723726 }
724727 else
725728 {
726- parser -> current .value = NUM_VAL (strtod (parser -> tokenStart , NULL ));
729+ parser -> next .value = NUM_VAL (strtod (parser -> tokenStart , NULL ));
727730 }
728731
729732 if (errno == ERANGE )
730733 {
731734 lexError (parser , "Number literal was too large (%d)." , sizeof (long int ));
732- parser -> current .value = NUM_VAL (0 );
735+ parser -> next .value = NUM_VAL (0 );
733736 }
734737
735738 // We don't check that the entire token is consumed after calling strtoll()
@@ -921,21 +924,23 @@ static void readString(Parser* parser)
921924 }
922925 }
923926
924- parser -> current .value = wrenNewStringLength (parser -> vm ,
927+ parser -> next .value = wrenNewStringLength (parser -> vm ,
925928 (char * )string .data , string .count );
926929
927930 wrenByteBufferClear (parser -> vm , & string );
928931 makeToken (parser , type );
929932}
930933
931- // Lex the next token and store it in [parser.current ].
934+ // Lex the next token and store it in [parser.next ].
932935static void nextToken (Parser * parser )
933936{
934937 parser -> previous = parser -> current ;
938+ parser -> current = parser -> next ;
935939
936940 // If we are out of tokens, don't try to tokenize any more. We *do* still
937941 // copy the TOKEN_EOF to previous so that code that expects it to be consumed
938942 // will still work.
943+ if (parser -> next .type == TOKEN_EOF ) return ;
939944 if (parser -> current .type == TOKEN_EOF ) return ;
940945
941946 while (peekChar (parser ) != '\0' )
@@ -1094,8 +1099,8 @@ static void nextToken(Parser* parser)
10941099 // even though the source code and console output are UTF-8.
10951100 lexError (parser , "Invalid byte 0x%x." , (uint8_t )c );
10961101 }
1097- parser -> current .type = TOKEN_ERROR ;
1098- parser -> current .length = 0 ;
1102+ parser -> next .type = TOKEN_ERROR ;
1103+ parser -> next .length = 0 ;
10991104 }
11001105 return ;
11011106 }
@@ -1114,6 +1119,12 @@ static TokenType peek(Compiler* compiler)
11141119 return compiler -> parser -> current .type ;
11151120}
11161121
1122+ // Returns the type of the current token.
1123+ static TokenType peekNext (Compiler * compiler )
1124+ {
1125+ return compiler -> parser -> next .type ;
1126+ }
1127+
11171128// Consumes the current token if its type is [expected]. Returns true if a
11181129// token was consumed.
11191130static bool match (Compiler * compiler , TokenType expected )
@@ -1162,6 +1173,12 @@ static void consumeLine(Compiler* compiler, const char* errorMessage)
11621173 ignoreNewlines (compiler );
11631174}
11641175
1176+ static void allowLineBeforeDot (Compiler * compiler ) {
1177+ if (peek (compiler ) == TOKEN_LINE && peekNext (compiler ) == TOKEN_DOT ) {
1178+ nextToken (compiler -> parser );
1179+ }
1180+ }
1181+
11651182// Variables and scopes --------------------------------------------------------
11661183
11671184// Emits one single-byte argument. Returns its index.
@@ -1949,6 +1966,7 @@ static void namedCall(Compiler* compiler, bool canAssign, Code instruction)
19491966 else
19501967 {
19511968 methodCall (compiler , instruction , & signature );
1969+ allowLineBeforeDot (compiler );
19521970 }
19531971}
19541972
@@ -2145,6 +2163,8 @@ static void field(Compiler* compiler, bool canAssign)
21452163 loadThis (compiler );
21462164 emitByteArg (compiler , isLoad ? CODE_LOAD_FIELD : CODE_STORE_FIELD , field );
21472165 }
2166+
2167+ allowLineBeforeDot (compiler );
21482168}
21492169
21502170// Compiles a read or assignment to [variable].
@@ -2176,6 +2196,8 @@ static void bareName(Compiler* compiler, bool canAssign, Variable variable)
21762196
21772197 // Emit the load instruction.
21782198 loadVariable (compiler , variable );
2199+
2200+ allowLineBeforeDot (compiler );
21792201}
21802202
21812203static void staticField (Compiler * compiler , bool canAssign )
@@ -2360,6 +2382,8 @@ static void subscript(Compiler* compiler, bool canAssign)
23602382 finishArgumentList (compiler , & signature );
23612383 consume (compiler , TOKEN_RIGHT_BRACKET , "Expect ']' after arguments." );
23622384
2385+ allowLineBeforeDot (compiler );
2386+
23632387 if (canAssign && match (compiler , TOKEN_EQ ))
23642388 {
23652389 signature .type = SIG_SUBSCRIPT_SETTER ;
@@ -3488,19 +3512,21 @@ ObjFn* wrenCompile(WrenVM* vm, ObjModule* module, const char* source,
34883512 parser .numParens = 0 ;
34893513
34903514 // Zero-init the current token. This will get copied to previous when
3491- // advance () is called below.
3492- parser .current .type = TOKEN_ERROR ;
3493- parser .current .start = source ;
3494- parser .current .length = 0 ;
3495- parser .current .line = 0 ;
3496- parser .current .value = UNDEFINED_VAL ;
3515+ // nextToken () is called below.
3516+ parser .next .type = TOKEN_ERROR ;
3517+ parser .next .start = source ;
3518+ parser .next .length = 0 ;
3519+ parser .next .line = 0 ;
3520+ parser .next .value = UNDEFINED_VAL ;
34973521
34983522 // Ignore leading newlines.
34993523 parser .skipNewlines = true;
35003524 parser .printErrors = printErrors ;
35013525 parser .hasError = false;
35023526
3503- // Read the first token.
3527+ // Read the first token into next
3528+ nextToken (& parser );
3529+ // Copy next -> current
35043530 nextToken (& parser );
35053531
35063532 int numExistingVariables = module -> variables .count ;
0 commit comments