static Object.Object evalHashLiteral(ast.HashLiteral node, Object.Environment env) { Dictionary <Object.HashKey, Object.HashPair> pairs = new Dictionary <Object.HashKey, Object.HashPair>(); foreach (KeyValuePair <ast.Expression, ast.Expression> _node_pair in node.Pairs) { Object.Object key = Eval(_node_pair.Key, env); if (isError(key)) { return(key); } if (!(key is Object.Hashable)) { return(newError("unusable as hash key: {0}", key.Type())); } Object.Hashable hashKey = (Object.Hashable)key; Object.Object value = Eval(_node_pair.Value, env); if (isError(value)) { return(value); } Object.HashKey hashed = hashKey.HashKey(); pairs.Add(hashed, new Object.HashPair { Key = key, Value = value }); } return(new Object.Hash { Pairs = pairs }); }
static ast.Expression parseHashLiteral() { ast.HashLiteral hash = new ast.HashLiteral { Token = curToken }; hash.Pairs = new Dictionary <ast.Expression, ast.Expression>(); while (!peekTokenIs(token.RBRACE)) { nextToken(); ast.Expression key = parseExpression(LOWEST); if (!expectPeek(token.COLON)) { return(null); } nextToken(); ast.Expression value = parseExpression(LOWEST); hash.Pairs.Add(key, value); if (!peekTokenIs(token.RBRACE) && !expectPeek(token.COMMA)) { return(null); } } if (!expectPeek(token.RBRACE)) { return(null); } return(hash); }
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); }