1 module wren.compiler;
2 import wren.common;
3 import wren.dbg;
4 import wren.opcodes;
5 import wren.utils;
6 import wren.value;
7 import wren.vm;
8 
9 // So we can throw errors without statically allocating them
10 import dplug.core : mallocNew;
11 
12 @nogc:
13 // This is written in bottom-up order, so the tokenization comes first, then
14 // parsing/code generation. This minimizes the number of explicit forward
15 // declarations needed.
16 
17 // The maximum number of local (i.e. not module level) variables that can be
18 // declared in a single function, method, or chunk of top level code. This is
19 // the maximum number of variables in scope at one time, and spans block scopes.
20 //
21 // Note that this limitation is also explicit in the bytecode. Since
22 // `CODE_LOAD_LOCAL` and `CODE_STORE_LOCAL` use a single argument byte to
23 // identify the local, only 256 can be in scope at one time.
24 enum MAX_LOCALS = 256;
25 
26 // The maximum number of upvalues (i.e. variables from enclosing functions)
27 // that a function can close over.
28 enum MAX_UPVALUES = 256;
29 
30 // The maximum number of distinct constants that a function can contain. This
31 // value is explicit in the bytecode since `CODE_CONSTANT` only takes a single
32 // two-byte argument.
33 enum MAX_CONSTANTS = (1 << 16);
34 
35 // The maximum distance a CODE_JUMP or CODE_JUMP_IF instruction can move the
36 // instruction pointer.
37 enum MAX_JUMP = (1 << 16);
38 
39 // The maximum depth that interpolation can nest. For example, this string has
40 // three levels:
41 //
42 //      "outside %(one + "%(two + "%(three)")")"
43 enum MAX_INTERPOLATION_NESTING = 8;
44 
45 // The buffer size used to format a compile error message, excluding the header
46 // with the module name and error location. Using a hardcoded buffer for this
47 // is kind of hairy, but fortunately we can control what the longest possible
48 // message is and handle that. Ideally, we'd use `snprintf()`, but that's not
49 // available in standard C++98.
50 enum ERROR_MESSAGE_SIZE = 80 + MAX_VARIABLE_NAME + 15;
51 
52 enum TokenType
53 {
54     TOKEN_LEFT_PAREN,
55     TOKEN_RIGHT_PAREN,
56     TOKEN_LEFT_BRACKET,
57     TOKEN_RIGHT_BRACKET,
58     TOKEN_LEFT_BRACE,
59     TOKEN_RIGHT_BRACE,
60     TOKEN_COLON,
61     TOKEN_DOT,
62     TOKEN_DOTDOT,
63     TOKEN_DOTDOTDOT,
64     TOKEN_COMMA,
65     TOKEN_STAR,
66     TOKEN_SLASH,
67     TOKEN_PERCENT,
68     TOKEN_HASH,
69     TOKEN_PLUS,
70     TOKEN_MINUS,
71     TOKEN_LTLT,
72     TOKEN_GTGT,
73     TOKEN_PIPE,
74     TOKEN_PIPEPIPE,
75     TOKEN_CARET,
76     TOKEN_AMP,
77     TOKEN_AMPAMP,
78     TOKEN_BANG,
79     TOKEN_TILDE,
80     TOKEN_QUESTION,
81     TOKEN_EQ,
82     TOKEN_LT,
83     TOKEN_GT,
84     TOKEN_LTEQ,
85     TOKEN_GTEQ,
86     TOKEN_EQEQ,
87     TOKEN_BANGEQ,
88 
89     TOKEN_BREAK,
90     TOKEN_CONTINUE,
91     TOKEN_CLASS,
92     TOKEN_CONSTRUCT,
93     TOKEN_ELSE,
94     TOKEN_FALSE,
95     TOKEN_FOR,
96     TOKEN_FOREIGN,
97     TOKEN_IF,
98     TOKEN_IMPORT,
99     TOKEN_AS,
100     TOKEN_IN,
101     TOKEN_IS,
102     TOKEN_NULL,
103     TOKEN_RETURN,
104     TOKEN_STATIC,
105     TOKEN_SUPER,
106     TOKEN_THIS,
107     TOKEN_TRUE,
108     TOKEN_VAR,
109     TOKEN_WHILE,
110 
111     TOKEN_FIELD,
112     TOKEN_STATIC_FIELD,
113     TOKEN_NAME,
114     TOKEN_NUMBER,
115     
116     // A string literal without any interpolation, or the last section of a
117     // string following the last interpolated expression.
118     TOKEN_STRING,
119     
120     // A portion of a string literal preceding an interpolated expression. This
121     // string:
122     //
123     //     "a %(b) c %(d) e"
124     //
125     // is tokenized to:
126     //
127     //     TOKEN_INTERPOLATION "a "
128     //     TOKEN_NAME          b
129     //     TOKEN_INTERPOLATION " c "
130     //     TOKEN_NAME          d
131     //     TOKEN_STRING        " e"
132     TOKEN_INTERPOLATION,
133 
134     TOKEN_LINE,
135 
136     TOKEN_ERROR,
137     TOKEN_EOF
138 }
139 
140 struct Token
141 {
142     TokenType type;
143 
144     // The beginning of the token, pointing directly into the source.
145     const(char)* start;
146 
147     // The length of the token in characters.
148     int length;
149 
150     // The 1-based line where the token appears.
151     int line;
152   
153     // The parsed value if the token is a literal.
154     Value value;
155 }
156 
157 struct Parser
158 {
159     WrenVM* vm;
160 
161     // The module being parsed.
162     ObjModule* module_;
163 
164     // The source code being parsed.
165     const(char)* source;
166 
167     // The beginning of the currently-being-lexed token in [source].
168     const(char)* tokenStart;
169 
170     // The current character being lexed in [source].
171     const(char)* currentChar;
172 
173     // The 1-based line number of [currentChar].
174     int currentLine;
175 
176     // The upcoming token.
177     Token next;
178 
179     // The most recently lexed token.
180     Token current;
181 
182     // The most recently consumed/advanced token.
183     Token previous;
184     
185     // Tracks the lexing state when tokenizing interpolated strings.
186     //
187     // Interpolated strings make the lexer not strictly regular: we don't know
188     // whether a ")" should be treated as a RIGHT_PAREN token or as ending an
189     // interpolated expression unless we know whether we are inside a string
190     // interpolation and how many unmatched "(" there are. This is particularly
191     // complex because interpolation can nest:
192     //
193     //     " %( " %( inner ) " ) "
194     //
195     // This tracks that state. The parser maintains a stack of ints, one for each
196     // level of current interpolation nesting. Each value is the number of
197     // unmatched "(" that are waiting to be closed.
198     int[MAX_INTERPOLATION_NESTING] parens;
199     int numParens;
200 
201     // Whether compile errors should be printed to stderr or discarded.
202     bool printErrors;
203 
204     // If a syntax or compile error has occurred.
205     bool hasError;
206 }
207 
208 struct Local
209 {
210     // The name of the local variable. This points directly into the original
211     // source code string.
212     const(char)* name;
213 
214     // The length of the local variable's name.
215     int length;
216 
217     // The depth in the scope chain that this variable was declared at. Zero is
218     // the outermost scope--parameters for a method, or the first local block in
219     // top level code. One is the scope within that, etc.
220     int depth;
221 
222     // If this local variable is being used as an upvalue.
223     bool isUpvalue;
224 }
225 
226 struct CompilerUpvalue
227 {
228     // True if this upvalue is capturing a local variable from the enclosing
229     // function. False if it's capturing an upvalue.
230     bool isLocal;
231 
232     // The index of the local or upvalue being captured in the enclosing function.
233     int index;
234 }
235 
236 struct Loop
237 {
238     // Index of the instruction that the loop should jump back to.
239     int start;
240 
241     // Index of the argument for the CODE_JUMP_IF instruction used to exit the
242     // loop. Stored so we can patch it once we know where the loop ends.
243     int exitJump;
244 
245     // Index of the first instruction of the body of the loop.
246     int body_;
247 
248     // Depth of the scope(s) that need to be exited if a break is hit inside the
249     // loop.
250     int scopeDepth;
251 
252     // The loop enclosing this one, or null if this is the outermost loop.
253     Loop* enclosing;
254 }
255 
256 // The different signature syntaxes for different kinds of methods.
257 enum SignatureType
258 {
259     // A name followed by a (possibly empty) parenthesized parameter list. Also
260     // used for binary operators.
261     SIG_METHOD,
262     
263     // Just a name. Also used for unary operators.
264     SIG_GETTER,
265     
266     // A name followed by "=".
267     SIG_SETTER,
268     
269     // A square bracketed parameter list.
270     SIG_SUBSCRIPT,
271     
272     // A square bracketed parameter list followed by "=".
273     SIG_SUBSCRIPT_SETTER,
274     
275     // A constructor initializer function. This has a distinct signature to
276     // prevent it from being invoked directly outside of the constructor on the
277     // metaclass.
278     SIG_INITIALIZER
279 }
280 
281 struct Signature
282 {
283     const(char)* name;
284     int length;
285     SignatureType type;
286     int arity;
287 }
288 
289 struct ClassInfo
290 {
291     // The name of the class.
292     ObjString* name;
293     
294     // Attributes for the class itself
295     ObjMap* classAttributes;
296     // Attributes for methods in this class
297     ObjMap* methodAttributes;
298 
299     // Symbol table for the fields of the class.
300     SymbolTable fields;
301 
302     // Symbols for the methods defined by the class. Used to detect duplicate
303     // method definitions.
304     IntBuffer methods;
305     IntBuffer staticMethods;
306 
307     // True if the class being compiled is a foreign class.
308     bool isForeign;
309     
310     // True if the current method being compiled is static.
311     bool inStatic;
312 
313     // The signature of the method being compiled.
314     Signature* signature;
315 }
316 
317 struct Compiler
318 {
319     Parser* parser;
320 
321     // The compiler for the function enclosing this one, or null if it's the
322     // top level.
323     Compiler* parent;
324 
325     // The currently in scope local variables.
326     Local[MAX_LOCALS] locals;
327 
328     // The number of local variables currently in scope.
329     int numLocals;
330 
331     // The upvalues that this function has captured from outer scopes. The count
332     // of them is stored in [numUpvalues].
333     CompilerUpvalue[MAX_UPVALUES] upvalues;
334 
335     // The current level of block scope nesting, where zero is no nesting. A -1
336     // here means top-level code is being compiled and there is no block scope
337     // in effect at all. Any variables declared will be module-level.
338     int scopeDepth;
339     
340     // The current number of slots (locals and temporaries) in use.
341     //
342     // We use this and maxSlots to track the maximum number of additional slots
343     // a function may need while executing. When the function is called, the
344     // fiber will check to ensure its stack has enough room to cover that worst
345     // case and grow the stack if needed.
346     //
347     // This value here doesn't include parameters to the function. Since those
348     // are already pushed onto the stack by the caller and tracked there, we
349     // don't need to double count them here.
350     int numSlots;
351 
352     // The current innermost loop being compiled, or null if not in a loop.
353     Loop* loop;
354 
355     // If this is a compiler for a method, keeps track of the class enclosing it.
356     ClassInfo* enclosingClass;
357 
358     // The function being compiled.
359     ObjFn* fn;
360     
361     // The constants for the function being compiled.
362     ObjMap* constants;
363 
364     // Whether or not the compiler is for a constructor initializer
365     bool isInitializer;
366 
367     // The number of attributes seen while parsing.
368     // We track this separately as compile time attributes
369     // are not stored, so we can't rely on attributes.count
370     // to enforce an error message when attributes are used
371     // anywhere other than methods or classes.
372     int numAttributes;
373     // Attributes for the next class or method.
374     ObjMap* attributes;
375 }
376 
377 // Describes where a variable is declared.
378 enum Scope
379 {
380     // A local variable in the current function.
381     SCOPE_LOCAL,
382     
383     // A local variable declared in an enclosing function.
384     SCOPE_UPVALUE,
385     
386     // A top-level module variable.
387     SCOPE_MODULE
388 }
389 
390 // A reference to a variable and the scope where it is defined. This contains
391 // enough information to emit correct code to load or store the variable.
392 struct Variable
393 {
394     // The stack slot, upvalue slot, or module symbol defining the variable.
395     int index;
396   
397     // Where the variable is declared.
398     Scope scope_;
399 }
400 
401 import core.stdc.stdarg;
402 static void printError(Parser* parser, int line, const(char)* label,
403                        const(char)* format, va_list args)
404 {
405     import core.stdc.stdio;
406     parser.hasError = true;
407     if (!parser.printErrors) return;
408 
409     // Only report errors if there is a WrenErrorFn to handle them.
410     if (parser.vm.config.errorFn == null) return;
411 
412     // Format the label and message.
413     char[ERROR_MESSAGE_SIZE] message;
414     int length = sprintf(message.ptr, "%s: ", label);
415     length += vsprintf(message.ptr + length, format, args);
416 
417     if (length > ERROR_MESSAGE_SIZE)
418         throw mallocNew!Error("Error should not exceed buffer.");
419     // assert(length < ERROR_MESSAGE_SIZE, "Error should not exceed buffer.");
420 
421     ObjString* module_ = parser.module_.name;
422     const(char)* module_name = module_ ? module_.value.ptr : "<unknown>";
423 
424     parser.vm.config.errorFn(parser.vm, WrenErrorType.WREN_ERROR_COMPILE,
425                                 module_name, line, message.ptr);
426 }
427 
428 // Outputs a lexical error.
429 static void lexError(Parser* parser, const char* format, ...)
430 {
431     va_list args;
432     va_start(args, format);
433     printError(parser, parser.currentLine, "Error", format, args);
434     va_end(args);
435 }
436 
437 // Outputs a compile or syntax error. This also marks the compilation as having
438 // an error, which ensures that the resulting code will be discarded and never
439 // run. This means that after calling error(), it's fine to generate whatever
440 // invalid bytecode you want since it won't be used.
441 //
442 // You'll note that most places that call error() continue to parse and compile
443 // after that. That's so that we can try to find as many compilation errors in
444 // one pass as possible instead of just bailing at the first one.
445 static void error(Compiler* compiler, const char* format, ...)
446 {
447     import core.stdc.stdio;
448     Token* token = &compiler.parser.previous;
449 
450     // If the parse error was caused by an error token, the lexer has already
451     // reported it.
452     if (token.type == TokenType.TOKEN_ERROR) return;
453     
454     va_list args;
455     va_start(args, format);
456     if (token.type == TokenType.TOKEN_LINE)
457     {
458         printError(compiler.parser, token.line, "Error at newline", format, args);
459     }
460     else if (token.type == TokenType.TOKEN_EOF)
461     {
462         printError(compiler.parser, token.line,
463                 "Error at end of file", format, args);
464     }
465     else
466     {
467         // Make sure we don't exceed the buffer with a very long token.
468         char[10 + MAX_VARIABLE_NAME + 4 + 1] label;
469         if (token.length <= MAX_VARIABLE_NAME)
470         {
471             sprintf(label.ptr, "Error at '%.*s'", token.length, token.start);
472         }
473         else
474         {
475             sprintf(label.ptr, "Error at '%.*s...'", MAX_VARIABLE_NAME, token.start);
476         }
477         printError(compiler.parser, token.line, label.ptr, format, args);
478     }
479     va_end(args);
480 }
481 
482 // Adds [constant] to the constant pool and returns its index.
483 static int addConstant(Compiler* compiler, Value constant)
484 {
485     if (compiler.parser.hasError) return -1;
486     
487     // See if we already have a constant for the value. If so, reuse it.
488     if (compiler.constants != null)
489     {
490         Value existing = wrenMapGet(compiler.constants, constant);
491         if (IS_NUM(existing)) return cast(int)AS_NUM(existing);
492     }
493     
494     // It's a new constant.
495     if (compiler.fn.constants.count < MAX_CONSTANTS)
496     {
497         if (IS_OBJ(constant)) wrenPushRoot(compiler.parser.vm, AS_OBJ(constant));
498         wrenValueBufferWrite(compiler.parser.vm, &compiler.fn.constants,
499                             constant);
500         if (IS_OBJ(constant)) wrenPopRoot(compiler.parser.vm);
501         
502         if (compiler.constants == null)
503         {
504             compiler.constants = wrenNewMap(compiler.parser.vm);
505         }
506         wrenMapSet(compiler.parser.vm, compiler.constants, constant,
507                 NUM_VAL(compiler.fn.constants.count - 1));
508     }
509     else
510     {
511         error(compiler, "A function may only contain %d unique constants.",
512             MAX_CONSTANTS);
513     }
514 
515     return compiler.fn.constants.count - 1;
516 }
517 
518 // Initializes [compiler].
519 static void initCompiler(Compiler* compiler, Parser* parser, Compiler* parent,
520                          bool isMethod)
521 {
522     compiler.parser = parser;
523     compiler.parent = parent;
524     compiler.loop = null;
525     compiler.enclosingClass = null;
526     compiler.isInitializer = false;
527     
528     // Initialize these to null before allocating in case a GC gets triggered in
529     // the middle of initializing the compiler.
530     compiler.fn = null;
531     compiler.constants = null;
532     compiler.attributes = null;
533 
534     parser.vm.compiler = compiler;
535 
536     // Declare a local slot for either the closure or method receiver so that we
537     // don't try to reuse that slot for a user-defined local variable. For
538     // methods, we name it "this", so that we can resolve references to that like
539     // a normal variable. For functions, they have no explicit "this", so we use
540     // an empty name. That way references to "this" inside a function walks up
541     // the parent chain to find a method enclosing the function whose "this" we
542     // can close over.
543     compiler.numLocals = 1;
544     compiler.numSlots = compiler.numLocals;
545 
546     if (isMethod)
547     {
548         compiler.locals[0].name = "this";
549         compiler.locals[0].length = 4;
550     }
551     else
552     {
553         compiler.locals[0].name = null;
554         compiler.locals[0].length = 0;
555     }
556     
557     compiler.locals[0].depth = -1;
558     compiler.locals[0].isUpvalue = false;
559 
560     if (parent == null)
561     {
562         // Compiling top-level code, so the initial scope is module-level.
563         compiler.scopeDepth = -1;
564     }
565     else
566     {
567         // The initial scope for functions and methods is local scope.
568         compiler.scopeDepth = 0;
569     }
570     
571     compiler.numAttributes = 0;
572     compiler.attributes = wrenNewMap(parser.vm);
573     compiler.fn = wrenNewFunction(parser.vm, parser.module_,
574                                     compiler.numLocals);
575 }
576 
577 // Lexing ----------------------------------------------------------------------
578 
579 struct Keyword
580 {
581     const(char)* identifier;
582     size_t      length;
583     TokenType   tokenType;
584 }
585 
586 static immutable Keyword[] keywords =
587 [
588     {"break",     5, TokenType.TOKEN_BREAK},
589     {"continue",  8, TokenType.TOKEN_CONTINUE},
590     {"class",     5, TokenType.TOKEN_CLASS},
591     {"construct", 9, TokenType.TOKEN_CONSTRUCT},
592     {"else",      4, TokenType.TOKEN_ELSE},
593     {"false",     5, TokenType.TOKEN_FALSE},
594     {"for",       3, TokenType.TOKEN_FOR},
595     {"foreign",   7, TokenType.TOKEN_FOREIGN},
596     {"if",        2, TokenType.TOKEN_IF},
597     {"import",    6, TokenType.TOKEN_IMPORT},
598     {"as",        2, TokenType.TOKEN_AS},
599     {"in",        2, TokenType.TOKEN_IN},
600     {"is",        2, TokenType.TOKEN_IS},
601     {"null",      4, TokenType.TOKEN_NULL},
602     {"return",    6, TokenType.TOKEN_RETURN},
603     {"static",    6, TokenType.TOKEN_STATIC},
604     {"super",     5, TokenType.TOKEN_SUPER},
605     {"this",      4, TokenType.TOKEN_THIS},
606     {"true",      4, TokenType.TOKEN_TRUE},
607     {"var",       3, TokenType.TOKEN_VAR},
608     {"while",     5, TokenType.TOKEN_WHILE},
609     {null,        0, TokenType.TOKEN_EOF} // Sentinel to mark the end of the array.
610 ];
611 
612 // Returns true if [c] is a valid (non-initial) identifier character.
613 static bool isName(char c)
614 {
615     return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_';
616 }
617 
618 // Returns true if [c] is a digit.
619 static bool isDigit(char c)
620 {
621     return c >= '0' && c <= '9';
622 }
623 
624 // Returns the current character the parser is sitting on.
625 static char peekChar(Parser* parser)
626 {
627     return *parser.currentChar;
628 }
629 
630 // Returns the character after the current character.
631 static char peekNextChar(Parser* parser)
632 {
633     // If we're at the end of the source, don't read past it.
634     if (peekChar(parser) == '\0') return '\0';
635     return *(parser.currentChar + 1);
636 }
637 
638 // Advances the parser forward one character.
639 static char nextChar(Parser* parser)
640 {
641     char c = peekChar(parser);
642     parser.currentChar++;
643     if (c == '\n') parser.currentLine++;
644     return c;
645 }
646 
647 // If the current character is [c], consumes it and returns `true`.
648 static bool matchChar(Parser* parser, char c)
649 {
650     if (peekChar(parser) != c) return false;
651     nextChar(parser);
652     return true;
653 }
654 
655 // Sets the parser's current token to the given [type] and current character
656 // range.
657 static void makeToken(Parser* parser, TokenType type)
658 {
659     parser.next.type = type;
660     parser.next.start = parser.tokenStart;
661     parser.next.length = cast(int)(parser.currentChar - parser.tokenStart);
662     parser.next.line = parser.currentLine;
663     
664     // Make line tokens appear on the line containing the "\n".
665     if (type == TokenType.TOKEN_LINE) parser.next.line--;
666 }
667 
668 // If the current character is [c], then consumes it and makes a token of type
669 // [two]. Otherwise makes a token of type [one].
670 static void twoCharToken(Parser* parser, char c, TokenType two, TokenType one)
671 {
672     makeToken(parser, matchChar(parser, c) ? two : one);
673 }
674 
675 // Skips the rest of the current line.
676 static void skipLineComment(Parser* parser)
677 {
678     while (peekChar(parser) != '\n' && peekChar(parser) != '\0')
679     {
680         nextChar(parser);
681     }
682 }
683 
684 // Skips the rest of a block comment.
685 static void skipBlockComment(Parser* parser)
686 {
687     int nesting = 1;
688     while (nesting > 0)
689     {
690         if (peekChar(parser) == '\0')
691         {
692             lexError(parser, "Unterminated block comment.");
693             return;
694         }
695 
696         if (peekChar(parser) == '/' && peekNextChar(parser) == '*')
697         {
698             nextChar(parser);
699             nextChar(parser);
700             nesting++;
701             continue;
702         }
703 
704         if (peekChar(parser) == '*' && peekNextChar(parser) == '/')
705         {
706             nextChar(parser);
707             nextChar(parser);
708             nesting--;
709             continue;
710         }
711 
712         // Regular comment character.
713         nextChar(parser);
714     }
715 }
716 
717 // Reads the next character, which should be a hex digit (0-9, a-f, or A-F) and
718 // returns its numeric value. If the character isn't a hex digit, returns -1.
719 static int readHexDigit(Parser* parser)
720 {
721     char c = nextChar(parser);
722     if (c >= '0' && c <= '9') return c - '0';
723     if (c >= 'a' && c <= 'f') return c - 'a' + 10;
724     if (c >= 'A' && c <= 'F') return c - 'A' + 10;
725 
726     // Don't consume it if it isn't expected. Keeps us from reading past the end
727     // of an unterminated string.
728     parser.currentChar--;
729     return -1;
730 }
731 
732 // Parses the numeric value of the current token.
733 static void makeNumber(Parser* parser, bool isHex)
734 {
735     import core.stdc.errno;
736     import core.stdc.stdlib;
737 
738     errno = 0;
739 
740     if (isHex)
741     {
742         parser.next.value = NUM_VAL(cast(double)strtoll(parser.tokenStart, null, 16));
743     }
744     else
745     {
746         parser.next.value = NUM_VAL(strtod(parser.tokenStart, null));
747     }
748 
749     if (errno == ERANGE)
750     {
751         lexError(parser, "Number literal was too large (%d).", ulong.sizeof);
752         parser.next.value = NUM_VAL(0);
753     }
754 
755     // We don't check that the entire token is consumed after calling strtoll()
756     // or strtod() because we've already scanned it ourselves and know it's valid.
757 
758     makeToken(parser, TokenType.TOKEN_NUMBER);
759 }
760 
761 // Finishes lexing a hexadecimal number literal.
762 static void readHexNumber(Parser* parser)
763 {
764     // Skip past the `x` used to denote a hexadecimal literal.
765     nextChar(parser);
766 
767     // Iterate over all the valid hexadecimal digits found.
768     while (readHexDigit(parser) != -1) continue;
769 
770     makeNumber(parser, true);
771 }
772 
773 // Finishes lexing a number literal.
774 static void readNumber(Parser* parser)
775 {
776     while (isDigit(peekChar(parser))) nextChar(parser);
777 
778     // See if it has a floating point. Make sure there is a digit after the "."
779     // so we don't get confused by method calls on number literals.
780     if (peekChar(parser) == '.' && isDigit(peekNextChar(parser)))
781     {
782         nextChar(parser);
783         while (isDigit(peekChar(parser))) nextChar(parser);
784     }
785 
786     // See if the number is in scientific notation.
787     if (matchChar(parser, 'e') || matchChar(parser, 'E'))
788     {
789         // Allow a single positive/negative exponent symbol.
790         if(!matchChar(parser, '+'))
791         {
792         matchChar(parser, '-');
793         }
794 
795         if (!isDigit(peekChar(parser)))
796         {
797         lexError(parser, "Unterminated scientific notation.");
798         }
799 
800         while (isDigit(peekChar(parser))) nextChar(parser);
801     }
802 
803     makeNumber(parser, false);
804 }
805 
806 // Finishes lexing an identifier. Handles reserved words.
807 static void readName(Parser* parser, TokenType type, char firstChar)
808 {
809     ByteBuffer string_;
810     wrenByteBufferInit(&string_);
811     wrenByteBufferWrite(parser.vm, &string_, firstChar);
812 
813     while (isName(peekChar(parser)) || isDigit(peekChar(parser)))
814     {
815         char c = nextChar(parser);
816         wrenByteBufferWrite(parser.vm, &string_, c);
817     }
818 
819     // Update the type if it's a keyword.
820     size_t length = parser.currentChar - parser.tokenStart;
821     for (int i = 0; keywords[i].identifier != null; i++)
822     {
823         import core.stdc.string : memcmp;
824         if (length == keywords[i].length &&
825             memcmp(parser.tokenStart, keywords[i].identifier, length) == 0)
826         {
827         type = keywords[i].tokenType;
828         break;
829         }
830     }
831     
832     parser.next.value = wrenNewStringLength(parser.vm,
833                                             cast(char*)string_.data, string_.count);
834 
835     wrenByteBufferClear(parser.vm, &string_);
836     makeToken(parser, type);
837 }
838 
839 // Reads [digits] hex digits in a string literal and returns their number value.
840 static int readHexEscape(Parser* parser, int digits, const char* description)
841 {
842   int value = 0;
843   for (int i = 0; i < digits; i++)
844   {
845     if (peekChar(parser) == '"' || peekChar(parser) == '\0')
846     {
847       lexError(parser, "Incomplete %s escape sequence.", description);
848 
849       // Don't consume it if it isn't expected. Keeps us from reading past the
850       // end of an unterminated string.
851       parser.currentChar--;
852       break;
853     }
854 
855     int digit = readHexDigit(parser);
856     if (digit == -1)
857     {
858       lexError(parser, "Invalid %s escape sequence.", description);
859       break;
860     }
861 
862     value = (value * 16) | digit;
863   }
864 
865   return value;
866 }
867 
868 // Reads a hex digit Unicode escape sequence in a string literal.
869 static void readUnicodeEscape(Parser* parser, ByteBuffer* string_, int length)
870 {
871   int value = readHexEscape(parser, length, "Unicode");
872 
873   // Grow the buffer enough for the encoded result.
874   int numBytes = wrenUtf8EncodeNumBytes(value);
875   if (numBytes != 0)
876   {
877     wrenByteBufferFill(parser.vm, string_, 0, numBytes);
878     wrenUtf8Encode(value, string_.data + string_.count - numBytes);
879   }
880 }
881 
882 static void readRawString(Parser* parser)
883 {
884     ByteBuffer string_;
885     wrenByteBufferInit(&string_);
886     TokenType type = TokenType.TOKEN_STRING;
887 
888     //consume the second and third "
889     nextChar(parser);
890     nextChar(parser);
891 
892     int skipStart = 0;
893     int firstNewline = -1;
894 
895     int skipEnd = -1;
896     int lastNewline = -1;
897 
898     for (;;)
899     {
900         char c = nextChar(parser);
901         char c1 = peekChar(parser);
902         char c2 = peekNextChar(parser);
903 
904         if (c == '\r') continue;
905 
906         if (c == '\n') {
907             lastNewline = string_.count;
908             skipEnd = lastNewline;
909             firstNewline = firstNewline == -1 ? string_.count : firstNewline;
910         }
911 
912         if (c == '"' && c1 == '"' && c2 == '"') break;
913         
914         bool isWhitespace = c == ' ' || c == '\t';
915         skipEnd = c == '\n' || isWhitespace ? skipEnd : -1;
916 
917         // If we haven't seen a newline or other character yet, 
918         // and still seeing whitespace, count the characters 
919         // as skippable till we know otherwise
920         bool skippable = skipStart != -1 && isWhitespace && firstNewline == -1;
921         skipStart = skippable ? string_.count + 1 : skipStart;
922         
923         // We've counted leading whitespace till we hit something else, 
924         // but it's not a newline, so we reset skipStart since we need these characters
925         if (firstNewline == -1 && !isWhitespace && c != '\n') skipStart = -1;
926 
927         if (c == '\0' || c1 == '\0' || c2 == '\0')
928         {
929             lexError(parser, "Unterminated raw string.");
930 
931             // Don't consume it if it isn't expected. Keeps us from reading past the
932             // end of an unterminated string.
933             parser.currentChar--;
934             break;
935         }
936     
937         wrenByteBufferWrite(parser.vm, &string_, c);
938     }
939 
940     //consume the second and third "
941     nextChar(parser);
942     nextChar(parser);
943 
944     int offset = 0;
945     int count = string_.count;
946 
947     if(firstNewline != -1 && skipStart == firstNewline) offset = firstNewline + 1;
948     if(lastNewline != -1 && skipEnd == lastNewline) count = lastNewline;
949 
950     count -= (offset > count) ? count : offset;
951 
952     parser.next.value = wrenNewStringLength(parser.vm, 
953                             (cast(char*)string_.data) + offset, count);
954     
955     wrenByteBufferClear(parser.vm, &string_);
956     makeToken(parser, type);
957 }
958 
959 // Finishes lexing a string literal.
960 static void readString(Parser* parser)
961 {
962     ByteBuffer string_;
963     TokenType type = TokenType.TOKEN_STRING;
964     wrenByteBufferInit(&string_);
965     
966     for (;;)
967     {
968         char c = nextChar(parser);
969         if (c == '"') break;
970         if (c == '\r') continue;
971 
972         if (c == '\0')
973         {
974         lexError(parser, "Unterminated string.");
975 
976         // Don't consume it if it isn't expected. Keeps us from reading past the
977         // end of an unterminated string.
978         parser.currentChar--;
979         break;
980         }
981 
982         if (c == '%')
983         {
984         if (parser.numParens < MAX_INTERPOLATION_NESTING)
985         {
986             // TODO: Allow format string.
987             if (nextChar(parser) != '(') lexError(parser, "Expect '(' after '%%'.");
988             
989             parser.parens[parser.numParens++] = 1;
990             type = TokenType.TOKEN_INTERPOLATION;
991             break;
992         }
993 
994         lexError(parser, "Interpolation may only nest %d levels deep.",
995                 MAX_INTERPOLATION_NESTING);
996         }
997         
998         if (c == '\\')
999         {
1000             switch (nextChar(parser))
1001             {
1002                 case '"':  wrenByteBufferWrite(parser.vm, &string_, '"'); break;
1003                 case '\\': wrenByteBufferWrite(parser.vm, &string_, '\\'); break;
1004                 case '%':  wrenByteBufferWrite(parser.vm, &string_, '%'); break;
1005                 case '0':  wrenByteBufferWrite(parser.vm, &string_, '\0'); break;
1006                 case 'a':  wrenByteBufferWrite(parser.vm, &string_, '\a'); break;
1007                 case 'b':  wrenByteBufferWrite(parser.vm, &string_, '\b'); break;
1008                 case 'e':  wrenByteBufferWrite(parser.vm, &string_, '\33'); break;
1009                 case 'f':  wrenByteBufferWrite(parser.vm, &string_, '\f'); break;
1010                 case 'n':  wrenByteBufferWrite(parser.vm, &string_, '\n'); break;
1011                 case 'r':  wrenByteBufferWrite(parser.vm, &string_, '\r'); break;
1012                 case 't':  wrenByteBufferWrite(parser.vm, &string_, '\t'); break;
1013                 case 'u':  readUnicodeEscape(parser, &string_, 4); break;
1014                 case 'U':  readUnicodeEscape(parser, &string_, 8); break;
1015                 case 'v':  wrenByteBufferWrite(parser.vm, &string_, '\v'); break;
1016                 case 'x':
1017                     wrenByteBufferWrite(parser.vm, &string_,
1018                                         cast(ubyte)readHexEscape(parser, 2, "byte"));
1019                 break;
1020 
1021                 default:
1022                     lexError(parser, "Invalid escape character '%c'.",
1023                             *(parser.currentChar - 1));
1024                 break;
1025             }
1026         }
1027         else
1028         {
1029         wrenByteBufferWrite(parser.vm, &string_, c);
1030         }
1031     }
1032 
1033     parser.next.value = wrenNewStringLength(parser.vm,
1034                                                 cast(char*)string_.data, string_.count);
1035     
1036     wrenByteBufferClear(parser.vm, &string_);
1037     makeToken(parser, type);
1038 }
1039 
1040 // Lex the next token and store it in [parser.next].
1041 static void nextToken(Parser* parser)
1042 {
1043     parser.previous = parser.current;
1044     parser.current = parser.next;
1045 
1046     // If we are out of tokens, don't try to tokenize any more. We *do* still
1047     // copy the TOKEN_EOF to previous so that code that expects it to be consumed
1048     // will still work.
1049     if (parser.next.type == TokenType.TOKEN_EOF) return;
1050     if (parser.current.type == TokenType.TOKEN_EOF) return;
1051     
1052     while (peekChar(parser) != '\0')
1053     {
1054         parser.tokenStart = parser.currentChar;
1055 
1056         char c = nextChar(parser);
1057         switch (c) with(TokenType)
1058         {
1059         case '(':
1060             // If we are inside an interpolated expression, count the unmatched "(".
1061             if (parser.numParens > 0) parser.parens[parser.numParens - 1]++;
1062             makeToken(parser, TokenType.TOKEN_LEFT_PAREN);
1063             return;
1064             
1065         case ')':
1066             // If we are inside an interpolated expression, count the ")".
1067             if (parser.numParens > 0 &&
1068                 --parser.parens[parser.numParens - 1] == 0)
1069             {
1070                 // This is the final ")", so the interpolation expression has ended.
1071                 // This ")" now begins the next section of the template string.
1072                 parser.numParens--;
1073                 readString(parser);
1074                 return;
1075             }
1076             
1077             makeToken(parser, TokenType.TOKEN_RIGHT_PAREN);
1078             return;
1079             
1080         case '[': makeToken(parser, TokenType.TOKEN_LEFT_BRACKET); return;
1081         case ']': makeToken(parser, TokenType.TOKEN_RIGHT_BRACKET); return;
1082         case '{': makeToken(parser, TokenType.TOKEN_LEFT_BRACE); return;
1083         case '}': makeToken(parser, TokenType.TOKEN_RIGHT_BRACE); return;
1084         case ':': makeToken(parser, TokenType.TOKEN_COLON); return;
1085         case ',': makeToken(parser, TokenType.TOKEN_COMMA); return;
1086         case '*': makeToken(parser, TokenType.TOKEN_STAR); return;
1087         case '%': makeToken(parser, TokenType.TOKEN_PERCENT); return;
1088         case '#': {
1089             // Ignore shebang on the first line.
1090             if (parser.currentLine == 1 && peekChar(parser) == '!' && peekNextChar(parser) == '/')
1091             {
1092                 skipLineComment(parser);
1093                 break;
1094             }
1095             // Otherwise we treat it as a token
1096             makeToken(parser, TokenType.TOKEN_HASH); 
1097             return;
1098         }
1099         case '^': makeToken(parser, TokenType.TOKEN_CARET); return;
1100         case '+': makeToken(parser, TokenType.TOKEN_PLUS); return;
1101         case '-': makeToken(parser, TokenType.TOKEN_MINUS); return;
1102         case '~': makeToken(parser, TokenType.TOKEN_TILDE); return;
1103         case '?': makeToken(parser, TokenType.TOKEN_QUESTION); return;
1104             
1105         case '|': twoCharToken(parser, '|', TokenType.TOKEN_PIPEPIPE, TokenType.TOKEN_PIPE); return;
1106         case '&': twoCharToken(parser, '&', TokenType.TOKEN_AMPAMP, TokenType.TOKEN_AMP); return;
1107         case '=': twoCharToken(parser, '=', TokenType.TOKEN_EQEQ, TokenType.TOKEN_EQ); return;
1108         case '!': twoCharToken(parser, '=', TokenType.TOKEN_BANGEQ, TokenType.TOKEN_BANG); return;
1109             
1110         case '.':
1111             if (matchChar(parser, '.'))
1112             {
1113                 twoCharToken(parser, '.', TokenType.TOKEN_DOTDOTDOT, TokenType.TOKEN_DOTDOT);
1114                 return;
1115             }
1116             
1117             makeToken(parser, TokenType.TOKEN_DOT);
1118             return;
1119             
1120         case '/':
1121             if (matchChar(parser, '/'))
1122             {
1123                 skipLineComment(parser);
1124                 break;
1125             }
1126 
1127             if (matchChar(parser, '*'))
1128             {
1129                 skipBlockComment(parser);
1130                 break;
1131             }
1132 
1133             makeToken(parser, TokenType.TOKEN_SLASH);
1134             return;
1135 
1136         case '<':
1137             if (matchChar(parser, '<'))
1138             {
1139                 makeToken(parser, TokenType.TOKEN_LTLT);
1140             }
1141             else
1142             {
1143                 twoCharToken(parser, '=', TokenType.TOKEN_LTEQ, TokenType.TOKEN_LT);
1144             }
1145             return;
1146 
1147         case '>':
1148             if (matchChar(parser, '>'))
1149             {
1150                 makeToken(parser, TokenType.TOKEN_GTGT);
1151             }
1152             else
1153             {
1154                 twoCharToken(parser, '=', TokenType.TOKEN_GTEQ, TokenType.TOKEN_GT);
1155             }
1156             return;
1157 
1158         case '\n':
1159             makeToken(parser, TokenType.TOKEN_LINE);
1160             return;
1161 
1162         case ' ':
1163         case '\r':
1164         case '\t':
1165             // Skip forward until we run out of whitespace.
1166             while (peekChar(parser) == ' ' ||
1167                 peekChar(parser) == '\r' ||
1168                 peekChar(parser) == '\t')
1169             {
1170                 nextChar(parser);
1171             }
1172             break;
1173 
1174         case '"': {
1175             if(peekChar(parser) == '"' && peekNextChar(parser)  == '"') {
1176                 readRawString(parser);
1177                 return;
1178             }
1179             readString(parser); return;
1180         }
1181         case '_':
1182             readName(parser,
1183                     peekChar(parser) == '_' ? TokenType.TOKEN_STATIC_FIELD : TokenType.TOKEN_FIELD, c);
1184             return;
1185 
1186         case '0':
1187             if (peekChar(parser) == 'x')
1188             {
1189                 readHexNumber(parser);
1190                 return;
1191             }
1192 
1193             readNumber(parser);
1194             return;
1195 
1196         default:
1197             if (isName(c))
1198             {
1199                 readName(parser, TokenType.TOKEN_NAME, c);
1200             }
1201             else if (isDigit(c))
1202             {
1203                 readNumber(parser);
1204             }
1205             else
1206             {
1207             if (c >= 32 && c <= 126)
1208             {
1209                 lexError(parser, "Invalid character '%c'.", c);
1210             }
1211             else
1212             {
1213                 // Don't show non-ASCII values since we didn't UTF-8 decode the
1214                 // bytes. Since there are no non-ASCII byte values that are
1215                 // meaningful code units in Wren, the lexer works on raw bytes,
1216                 // even though the source code and console output are UTF-8.
1217                 lexError(parser, "Invalid byte 0x%x.", cast(ubyte)c);
1218             }
1219             parser.next.type = TokenType.TOKEN_ERROR;
1220             parser.next.length = 0;
1221             }
1222             return;
1223         }
1224     }
1225 
1226     // If we get here, we're out of source, so just make EOF tokens.
1227     parser.tokenStart = parser.currentChar;
1228     makeToken(parser, TokenType.TOKEN_EOF);
1229 }
1230 
1231 // Parsing ---------------------------------------------------------------------
1232 
1233 // Returns the type of the current token.
1234 static TokenType peek(Compiler* compiler)
1235 {
1236   return compiler.parser.current.type;
1237 }
1238 
1239 // Returns the type of the current token.
1240 static TokenType peekNext(Compiler* compiler)
1241 {
1242   return compiler.parser.next.type;
1243 }
1244 
1245 // Consumes the current token if its type is [expected]. Returns true if a
1246 // token was consumed.
1247 static bool match(Compiler* compiler, TokenType expected)
1248 {
1249     if (peek(compiler) != expected) return false;
1250 
1251     nextToken(compiler.parser);
1252     return true;
1253 }
1254 
1255 // Consumes the current token. Emits an error if its type is not [expected].
1256 static void consume(Compiler* compiler, TokenType expected,
1257                     const char* errorMessage)
1258 {
1259     nextToken(compiler.parser);
1260     if (compiler.parser.previous.type != expected)
1261     {
1262         error(compiler, errorMessage);
1263 
1264         // If the next token is the one we want, assume the current one is just a
1265         // spurious error and discard it to minimize the number of cascaded errors.
1266         if (compiler.parser.current.type == expected) nextToken(compiler.parser);
1267     }
1268 }
1269 
1270 // Matches one or more newlines. Returns true if at least one was found.
1271 static bool matchLine(Compiler* compiler)
1272 {
1273     if (!match(compiler, TokenType.TOKEN_LINE)) return false;
1274 
1275     while (match(compiler, TokenType.TOKEN_LINE)) {}
1276     return true;
1277 }
1278 
1279 // Discards any newlines starting at the current token.
1280 static void ignoreNewlines(Compiler* compiler)
1281 {
1282     matchLine(compiler);
1283 }
1284 
1285 // Consumes the current token. Emits an error if it is not a newline. Then
1286 // discards any duplicate newlines following it.
1287 static void consumeLine(Compiler* compiler, const char* errorMessage)
1288 {
1289     consume(compiler, TokenType.TOKEN_LINE, errorMessage);
1290     ignoreNewlines(compiler);
1291 }
1292 
1293 static void allowLineBeforeDot(Compiler* compiler) {
1294     if (peek(compiler) == TokenType.TOKEN_LINE && peekNext(compiler) == TokenType.TOKEN_DOT) {
1295         nextToken(compiler.parser);
1296     }
1297 }
1298 
1299 // Variables and scopes --------------------------------------------------------
1300 
1301 // Emits one single-byte argument. Returns its index.
1302 static int emitByte(Compiler* compiler, int byte_)
1303 {
1304     wrenByteBufferWrite(compiler.parser.vm, &compiler.fn.code, cast(ubyte)byte_);
1305     
1306     // Assume the instruction is associated with the most recently consumed token.
1307     wrenIntBufferWrite(compiler.parser.vm, &compiler.fn.debug_.sourceLines,
1308                         compiler.parser.previous.line);
1309     
1310     return compiler.fn.code.count - 1;
1311 }
1312 
1313 // Emits one bytecode instruction.
1314 static void emitOp(Compiler* compiler, Code instruction)
1315 {
1316     emitByte(compiler, instruction);
1317     
1318     // Keep track of the stack's high water mark.
1319     compiler.numSlots += stackEffects[instruction];
1320     if (compiler.numSlots > compiler.fn.maxSlots)
1321     {
1322         compiler.fn.maxSlots = compiler.numSlots;
1323     }
1324 }
1325 
1326 // Emits one 16-bit argument, which will be written big endian.
1327 static void emitShort(Compiler* compiler, int arg)
1328 {
1329     emitByte(compiler, (arg >> 8) & 0xff);
1330     emitByte(compiler, arg & 0xff);
1331 }
1332 
1333 // Emits one bytecode instruction followed by a 8-bit argument. Returns the
1334 // index of the argument in the bytecode.
1335 static int emitByteArg(Compiler* compiler, Code instruction, int arg)
1336 {
1337     emitOp(compiler, instruction);
1338     return emitByte(compiler, arg);
1339 }
1340 
1341 // Emits one bytecode instruction followed by a 16-bit argument, which will be
1342 // written big endian.
1343 static void emitShortArg(Compiler* compiler, Code instruction, int arg)
1344 {
1345     emitOp(compiler, instruction);
1346     emitShort(compiler, arg);
1347 }
1348 
1349 // Emits [instruction] followed by a placeholder for a jump offset. The
1350 // placeholder can be patched by calling [jumpPatch]. Returns the index of the
1351 // placeholder.
1352 static int emitJump(Compiler* compiler, Code instruction)
1353 {
1354     emitOp(compiler, instruction);
1355     emitByte(compiler, 0xff);
1356     return emitByte(compiler, 0xff) - 1;
1357 }
1358 
1359 // Creates a new constant for the current value and emits the bytecode to load
1360 // it from the constant table.
1361 static void emitConstant(Compiler* compiler, Value value)
1362 {
1363     int constant = addConstant(compiler, value);
1364     
1365     // Compile the code to load the constant.
1366     emitShortArg(compiler, Code.CODE_CONSTANT, constant);
1367 }
1368 
1369 // Create a new local variable with [name]. Assumes the current scope is local
1370 // and the name is unique.
1371 static int addLocal(Compiler* compiler, const char* name, int length)
1372 {
1373     Local* local = &compiler.locals[compiler.numLocals];
1374     local.name = name;
1375     local.length = length;
1376     local.depth = compiler.scopeDepth;
1377     local.isUpvalue = false;
1378     return compiler.numLocals++;
1379 }
1380 
1381 // Declares a variable in the current scope whose name is the given token.
1382 //
1383 // If [token] is `null`, uses the previously consumed token. Returns its symbol.
1384 static int declareVariable(Compiler* compiler, Token* token)
1385 {
1386     if (token == null) token = &compiler.parser.previous;
1387 
1388     if (token.length > MAX_VARIABLE_NAME)
1389     {
1390         error(compiler, "Variable name cannot be longer than %d characters.",
1391                 MAX_VARIABLE_NAME);
1392     }
1393 
1394     // Top-level module scope.
1395     if (compiler.scopeDepth == -1)
1396     {
1397         int line = -1;
1398         int symbol = wrenDefineVariable(compiler.parser.vm,
1399                                         compiler.parser.module_,
1400                                         token.start, token.length,
1401                                         NULL_VAL, &line);
1402 
1403         if (symbol == -1)
1404         {
1405             error(compiler, "Module variable is already defined.");
1406         }
1407         else if (symbol == -2)
1408         {
1409             error(compiler, "Too many module variables defined.");
1410         }
1411         else if (symbol == -3)
1412         {
1413             error(compiler,
1414                 "Variable '%.*s' referenced before this definition (first use at line %d).",
1415                 token.length, token.start, line);
1416         }
1417 
1418         return symbol;
1419     }
1420 
1421     // See if there is already a variable with this name declared in the current
1422     // scope. (Outer scopes are OK: those get shadowed.)
1423     for (int i = compiler.numLocals - 1; i >= 0; i--)
1424     {
1425         import core.stdc.string : memcmp;
1426         Local* local = &compiler.locals[i];
1427 
1428         // Once we escape this scope and hit an outer one, we can stop.
1429         if (local.depth < compiler.scopeDepth) break;
1430 
1431         if (local.length == token.length &&
1432             memcmp(local.name, token.start, token.length) == 0)
1433         {
1434             error(compiler, "Variable is already declared in this scope.");
1435             return i;
1436         }
1437     }
1438 
1439     if (compiler.numLocals == MAX_LOCALS)
1440     {
1441         error(compiler, "Cannot declare more than %d variables in one scope.",
1442             MAX_LOCALS);
1443         return -1;
1444     }
1445 
1446     return addLocal(compiler, token.start, token.length);
1447 }
1448 
1449 // Parses a name token and declares a variable in the current scope with that
1450 // name. Returns its slot.
1451 static int declareNamedVariable(Compiler* compiler)
1452 {
1453     consume(compiler, TokenType.TOKEN_NAME, "Expect variable name.");
1454     return declareVariable(compiler, null);
1455 }
1456 
1457 // Stores a variable with the previously defined symbol in the current scope.
1458 static void defineVariable(Compiler* compiler, int symbol)
1459 {
1460     // Store the variable. If it's a local, the result of the initializer is
1461     // in the correct slot on the stack already so we're done.
1462     if (compiler.scopeDepth >= 0) return;
1463 
1464     // It's a module-level variable, so store the value in the module slot and
1465     // then discard the temporary for the initializer.
1466     emitShortArg(compiler, Code.CODE_STORE_MODULE_VAR, symbol);
1467     emitOp(compiler, Code.CODE_POP);
1468 }
1469 
1470 // Starts a new local block scope.
1471 static void pushScope(Compiler* compiler)
1472 {
1473     compiler.scopeDepth++;
1474 }
1475 
1476 // Generates code to discard local variables at [depth] or greater. Does *not*
1477 // actually undeclare variables or pop any scopes, though. This is called
1478 // directly when compiling "break" statements to ditch the local variables
1479 // before jumping out of the loop even though they are still in scope *past*
1480 // the break instruction.
1481 //
1482 // Returns the number of local variables that were eliminated.
1483 static int discardLocals(Compiler* compiler, int depth)
1484 {
1485     if (compiler.scopeDepth < -1)
1486         throw mallocNew!Error("Cannot exit top-level scope.");
1487     // assert(compiler.scopeDepth > -1, "Cannot exit top-level scope.");
1488 
1489     int local = compiler.numLocals - 1;
1490     while (local >= 0 && compiler.locals[local].depth >= depth)
1491     {
1492         // If the local was closed over, make sure the upvalue gets closed when it
1493         // goes out of scope on the stack. We use emitByte() and not emitOp() here
1494         // because we don't want to track that stack effect of these pops since the
1495         // variables are still in scope after the break.
1496         if (compiler.locals[local].isUpvalue)
1497         {
1498             emitByte(compiler, Code.CODE_CLOSE_UPVALUE);
1499         }
1500         else
1501         {
1502             emitByte(compiler, Code.CODE_POP);
1503         }
1504         
1505 
1506         local--;
1507     }
1508 
1509     return compiler.numLocals - local - 1;
1510 }
1511 
1512 // Closes the last pushed block scope and discards any local variables declared
1513 // in that scope. This should only be called in a statement context where no
1514 // temporaries are still on the stack.
1515 static void popScope(Compiler* compiler)
1516 {
1517     int popped = discardLocals(compiler, compiler.scopeDepth);
1518     compiler.numLocals -= popped;
1519     compiler.numSlots -= popped;
1520     compiler.scopeDepth--;
1521 }
1522 
1523 // Attempts to look up the name in the local variables of [compiler]. If found,
1524 // returns its index, otherwise returns -1.
1525 static int resolveLocal(Compiler* compiler, const char* name, int length)
1526 {
1527     import core.stdc.string : memcmp;
1528     // Look it up in the local scopes. Look in reverse order so that the most
1529     // nested variable is found first and shadows outer ones.
1530     for (int i = compiler.numLocals - 1; i >= 0; i--)
1531     {
1532         if (compiler.locals[i].length == length &&
1533             memcmp(name, compiler.locals[i].name, length) == 0)
1534         {
1535         return i;
1536         }
1537     }
1538 
1539     return -1;
1540 }
1541 
1542 // Adds an upvalue to [compiler]'s function with the given properties. Does not
1543 // add one if an upvalue for that variable is already in the list. Returns the
1544 // index of the upvalue.
1545 static int addUpvalue(Compiler* compiler, bool isLocal, int index)
1546 {
1547     // Look for an existing one.
1548     for (int i = 0; i < compiler.fn.numUpvalues; i++)
1549     {
1550         CompilerUpvalue* upvalue = &compiler.upvalues[i];
1551         if (upvalue.index == index && upvalue.isLocal == isLocal) return i;
1552     }
1553 
1554     // If we got here, it's a new upvalue.
1555     compiler.upvalues[compiler.fn.numUpvalues].isLocal = isLocal;
1556     compiler.upvalues[compiler.fn.numUpvalues].index = index;
1557     return compiler.fn.numUpvalues++;
1558 }
1559 
1560 // Attempts to look up [name] in the functions enclosing the one being compiled
1561 // by [compiler]. If found, it adds an upvalue for it to this compiler's list
1562 // of upvalues (unless it's already in there) and returns its index. If not
1563 // found, returns -1.
1564 //
1565 // If the name is found outside of the immediately enclosing function, this
1566 // will flatten the closure and add upvalues to all of the intermediate
1567 // functions so that it gets walked down to this one.
1568 //
1569 // If it reaches a method boundary, this stops and returns -1 since methods do
1570 // not close over local variables.
1571 static int findUpvalue(Compiler* compiler, const char* name, int length)
1572 {
1573     // If we are at the top level, we didn't find it.
1574     if (compiler.parent == null) return -1;
1575     
1576     // If we hit the method boundary (and the name isn't a static field), then
1577     // stop looking for it. We'll instead treat it as a self send.
1578     if (name[0] != '_' && compiler.parent.enclosingClass != null) return -1;
1579     
1580     // See if it's a local variable in the immediately enclosing function.
1581     int local = resolveLocal(compiler.parent, name, length);
1582     if (local != -1)
1583     {
1584         // Mark the local as an upvalue so we know to close it when it goes out of
1585         // scope.
1586         compiler.parent.locals[local].isUpvalue = true;
1587 
1588         return addUpvalue(compiler, true, local);
1589     }
1590 
1591     // See if it's an upvalue in the immediately enclosing function. In other
1592     // words, if it's a local variable in a non-immediately enclosing function.
1593     // This "flattens" closures automatically: it adds upvalues to all of the
1594     // intermediate functions to get from the function where a local is declared
1595     // all the way into the possibly deeply nested function that is closing over
1596     // it.
1597     int upvalue = findUpvalue(compiler.parent, name, length);
1598     if (upvalue != -1)
1599     {
1600         return addUpvalue(compiler, false, upvalue);
1601     }
1602 
1603     // If we got here, we walked all the way up the parent chain and couldn't
1604     // find it.
1605     return -1;
1606 }
1607 
1608 // Look up [name] in the current scope to see what variable it refers to.
1609 // Returns the variable either in local scope, or the enclosing function's
1610 // upvalue list. Does not search the module scope. Returns a variable with
1611 // index -1 if not found.
1612 static Variable resolveNonmodule(Compiler* compiler,
1613                                  const char* name, int length)
1614 {
1615     // Look it up in the local scopes.
1616     Variable variable;
1617     variable.scope_ = Scope.SCOPE_LOCAL;
1618     variable.index = resolveLocal(compiler, name, length);
1619     if (variable.index != -1) return variable;
1620 
1621     // Tt's not a local, so guess that it's an upvalue.
1622     variable.scope_ = Scope.SCOPE_UPVALUE;
1623     variable.index = findUpvalue(compiler, name, length);
1624     return variable;
1625 }
1626 
1627 // Look up [name] in the current scope to see what variable it refers to.
1628 // Returns the variable either in module scope, local scope, or the enclosing
1629 // function's upvalue list. Returns a variable with index -1 if not found.
1630 static Variable resolveName(Compiler* compiler, const char* name, int length)
1631 {
1632     Variable variable = resolveNonmodule(compiler, name, length);
1633     if (variable.index != -1) return variable;
1634 
1635     variable.scope_ = Scope.SCOPE_MODULE;
1636     variable.index = wrenSymbolTableFind(&compiler.parser.module_.variableNames,
1637                                         name, length);
1638     return variable;
1639 }
1640 
1641 static void loadLocal(Compiler* compiler, int slot)
1642 {
1643     if (slot <= 8)
1644     {
1645         emitOp(compiler, cast(Code)(Code.CODE_LOAD_LOCAL_0 + slot));
1646         return;
1647     }
1648 
1649     emitByteArg(compiler, Code.CODE_LOAD_LOCAL, slot);
1650 }
1651 
1652 // Finishes [compiler], which is compiling a function, method, or chunk of top
1653 // level code. If there is a parent compiler, then this emits code in the
1654 // parent compiler to load the resulting function.
1655 static ObjFn* endCompiler(Compiler* compiler,
1656                           const char* debugName, int debugNameLength)
1657 {
1658     // If we hit an error, don't finish the function since it's borked anyway.
1659     if (compiler.parser.hasError)
1660     {
1661         compiler.parser.vm.compiler = compiler.parent;
1662         return null;
1663     }
1664 
1665     // Mark the end of the bytecode. Since it may contain multiple early returns,
1666     // we can't rely on CODE_RETURN to tell us we're at the end.
1667     emitOp(compiler, Code.CODE_END);
1668 
1669     wrenFunctionBindName(compiler.parser.vm, compiler.fn,
1670                         debugName, debugNameLength);
1671     
1672     // In the function that contains this one, load the resulting function object.
1673     if (compiler.parent != null)
1674     {
1675         int constant = addConstant(compiler.parent, OBJ_VAL(compiler.fn));
1676 
1677         // Wrap the function in a closure. We do this even if it has no upvalues so
1678         // that the VM can uniformly assume all called objects are closures. This
1679         // makes creating a function a little slower, but makes invoking them
1680         // faster. Given that functions are invoked more often than they are
1681         // created, this is a win.
1682         emitShortArg(compiler.parent, Code.CODE_CLOSURE, constant);
1683 
1684         // Emit arguments for each upvalue to know whether to capture a local or
1685         // an upvalue.
1686         for (int i = 0; i < compiler.fn.numUpvalues; i++)
1687         {
1688             emitByte(compiler.parent, compiler.upvalues[i].isLocal ? 1 : 0);
1689             emitByte(compiler.parent, compiler.upvalues[i].index);
1690         }
1691     }
1692 
1693     // Pop this compiler off the stack.
1694     compiler.parser.vm.compiler = compiler.parent;
1695     
1696     static if (WREN_DEBUG_DUMP_COMPILED_CODE) {
1697         wrenDumpCode(compiler.parser.vm, compiler.fn);
1698     }
1699 
1700     return compiler.fn;
1701 }
1702 
1703 // Grammar ---------------------------------------------------------------------
1704 enum Precedence
1705 {
1706     PREC_NONE,
1707     PREC_LOWEST,
1708     PREC_ASSIGNMENT,    // =
1709     PREC_CONDITIONAL,   // ?:
1710     PREC_LOGICAL_OR,    // ||
1711     PREC_LOGICAL_AND,   // &&
1712     PREC_EQUALITY,      // == !=
1713     PREC_IS,            // is
1714     PREC_COMPARISON,    // < > <= >=
1715     PREC_BITWISE_OR,    // |
1716     PREC_BITWISE_XOR,   // ^
1717     PREC_BITWISE_AND,   // &
1718     PREC_BITWISE_SHIFT, // << >>
1719     PREC_RANGE,         // .. ...
1720     PREC_TERM,          // + -
1721     PREC_FACTOR,        // * / %
1722     PREC_UNARY,         // unary - ! ~
1723     PREC_CALL,          // . () []
1724     PREC_PRIMARY   
1725 }
1726 
1727 alias GrammarFn = void function(Compiler*, bool canAssign);
1728 
1729 alias SignatureFn = void function(Compiler*, Signature* signature);
1730 
1731 struct GrammarRule
1732 {
1733     GrammarFn prefix;
1734     GrammarFn infix;
1735     SignatureFn method;
1736     Precedence precedence;
1737     const(char)* name;
1738 }
1739 
1740 // Replaces the placeholder argument for a previous CODE_JUMP or CODE_JUMP_IF
1741 // instruction with an offset that jumps to the current end of bytecode.
1742 static void patchJump(Compiler* compiler, int offset)
1743 {
1744     // -2 to adjust for the bytecode for the jump offset itself.
1745     int jump = compiler.fn.code.count - offset - 2;
1746     if (jump > MAX_JUMP) error(compiler, "Too much code to jump over.");
1747 
1748     compiler.fn.code.data[offset] = (jump >> 8) & 0xff;
1749     compiler.fn.code.data[offset + 1] = jump & 0xff;
1750 }
1751 
1752 // Parses a block body, after the initial "{" has been consumed.
1753 //
1754 // Returns true if it was a expression body, false if it was a statement body.
1755 // (More precisely, returns true if a value was left on the stack. An empty
1756 // block returns false.)
1757 static bool finishBlock(Compiler* compiler)
1758 {
1759     // Empty blocks do nothing.
1760     if (match(compiler, TokenType.TOKEN_RIGHT_BRACE)) return false;
1761 
1762     // If there's no line after the "{", it's a single-expression body.
1763     if (!matchLine(compiler))
1764     {
1765         expression(compiler);
1766         consume(compiler, TokenType.TOKEN_RIGHT_BRACE, "Expect '}' at end of block.");
1767         return true;
1768     }
1769 
1770     // Empty blocks (with just a newline inside) do nothing.
1771     if (match(compiler, TokenType.TOKEN_RIGHT_BRACE)) return false;
1772 
1773     // Compile the definition list.
1774     do
1775     {
1776         definition(compiler);
1777         consumeLine(compiler, "Expect newline after statement.");
1778     }
1779     while (peek(compiler) != TokenType.TOKEN_RIGHT_BRACE && peek(compiler) != TokenType.TOKEN_EOF);
1780     
1781     consume(compiler, TokenType.TOKEN_RIGHT_BRACE, "Expect '}' at end of block.");
1782     return false;
1783 }
1784 
1785 // Parses a method or function body, after the initial "{" has been consumed.
1786 //
1787 // If [Compiler.isInitializer] is `true`, this is the body of a constructor
1788 // initializer. In that case, this adds the code to ensure it returns `this`.
1789 static void finishBody(Compiler* compiler)
1790 {
1791     bool isExpressionBody = finishBlock(compiler);
1792 
1793     if (compiler.isInitializer)
1794     {
1795         // If the initializer body evaluates to a value, discard it.
1796         if (isExpressionBody) emitOp(compiler, Code.CODE_POP);
1797 
1798         // The receiver is always stored in the first local slot.
1799         emitOp(compiler, Code.CODE_LOAD_LOCAL_0);
1800     }
1801     else if (!isExpressionBody)
1802     {
1803         // Implicitly return null in statement bodies.
1804         emitOp(compiler, Code.CODE_NULL);
1805     }
1806 
1807     emitOp(compiler, Code.CODE_RETURN);
1808 }
1809 
1810 // The VM can only handle a certain number of parameters, so check that we
1811 // haven't exceeded that and give a usable error.
1812 static void validateNumParameters(Compiler* compiler, int numArgs)
1813 {
1814     if (numArgs == MAX_PARAMETERS + 1)
1815     {
1816         // Only show an error at exactly max + 1 so that we can keep parsing the
1817         // parameters and minimize cascaded errors.
1818         error(compiler, "Methods cannot have more than %d parameters.",
1819             MAX_PARAMETERS);
1820     }
1821 }
1822 
1823 // Parses the rest of a comma-separated parameter list after the opening
1824 // delimeter. Updates `arity` in [signature] with the number of parameters.
1825 static void finishParameterList(Compiler* compiler, Signature* signature)
1826 {
1827     do
1828     {
1829         ignoreNewlines(compiler);
1830         validateNumParameters(compiler, ++signature.arity);
1831 
1832         // Define a local variable in the method for the parameter.
1833         declareNamedVariable(compiler);
1834     }
1835     while (match(compiler, TokenType.TOKEN_COMMA));
1836 }
1837 
1838 // Gets the symbol for a method [name] with [length].
1839 static int methodSymbol(Compiler* compiler, const char* name, int length)
1840 {
1841     return wrenSymbolTableEnsure(compiler.parser.vm,
1842         &compiler.parser.vm.methodNames, name, length);
1843 }
1844 
1845 // Appends characters to [name] (and updates [length]) for [numParams] "_"
1846 // surrounded by [leftBracket] and [rightBracket].
1847 static void signatureParameterList(char* name, int* length,
1848                                    int numParams, char leftBracket, char rightBracket)
1849 {
1850     name[(*length)++] = leftBracket;
1851 
1852     // This function may be called with too many parameters. When that happens,
1853     // a compile error has already been reported, but we need to make sure we
1854     // don't overflow the string too, hence the MAX_PARAMETERS check.
1855     for (int i = 0; i < numParams && i < MAX_PARAMETERS; i++)
1856     {
1857         if (i > 0) name[(*length)++] = ',';
1858         name[(*length)++] = '_';
1859     }
1860     name[(*length)++] = rightBracket;
1861 }
1862 
1863 // Fills [name] with the stringified version of [signature] and updates
1864 // [length] to the resulting length.
1865 static void signatureToString(Signature* signature,
1866                               char* name, int* length)
1867 {
1868     import core.stdc.string : memcpy;
1869     *length = 0;
1870 
1871     // Build the full name from the signature.
1872     memcpy(name + *length, signature.name, signature.length);
1873     *length += signature.length;
1874 
1875     switch (signature.type) with(SignatureType)
1876     {
1877         case SIG_METHOD:
1878             signatureParameterList(name, length, signature.arity, '(', ')');
1879             break;
1880 
1881         case SIG_GETTER:
1882             // The signature is just the name.
1883             break;
1884 
1885         case SIG_SETTER:
1886             name[(*length)++] = '=';
1887             signatureParameterList(name, length, 1, '(', ')');
1888             break;
1889 
1890         case SIG_SUBSCRIPT:
1891             signatureParameterList(name, length, signature.arity, '[', ']');
1892             break;
1893 
1894         case SIG_SUBSCRIPT_SETTER:
1895             signatureParameterList(name, length, signature.arity - 1, '[', ']');
1896             name[(*length)++] = '=';
1897             signatureParameterList(name, length, 1, '(', ')');
1898             break;
1899         
1900         case SIG_INITIALIZER:
1901             memcpy(name, "init ".ptr, 5);
1902             memcpy(name + 5, signature.name, signature.length);
1903             *length = 5 + signature.length;
1904             signatureParameterList(name, length, signature.arity, '(', ')');
1905             break;
1906 
1907         default:
1908             throw mallocNew!Error("Unexpected signature type hit");
1909     }
1910 
1911     name[*length] = '\0';
1912 }
1913 
1914 // Gets the symbol for a method with [signature].
1915 static int signatureSymbol(Compiler* compiler, Signature* signature)
1916 {
1917     // Build the full name from the signature.
1918     char[MAX_METHOD_SIGNATURE] name = 0;
1919     int length;
1920     signatureToString(signature, name.ptr, &length);
1921 
1922     return methodSymbol(compiler, name.ptr, length);
1923 }
1924 
1925 // Returns a signature with [type] whose name is from the last consumed token.
1926 static Signature signatureFromToken(Compiler* compiler, SignatureType type)
1927 {
1928     Signature signature;
1929     
1930     // Get the token for the method name.
1931     Token* token = &compiler.parser.previous;
1932     signature.name = token.start;
1933     signature.length = token.length;
1934     signature.type = type;
1935     signature.arity = 0;
1936 
1937     if (signature.length > MAX_METHOD_NAME)
1938     {
1939         error(compiler, "Method names cannot be longer than %d characters.",
1940             MAX_METHOD_NAME);
1941         signature.length = MAX_METHOD_NAME;
1942     }
1943     
1944     return signature;
1945 }
1946 
1947 // Parses a comma-separated list of arguments. Modifies [signature] to include
1948 // the arity of the argument list.
1949 static void finishArgumentList(Compiler* compiler, Signature* signature)
1950 {
1951     do
1952     {
1953         ignoreNewlines(compiler);
1954         validateNumParameters(compiler, ++signature.arity);
1955         expression(compiler);
1956     }
1957     while (match(compiler, TokenType.TOKEN_COMMA));
1958 
1959     // Allow a newline before the closing delimiter.
1960     ignoreNewlines(compiler);
1961 }
1962 
1963 // Compiles a method call with [signature] using [instruction].
1964 static void callSignature(Compiler* compiler, Code instruction,
1965                           Signature* signature)
1966 {
1967     int symbol = signatureSymbol(compiler, signature);
1968     emitShortArg(compiler, cast(Code)(instruction + signature.arity), symbol);
1969 
1970     if (instruction == Code.CODE_SUPER_0)
1971     {
1972         // Super calls need to be statically bound to the class's superclass. This
1973         // ensures we call the right method even when a method containing a super
1974         // call is inherited by another subclass.
1975         //
1976         // We bind it at class definition time by storing a reference to the
1977         // superclass in a constant. So, here, we create a slot in the constant
1978         // table and store NULL in it. When the method is bound, we'll look up the
1979         // superclass then and store it in the constant slot.
1980         emitShort(compiler, addConstant(compiler, NULL_VAL));
1981     }
1982 }
1983 
1984 // Compiles a method call with [numArgs] for a method with [name] with [length].
1985 static void callMethod(Compiler* compiler, int numArgs, const char* name,
1986                        int length)
1987 {
1988     int symbol = methodSymbol(compiler, name, length);
1989     emitShortArg(compiler, cast(Code)(Code.CODE_CALL_0 + numArgs), symbol);
1990 }
1991 
1992 // Compiles an (optional) argument list for a method call with [methodSignature]
1993 // and then calls it.
1994 static void methodCall(Compiler* compiler, Code instruction,
1995                        Signature* signature)
1996 {
1997     import core.stdc.string : memmove;
1998     // Make a new signature that contains the updated arity and type based on
1999     // the arguments we find.
2000     Signature called = { signature.name, signature.length, SignatureType.SIG_GETTER, 0 };
2001 
2002     // Parse the argument list, if any.
2003     if (match(compiler, TokenType.TOKEN_LEFT_PAREN))
2004     {
2005         called.type = SignatureType.SIG_METHOD;
2006 
2007         // Allow new line before an empty argument list
2008         ignoreNewlines(compiler);
2009 
2010         // Allow empty an argument list.
2011         if (peek(compiler) != TokenType.TOKEN_RIGHT_PAREN)
2012         {
2013             finishArgumentList(compiler, &called);
2014         }
2015         consume(compiler, TokenType.TOKEN_RIGHT_PAREN, "Expect ')' after arguments.");
2016     }
2017 
2018     // Parse the block argument, if any.
2019     if (match(compiler, TokenType.TOKEN_LEFT_BRACE))
2020     {
2021         // Include the block argument in the arity.
2022         called.type = SignatureType.SIG_METHOD;
2023         called.arity++;
2024 
2025         Compiler fnCompiler;
2026         initCompiler(&fnCompiler, compiler.parser, compiler, false);
2027 
2028         // Make a dummy signature to track the arity.
2029         Signature fnSignature = { "", 0, SignatureType.SIG_METHOD, 0 };
2030 
2031         // Parse the parameter list, if any.
2032         if (match(compiler, TokenType.TOKEN_PIPE))
2033         {
2034             finishParameterList(&fnCompiler, &fnSignature);
2035             consume(compiler, TokenType.TOKEN_PIPE, "Expect '|' after function parameters.");
2036         }
2037 
2038         fnCompiler.fn.arity = fnSignature.arity;
2039 
2040         finishBody(&fnCompiler);
2041 
2042         // Name the function based on the method its passed to.
2043         char[MAX_METHOD_SIGNATURE + 15] blockName;
2044         int blockLength;
2045         signatureToString(&called, blockName.ptr, &blockLength);
2046         memmove(blockName.ptr + blockLength, " block argument".ptr, 16);
2047 
2048         endCompiler(&fnCompiler, blockName.ptr, blockLength + 15);
2049     }
2050 
2051     // TODO: Allow Grace-style mixfix methods?
2052 
2053     // If this is a super() call for an initializer, make sure we got an actual
2054     // argument list.
2055     if (signature.type == SignatureType.SIG_INITIALIZER)
2056     {
2057         if (called.type != SignatureType.SIG_METHOD)
2058         {
2059             error(compiler, "A superclass constructor must have an argument list.");
2060         }
2061         
2062         called.type = SignatureType.SIG_INITIALIZER;
2063     }
2064     
2065     callSignature(compiler, instruction, &called);
2066 }
2067 
2068 // Compiles a call whose name is the previously consumed token. This includes
2069 // getters, method calls with arguments, and setter calls.
2070 static void namedCall(Compiler* compiler, bool canAssign, Code instruction)
2071 {
2072   // Get the token for the method name.
2073   Signature signature = signatureFromToken(compiler, SignatureType.SIG_GETTER);
2074 
2075   if (canAssign && match(compiler, TokenType.TOKEN_EQ))
2076   {
2077     ignoreNewlines(compiler);
2078 
2079     // Build the setter signature.
2080     signature.type = SignatureType.SIG_SETTER;
2081     signature.arity = 1;
2082 
2083     // Compile the assigned value.
2084     expression(compiler);
2085     callSignature(compiler, instruction, &signature);
2086   }
2087   else
2088   {
2089     methodCall(compiler, instruction, &signature);
2090     allowLineBeforeDot(compiler);
2091   }
2092 }
2093 
2094 // Emits the code to load [variable] onto the stack.
2095 static void loadVariable(Compiler* compiler, Variable variable)
2096 {
2097     switch (variable.scope_) with(Scope)
2098     {
2099         case SCOPE_LOCAL:
2100             loadLocal(compiler, variable.index);
2101             break;
2102         case SCOPE_UPVALUE:
2103             emitByteArg(compiler, Code.CODE_LOAD_UPVALUE, variable.index);
2104             break;
2105         case SCOPE_MODULE:
2106             emitShortArg(compiler, Code.CODE_LOAD_MODULE_VAR, variable.index);
2107             break;
2108         default:
2109             throw mallocNew!Error("Unreachable code hit");
2110     }
2111 }
2112 
2113 // Loads the receiver of the currently enclosing method. Correctly handles
2114 // functions defined inside methods.
2115 static void loadThis(Compiler* compiler)
2116 {
2117     loadVariable(compiler, resolveNonmodule(compiler, "this", 4));
2118 }
2119 
2120 // Pushes the value for a module-level variable implicitly imported from core.
2121 static void loadCoreVariable(Compiler* compiler, const(char)* name)
2122 {
2123     import core.stdc.string : strlen;
2124     int symbol = wrenSymbolTableFind(&compiler.parser.module_.variableNames,
2125                                     name, strlen(name));
2126     // assert(symbol != -1, "Should have already defined core name.");
2127     if (symbol == -1)
2128         throw mallocNew!Error("Should have already defined core name.");
2129     emitShortArg(compiler, Code.CODE_LOAD_MODULE_VAR, symbol);
2130 }
2131 
2132 // A parenthesized expression.
2133 static void grouping(Compiler* compiler, bool canAssign)
2134 {
2135     expression(compiler);
2136     consume(compiler, TokenType.TOKEN_RIGHT_PAREN, "Expect ')' after expression.");
2137 }
2138 
2139 // A list literal.
2140 static void list(Compiler* compiler, bool canAssign)
2141 {
2142     // Instantiate a new list.
2143     loadCoreVariable(compiler, "List");
2144     callMethod(compiler, 0, "new()", 5);
2145     
2146     // Compile the list elements. Each one compiles to a ".add()" call.
2147     do
2148     {
2149         ignoreNewlines(compiler);
2150 
2151         // Stop if we hit the end of the list.
2152         if (peek(compiler) == TokenType.TOKEN_RIGHT_BRACKET) break;
2153 
2154         // The element.
2155         expression(compiler);
2156         callMethod(compiler, 1, "addCore_(_)", 11);
2157     } while (match(compiler, TokenType.TOKEN_COMMA));
2158 
2159     // Allow newlines before the closing ']'.
2160     ignoreNewlines(compiler);
2161     consume(compiler, TokenType.TOKEN_RIGHT_BRACKET, "Expect ']' after list elements.");
2162 }
2163 
2164 // A map literal.
2165 static void map(Compiler* compiler, bool canAssign)
2166 {
2167     // Instantiate a new map.
2168     loadCoreVariable(compiler, "Map");
2169     callMethod(compiler, 0, "new()", 5);
2170 
2171     // Compile the map elements. Each one is compiled to just invoke the
2172     // subscript setter on the map.
2173     do
2174     {
2175         ignoreNewlines(compiler);
2176 
2177         // Stop if we hit the end of the map.
2178         if (peek(compiler) == TokenType.TOKEN_RIGHT_BRACE) break;
2179 
2180         // The key.
2181         parsePrecedence(compiler, Precedence.PREC_UNARY);
2182         consume(compiler, TokenType.TOKEN_COLON, "Expect ':' after map key.");
2183         ignoreNewlines(compiler);
2184 
2185         // The value.
2186         expression(compiler);
2187         callMethod(compiler, 2, "addCore_(_,_)", 13);
2188     } while (match(compiler, TokenType.TOKEN_COMMA));
2189 
2190     // Allow newlines before the closing '}'.
2191     ignoreNewlines(compiler);
2192     consume(compiler, TokenType.TOKEN_RIGHT_BRACE, "Expect '}' after map entries.");
2193 }
2194 
2195 // Unary operators like `-foo`.
2196 static void unaryOp(Compiler* compiler, bool canAssign)
2197 {
2198     GrammarRule* rule = getRule(compiler.parser.previous.type);
2199 
2200     ignoreNewlines(compiler);
2201 
2202     // Compile the argument.
2203     parsePrecedence(compiler, cast(Precedence)(Precedence.PREC_UNARY + 1));
2204 
2205     // Call the operator method on the left-hand side.
2206     callMethod(compiler, 0, rule.name, 1);
2207 }
2208 
2209 static void boolean(Compiler* compiler, bool canAssign)
2210 {
2211     emitOp(compiler,
2212         compiler.parser.previous.type == TokenType.TOKEN_FALSE ? Code.CODE_FALSE : Code.CODE_TRUE);
2213 }
2214 
2215 // Walks the compiler chain to find the compiler for the nearest class
2216 // enclosing this one. Returns NULL if not currently inside a class definition.
2217 static Compiler* getEnclosingClassCompiler(Compiler* compiler)
2218 {
2219     while (compiler != null)
2220     {
2221         if (compiler.enclosingClass != null) return compiler;
2222         compiler = compiler.parent;
2223     }
2224 
2225     return null;
2226 }
2227 
2228 // Walks the compiler chain to find the nearest class enclosing this one.
2229 // Returns NULL if not currently inside a class definition.
2230 static ClassInfo* getEnclosingClass(Compiler* compiler)
2231 {
2232     compiler = getEnclosingClassCompiler(compiler);
2233     return compiler == null ? null : compiler.enclosingClass;
2234 }
2235 
2236 static void field(Compiler* compiler, bool canAssign)
2237 {
2238     // Initialize it with a fake value so we can keep parsing and minimize the
2239     // number of cascaded errors.
2240     int field = MAX_FIELDS;
2241 
2242     ClassInfo* enclosingClass = getEnclosingClass(compiler);
2243 
2244     if (enclosingClass == null)
2245     {
2246         error(compiler, "Cannot reference a field outside of a class definition.");
2247     }
2248     else if (enclosingClass.isForeign)
2249     {
2250         error(compiler, "Cannot define fields in a foreign class.");
2251     }
2252     else if (enclosingClass.inStatic)
2253     {
2254         error(compiler, "Cannot use an instance field in a static method.");
2255     }
2256     else
2257     {
2258         // Look up the field, or implicitly define it.
2259         field = wrenSymbolTableEnsure(compiler.parser.vm, &enclosingClass.fields,
2260             compiler.parser.previous.start,
2261             compiler.parser.previous.length);
2262 
2263         if (field >= MAX_FIELDS)
2264         {
2265             error(compiler, "A class can only have %d fields.", MAX_FIELDS);
2266         }
2267     }
2268 
2269     // If there's an "=" after a field name, it's an assignment.
2270     bool isLoad = true;
2271     if (canAssign && match(compiler, TokenType.TOKEN_EQ))
2272     {
2273         // Compile the right-hand side.
2274         expression(compiler);
2275         isLoad = false;
2276     }
2277 
2278     // If we're directly inside a method, use a more optimal instruction.
2279     if (compiler.parent != null &&
2280         compiler.parent.enclosingClass == enclosingClass)
2281     {
2282         emitByteArg(compiler, isLoad ? Code.CODE_LOAD_FIELD_THIS : Code.CODE_STORE_FIELD_THIS,
2283                     field);
2284     }
2285     else
2286     {
2287         loadThis(compiler);
2288         emitByteArg(compiler, isLoad ? Code.CODE_LOAD_FIELD : Code.CODE_STORE_FIELD, field);
2289     }
2290 
2291     allowLineBeforeDot(compiler);
2292 }
2293 
2294 // Compiles a read or assignment to [variable].
2295 static void bareName(Compiler* compiler, bool canAssign, Variable variable)
2296 {
2297     // If there's an "=" after a bare name, it's a variable assignment.
2298     if (canAssign && match(compiler, TokenType.TOKEN_EQ))
2299     {
2300         // Compile the right-hand side.
2301         expression(compiler);
2302 
2303         // Emit the store instruction.
2304         switch (variable.scope_)
2305         {
2306         case Scope.SCOPE_LOCAL:
2307             emitByteArg(compiler, Code.CODE_STORE_LOCAL, variable.index);
2308             break;
2309         case Scope.SCOPE_UPVALUE:
2310             emitByteArg(compiler, Code.CODE_STORE_UPVALUE, variable.index);
2311             break;
2312         case Scope.SCOPE_MODULE:
2313             emitShortArg(compiler, Code.CODE_STORE_MODULE_VAR, variable.index);
2314             break;
2315         default:
2316             throw mallocNew!Error("Unreachable code hit.");
2317             // assert(0, "Unreachable");
2318         }
2319         return;
2320     }
2321 
2322     // Emit the load instruction.
2323     loadVariable(compiler, variable);
2324 
2325     allowLineBeforeDot(compiler);
2326 }
2327 
2328 static void staticField(Compiler* compiler, bool canAssign)
2329 {
2330     Compiler* classCompiler = getEnclosingClassCompiler(compiler);
2331     if (classCompiler == null)
2332     {
2333         error(compiler, "Cannot use a static field outside of a class definition.");
2334         return;
2335     }
2336 
2337     // Look up the name in the scope chain.
2338     Token* token = &compiler.parser.previous;
2339 
2340     // If this is the first time we've seen this static field, implicitly
2341     // define it as a variable in the scope surrounding the class definition.
2342     if (resolveLocal(classCompiler, token.start, token.length) == -1)
2343     {
2344         int symbol = declareVariable(classCompiler, null);
2345 
2346         // Implicitly initialize it to null.
2347         emitOp(classCompiler, Code.CODE_NULL);
2348         defineVariable(classCompiler, symbol);
2349     }
2350 
2351     // It definitely exists now, so resolve it properly. This is different from
2352     // the above resolveLocal() call because we may have already closed over it
2353     // as an upvalue.
2354     Variable variable = resolveName(compiler, token.start, token.length);
2355     bareName(compiler, canAssign, variable);
2356 }
2357 
2358 // Compiles a variable name or method call with an implicit receiver.
2359 static void name(Compiler* compiler, bool canAssign)
2360 {
2361     // Look for the name in the scope chain up to the nearest enclosing method.
2362     Token* token = &compiler.parser.previous;
2363 
2364     Variable variable = resolveNonmodule(compiler, token.start, token.length);
2365     if (variable.index != -1)
2366     {
2367         bareName(compiler, canAssign, variable);
2368         return;
2369     }
2370 
2371     // TODO: The fact that we return above here if the variable is known and parse
2372     // an optional argument list below if not means that the grammar is not
2373     // context-free. A line of code in a method like "someName(foo)" is a parse
2374     // error if "someName" is a defined variable in the surrounding scope and not
2375     // if it isn't. Fix this. One option is to have "someName(foo)" always
2376     // resolve to a self-call if there is an argument list, but that makes
2377     // getters a little confusing.
2378 
2379     // If we're inside a method and the name is lowercase, treat it as a method
2380     // on this.
2381     if (wrenIsLocalName(token.start) && getEnclosingClass(compiler) != null)
2382     {
2383         loadThis(compiler);
2384         namedCall(compiler, canAssign, Code.CODE_CALL_0);
2385         return;
2386     }
2387 
2388     // Otherwise, look for a module-level variable with the name.
2389     variable.scope_ = Scope.SCOPE_MODULE;
2390     variable.index = wrenSymbolTableFind(&compiler.parser.module_.variableNames,
2391                                         token.start, token.length);
2392     if (variable.index == -1)
2393     {
2394         // Implicitly define a module-level variable in
2395         // the hopes that we get a real definition later.
2396         variable.index = wrenDeclareVariable(compiler.parser.vm,
2397                                             compiler.parser.module_,
2398                                             token.start, token.length,
2399                                             token.line);
2400 
2401         if (variable.index == -2)
2402         {
2403             error(compiler, "Too many module variables defined.");
2404         }
2405     }
2406     
2407     bareName(compiler, canAssign, variable);
2408 }
2409 
2410 static void null_(Compiler* compiler, bool canAssign)
2411 {
2412     emitOp(compiler, Code.CODE_NULL);
2413 }
2414 
2415 // A number or string literal.
2416 static void literal(Compiler* compiler, bool canAssign)
2417 {
2418     emitConstant(compiler, compiler.parser.previous.value);
2419 }
2420 
2421 // A string literal that contains interpolated expressions.
2422 //
2423 // Interpolation is syntactic sugar for calling ".join()" on a list. So the
2424 // string:
2425 //
2426 //     "a %(b + c) d"
2427 //
2428 // is compiled roughly like:
2429 //
2430 //     ["a ", b + c, " d"].join()
2431 static void stringInterpolation(Compiler* compiler, bool canAssign)
2432 {
2433     // Instantiate a new list.
2434     loadCoreVariable(compiler, "List");
2435     callMethod(compiler, 0, "new()", 5);
2436     
2437     do
2438     {
2439         // The opening string part.
2440         literal(compiler, false);
2441         callMethod(compiler, 1, "addCore_(_)", 11);
2442         
2443         // The interpolated expression.
2444         ignoreNewlines(compiler);
2445         expression(compiler);
2446         callMethod(compiler, 1, "addCore_(_)", 11);
2447         
2448         ignoreNewlines(compiler);
2449     } while (match(compiler, TokenType.TOKEN_INTERPOLATION));
2450     
2451     // The trailing string part.
2452     consume(compiler, TokenType.TOKEN_STRING, "Expect end of string interpolation.");
2453     literal(compiler, false);
2454     callMethod(compiler, 1, "addCore_(_)", 11);
2455     
2456     // The list of interpolated parts.
2457     callMethod(compiler, 0, "join()", 6);
2458 }
2459 
2460 static void super_(Compiler* compiler, bool canAssign)
2461 {
2462     ClassInfo* enclosingClass = getEnclosingClass(compiler);
2463     if (enclosingClass == null)
2464     {
2465         error(compiler, "Cannot use 'super' outside of a method.");
2466     }
2467 
2468     loadThis(compiler);
2469 
2470     // TODO: Super operator calls.
2471     // TODO: There's no syntax for invoking a superclass constructor with a
2472     // different name from the enclosing one. Figure that out.
2473 
2474     // See if it's a named super call, or an unnamed one.
2475     if (match(compiler, TokenType.TOKEN_DOT))
2476     {
2477         // Compile the superclass call.
2478         consume(compiler, TokenType.TOKEN_NAME, "Expect method name after 'super.'.");
2479         namedCall(compiler, canAssign, Code.CODE_SUPER_0);
2480     }
2481     else if (enclosingClass != null)
2482     {
2483         // No explicit name, so use the name of the enclosing method. Make sure we
2484         // check that enclosingClass isn't NULL first. We've already reported the
2485         // error, but we don't want to crash here.
2486         methodCall(compiler, Code.CODE_SUPER_0, enclosingClass.signature);
2487     }
2488 }
2489 
2490 static void this_(Compiler* compiler, bool canAssign)
2491 {
2492     if (getEnclosingClass(compiler) == null)
2493     {
2494         error(compiler, "Cannot use 'this' outside of a method.");
2495         return;
2496     }
2497 
2498     loadThis(compiler);
2499 }
2500 
2501 // Subscript or "array indexing" operator like `foo[bar]`.
2502 static void subscript(Compiler* compiler, bool canAssign)
2503 {
2504     Signature signature = { "", 0, SignatureType.SIG_SUBSCRIPT, 0 };
2505 
2506     // Parse the argument list.
2507     finishArgumentList(compiler, &signature);
2508     consume(compiler, TokenType.TOKEN_RIGHT_BRACKET, "Expect ']' after arguments.");
2509 
2510     allowLineBeforeDot(compiler);
2511 
2512     if (canAssign && match(compiler, TokenType.TOKEN_EQ))
2513     {
2514         signature.type = SignatureType.SIG_SUBSCRIPT_SETTER;
2515 
2516         // Compile the assigned value.
2517         validateNumParameters(compiler, ++signature.arity);
2518         expression(compiler);
2519     }
2520 
2521     callSignature(compiler, Code.CODE_CALL_0, &signature);
2522 }
2523 
2524 static void call(Compiler* compiler, bool canAssign)
2525 {
2526     ignoreNewlines(compiler);
2527     consume(compiler, TokenType.TOKEN_NAME, "Expect method name after '.'.");
2528     namedCall(compiler, canAssign, Code.CODE_CALL_0);
2529 }
2530 
2531 static void and_(Compiler* compiler, bool canAssign)
2532 {
2533     ignoreNewlines(compiler);
2534 
2535     // Skip the right argument if the left is false.
2536     int jump = emitJump(compiler, Code.CODE_AND);
2537     parsePrecedence(compiler, Precedence.PREC_LOGICAL_AND);
2538     patchJump(compiler, jump);
2539 }
2540 
2541 static void or_(Compiler* compiler, bool canAssign)
2542 {
2543     ignoreNewlines(compiler);
2544 
2545     // Skip the right argument if the left is true.
2546     int jump = emitJump(compiler, Code.CODE_OR);
2547     parsePrecedence(compiler, Precedence.PREC_LOGICAL_OR);
2548     patchJump(compiler, jump);
2549 }
2550 
2551 static void conditional(Compiler* compiler, bool canAssign)
2552 {
2553     // Ignore newline after '?'.
2554     ignoreNewlines(compiler);
2555 
2556     // Jump to the else branch if the condition is false.
2557     int ifJump = emitJump(compiler, Code.CODE_JUMP_IF);
2558 
2559     // Compile the then branch.
2560     parsePrecedence(compiler, Precedence.PREC_CONDITIONAL);
2561 
2562     consume(compiler, TokenType.TOKEN_COLON,
2563             "Expect ':' after then branch of conditional operator.");
2564     ignoreNewlines(compiler);
2565 
2566     // Jump over the else branch when the if branch is taken.
2567     int elseJump = emitJump(compiler, Code.CODE_JUMP);
2568 
2569     // Compile the else branch.
2570     patchJump(compiler, ifJump);
2571 
2572     parsePrecedence(compiler, Precedence.PREC_ASSIGNMENT);
2573 
2574     // Patch the jump over the else.
2575     patchJump(compiler, elseJump);
2576 }
2577 
2578 void infixOp(Compiler* compiler, bool canAssign)
2579 {
2580     import core.stdc.string : strlen;
2581     GrammarRule* rule = getRule(compiler.parser.previous.type);
2582 
2583     // An infix operator cannot end an expression.
2584     ignoreNewlines(compiler);
2585 
2586     // Compile the right-hand side.
2587     parsePrecedence(compiler, cast(Precedence)(rule.precedence + 1));
2588 
2589     // Call the operator method on the left-hand side.
2590     Signature signature = { rule.name, cast(int)strlen(rule.name), SignatureType.SIG_METHOD, 1 };
2591     callSignature(compiler, Code.CODE_CALL_0, &signature);
2592 }
2593 
2594 // Compiles a method signature for an infix operator.
2595 void infixSignature(Compiler* compiler, Signature* signature)
2596 {
2597     // Add the RHS parameter.
2598     signature.type = SignatureType.SIG_METHOD;
2599     signature.arity = 1;
2600 
2601     // Parse the parameter name.
2602     consume(compiler, TokenType.TOKEN_LEFT_PAREN, "Expect '(' after operator name.");
2603     declareNamedVariable(compiler);
2604     consume(compiler, TokenType.TOKEN_RIGHT_PAREN, "Expect ')' after parameter name.");
2605 }
2606 
2607 // Compiles a method signature for an unary operator (i.e. "!").
2608 void unarySignature(Compiler* compiler, Signature* signature)
2609 {
2610     // Do nothing. The name is already complete.
2611     signature.type = SignatureType.SIG_GETTER;
2612 }
2613 
2614 // Compiles a method signature for an operator that can either be unary or
2615 // infix (i.e. "-").
2616 void mixedSignature(Compiler* compiler, Signature* signature)
2617 {
2618     signature.type = SignatureType.SIG_GETTER;
2619 
2620     // If there is a parameter, it's an infix operator, otherwise it's unary.
2621     if (match(compiler, TokenType.TOKEN_LEFT_PAREN))
2622     {
2623         // Add the RHS parameter.
2624         signature.type = SignatureType.SIG_METHOD;
2625         signature.arity = 1;
2626 
2627         // Parse the parameter name.
2628         declareNamedVariable(compiler);
2629         consume(compiler, TokenType.TOKEN_RIGHT_PAREN, "Expect ')' after parameter name.");
2630     }
2631 }
2632 
2633 // Compiles an optional setter parameter in a method [signature].
2634 //
2635 // Returns `true` if it was a setter.
2636 static bool maybeSetter(Compiler* compiler, Signature* signature)
2637 {
2638     // See if it's a setter.
2639     if (!match(compiler, TokenType.TOKEN_EQ)) return false;
2640 
2641     // It's a setter.
2642     if (signature.type == SignatureType.SIG_SUBSCRIPT)
2643     {
2644         signature.type = SignatureType.SIG_SUBSCRIPT_SETTER;
2645     }
2646     else
2647     {
2648         signature.type = SignatureType.SIG_SETTER;
2649     }
2650 
2651     // Parse the value parameter.
2652     consume(compiler, TokenType.TOKEN_LEFT_PAREN, "Expect '(' after '='.");
2653     declareNamedVariable(compiler);
2654     consume(compiler, TokenType.TOKEN_RIGHT_PAREN, "Expect ')' after parameter name.");
2655 
2656     signature.arity++;
2657 
2658     return true;
2659 }
2660 
2661 // Compiles a method signature for a subscript operator.
2662 void subscriptSignature(Compiler* compiler, Signature* signature)
2663 {
2664     signature.type = SignatureType.SIG_SUBSCRIPT;
2665 
2666     // The signature currently has "[" as its name since that was the token that
2667     // matched it. Clear that out.
2668     signature.length = 0;
2669 
2670     // Parse the parameters inside the subscript.
2671     finishParameterList(compiler, signature);
2672     consume(compiler, TokenType.TOKEN_RIGHT_BRACKET, "Expect ']' after parameters.");
2673 
2674     maybeSetter(compiler, signature);
2675 }
2676 
2677 // Parses an optional parenthesized parameter list. Updates `type` and `arity`
2678 // in [signature] to match what was parsed.
2679 static void parameterList(Compiler* compiler, Signature* signature)
2680 {
2681     // The parameter list is optional.
2682     if (!match(compiler, TokenType.TOKEN_LEFT_PAREN)) return;
2683     
2684     signature.type = SignatureType.SIG_METHOD;
2685     
2686     // Allow new line before an empty argument list
2687     ignoreNewlines(compiler);
2688 
2689     // Allow an empty parameter list.
2690     if (match(compiler, TokenType.TOKEN_RIGHT_PAREN)) return;
2691 
2692     finishParameterList(compiler, signature);
2693     consume(compiler, TokenType.TOKEN_RIGHT_PAREN, "Expect ')' after parameters.");
2694 }
2695 
2696 // Compiles a method signature for a named method or setter.
2697 void namedSignature(Compiler* compiler, Signature* signature)
2698 {
2699     signature.type = SignatureType.SIG_GETTER;
2700     
2701     // If it's a setter, it can't also have a parameter list.
2702     if (maybeSetter(compiler, signature)) return;
2703 
2704     // Regular named method with an optional parameter list.
2705     parameterList(compiler, signature);
2706 }
2707 
2708 // Compiles a method signature for a constructor.
2709 void constructorSignature(Compiler* compiler, Signature* signature)
2710 {
2711     consume(compiler, TokenType.TOKEN_NAME, "Expect constructor name after 'construct'.");
2712     
2713     // Capture the name.
2714     *signature = signatureFromToken(compiler, SignatureType.SIG_INITIALIZER);
2715     
2716     if (match(compiler, TokenType.TOKEN_EQ))
2717     {
2718         error(compiler, "A constructor cannot be a setter.");
2719     }
2720 
2721     if (!match(compiler, TokenType.TOKEN_LEFT_PAREN))
2722     {
2723         error(compiler, "A constructor cannot be a getter.");
2724         return;
2725     }
2726     
2727     // Allow an empty parameter list.
2728     if (match(compiler, TokenType.TOKEN_RIGHT_PAREN)) return;
2729     
2730     finishParameterList(compiler, signature);
2731     consume(compiler, TokenType.TOKEN_RIGHT_PAREN, "Expect ')' after parameters.");
2732 }
2733 
2734 enum UNUSED = GrammarRule(null, null, null, Precedence.PREC_NONE, null);
2735 enum PREFIX(alias fn) = GrammarRule(&fn, null, null, Precedence.PREC_NONE, null);
2736 enum INFIX(Precedence prec, alias fn) = GrammarRule(null, &fn, null, prec, null);
2737 enum INFIX_OPERATOR(Precedence prec, const(char)* name) = GrammarRule(null, &infixOp, &infixSignature, prec, name);
2738 enum PREFIX_OPERATOR(const(char)* name) = GrammarRule(&unaryOp, null, &unarySignature, Precedence.PREC_NONE, name);
2739 enum OPERATOR(const(char)* name) = GrammarRule(&unaryOp, &infixOp, &mixedSignature, Precedence.PREC_TERM, name);
2740 
2741 static immutable GrammarRule[] rules = [
2742   /* TOKEN_LEFT_PAREN    */ PREFIX!(grouping),
2743   /* TOKEN_RIGHT_PAREN   */ UNUSED,
2744   /* TOKEN_LEFT_BRACKET  */ GrammarRule(&list, &subscript, &subscriptSignature, Precedence.PREC_CALL, null),
2745   /* TOKEN_RIGHT_BRACKET */ UNUSED,
2746   /* TOKEN_LEFT_BRACE    */ PREFIX!(map),
2747   /* TOKEN_RIGHT_BRACE   */ UNUSED,
2748   /* TOKEN_COLON         */ UNUSED,
2749   /* TOKEN_DOT           */ INFIX!(Precedence.PREC_CALL, call),
2750   /* TOKEN_DOTDOT        */ INFIX_OPERATOR!(Precedence.PREC_RANGE, ".."),
2751   /* TOKEN_DOTDOTDOT     */ INFIX_OPERATOR!(Precedence.PREC_RANGE, "..."),
2752   /* TOKEN_COMMA         */ UNUSED,
2753   /* TOKEN_STAR          */ INFIX_OPERATOR!(Precedence.PREC_FACTOR, "*"),
2754   /* TOKEN_SLASH         */ INFIX_OPERATOR!(Precedence.PREC_FACTOR, "/"),
2755   /* TOKEN_PERCENT       */ INFIX_OPERATOR!(Precedence.PREC_FACTOR, "%"),
2756   /* TOKEN_HASH          */ UNUSED,
2757   /* TOKEN_PLUS          */ INFIX_OPERATOR!(Precedence.PREC_TERM, "+"),
2758   /* TOKEN_MINUS         */ OPERATOR!("-"),
2759   /* TOKEN_LTLT          */ INFIX_OPERATOR!(Precedence.PREC_BITWISE_SHIFT, "<<"),
2760   /* TOKEN_GTGT          */ INFIX_OPERATOR!(Precedence.PREC_BITWISE_SHIFT, ">>"),
2761   /* TOKEN_PIPE          */ INFIX_OPERATOR!(Precedence.PREC_BITWISE_OR, "|"),
2762   /* TOKEN_PIPEPIPE      */ INFIX!(Precedence.PREC_LOGICAL_OR, or_),
2763   /* TOKEN_CARET         */ INFIX_OPERATOR!(Precedence.PREC_BITWISE_XOR, "^"),
2764   /* TOKEN_AMP           */ INFIX_OPERATOR!(Precedence.PREC_BITWISE_AND, "&"),
2765   /* TOKEN_AMPAMP        */ INFIX!(Precedence.PREC_LOGICAL_AND, and_),
2766   /* TOKEN_BANG          */ PREFIX_OPERATOR!("!"),
2767   /* TOKEN_TILDE         */ PREFIX_OPERATOR!("~"),
2768   /* TOKEN_QUESTION      */ INFIX!(Precedence.PREC_ASSIGNMENT, conditional),
2769   /* TOKEN_EQ            */ UNUSED,
2770   /* TOKEN_LT            */ INFIX_OPERATOR!(Precedence.PREC_COMPARISON, "<"),
2771   /* TOKEN_GT            */ INFIX_OPERATOR!(Precedence.PREC_COMPARISON, ">"),
2772   /* TOKEN_LTEQ          */ INFIX_OPERATOR!(Precedence.PREC_COMPARISON, "<="),
2773   /* TOKEN_GTEQ          */ INFIX_OPERATOR!(Precedence.PREC_COMPARISON, ">="),
2774   /* TOKEN_EQEQ          */ INFIX_OPERATOR!(Precedence.PREC_EQUALITY, "=="),
2775   /* TOKEN_BANGEQ        */ INFIX_OPERATOR!(Precedence.PREC_EQUALITY, "!="),
2776   /* TOKEN_BREAK         */ UNUSED,
2777   /* TOKEN_CONTINUE      */ UNUSED,
2778   /* TOKEN_CLASS         */ UNUSED,
2779   /* TOKEN_CONSTRUCT     */ GrammarRule(null, null, &constructorSignature, Precedence.PREC_NONE, null),
2780   /* TOKEN_ELSE          */ UNUSED,
2781   /* TOKEN_FALSE         */ PREFIX!(boolean),
2782   /* TOKEN_FOR           */ UNUSED,
2783   /* TOKEN_FOREIGN       */ UNUSED,
2784   /* TOKEN_IF            */ UNUSED,
2785   /* TOKEN_IMPORT        */ UNUSED,
2786   /* TOKEN_AS            */ UNUSED,
2787   /* TOKEN_IN            */ UNUSED,
2788   /* TOKEN_IS            */ INFIX_OPERATOR!(Precedence.PREC_IS, "is"),
2789   /* TOKEN_NULL          */ PREFIX!(null_),
2790   /* TOKEN_RETURN        */ UNUSED,
2791   /* TOKEN_STATIC        */ UNUSED,
2792   /* TOKEN_SUPER         */ PREFIX!(super_),
2793   /* TOKEN_THIS          */ PREFIX!(this_),
2794   /* TOKEN_TRUE          */ PREFIX!(boolean),
2795   /* TOKEN_VAR           */ UNUSED,
2796   /* TOKEN_WHILE         */ UNUSED,
2797   /* TOKEN_FIELD         */ PREFIX!(field),
2798   /* TOKEN_STATIC_FIELD  */ PREFIX!(staticField),
2799   /* TOKEN_NAME          */ GrammarRule(&name, null, &namedSignature, Precedence.PREC_NONE, null),
2800   /* TOKEN_NUMBER        */ PREFIX!(literal),
2801   /* TOKEN_STRING        */ PREFIX!(literal),
2802   /* TOKEN_INTERPOLATION */ PREFIX!(stringInterpolation),
2803   /* TOKEN_LINE          */ UNUSED,
2804   /* TOKEN_ERROR         */ UNUSED,
2805   /* TOKEN_EOF           */ UNUSED
2806 ];
2807 
2808 // Gets the [GrammarRule] associated with tokens of [type].
2809 static GrammarRule* getRule(TokenType type)
2810 {
2811     return cast(typeof(return))&rules[type];
2812 }
2813 
2814 // The main entrypoint for the top-down operator precedence parser.
2815 void parsePrecedence(Compiler* compiler, Precedence precedence)
2816 {
2817     nextToken(compiler.parser);
2818     GrammarFn prefix = rules[compiler.parser.previous.type].prefix;
2819 
2820     if (prefix == null)
2821     {
2822         error(compiler, "Expected expression.");
2823         return;
2824     }
2825 
2826     // Track if the precendence of the surrounding expression is low enough to
2827     // allow an assignment inside this one. We can't compile an assignment like
2828     // a normal expression because it requires us to handle the LHS specially --
2829     // it needs to be an lvalue, not an rvalue. So, for each of the kinds of
2830     // expressions that are valid lvalues -- names, subscripts, fields, etc. --
2831     // we pass in whether or not it appears in a context loose enough to allow
2832     // "=". If so, it will parse the "=" itself and handle it appropriately.
2833     bool canAssign = precedence <= Precedence.PREC_CONDITIONAL;
2834     prefix(compiler, canAssign);
2835 
2836     while (precedence <= rules[compiler.parser.current.type].precedence)
2837     {
2838         nextToken(compiler.parser);
2839         GrammarFn infix = rules[compiler.parser.previous.type].infix;
2840         infix(compiler, canAssign);
2841     }
2842 }
2843 
2844 // Parses an expression. Unlike statements, expressions leave a resulting value
2845 // on the stack.
2846 void expression(Compiler* compiler)
2847 {
2848     parsePrecedence(compiler, Precedence.PREC_LOWEST);
2849 }
2850 
2851 // Returns the number of bytes for the arguments to the instruction 
2852 // at [ip] in [fn]'s bytecode.
2853 static int getByteCountForArguments(const ubyte* bytecode,
2854                             const Value* constants, int ip)
2855 {
2856     Code instruction = cast(Code)bytecode[ip];
2857     switch (instruction) with(Code)
2858     {
2859         case CODE_NULL:
2860         case CODE_FALSE:
2861         case CODE_TRUE:
2862         case CODE_POP:
2863         case CODE_CLOSE_UPVALUE:
2864         case CODE_RETURN:
2865         case CODE_END:
2866         case CODE_LOAD_LOCAL_0:
2867         case CODE_LOAD_LOCAL_1:
2868         case CODE_LOAD_LOCAL_2:
2869         case CODE_LOAD_LOCAL_3:
2870         case CODE_LOAD_LOCAL_4:
2871         case CODE_LOAD_LOCAL_5:
2872         case CODE_LOAD_LOCAL_6:
2873         case CODE_LOAD_LOCAL_7:
2874         case CODE_LOAD_LOCAL_8:
2875         case CODE_CONSTRUCT:
2876         case CODE_FOREIGN_CONSTRUCT:
2877         case CODE_FOREIGN_CLASS:
2878         case CODE_END_MODULE:
2879         case CODE_END_CLASS:
2880             return 0;
2881 
2882         case CODE_LOAD_LOCAL:
2883         case CODE_STORE_LOCAL:
2884         case CODE_LOAD_UPVALUE:
2885         case CODE_STORE_UPVALUE:
2886         case CODE_LOAD_FIELD_THIS:
2887         case CODE_STORE_FIELD_THIS:
2888         case CODE_LOAD_FIELD:
2889         case CODE_STORE_FIELD:
2890         case CODE_CLASS:
2891             return 1;
2892 
2893         case CODE_CONSTANT:
2894         case CODE_LOAD_MODULE_VAR:
2895         case CODE_STORE_MODULE_VAR:
2896         case CODE_CALL_0:
2897         case CODE_CALL_1:
2898         case CODE_CALL_2:
2899         case CODE_CALL_3:
2900         case CODE_CALL_4:
2901         case CODE_CALL_5:
2902         case CODE_CALL_6:
2903         case CODE_CALL_7:
2904         case CODE_CALL_8:
2905         case CODE_CALL_9:
2906         case CODE_CALL_10:
2907         case CODE_CALL_11:
2908         case CODE_CALL_12:
2909         case CODE_CALL_13:
2910         case CODE_CALL_14:
2911         case CODE_CALL_15:
2912         case CODE_CALL_16:
2913         case CODE_JUMP:
2914         case CODE_LOOP:
2915         case CODE_JUMP_IF:
2916         case CODE_AND:
2917         case CODE_OR:
2918         case CODE_METHOD_INSTANCE:
2919         case CODE_METHOD_STATIC:
2920         case CODE_IMPORT_MODULE:
2921         case CODE_IMPORT_VARIABLE:
2922             return 2;
2923 
2924         case CODE_SUPER_0:
2925         case CODE_SUPER_1:
2926         case CODE_SUPER_2:
2927         case CODE_SUPER_3:
2928         case CODE_SUPER_4:
2929         case CODE_SUPER_5:
2930         case CODE_SUPER_6:
2931         case CODE_SUPER_7:
2932         case CODE_SUPER_8:
2933         case CODE_SUPER_9:
2934         case CODE_SUPER_10:
2935         case CODE_SUPER_11:
2936         case CODE_SUPER_12:
2937         case CODE_SUPER_13:
2938         case CODE_SUPER_14:
2939         case CODE_SUPER_15:
2940         case CODE_SUPER_16:
2941             return 4;
2942 
2943         case CODE_CLOSURE:
2944         {
2945             int constant = (bytecode[ip + 1] << 8) | bytecode[ip + 2];
2946             ObjFn* loadedFn = AS_FN(constants[constant]);
2947 
2948             // There are two bytes for the constant, then two for each upvalue.
2949             return 2 + (loadedFn.numUpvalues * 2);
2950         }
2951         default:
2952             throw mallocNew!Error("Unreachable code hit");
2953             // assert(0, "Unreachable");
2954     }
2955 }
2956 
2957 // Marks the beginning of a loop. Keeps track of the current instruction so we
2958 // know what to loop back to at the end of the body.
2959 static void startLoop(Compiler* compiler, Loop* loop)
2960 {
2961     loop.enclosing = compiler.loop;
2962     loop.start = compiler.fn.code.count - 1;
2963     loop.scopeDepth = compiler.scopeDepth;
2964     compiler.loop = loop;
2965 }
2966 
2967 // Emits the [CODE_JUMP_IF] instruction used to test the loop condition and
2968 // potentially exit the loop. Keeps track of the instruction so we can patch it
2969 // later once we know where the end of the body is.
2970 static void testExitLoop(Compiler* compiler)
2971 {
2972     compiler.loop.exitJump = emitJump(compiler, Code.CODE_JUMP_IF);
2973 }
2974 
2975 // Compiles the body of the loop and tracks its extent so that contained "break"
2976 // statements can be handled correctly.
2977 static void loopBody(Compiler* compiler)
2978 {
2979     compiler.loop.body_ = compiler.fn.code.count;
2980     statement(compiler);
2981 }
2982 
2983 // Ends the current innermost loop. Patches up all jumps and breaks now that
2984 // we know where the end of the loop is.
2985 static void endLoop(Compiler* compiler)
2986 {
2987     // We don't check for overflow here since the forward jump over the loop body
2988     // will report an error for the same problem.
2989     int loopOffset = compiler.fn.code.count - compiler.loop.start + 2;
2990     emitShortArg(compiler, Code.CODE_LOOP, loopOffset);
2991 
2992     patchJump(compiler, compiler.loop.exitJump);
2993 
2994     // Find any break placeholder instructions (which will be CODE_END in the
2995     // bytecode) and replace them with real jumps.
2996     int i = compiler.loop.body_;
2997     while (i < compiler.fn.code.count)
2998     {
2999         if (compiler.fn.code.data[i] == Code.CODE_END)
3000         {
3001             compiler.fn.code.data[i] = Code.CODE_JUMP;
3002             patchJump(compiler, i + 1);
3003             i += 3;
3004         }
3005         else
3006         {
3007             // Skip this instruction and its arguments.
3008             i += 1 + getByteCountForArguments(compiler.fn.code.data,
3009                                     compiler.fn.constants.data, i);
3010         }
3011     }
3012 
3013     compiler.loop = compiler.loop.enclosing;
3014 }
3015 
3016 static void forStatement(Compiler* compiler)
3017 {
3018     // A for statement like:
3019     //
3020     //     for (i in sequence.expression) {
3021     //       System.print(i)
3022     //     }
3023     //
3024     // Is compiled to bytecode almost as if the source looked like this:
3025     //
3026     //     {
3027     //       var seq_ = sequence.expression
3028     //       var iter_
3029     //       while (iter_ = seq_.iterate(iter_)) {
3030     //         var i = seq_.iteratorValue(iter_)
3031     //         System.print(i)
3032     //       }
3033     //     }
3034     //
3035     // It's not exactly this, because the synthetic variables `seq_` and `iter_`
3036     // actually get names that aren't valid Wren identfiers, but that's the basic
3037     // idea.
3038     //
3039     // The important parts are:
3040     // - The sequence expression is only evaluated once.
3041     // - The .iterate() method is used to advance the iterator and determine if
3042     //   it should exit the loop.
3043     // - The .iteratorValue() method is used to get the value at the current
3044     //   iterator position.
3045 
3046     // Create a scope for the hidden local variables used for the iterator.
3047     pushScope(compiler);
3048 
3049     consume(compiler, TokenType.TOKEN_LEFT_PAREN, "Expect '(' after 'for'.");
3050     consume(compiler, TokenType.TOKEN_NAME, "Expect for loop variable name.");
3051 
3052     // Remember the name of the loop variable.
3053     const char* name = compiler.parser.previous.start;
3054     int length = compiler.parser.previous.length;
3055 
3056     consume(compiler, TokenType.TOKEN_IN, "Expect 'in' after loop variable.");
3057     ignoreNewlines(compiler);
3058 
3059     // Evaluate the sequence expression and store it in a hidden local variable.
3060     // The space in the variable name ensures it won't collide with a user-defined
3061     // variable.
3062     expression(compiler);
3063 
3064     // Verify that there is space to hidden local variables.
3065     // Note that we expect only two addLocal calls next to each other in the
3066     // following code.
3067     if (compiler.numLocals + 2 > MAX_LOCALS)
3068     {
3069         error(compiler, "Cannot declare more than %d variables in one scope. (Not enough space for for-loops internal variables)",
3070             MAX_LOCALS);
3071         return;
3072     }
3073     int seqSlot = addLocal(compiler, "seq ", 4);
3074 
3075     // Create another hidden local for the iterator object.
3076     null_(compiler, false);
3077     int iterSlot = addLocal(compiler, "iter ", 5);
3078 
3079     consume(compiler, TokenType.TOKEN_RIGHT_PAREN, "Expect ')' after loop expression.");
3080 
3081     Loop loop;
3082     startLoop(compiler, &loop);
3083 
3084     // Advance the iterator by calling the ".iterate" method on the sequence.
3085     loadLocal(compiler, seqSlot);
3086     loadLocal(compiler, iterSlot);
3087 
3088     // Update and test the iterator.
3089     callMethod(compiler, 1, "iterate(_)", 10);
3090     emitByteArg(compiler, Code.CODE_STORE_LOCAL, iterSlot);
3091     testExitLoop(compiler);
3092 
3093     // Get the current value in the sequence by calling ".iteratorValue".
3094     loadLocal(compiler, seqSlot);
3095     loadLocal(compiler, iterSlot);
3096     callMethod(compiler, 1, "iteratorValue(_)", 16);
3097 
3098     // Bind the loop variable in its own scope. This ensures we get a fresh
3099     // variable each iteration so that closures for it don't all see the same one.
3100     pushScope(compiler);
3101     addLocal(compiler, name, length);
3102 
3103     loopBody(compiler);
3104 
3105     // Loop variable.
3106     popScope(compiler);
3107 
3108     endLoop(compiler);
3109 
3110     // Hidden variables.
3111     popScope(compiler);
3112 }
3113 
3114 static void ifStatement(Compiler* compiler)
3115 {
3116     // Compile the condition.
3117     consume(compiler, TokenType.TOKEN_LEFT_PAREN, "Expect '(' after 'if'.");
3118     expression(compiler);
3119     consume(compiler, TokenType.TOKEN_RIGHT_PAREN, "Expect ')' after if condition.");
3120     
3121     // Jump to the else branch if the condition is false.
3122     int ifJump = emitJump(compiler, Code.CODE_JUMP_IF);
3123     
3124     // Compile the then branch.
3125     statement(compiler);
3126     
3127     // Compile the else branch if there is one.
3128     if (match(compiler, TokenType.TOKEN_ELSE))
3129     {
3130         // Jump over the else branch when the if branch is taken.
3131         int elseJump = emitJump(compiler, Code.CODE_JUMP);
3132         patchJump(compiler, ifJump);
3133         
3134         statement(compiler);
3135         
3136         // Patch the jump over the else.
3137         patchJump(compiler, elseJump);
3138     }
3139     else
3140     {
3141         patchJump(compiler, ifJump);
3142     }
3143 }
3144 
3145 static void whileStatement(Compiler* compiler)
3146 {
3147     Loop loop;
3148     startLoop(compiler, &loop);
3149 
3150     // Compile the condition.
3151     consume(compiler, TokenType.TOKEN_LEFT_PAREN, "Expect '(' after 'while'.");
3152     expression(compiler);
3153     consume(compiler, TokenType.TOKEN_RIGHT_PAREN, "Expect ')' after while condition.");
3154 
3155     testExitLoop(compiler);
3156     loopBody(compiler);
3157     endLoop(compiler);
3158 }
3159 
3160 // Compiles a simple statement. These can only appear at the top-level or
3161 // within curly blocks. Simple statements exclude variable binding statements
3162 // like "var" and "class" which are not allowed directly in places like the
3163 // branches of an "if" statement.
3164 //
3165 // Unlike expressions, statements do not leave a value on the stack.
3166 void statement(Compiler* compiler)
3167 {
3168     if (match(compiler, TokenType.TOKEN_BREAK))
3169     {
3170         if (compiler.loop == null)
3171         {
3172             error(compiler, "Cannot use 'break' outside of a loop.");
3173             return;
3174         }
3175 
3176         // Since we will be jumping out of the scope, make sure any locals in it
3177         // are discarded first.
3178         discardLocals(compiler, compiler.loop.scopeDepth + 1);
3179 
3180         // Emit a placeholder instruction for the jump to the end of the body. When
3181         // we're done compiling the loop body and know where the end is, we'll
3182         // replace these with `CODE_JUMP` instructions with appropriate offsets.
3183         // We use `CODE_END` here because that can't occur in the middle of
3184         // bytecode.
3185         emitJump(compiler, Code.CODE_END);
3186     }
3187     else if (match(compiler, TokenType.TOKEN_CONTINUE))
3188     {
3189         if (compiler.loop == null)
3190         {
3191             error(compiler, "Cannot use 'continue' outside of a loop.");
3192             return;
3193         }
3194 
3195         // Since we will be jumping out of the scope, make sure any locals in it
3196         // are discarded first.
3197         discardLocals(compiler, compiler.loop.scopeDepth + 1);
3198 
3199         // emit a jump back to the top of the loop
3200         int loopOffset = compiler.fn.code.count - compiler.loop.start + 2;
3201         emitShortArg(compiler, Code.CODE_LOOP, loopOffset);
3202     }
3203     else if (match(compiler, TokenType.TOKEN_FOR))
3204     {
3205         forStatement(compiler);
3206     }
3207     else if (match(compiler, TokenType.TOKEN_IF))
3208     {
3209         ifStatement(compiler);
3210     }
3211     else if (match(compiler, TokenType.TOKEN_RETURN))
3212     {
3213         // Compile the return value.
3214         if (peek(compiler) == TokenType.TOKEN_LINE)
3215         {
3216             // If there's no expression after return, initializers should 
3217             // return 'this' and regular methods should return null
3218             Code result = compiler.isInitializer ? Code.CODE_LOAD_LOCAL_0 : Code.CODE_NULL;
3219             emitOp(compiler, result);
3220         }
3221         else
3222         {
3223             if (compiler.isInitializer)
3224             {
3225                 error(compiler, "A constructor cannot return a value.");
3226             }
3227 
3228             expression(compiler);
3229         }
3230 
3231         emitOp(compiler, Code.CODE_RETURN);
3232     }
3233     else if (match(compiler, TokenType.TOKEN_WHILE))
3234     {
3235         whileStatement(compiler);
3236     }
3237     else if (match(compiler, TokenType.TOKEN_LEFT_BRACE))
3238     {
3239         // Block statement.
3240         pushScope(compiler);
3241         if (finishBlock(compiler))
3242         {
3243             // Block was an expression, so discard it.
3244             emitOp(compiler, Code.CODE_POP);
3245         }
3246         popScope(compiler);
3247     }
3248     else
3249     {
3250         // Expression statement.
3251         expression(compiler);
3252         emitOp(compiler, Code.CODE_POP);
3253     }
3254 }
3255 
3256 // Creates a matching constructor method for an initializer with [signature]
3257 // and [initializerSymbol].
3258 //
3259 // Construction is a two-stage process in Wren that involves two separate
3260 // methods. There is a static method that allocates a new instance of the class.
3261 // It then invokes an initializer method on the new instance, forwarding all of
3262 // the constructor arguments to it.
3263 //
3264 // The allocator method always has a fixed implementation:
3265 //
3266 //     CODE_CONSTRUCT - Replace the class in slot 0 with a new instance of it.
3267 //     CODE_CALL      - Invoke the initializer on the new instance.
3268 //
3269 // This creates that method and calls the initializer with [initializerSymbol].
3270 static void createConstructor(Compiler* compiler, Signature* signature,
3271                               int initializerSymbol)
3272 {
3273     Compiler methodCompiler;
3274     initCompiler(&methodCompiler, compiler.parser, compiler, true);
3275     
3276     // Allocate the instance.
3277     emitOp(&methodCompiler, compiler.enclosingClass.isForeign
3278         ? Code.CODE_FOREIGN_CONSTRUCT : Code.CODE_CONSTRUCT);
3279     
3280     // Run its initializer.
3281     emitShortArg(&methodCompiler, cast(Code)(Code.CODE_CALL_0 + signature.arity),
3282                 initializerSymbol);
3283     
3284     // Return the instance.
3285     emitOp(&methodCompiler, Code.CODE_RETURN);
3286     
3287     endCompiler(&methodCompiler, "", 0);
3288 }
3289 
3290 // Loads the enclosing class onto the stack and then binds the function already
3291 // on the stack as a method on that class.
3292 static void defineMethod(Compiler* compiler, Variable classVariable,
3293                          bool isStatic, int methodSymbol)
3294 {
3295     // Load the class. We have to do this for each method because we can't
3296     // keep the class on top of the stack. If there are static fields, they
3297     // will be locals above the initial variable slot for the class on the
3298     // stack. To skip past those, we just load the class each time right before
3299     // defining a method.
3300     loadVariable(compiler, classVariable);
3301 
3302     // Define the method.
3303     Code instruction = isStatic ? Code.CODE_METHOD_STATIC : Code.CODE_METHOD_INSTANCE;
3304     emitShortArg(compiler, instruction, methodSymbol);
3305 }
3306 
3307 // Declares a method in the enclosing class with [signature].
3308 //
3309 // Reports an error if a method with that signature is already declared.
3310 // Returns the symbol for the method.
3311 static int declareMethod(Compiler* compiler, Signature* signature,
3312                          const(char)* name, int length)
3313 {
3314     int symbol = signatureSymbol(compiler, signature);
3315     
3316     // See if the class has already declared method with this signature.
3317     ClassInfo* classInfo = compiler.enclosingClass;
3318     IntBuffer* methods = classInfo.inStatic
3319         ? &classInfo.staticMethods : &classInfo.methods;
3320     for (int i = 0; i < methods.count; i++)
3321     {
3322         if (methods.data[i] == symbol)
3323         {
3324             const(char)* staticPrefix = classInfo.inStatic ? "static " : "";
3325             error(compiler, "Class %s already defines a %smethod '%s'.",
3326                     compiler.enclosingClass.name.value.ptr, staticPrefix, name);
3327             break;
3328         }
3329     }
3330     
3331     wrenIntBufferWrite(compiler.parser.vm, methods, symbol);
3332     return symbol;
3333 }
3334 
3335 static Value consumeLiteral(Compiler* compiler, const char* message) 
3336 {
3337     if(match(compiler, TokenType.TOKEN_FALSE))  return FALSE_VAL;
3338     if(match(compiler, TokenType.TOKEN_TRUE))   return TRUE_VAL;
3339     if(match(compiler, TokenType.TOKEN_NUMBER)) return compiler.parser.previous.value;
3340     if(match(compiler, TokenType.TOKEN_STRING)) return compiler.parser.previous.value;
3341     if(match(compiler, TokenType.TOKEN_NAME))   return compiler.parser.previous.value;
3342 
3343     error(compiler, message);
3344     nextToken(compiler.parser);
3345     return NULL_VAL;
3346 }
3347 
3348 static bool matchAttribute(Compiler* compiler) {
3349 
3350     if(match(compiler, TokenType.TOKEN_HASH)) 
3351     {
3352         compiler.numAttributes++;
3353         bool runtimeAccess = match(compiler, TokenType.TOKEN_BANG);
3354         if(match(compiler, TokenType.TOKEN_NAME)) 
3355         {
3356             Value group = compiler.parser.previous.value;
3357             TokenType ahead = peek(compiler);
3358             if(ahead == TokenType.TOKEN_EQ || ahead == TokenType.TOKEN_LINE)
3359             {
3360                 Value key = group;
3361                 Value value = NULL_VAL;
3362                 if(match(compiler, TokenType.TOKEN_EQ)) 
3363                 {
3364                     value = consumeLiteral(compiler, "Expect a Bool, Num, String or Identifier literal for an attribute value.");
3365                 }
3366                 if(runtimeAccess) addToAttributeGroup(compiler, NULL_VAL, key, value);
3367             }
3368             else if(match(compiler, TokenType.TOKEN_LEFT_PAREN))
3369             {
3370                 ignoreNewlines(compiler);
3371                 if(match(compiler, TokenType.TOKEN_RIGHT_PAREN))
3372                 {
3373                     error(compiler, "Expected attributes in group, group cannot be empty.");
3374                 } 
3375                 else 
3376                 {
3377                     while(peek(compiler) != TokenType.TOKEN_RIGHT_PAREN)
3378                     {
3379                         consume(compiler, TokenType.TOKEN_NAME, "Expect name for attribute key.");
3380                         Value key = compiler.parser.previous.value;
3381                         Value value = NULL_VAL;
3382                         if(match(compiler, TokenType.TOKEN_EQ))
3383                         {
3384                             value = consumeLiteral(compiler, "Expect a Bool, Num, String or Identifier literal for an attribute value.");
3385                         }
3386                         if(runtimeAccess) addToAttributeGroup(compiler, group, key, value);
3387                         ignoreNewlines(compiler);
3388                         if(!match(compiler, TokenType.TOKEN_COMMA)) break;
3389                         ignoreNewlines(compiler);
3390                     }
3391                     ignoreNewlines(compiler);
3392                     consume(compiler, TokenType.TOKEN_RIGHT_PAREN, 
3393                         "Expected ')' after grouped attributes.");
3394                 }
3395             }
3396             else
3397             {
3398                 error(compiler, "Expect an equal, newline or grouping after an attribute key.");
3399             }
3400         }
3401         else 
3402         {
3403             error(compiler, "Expect an attribute definition after #.");
3404         }
3405         consumeLine(compiler, "Expect newline after attribute.");
3406         return true;
3407     }
3408 
3409     return false;
3410 }
3411 
3412 // Compiles a method definition inside a class body.
3413 //
3414 // Returns `true` if it compiled successfully, or `false` if the method couldn't
3415 // be parsed.
3416 static bool method(Compiler* compiler, Variable classVariable)
3417 {
3418     // Parse any attributes before the method and store them
3419     if(matchAttribute(compiler)) {
3420         return method(compiler, classVariable);
3421     }
3422 
3423     // TODO: What about foreign constructors?
3424     bool isForeign = match(compiler, TokenType.TOKEN_FOREIGN);
3425     bool isStatic = match(compiler, TokenType.TOKEN_STATIC);
3426     compiler.enclosingClass.inStatic = isStatic;
3427         
3428     SignatureFn signatureFn = rules[compiler.parser.current.type].method;
3429     nextToken(compiler.parser);
3430     
3431     if (signatureFn == null)
3432     {
3433         error(compiler, "Expect method definition.");
3434         return false;
3435     }
3436     
3437     // Build the method signature.
3438     Signature signature = signatureFromToken(compiler, SignatureType.SIG_GETTER);
3439     compiler.enclosingClass.signature = &signature;
3440 
3441     Compiler methodCompiler;
3442     initCompiler(&methodCompiler, compiler.parser, compiler, true);
3443 
3444     // Compile the method signature.
3445     signatureFn(&methodCompiler, &signature);
3446 
3447     methodCompiler.isInitializer = signature.type == SignatureType.SIG_INITIALIZER;
3448     
3449     if (isStatic && signature.type == SignatureType.SIG_INITIALIZER)
3450     {
3451         error(compiler, "A constructor cannot be static.");
3452     }
3453     
3454     // Include the full signature in debug messages in stack traces.
3455     char[MAX_METHOD_SIGNATURE] fullSignature = 0;
3456     int length;
3457     signatureToString(&signature, fullSignature.ptr, &length);
3458 
3459     // Copy any attributes the compiler collected into the enclosing class 
3460     copyMethodAttributes(compiler, isForeign, isStatic, fullSignature.ptr, length);
3461 
3462     // Check for duplicate methods. Doesn't matter that it's already been
3463     // defined, error will discard bytecode anyway.
3464     // Check if the method table already contains this symbol
3465     int methodSymbol = declareMethod(compiler, &signature, fullSignature.ptr, length);
3466     
3467     if (isForeign)
3468     {
3469         // Define a constant for the signature.
3470         emitConstant(compiler, wrenNewStringLength(compiler.parser.vm,
3471                                                 fullSignature.ptr, length));
3472 
3473         // We don't need the function we started compiling in the parameter list
3474         // any more.
3475         methodCompiler.parser.vm.compiler = methodCompiler.parent;
3476     }
3477     else
3478     {
3479         consume(compiler, TokenType.TOKEN_LEFT_BRACE, "Expect '{' to begin method body.");
3480         finishBody(&methodCompiler);
3481         endCompiler(&methodCompiler, fullSignature.ptr, length);
3482     }
3483     
3484     // Define the method. For a constructor, this defines the instance
3485     // initializer method.
3486     defineMethod(compiler, classVariable, isStatic, methodSymbol);
3487 
3488     if (signature.type == SignatureType.SIG_INITIALIZER)
3489     {
3490         // Also define a matching constructor method on the metaclass.
3491         signature.type = SignatureType.SIG_METHOD;
3492         int constructorSymbol = signatureSymbol(compiler, &signature);
3493         
3494         createConstructor(compiler, &signature, methodSymbol);
3495         defineMethod(compiler, classVariable, true, constructorSymbol);
3496     }
3497 
3498     return true;
3499 }
3500 
3501 // Compiles a class definition. Assumes the "class" token has already been
3502 // consumed (along with a possibly preceding "foreign" token).
3503 static void classDefinition(Compiler* compiler, bool isForeign)
3504 {
3505     // Create a variable to store the class in.
3506     Variable classVariable;
3507     classVariable.scope_ = compiler.scopeDepth == -1 ? Scope.SCOPE_MODULE : Scope.SCOPE_LOCAL;
3508     classVariable.index = declareNamedVariable(compiler);
3509     
3510     // Create shared class name value
3511     Value classNameString = wrenNewStringLength(compiler.parser.vm,
3512         compiler.parser.previous.start, compiler.parser.previous.length);
3513     
3514     // Create class name string to track method duplicates
3515     ObjString* className = AS_STRING(classNameString);
3516     
3517     // Make a string constant for the name.
3518     emitConstant(compiler, classNameString);
3519 
3520     // Load the superclass (if there is one).
3521     if (match(compiler, TokenType.TOKEN_IS))
3522     {
3523         parsePrecedence(compiler, Precedence.PREC_CALL);
3524     }
3525     else
3526     {
3527         // Implicitly inherit from Object.
3528         loadCoreVariable(compiler, "Object");
3529     }
3530 
3531     // Store a placeholder for the number of fields argument. We don't know the
3532     // count until we've compiled all the methods to see which fields are used.
3533     int numFieldsInstruction = -1;
3534     if (isForeign)
3535     {
3536         emitOp(compiler, Code.CODE_FOREIGN_CLASS);
3537     }
3538     else
3539     {
3540         numFieldsInstruction = emitByteArg(compiler, Code.CODE_CLASS, 255);
3541     }
3542 
3543     // Store it in its name.
3544     defineVariable(compiler, classVariable.index);
3545 
3546     // Push a local variable scope. Static fields in a class body are hoisted out
3547     // into local variables declared in this scope. Methods that use them will
3548     // have upvalues referencing them.
3549     pushScope(compiler);
3550 
3551     ClassInfo classInfo;
3552     classInfo.isForeign = isForeign;
3553     classInfo.name = className;
3554 
3555     // Allocate attribute maps if necessary. 
3556     // A method will allocate the methods one if needed
3557     classInfo.classAttributes = compiler.attributes.count > 0 
3558             ? wrenNewMap(compiler.parser.vm) 
3559             : null;
3560     classInfo.methodAttributes = null;
3561     // Copy any existing attributes into the class
3562     copyAttributes(compiler, classInfo.classAttributes);
3563 
3564     // Set up a symbol table for the class's fields. We'll initially compile
3565     // them to slots starting at zero. When the method is bound to the class, the
3566     // bytecode will be adjusted by [wrenBindMethod] to take inherited fields
3567     // into account.
3568     wrenSymbolTableInit(&classInfo.fields);
3569     
3570     // Set up symbol buffers to track duplicate static and instance methods.
3571     wrenIntBufferInit(&classInfo.methods);
3572     wrenIntBufferInit(&classInfo.staticMethods);
3573     compiler.enclosingClass = &classInfo;
3574 
3575     // Compile the method definitions.
3576     consume(compiler, TokenType.TOKEN_LEFT_BRACE, "Expect '{' after class declaration.");
3577     matchLine(compiler);
3578 
3579     while (!match(compiler, TokenType.TOKEN_RIGHT_BRACE))
3580     {
3581         if (!method(compiler, classVariable)) break;
3582         
3583         // Don't require a newline after the last definition.
3584         if (match(compiler, TokenType.TOKEN_RIGHT_BRACE)) break;
3585 
3586         consumeLine(compiler, "Expect newline after definition in class.");
3587     }
3588     
3589     // If any attributes are present, 
3590     // instantiate a ClassAttributes instance for the class
3591     // and send it over to CODE_END_CLASS
3592     bool hasAttr = classInfo.classAttributes != null || 
3593                     classInfo.methodAttributes != null;
3594     if(hasAttr) {
3595         emitClassAttributes(compiler, &classInfo);
3596         loadVariable(compiler, classVariable);
3597         // At the moment, we don't have other uses for CODE_END_CLASS,
3598         // so we put it inside this condition. Later, we can always
3599         // emit it and use it as needed.
3600         emitOp(compiler, Code.CODE_END_CLASS);
3601     }
3602 
3603     // Update the class with the number of fields.
3604     if (!isForeign)
3605     {
3606         compiler.fn.code.data[numFieldsInstruction] =
3607             cast(ubyte)classInfo.fields.count;
3608     }
3609     
3610     // Clear symbol tables for tracking field and method names.
3611     wrenSymbolTableClear(compiler.parser.vm, &classInfo.fields);
3612     wrenIntBufferClear(compiler.parser.vm, &classInfo.methods);
3613     wrenIntBufferClear(compiler.parser.vm, &classInfo.staticMethods);
3614     compiler.enclosingClass = null;
3615     popScope(compiler);
3616 }
3617 
3618 // Compiles an "import" statement.
3619 //
3620 // An import compiles to a series of instructions. Given:
3621 //
3622 //     import "foo" for Bar, Baz
3623 //
3624 // We compile a single IMPORT_MODULE "foo" instruction to load the module
3625 // itself. When that finishes executing the imported module, it leaves the
3626 // ObjModule in vm.lastModule. Then, for Bar and Baz, we:
3627 //
3628 // * Declare a variable in the current scope with that name.
3629 // * Emit an IMPORT_VARIABLE instruction to load the variable's value from the
3630 //   other module.
3631 // * Compile the code to store that value in the variable in this scope.
3632 static void import_(Compiler* compiler)
3633 {
3634     ignoreNewlines(compiler);
3635     consume(compiler, TokenType.TOKEN_STRING, "Expect a string after 'import'.");
3636     int moduleConstant = addConstant(compiler, compiler.parser.previous.value);
3637 
3638     // Load the module.
3639     emitShortArg(compiler, Code.CODE_IMPORT_MODULE, moduleConstant);
3640 
3641     // Discard the unused result value from calling the module body's closure.
3642     emitOp(compiler, Code.CODE_POP);
3643     
3644     // The for clause is optional.
3645     if (!match(compiler, TokenType.TOKEN_FOR)) return;
3646 
3647     // Compile the comma-separated list of variables to import.
3648     do
3649     {
3650         ignoreNewlines(compiler);
3651         
3652         consume(compiler, TokenType.TOKEN_NAME, "Expect variable name.");
3653         
3654         // We need to hold onto the source variable, 
3655         // in order to reference it in the import later
3656         Token sourceVariableToken = compiler.parser.previous;
3657 
3658         // Define a string constant for the original variable name.
3659         int sourceVariableConstant = addConstant(compiler,
3660             wrenNewStringLength(compiler.parser.vm,
3661                             sourceVariableToken.start,
3662                             sourceVariableToken.length));
3663 
3664         // Store the symbol we care about for the variable
3665         int slot = -1;
3666         if(match(compiler, TokenType.TOKEN_AS))
3667         {
3668             //import "module" for Source as Dest
3669             //Use 'Dest' as the name by declaring a new variable for it.
3670             //This parses a name after the 'as' and defines it.
3671             slot = declareNamedVariable(compiler);
3672         }
3673         else
3674         {
3675             //import "module" for Source
3676             //Uses 'Source' as the name directly
3677             slot = declareVariable(compiler, &sourceVariableToken);
3678         }
3679 
3680         // Load the variable from the other module.
3681         emitShortArg(compiler, Code.CODE_IMPORT_VARIABLE, sourceVariableConstant);
3682 
3683         // Store the result in the variable here.
3684         defineVariable(compiler, slot);
3685     } while (match(compiler, TokenType.TOKEN_COMMA));
3686 }
3687 
3688 // Compiles a "var" variable definition statement.
3689 static void variableDefinition(Compiler* compiler)
3690 {
3691     // Grab its name, but don't declare it yet. A (local) variable shouldn't be
3692     // in scope in its own initializer.
3693     consume(compiler, TokenType.TOKEN_NAME, "Expect variable name.");
3694     Token nameToken = compiler.parser.previous;
3695 
3696     // Compile the initializer.
3697     if (match(compiler, TokenType.TOKEN_EQ))
3698     {
3699         ignoreNewlines(compiler);
3700         expression(compiler);
3701     }
3702     else
3703     {
3704         // Default initialize it to null.
3705         null_(compiler, false);
3706     }
3707 
3708     // Now put it in scope.
3709     int symbol = declareVariable(compiler, &nameToken);
3710     defineVariable(compiler, symbol);
3711 }
3712 
3713 // Compiles a "definition". These are the statements that bind new variables.
3714 // They can only appear at the top level of a block and are prohibited in places
3715 // like the non-curly body of an if or while.
3716 void definition(Compiler* compiler)
3717 {
3718     if(matchAttribute(compiler)) {
3719         definition(compiler);
3720         return;
3721     }
3722 
3723     if (match(compiler, TokenType.TOKEN_CLASS))
3724     {
3725         classDefinition(compiler, false);
3726         return;
3727     }
3728     else if (match(compiler, TokenType.TOKEN_FOREIGN))
3729     {
3730         consume(compiler, TokenType.TOKEN_CLASS, "Expect 'class' after 'foreign'.");
3731         classDefinition(compiler, true);
3732         return;
3733     }
3734 
3735     disallowAttributes(compiler);
3736 
3737     if (match(compiler, TokenType.TOKEN_IMPORT))
3738     {
3739         import_(compiler);
3740     }
3741     else if (match(compiler, TokenType.TOKEN_VAR))
3742     {
3743         variableDefinition(compiler);
3744     }
3745     else
3746     {
3747         statement(compiler);
3748     }
3749 }
3750 
3751 ObjFn* wrenCompile(WrenVM* vm, ObjModule* module_, const(char)* source,
3752                    bool isExpression, bool printErrors)
3753 {
3754     import core.stdc.string : strncmp;
3755     // Skip the UTF-8 BOM if there is one.
3756     if (strncmp(source, "\xEF\xBB\xBF", 3) == 0) source += 3;
3757     
3758     Parser parser;
3759     parser.vm = vm;
3760     parser.module_ = module_;
3761     parser.source = source;
3762 
3763     parser.tokenStart = source;
3764     parser.currentChar = source;
3765     parser.currentLine = 1;
3766     parser.numParens = 0;
3767 
3768     // Zero-init the current token. This will get copied to previous when
3769     // nextToken() is called below.
3770     parser.next.type = TokenType.TOKEN_ERROR;
3771     parser.next.start = source;
3772     parser.next.length = 0;
3773     parser.next.line = 0;
3774     parser.next.value = UNDEFINED_VAL;
3775 
3776     parser.printErrors = printErrors;
3777     parser.hasError = false;
3778 
3779     // Read the first token into next
3780     nextToken(&parser);
3781     // Copy next . current
3782     nextToken(&parser);
3783 
3784     int numExistingVariables = module_.variables.count;
3785 
3786     Compiler compiler;
3787     initCompiler(&compiler, &parser, null, false);
3788     ignoreNewlines(&compiler);
3789 
3790     if (isExpression)
3791     {
3792         expression(&compiler);
3793         consume(&compiler, TokenType.TOKEN_EOF, "Expect end of expression.");
3794     }
3795     else
3796     {
3797         while (!match(&compiler, TokenType.TOKEN_EOF))
3798         {
3799             definition(&compiler);
3800             
3801             // If there is no newline, it must be the end of file on the same line.
3802             if (!matchLine(&compiler))
3803             {
3804                 consume(&compiler, TokenType.TOKEN_EOF, "Expect end of file.");
3805                 break;
3806             }
3807         }
3808         
3809         emitOp(&compiler, Code.CODE_END_MODULE);
3810     }
3811     
3812     emitOp(&compiler, Code.CODE_RETURN);
3813 
3814     // See if there are any implicitly declared module-level variables that never
3815     // got an explicit definition. They will have values that are numbers
3816     // indicating the line where the variable was first used.
3817     for (int i = numExistingVariables; i < parser.module_.variables.count; i++)
3818     {
3819         if (IS_NUM(parser.module_.variables.data[i]))
3820         {
3821             // Synthesize a token for the original use site.
3822             parser.previous.type = TokenType.TOKEN_NAME;
3823             parser.previous.start = parser.module_.variableNames.data[i].value.ptr;
3824             parser.previous.length = parser.module_.variableNames.data[i].length;
3825             parser.previous.line = cast(int)AS_NUM(parser.module_.variables.data[i]);
3826             error(&compiler, "Variable is used but not defined.");
3827         }
3828     }
3829     
3830     return endCompiler(&compiler, "(script)", 8);
3831 }
3832 
3833 void wrenBindMethodCode(ObjClass* classObj, ObjFn* fn)
3834 {
3835     int ip = 0;
3836     for (;;)
3837     {
3838         Code instruction = cast(Code)fn.code.data[ip];
3839         switch (instruction) with(Code)
3840         {
3841         case CODE_LOAD_FIELD:
3842         case CODE_STORE_FIELD:
3843         case CODE_LOAD_FIELD_THIS:
3844         case CODE_STORE_FIELD_THIS:
3845             // Shift this class's fields down past the inherited ones. We don't
3846             // check for overflow here because we'll see if the number of fields
3847             // overflows when the subclass is created.
3848             fn.code.data[ip + 1] += classObj.superclass.numFields;
3849             break;
3850 
3851         case CODE_SUPER_0:
3852         case CODE_SUPER_1:
3853         case CODE_SUPER_2:
3854         case CODE_SUPER_3:
3855         case CODE_SUPER_4:
3856         case CODE_SUPER_5:
3857         case CODE_SUPER_6:
3858         case CODE_SUPER_7:
3859         case CODE_SUPER_8:
3860         case CODE_SUPER_9:
3861         case CODE_SUPER_10:
3862         case CODE_SUPER_11:
3863         case CODE_SUPER_12:
3864         case CODE_SUPER_13:
3865         case CODE_SUPER_14:
3866         case CODE_SUPER_15:
3867         case CODE_SUPER_16:
3868         {
3869             // Fill in the constant slot with a reference to the superclass.
3870             int constant = (fn.code.data[ip + 3] << 8) | fn.code.data[ip + 4];
3871             fn.constants.data[constant] = OBJ_VAL(classObj.superclass);
3872             break;
3873         }
3874 
3875         case CODE_CLOSURE:
3876         {
3877             // Bind the nested closure too.
3878             int constant = (fn.code.data[ip + 1] << 8) | fn.code.data[ip + 2];
3879             wrenBindMethodCode(classObj, AS_FN(fn.constants.data[constant]));
3880             break;
3881         }
3882 
3883         case CODE_END:
3884             return;
3885 
3886         default:
3887             // Other instructions are unaffected, so just skip over them.
3888             break;
3889         }
3890         ip += 1 + getByteCountForArguments(fn.code.data, fn.constants.data, ip);
3891     }
3892 }
3893 
3894 void wrenMarkCompiler(WrenVM* vm, Compiler* compiler)
3895 {
3896     wrenGrayValue(vm, compiler.parser.current.value);
3897     wrenGrayValue(vm, compiler.parser.previous.value);
3898     wrenGrayValue(vm, compiler.parser.next.value);
3899 
3900     // Walk up the parent chain to mark the outer compilers too. The VM only
3901     // tracks the innermost one.
3902     do
3903     {
3904         wrenGrayObj(vm, cast(Obj*)compiler.fn);
3905         wrenGrayObj(vm, cast(Obj*)compiler.constants);
3906         wrenGrayObj(vm, cast(Obj*)compiler.attributes);
3907         
3908         if (compiler.enclosingClass != null)
3909         {
3910         wrenBlackenSymbolTable(vm, &compiler.enclosingClass.fields);
3911 
3912         if(compiler.enclosingClass.methodAttributes != null) 
3913         {
3914             wrenGrayObj(vm, cast(Obj*)compiler.enclosingClass.methodAttributes);
3915         }
3916         if(compiler.enclosingClass.classAttributes != null) 
3917         {
3918             wrenGrayObj(vm, cast(Obj*)compiler.enclosingClass.classAttributes);
3919         }
3920         }
3921         
3922         compiler = compiler.parent;
3923     }
3924     while (compiler != null);
3925 }
3926 
3927 // Helpers for Attributes
3928 
3929 // Throw an error if any attributes were found preceding, 
3930 // and clear the attributes so the error doesn't keep happening.
3931 static void disallowAttributes(Compiler* compiler)
3932 {
3933     if (compiler.numAttributes > 0)
3934     {
3935         error(compiler, "Attributes can only specified before a class or a method");
3936         wrenMapClear(compiler.parser.vm, compiler.attributes);
3937         compiler.numAttributes = 0;
3938     }
3939 }
3940 // Add an attribute to a given group in the compiler attribues map
3941 static void addToAttributeGroup(Compiler* compiler, 
3942                                 Value group, Value key, Value value) 
3943 {
3944     WrenVM* vm = compiler.parser.vm;
3945 
3946     if(IS_OBJ(group)) wrenPushRoot(vm, AS_OBJ(group));
3947     if(IS_OBJ(key))   wrenPushRoot(vm, AS_OBJ(key));
3948     if(IS_OBJ(value)) wrenPushRoot(vm, AS_OBJ(value));
3949 
3950     Value groupMapValue = wrenMapGet(compiler.attributes, group);
3951     if(IS_UNDEFINED(groupMapValue)) 
3952     {
3953         groupMapValue = OBJ_VAL(wrenNewMap(vm));
3954         wrenMapSet(vm, compiler.attributes, group, groupMapValue);
3955     }
3956 
3957     //we store them as a map per so we can maintain duplicate keys 
3958     //group = { key:[value, ...], }
3959     ObjMap* groupMap = AS_MAP(groupMapValue);
3960 
3961     //var keyItems = group[key]
3962     //if(!keyItems) keyItems = group[key] = [] 
3963     Value keyItemsValue = wrenMapGet(groupMap, key);
3964     if(IS_UNDEFINED(keyItemsValue)) 
3965     {
3966         keyItemsValue = OBJ_VAL(wrenNewList(vm, 0));
3967         wrenMapSet(vm, groupMap, key, keyItemsValue);
3968     }
3969 
3970     //keyItems.add(value)
3971     ObjList* keyItems = AS_LIST(keyItemsValue);
3972     wrenValueBufferWrite(vm, &keyItems.elements, value);
3973 
3974     if(IS_OBJ(group)) wrenPopRoot(vm);
3975     if(IS_OBJ(key))   wrenPopRoot(vm);
3976     if(IS_OBJ(value)) wrenPopRoot(vm);
3977 }
3978 
3979 
3980 // Emit the attributes in the give map onto the stack
3981 static void emitAttributes(Compiler* compiler, ObjMap* attributes) 
3982 {
3983     // Instantiate a new map for the attributes
3984     loadCoreVariable(compiler, "Map");
3985     callMethod(compiler, 0, "new()", 5);
3986 
3987     // The attributes are stored as group = { key:[value, value, ...] }
3988     // so our first level is the group map
3989     for(uint groupIdx = 0; groupIdx < attributes.capacity; groupIdx++)
3990     {
3991         const MapEntry* groupEntry = &attributes.entries[groupIdx];
3992         if(IS_UNDEFINED(groupEntry.key)) continue;
3993         //group key
3994         emitConstant(compiler, groupEntry.key);
3995 
3996         //group value is gonna be a map
3997         loadCoreVariable(compiler, "Map");
3998         callMethod(compiler, 0, "new()", 5);
3999 
4000         ObjMap* groupItems = AS_MAP(groupEntry.value);
4001         for(uint itemIdx = 0; itemIdx < groupItems.capacity; itemIdx++)
4002         {
4003             const MapEntry* itemEntry = &groupItems.entries[itemIdx];
4004             if(IS_UNDEFINED(itemEntry.key)) continue;
4005 
4006             emitConstant(compiler, itemEntry.key);
4007             // Attribute key value, key = []
4008             loadCoreVariable(compiler, "List");
4009             callMethod(compiler, 0, "new()", 5);
4010             // Add the items to the key list
4011             ObjList* items = AS_LIST(itemEntry.value);
4012             for(int itemIdx2 = 0; itemIdx2 < items.elements.count; ++itemIdx2)
4013             {
4014                 emitConstant(compiler, items.elements.data[itemIdx2]);
4015                 callMethod(compiler, 1, "addCore_(_)", 11);
4016             }
4017             // Add the list to the map
4018             callMethod(compiler, 2, "addCore_(_,_)", 13);
4019         }
4020 
4021         // Add the key/value to the map
4022         callMethod(compiler, 2, "addCore_(_,_)", 13);
4023     }
4024 
4025 }
4026 
4027 // Methods are stored as method <. attributes, so we have to have 
4028 // an indirection to resolve for methods
4029 static void emitAttributeMethods(Compiler* compiler, ObjMap* attributes)
4030 {
4031     // Instantiate a new map for the attributes
4032     loadCoreVariable(compiler, "Map");
4033     callMethod(compiler, 0, "new()", 5);
4034 
4035     for(uint methodIdx = 0; methodIdx < attributes.capacity; methodIdx++)
4036     {
4037         const MapEntry* methodEntry = &attributes.entries[methodIdx];
4038         if(IS_UNDEFINED(methodEntry.key)) continue;
4039         emitConstant(compiler, methodEntry.key);
4040         ObjMap* attributeMap = AS_MAP(methodEntry.value);
4041         emitAttributes(compiler, attributeMap);
4042         callMethod(compiler, 2, "addCore_(_,_)", 13);
4043     }
4044 }
4045 
4046 
4047 // Emit the final ClassAttributes that exists at runtime
4048 static void emitClassAttributes(Compiler* compiler, ClassInfo* classInfo)
4049 {
4050     loadCoreVariable(compiler, "ClassAttributes");
4051 
4052     classInfo.classAttributes 
4053         ? emitAttributes(compiler, classInfo.classAttributes) 
4054         : null_(compiler, false);
4055 
4056     classInfo.methodAttributes 
4057         ? emitAttributeMethods(compiler, classInfo.methodAttributes) 
4058         : null_(compiler, false);
4059 
4060     callMethod(compiler, 2, "new(_,_)", 8);
4061 }
4062 
4063 // Copy the current attributes stored in the compiler into a destination map
4064 // This also resets the counter, since the intent is to consume the attributes
4065 static void copyAttributes(Compiler* compiler, ObjMap* into)
4066 {
4067     compiler.numAttributes = 0;
4068 
4069     if(compiler.attributes.count == 0) return;
4070     if(into == null) return;
4071 
4072     WrenVM* vm = compiler.parser.vm;
4073     
4074     // Note we copy the actual values as is since we'll take ownership 
4075     // and clear the original map
4076     for(uint attrIdx = 0; attrIdx < compiler.attributes.capacity; attrIdx++)
4077     {
4078         const MapEntry* attrEntry = &compiler.attributes.entries[attrIdx];
4079         if(IS_UNDEFINED(attrEntry.key)) continue;
4080         wrenMapSet(vm, into, attrEntry.key, attrEntry.value);
4081     }
4082     
4083     wrenMapClear(vm, compiler.attributes);
4084 }
4085 
4086 // Copy the current attributes stored in the compiler into the method specific
4087 // attributes for the current enclosingClass.
4088 // This also resets the counter, since the intent is to consume the attributes
4089 static void copyMethodAttributes(Compiler* compiler, bool isForeign,
4090             bool isStatic, const char* fullSignature, int length) 
4091 {
4092     import core.stdc.stdio : sprintf;
4093     compiler.numAttributes = 0;
4094 
4095     if(compiler.attributes.count == 0) return;
4096 
4097     WrenVM* vm = compiler.parser.vm;
4098     
4099     // Make a map for this method to copy into
4100     ObjMap* methodAttr = wrenNewMap(vm);
4101     wrenPushRoot(vm, cast(Obj*)methodAttr);
4102     copyAttributes(compiler, methodAttr);
4103 
4104     // Include 'foreign static ' in front as needed
4105     int fullLength = length;
4106     if(isForeign) fullLength += 8;
4107     if(isStatic) fullLength += 7;
4108     char[MAX_METHOD_SIGNATURE + 8 + 7] fullSignatureWithPrefix = 0;
4109     const char* foreignPrefix = isForeign ? "foreign " : "";
4110     const char* staticPrefix = isStatic ? "static " : "";
4111     sprintf(fullSignatureWithPrefix.ptr, "%s%s%.*s", foreignPrefix, staticPrefix, 
4112                                                 length, fullSignature);
4113     fullSignatureWithPrefix[fullLength] = '\0';
4114 
4115     if(compiler.enclosingClass.methodAttributes == null) {
4116         compiler.enclosingClass.methodAttributes = wrenNewMap(vm);
4117     }
4118     
4119     // Store the method attributes in the class map
4120     Value key = wrenNewStringLength(vm, fullSignatureWithPrefix.ptr, fullLength);
4121     wrenMapSet(vm, compiler.enclosingClass.methodAttributes, key, OBJ_VAL(methodAttr));
4122 
4123     wrenPopRoot(vm);
4124 }