// Compiles an (optional) argument list and then calls it. private void MethodCall(Instruction instruction, string name, int length) { Signature signature = new Signature { Type = SignatureType.Getter, Arity = 0, Name = name, Length = length }; // Parse the argument list, if any. if (Match(TokenType.LeftParen)) { signature.Type = SignatureType.Method; // Allow empty an argument list. if (Peek() != TokenType.RightParen) { FinishArgumentList(signature); } Consume(TokenType.RightParen, "Expect ')' after arguments."); } // Parse the block argument, if any. if (Match(TokenType.LeftBrace)) { // Include the block argument in the arity. signature.Type = SignatureType.Method; signature.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); // TODO: Use the name of the method the block is being provided to. fnCompiler.EndCompiler(); } // TODO: Allow Grace-style mixfix methods? CallSignature(instruction, signature); }
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(); }
// Compiles a method definition inside a class body. Returns the symbol in the // method table for the new method. private int Method(ClassCompiler classCompiler, bool isConstructor, SignatureFn signatureFn) { // Build the method signature. Signature signature = new Signature(); SignatureFromToken(signature); classCompiler.MethodName = signature.Name; classCompiler.MethodLength = signature.Length; Compiler methodCompiler = new Compiler(_parser, this, false); // Compile the method signature. signatureFn(methodCompiler, signature); // Include the full signature in debug messages in stack traces. Consume(TokenType.LeftBrace, "Expect '{' to begin method body."); methodCompiler.FinishBody(isConstructor); methodCompiler.EndCompiler(); return SignatureSymbol(signature); }