public static ObjFn Compile(WrenVM 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 }, SkipNewlines = true, 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("(script)"); }
private void CreateConstructor(Signature signature, int initializerSymbol) { Compiler methodCompiler = new Compiler(_parser, this, false); methodCompiler.Emit(_enclosingClass.IsForeign ? Instruction.FOREIGN_CONSTRUCT : Instruction.CONSTRUCT); methodCompiler.EmitShortArg(Instruction.CALL_0 + signature.Arity, initializerSymbol); methodCompiler.Emit(Instruction.RETURN); methodCompiler.EndCompiler(""); }
// Compiles a method definition inside a class body. Returns the symbol in the // method table for the new method. private bool Method(ClassCompiler classCompiler, int classSlot) { bool isForeign = Match(TokenType.Foreign); classCompiler.IsStaticMethod = Match(TokenType.Static); SignatureFn signatureFn = GetRule(_parser.Current.Type).Method; NextToken(); if (signatureFn == null) { Error("Expect method definition."); return false; } // Build the method signature. Signature signature = SignatureFromToken(new Signature(), SignatureType.Getter); classCompiler.Signature = signature; Compiler methodCompiler = new Compiler(_parser, this, false); signatureFn(methodCompiler, signature); if (classCompiler.IsStaticMethod && signature.Type == SignatureType.Initializer) { Error("A constructor cannot be static."); } String fullSignature = SignatureToString(signature); if (isForeign) { int constant = AddConstant(Obj.MakeString(fullSignature)); EmitShortArg(Instruction.CONSTANT, constant); } else { Consume(TokenType.LeftBrace, "Expect '{' to begin method body."); methodCompiler.FinishBody(signature.Type == SignatureType.Initializer); methodCompiler.EndCompiler(fullSignature); } // Define the method. For a constructor, this defines the instance // initializer method. int methodSymbol = SignatureSymbol(signature); DefineMethod(classSlot, classCompiler.IsStaticMethod, methodSymbol); if (signature.Type == SignatureType.Initializer) { signature.Type = SignatureType.Method; int constructorSymbol = SignatureSymbol(signature); CreateConstructor(signature, methodSymbol); DefineMethod(classSlot, true, constructorSymbol); } return true; }
// Compiles an (optional) argument list and then calls it. private void MethodCall(Instruction instruction, Signature signature) { Signature called = new Signature { Type = SignatureType.Getter, Arity = 0, Name = signature.Name, Length = signature.Length }; // Parse the argument list, if any. if (Match(TokenType.LeftParen)) { called.Type = SignatureType.Method; // Allow empty an argument list. if (Peek() != TokenType.RightParen) { FinishArgumentList(called); } Consume(TokenType.RightParen, "Expect ')' after arguments."); } // Parse the block argument, if any. if (Match(TokenType.LeftBrace)) { // Include the block argument in the arity. called.Type = SignatureType.Method; called.Arity++; Compiler fnCompiler = new Compiler(_parser, this, true); // Make a dummy signature to track the arity. Signature fnSignature = new Signature { Arity = 0 }; // Parse the parameter list, if any. if (Match(TokenType.Pipe)) { fnCompiler.FinishParameterList(fnSignature); Consume(TokenType.Pipe, "Expect '|' after function parameters."); } fnCompiler._numParams = fnSignature.Arity; fnCompiler.FinishBody(false); String blockName = SignatureToString(called) + " block argument"; fnCompiler.EndCompiler(blockName); } // TODO: Allow Grace-style mixfix methods? // If this is a super() call for an initializer, make sure we got an actual // argument list. if (signature.Type == SignatureType.Initializer) { if (called.Type != SignatureType.Method) { Error("A superclass constructor must have an argument list."); } called.Type = SignatureType.Initializer; } CallSignature(instruction, called); }
// Compiles a method definition inside a class body. Returns the symbol in the // method table for the new method. private bool Method(ClassCompiler classCompiler, int classSlot, out bool hasConstructor) { hasConstructor = false; bool isForeign = Match(TokenType.TOKEN_FOREIGN); classCompiler.isStaticMethod = Match(TokenType.TOKEN_STATIC); SignatureFn signatureFn = GetRule(parser.current.type).method; NextToken(); if (signatureFn == null) { Error("Expect method definition."); return false; } // Build the method signature. Signature signature = SignatureFromToken(SignatureType.SIG_GETTER); classCompiler.signature = signature; Compiler methodCompiler = new Compiler(parser, this, false); signatureFn(methodCompiler, signature); if (classCompiler.isStaticMethod && signature.Type == SignatureType.SIG_INITIALIZER) { Error("A constructor cannot be static."); } String fullSignature = SignatureToString(signature); if (isForeign) { int constant = AddConstant(new Value(fullSignature)); EmitShortArg(Instruction.CONSTANT, constant); } else { Consume(TokenType.TOKEN_LEFT_BRACE, "Expect '{' to begin method body."); methodCompiler.FinishBody(signature.Type == SignatureType.SIG_INITIALIZER); methodCompiler.EndCompiler(fullSignature); } // Define the method. For a constructor, this defines the instance // initializer method. int methodSymbol = SignatureSymbol(signature); DefineMethod(classSlot, classCompiler.isStaticMethod, methodSymbol); if (signature.Type == SignatureType.SIG_INITIALIZER) { signature.Type = SignatureType.SIG_METHOD; int constructorSymbol = SignatureSymbol(signature); CreateConstructor(signature, methodSymbol); DefineMethod(classSlot, true, constructorSymbol); hasConstructor = true; } return true; }
// Compiles an (optional) argument list and then calls it. private void MethodCall(Instruction instruction, Signature signature) { Signature called = new Signature { Type = SignatureType.SIG_GETTER, Arity = 0, Name = signature.Name, Length = signature.Length }; // Parse the argument list, if any. if (Match(TokenType.TOKEN_LEFT_PAREN)) { called.Type = SignatureType.SIG_METHOD; // Allow empty an argument list. if (Peek() != TokenType.TOKEN_RIGHT_PAREN) { FinishArgumentList(called); } Consume(TokenType.TOKEN_RIGHT_PAREN, "Expect ')' after arguments."); } // Parse the block argument, if any. if (Match(TokenType.TOKEN_LEFT_BRACE)) { // Include the block argument in the arity. called.Type = SignatureType.SIG_METHOD; called.Arity++; Compiler fnCompiler = new Compiler(parser, this, true); // Make a dummy signature to track the arity. Signature fnSignature = new Signature { Arity = 0 }; // Parse the parameter list, if any. if (Match(TokenType.TOKEN_PIPE)) { fnCompiler.FinishParameterList(fnSignature); Consume(TokenType.TOKEN_PIPE, "Expect '|' after function parameters."); } fnCompiler.numParams = fnSignature.Arity; fnCompiler.FinishBody(false); String blockName = SignatureToString(called) + " block argument"; fnCompiler.EndCompiler(blockName); } // TODO: Allow Grace-style mixfix methods? // If this is a super() call for an initializer, make sure we got an actual // argument list. if (signature.Type == SignatureType.SIG_INITIALIZER) { if (called.Type != SignatureType.SIG_METHOD) { Error("A superclass constructor must have an argument list."); } called.Type = SignatureType.SIG_INITIALIZER; } CallSignature(instruction, called); }