// 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 Boolean(Compiler c, bool allowAssignment) { c.Emit(c._parser.Previous.Type == TokenType.False ? Instruction.False : Instruction.True); }
public static ObjFn Compile(SophieVM vm, ObjModule module, string sourcePath, string source, bool printErrors) { Parser parser = new Parser { Vm = vm, Module = module, SourcePath = sourcePath, Source = source, TokenStart = 0, CurrentChar = 0, CurrentLine = 1, Current = { Type = TokenType.Error, Start = 0, Length = 0, Line = 0 }, PrintErrors = printErrors, HasError = false, Raw = "" }; Compiler compiler = new Compiler(parser, null, true); // Read the first token. compiler.NextToken(); compiler.IgnoreNewlines(); while (!compiler.Match(TokenType.Eof)) { compiler.Definition(); // If there is no newline, it must be the end of the block on the same line. if (!compiler.MatchLine()) { compiler.Consume(TokenType.Eof, "Expect end of file."); break; } } compiler.Emit(Instruction.Null); compiler.Emit(Instruction.Return); // See if there are any implicitly declared module-level variables that never // got an explicit definition. // TODO: It would be nice if the error was on the line where it was used. for (int i = 0; i < parser.Module.Variables.Count; i++) { ModuleVariable t = parser.Module.Variables[i]; if (t.Container == Obj.Undefined) { compiler.Error(string.Format("Variable '{0}' is used but not defined.", t.Name)); } } return compiler.EndCompiler(); }
private static void Number(Compiler c, bool allowAssignment) { if (c._parser.Number == 0.0) { c.Emit(Instruction.Zero); return; } if (c._parser.Number == 1.0) { c.Emit(Instruction.One); return; } int constant = c.AddConstant(new Obj(c._parser.Number)); // Compile the code to load the constant. c.EmitConstant(constant); }
private static void null_(Compiler c, bool allowAssignment) { c.Emit(Instruction.Null); }