// A map literal. private static void Map(Compiler c, bool allowAssignment) { // Load the Map class. int mapClassSymbol = c._parser.Module.Variables.FindIndex(v => v.Name == "Map"); c.EmitShortArg(Instruction.LoadModuleVar, mapClassSymbol); // Instantiate a new map. c.CallMethod(0, "<instantiate>"); // Compile the map elements. Each one is compiled to just invoke the // subscript setter on the map. if (c.Peek() != TokenType.RightBrace) { do { c.IgnoreNewlines(); // Push a copy of the map since the subscript call will consume it. c.Emit(Instruction.Dup); // The key. c.ParsePrecedence(false, Precedence.Primary); c.Consume(TokenType.Colon, "Expect ':' after map key."); // The value. c.Expression(); c.CallMethod(2, "[_]=(_)"); // Discard the result of the setter call. c.Emit(Instruction.Pop); } while (c.Match(TokenType.Comma)); } // Allow newlines before the closing '}'. c.IgnoreNewlines(); c.Consume(TokenType.RightBrace, "Expect '}' after map entries."); }
// A list literal. private static void List(Compiler c, bool allowAssignment) { // Load the List class. int listClassSymbol = c._parser.Module.Variables.FindIndex(v => v.Name == "List"); //ASSERT(listClassSymbol != -1, "Should have already defined 'List' variable."); c.EmitShortArg(Instruction.LoadModuleVar, listClassSymbol); // Instantiate a new list. c.CallMethod(0, "<instantiate>"); // Compile the list elements. Each one compiles to a ".add()" call. if (c.Peek() != TokenType.RightBracket) { do { c.IgnoreNewlines(); // Push a copy of the list since the add() call will consume it. c.Emit(Instruction.Dup); // The element. c.Expression(); c.CallMethod(1, "add(_)"); // Discard the result of the add() call. c.Emit(Instruction.Pop); } while (c.Match(TokenType.Comma)); } // Allow newlines before the closing ']'. c.IgnoreNewlines(); c.Consume(TokenType.RightBracket, "Expect ']' after list elements."); }
private static void Field(Compiler c, bool allowAssignment) { // Initialize it with a fake value so we can keep parsing and minimize the // number of cascaded errors. int field = 255; ClassCompiler enclosingClass = c.GetEnclosingClass(); if (enclosingClass == null) { c.Error("Cannot reference a field outside of a class definition."); } else if (enclosingClass.IsStaticMethod) { c.Error("Cannot use an instance field in a static method."); } else { // Look up the field, or implicitly define it. string fieldName = c._parser.Source.Substring(c._parser.Previous.Start, c._parser.Previous.Length); field = enclosingClass.Fields.IndexOf(fieldName); if (field < 0) { enclosingClass.Fields.Add(fieldName); field = enclosingClass.Fields.IndexOf(fieldName); } if (field >= MaxFields) { c.Error(string.Format("A class can only have {0} fields.", MaxFields)); } } // If there's an "=" after a field name, it's an assignment. bool isLoad = true; if (c.Match(TokenType.Eq)) { if (!allowAssignment) c.Error("Invalid assignment."); // Compile the right-hand side. c.Expression(); isLoad = false; } // If we're directly inside a method, use a more optimal instruction. if (c._parent != null && c._parent._enclosingClass == enclosingClass) { c.EmitByteArg(isLoad ? Instruction.LoadFieldThis : Instruction.StoreFieldThis, field); } else { c.LoadThis(); c.EmitByteArg(isLoad ? Instruction.LoadField : Instruction.StoreField, field); } }
// A parenthesized expression. private static void Grouping(Compiler c, bool allowAssignment) { c.Expression(); c.Consume(TokenType.RightParen, "Expect ')' after expression."); }
// Subscript or "array indexing" operator like `foo[bar]`. private static void Subscript(Compiler c, bool allowAssignment) { Signature signature = new Signature { Name = "", Length = 0, Type = SignatureType.Subscript, Arity = 0 }; // Parse the argument list. c.FinishArgumentList(signature); c.Consume(TokenType.RightBracket, "Expect ']' after arguments."); if (c.Match(TokenType.Eq)) { if (!allowAssignment) c.Error("Invalid assignment."); signature.Type = SignatureType.SubscriptSetter; // Compile the assigned value. c.ValidateNumParameters(++signature.Arity); c.Expression(); } c.CallSignature(Instruction.Call0, signature); }