public static VM_t New(compiler.Bytecode bytecode) { Object.CompiledFunction mainFn = new Object.CompiledFunction { Instructions = bytecode.Instructions }; Object.Closure mainClosure = new Object.Closure { Fn = mainFn }; Frame_t mainFrame = Frame.NewFrame(mainClosure, 0); Frame_t[] frames = new Frame_t[MaxFrames]; frames[0] = mainFrame; return(new VM_t { constants = bytecode.Constants, stack = new List <Object.Object>(new Object.Object[StackSize]), sp = 0, globals = new List <Object.Object>(new Object.Object[GlobalSize]), frames = frames, frameIndex = 1, }); }
static error pushClosure(int constIndex, int numFree) { Object.Object constant = vm.constants[constIndex]; if (!(constant is Object.CompiledFunction)) { return(string.Format("not a function {0}", constant.ToString())); } Object.CompiledFunction function = (Object.CompiledFunction)constant; List <Object.Object> free = new List <Object.Object>(new Object.Object[numFree]); for (int i = 0; i < numFree; i++) { free[i] = vm.stack[vm.sp - numFree - i]; } vm.sp = vm.sp - numFree; Object.Closure closure = new Object.Closure { Fn = function, Free = free }; return(push(closure)); }
static error functionLiteral() { enterScope(); if (functionName != null && functionName != "") { symbol_table.DefineFunctionName(ref compiler.symbolTable, functionName); functionName = null; } if (!expectPeek(TokenType.LPAREN)) { return("expect '('"); } int paramCount = functionParameters(); // parameters if (paramCount < 0) { return("error parsing parameters"); } if (!expectPeek(TokenType.LBRACE)) { return("expect '{'"); } error err = blockStatement(); // function body if (err != null) { return(err); } if (lastInstructionIs(Opcode.OpPop)) { replaceLastPopWithReturn(); } if (!lastInstructionIs(Opcode.OpReturnValue)) { /* * alternate implicit null return * will require 2 VM "cycles" * emit(Opcode.OpNull); * emit(Opcode.OpReturnValue); */ emit(Opcode.OpReturn); } List <symbol_table.Symbol> freeSymbols = compiler.symbolTable.FreeSymbols; int numLocals = compiler.symbolTable.numDefinitions; Instructions instructions = leaveScope(); foreach (symbol_table.Symbol s in freeSymbols) { loadSymbols(s); } Object.CompiledFunction compiledFn = new Object.CompiledFunction { Instructions = instructions, NumLocals = numLocals, NumParameters = paramCount, }; int fnIndex = addConstant(compiledFn); if (fnIndex < 0) { return("error parsing parameters"); } emit(Opcode.OpClosure, fnIndex, freeSymbols.Count); return(null); }
public static error Compile(ast.Node node) { if (node is ast.Program) { foreach (ast.Statement s in ((ast.Program)node).Statements) { error err = Compile(s); if (err != null) { return(err); } } return(null); } if (node is ast.ExpressionStatement) { error err = Compile(((ast.ExpressionStatement)node).Expression); if (err != null) { return(err); } emit(code.OpPop); return(null); } if (node is ast.InfixExpression) { ast.InfixExpression _node = (ast.InfixExpression)node; error err; if (_node.Operator == "<") { err = Compile(_node.Right); if (err != null) { return(err); } err = Compile(_node.Left); if (err != null) { return(err); } emit(code.OpGreaterThan); return(null); } err = Compile(_node.Left); if (err != null) { return(err); } err = Compile(_node.Right); if (err != null) { return(err); } switch (_node.Operator) { case "+": emit(code.OpAdd); break; case "-": emit(code.OpSub); break; case "*": emit(code.OpMul); break; case "/": emit(code.OpDiv); break; case ">": emit(code.OpGreaterThan); break; case "==": emit(code.OpEqual); break; case "!=": emit(code.OpNotEqual); break; default: return(string.Format("unknown operator {0}", _node.Operator)); } return(null); } if (node is ast.IntegerLiteral) { Object.Integer integer = new Object.Integer { Value = ((ast.IntegerLiteral)node).Value }; emit(code.OpConstant, (Opcode)addConstant(integer)); return(null); } if (node is ast.Boolean) { if (((ast.Boolean)node).Value) { emit(code.OpTrue); } else { emit(code.OpFalse); } return(null); } if (node is ast.PrefixExpression) { ast.PrefixExpression _node = (ast.PrefixExpression)node; error err = Compile(_node.Right); if (err != null) { return(err); } switch (_node.Operator) { case "!": emit(code.OpBang); break; case "-": emit(code.OpMinus); break; default: return(string.Format("unknown operator {0}", _node.Operator)); } return(null); } if (node is ast.IfExpression) { ast.IfExpression _node = (ast.IfExpression)node; error err = Compile(_node.Condition); if (err != null) { return(err); } //Emit an 'OpJumpNotTruthy' with bogus value int jumpNotTruthyPos = emit(code.OpJumpNotTruthy, 9999); err = Compile(_node.Consequence); if (err != null) { return(err); } if (lastInstructionIs(code.OpPop)) { removeLastPop(); } // Emit an 'OpJump' with a bogus value int jumpPos = emit(code.OpJump, 9999); int afterConsequencePos = currentInstructions().Count; changeOperand(jumpNotTruthyPos, afterConsequencePos); if (_node.Alternative == null) { emit(code.OpNull); } else { err = Compile(_node.Alternative); if (err != null) { return(err); } if (lastInstructionIs(code.OpPop)) { removeLastPop(); } } int afterAlternativePos = currentInstructions().Count; changeOperand(jumpPos, afterAlternativePos); return(null); } if (node is ast.BlockStatement) { foreach (ast.Statement s in ((ast.BlockStatement)node).Statements) { error err = Compile(s); if (err != null) { return(err); } } return(null); } if (node is ast.LetStatement) { ast.LetStatement _node = (ast.LetStatement)node; symbol_table.Symbol symbol = symbol_table.Define(ref c.symbolTable, _node.Name.Value); error err = Compile(_node.Value); if (err != null) { return(err); } if (symbol.Scope == symbol_table.GlobalScope) { emit(code.OpSetGlobal, symbol.Index); } else { emit(code.OpSetLocal, symbol.Index); } return(null); } if (node is ast.Identifier) { ast.Identifier _node = (ast.Identifier)node; symbol_table.Symbol symbol = symbol_table.Resolve(ref c.symbolTable, _node.Value); if (symbol == null) { return(string.Format("undefined variable {0}", _node.Value)); } loadSymbols(symbol); return(null); } if (node is ast.StringLiteral) { ast.StringLiteral _node = (ast.StringLiteral)node; Object.String str = new Object.String { Value = _node.Value }; emit(code.OpConstant, addConstant(str)); return(null); } if (node is ast.ArrayLiteral) { ast.ArrayLiteral _node = (ast.ArrayLiteral)node; foreach (ast.Expression el in _node.Elements) { error err = Compile(el); if (err != null) { return(err); } } emit(code.OpArray, _node.Elements.Count); return(null); } if (node is ast.HashLiteral) { ast.HashLiteral _node = (ast.HashLiteral)node; // the sorting is not strictly needed and was only done to pass the test // since the test assumes a specific order for the keys foreach (KeyValuePair <Expression, Expression> k in _node.Pairs) { error err = Compile(k.Key); if (err != null) { return(err); } err = Compile(_node.Pairs[k.Key]); if (err != null) { return(err); } } emit(code.OpHash, _node.Pairs.Count * 2); return(null); } if (node is ast.IndexExpression) { ast.IndexExpression _node = (ast.IndexExpression)node; error err = Compile(_node.Left); if (err != null) { return(err); } err = Compile(_node.Index); if (err != null) { return(err); } emit(code.OpIndex); return(null); } if (node is ast.FunctionLiteral) { ast.FunctionLiteral _node = (ast.FunctionLiteral)node; enterScope(); if (_node.Name != null && _node.Name != "") { symbol_table.DefineFunctionName(ref c.symbolTable, _node.Name); } foreach (ast.Identifier p in _node.Parameters) { symbol_table.Define(ref c.symbolTable, p.Value); } error err = Compile(_node.Body); if (err != null) { return(err); } if (lastInstructionIs(code.OpPop)) { replaceLastPopWithReturn(); } if (!lastInstructionIs(code.OpReturnValue)) { emit(code.OpReturn); } List <symbol_table.Symbol> freeSymbols = c.symbolTable.FreeSymbols; int numLocals = c.symbolTable.numDefinitions; Instructions instructions = leaveScope(); foreach (symbol_table.Symbol s in freeSymbols) { loadSymbols(s); } Object.CompiledFunction compiledFn = new Object.CompiledFunction { Instructions = instructions, NumLocals = numLocals, NumParameters = _node.Parameters.Count, }; int fnIndex = addConstant(compiledFn); emit(code.OpClosure, fnIndex, freeSymbols.Count); return(null); } if (node is ast.ReturnStatement) { ast.ReturnStatement _node = (ast.ReturnStatement)node; error err = Compile(_node.ReturnValue); if (err != null) { return(err); } emit(code.OpReturnValue); return(null); } if (node is ast.CallExpression) { ast.CallExpression _node = (ast.CallExpression)node; error err = Compile(_node.Function); if (err != null) { return(err); } foreach (Expression a in _node.Arguments) { err = Compile(a); if (err != null) { return(err); } } emit(code.OpCall, _node.Arguments.Count); return(null); } return(null); }