private static MonkeyObject evalInfixExpression(string op, MonkeyObject left, MonkeyObject right) { if (left.Type == MonkeyObjectType.INTEGER && right.Type == MonkeyObjectType.INTEGER) { return(evalIntegerInfixExpression(op, left, right)); } if (left.Type == MonkeyObjectType.STRING && right.Type == MonkeyObjectType.STRING) { return(evalStringInfixExpression(op, left, right)); } if (op == "==") { return(nativeBoolToMonkeyBoolean(left == right)); } if (op == "!=") { return(nativeBoolToMonkeyBoolean(left != right)); } if (left.Type != right.Type) { return(new MonkeyError { Message = $"type mismatch: {left.Type} {op} {right.Type}" }); } return(new MonkeyError { Message = $"unknown operator: {left.Type} {op} {right.Type}" }); }
private static MonkeyObject unwrapReturnValue(MonkeyObject obj) { if (obj is MonkeyReturnValue rv) { return(rv.Value); } return(obj); }
private static bool IsTruthy(this MonkeyObject value) { if (value == NULL || value == FALSE) { return(false); } return(true); }
public bool Get(string name, out MonkeyObject value) { if (_store.TryGetValue(name, out value)) { return(true); } if (_outer != null) { return(_outer.Get(name, out value)); } return(false); }
private static MonkeyObject evalArrayIndexExpression(MonkeyObject array, MonkeyObject index) { var arrayObject = array as MonkeyArray; var idx = (index as MonkeyInteger).Value; var max = arrayObject.Elements.Count - 1; if (idx < 0 || idx > max) { return(NULL); } return(arrayObject.Elements[(int)idx]); }
private static MonkeyObject evalMinusPrefixOperatorExpression(MonkeyObject right) { if (right.Type != MonkeyObjectType.INTEGER) { return(new MonkeyError { Message = $"unknown operator: -{right.Type}" }); } var value = (MonkeyInteger)(right); return(new MonkeyInteger { Value = -value.Value }); }
private static MonkeyObject evalIndexExpression(MonkeyObject left, MonkeyObject index) { if (left.Type == MonkeyObjectType.ARRAY && index.Type == MonkeyObjectType.INTEGER) { return(evalArrayIndexExpression(left, index)); } if (left.Type == MonkeyObjectType.HASH) { return(evalHashIndexExpression(left, index)); } return(new MonkeyError { Message = $"index operator not supported: {left.Type}" }); }
private static MonkeyObject evalBlockStatement(BlockStatement blockStatement, Object.Environment environment) { MonkeyObject result = NULL; foreach (var statement in blockStatement.Statements) { result = Eval(statement, environment); if (result?.Type == MonkeyObjectType.RETURN_VALUE || result?.Type == MonkeyObjectType.ERROR) { return(result); } } return(result); }
private static MonkeyObject evalStringInfixExpression(string op, MonkeyObject left, MonkeyObject right) { if (op != "+") { return(new MonkeyError { Message = $"unknown operator: {left.Type} {op} {right.Type}" }); } var leftVal = (left as MonkeyString).Value; var rightVal = (right as MonkeyString).Value; return(new MonkeyString { Value = leftVal + rightVal }); }
private static MonkeyObject evalPrefixExpression(string op, MonkeyObject right) { switch (op) { case "!": return(evalBangOperatorExpression(right)); case "-": return(evalMinusPrefixOperatorExpression(right)); default: return(new MonkeyError { Message = $"unknown operator: {op}{right.Type}" }); } }
private static MonkeyObject evalIntegerInfixExpression(string op, MonkeyObject left, MonkeyObject right) { var leftVal = ((MonkeyInteger)left).Value; var rightVal = ((MonkeyInteger)right).Value; switch (op) { case "+": return(new MonkeyInteger { Value = leftVal + rightVal }); case "-": return(new MonkeyInteger { Value = leftVal - rightVal }); case "*": return(new MonkeyInteger { Value = leftVal * rightVal }); case "/": return(new MonkeyInteger { Value = leftVal / rightVal }); case "<": return(nativeBoolToMonkeyBoolean(leftVal < rightVal)); case ">": return(nativeBoolToMonkeyBoolean(leftVal > rightVal)); case "==": return(nativeBoolToMonkeyBoolean(leftVal == rightVal)); case "!=": return(nativeBoolToMonkeyBoolean(leftVal != rightVal)); default: return(new MonkeyError { Message = $"unknown operator: {left.Type} {op} {right.Type}" }); } }
private static MonkeyObject applyFunction(MonkeyObject function, IImmutableList <MonkeyObject> args) { if (function is Function fn) { var extendedEnv = extendFunctionEnv(fn, args); var evaluated = Eval(fn.Body, extendedEnv); return(unwrapReturnValue(evaluated)); } if (function is Builtin builtin) { return(builtin.Fn(args)); } return(new MonkeyError { Message = $"not a function: {function.Type}" }); }
private static MonkeyObject evalHashIndexExpression(MonkeyObject left, MonkeyObject index) { var hashObject = left as MonkeyHash; if (!(index is Hashable key)) { return(new MonkeyError { Message = $"unusable as hash key: {index.Type}" }); } if (!hashObject.Pairs.TryGetValue(key.HashKey(), out var pair)) { return(NULL); } return(pair.Value); }
private static MonkeyObject evalBangOperatorExpression(MonkeyObject right) { if (right == FALSE) { return(TRUE); } if (right == TRUE) { return(FALSE); } if (right == NULL) { return(TRUE); } return(FALSE); }
private static MonkeyObject evalProgram(Program p, Object.Environment environment) { MonkeyObject result = NULL; foreach (var statement in p.Statements) { result = Eval(statement, environment); switch (result) { case MonkeyReturnValue rv: return(rv.Value); case MonkeyError: return(result); default: break; } } return(result); }
private void TestBooleanObject(MonkeyObject evaluated, bool expected) { var b = Assert.IsType <MonkeyBoolean>(evaluated); Assert.Equal(expected, b.Value); }
private void TestIntegerObject(MonkeyObject evaluated, Int64 expected) { var result = Assert.IsType <MonkeyInteger>(evaluated); Assert.Equal(expected, result.Value); }
private void TestNullObject(MonkeyObject evaluated) { Assert.Equal(Evaluator.NULL, evaluated); }
public MonkeyObject Set(string name, MonkeyObject value) { _store.Add(name, value); return(value); }