Created
January 23, 2023 08:45
-
-
Save MarioAriasC/b1717ed42f4866cf82ddb547758de57e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function evaluateNode(node, env) { | |
if (node instanceof Identifier) { | |
const value = env.get(node.value); | |
if (value === null) { | |
const builtin = builtins.get(node.value); | |
if (builtin !== undefined) { | |
return builtin; | |
} | |
return new MError(`identifier not found: ${node.value}`); | |
} | |
return value; | |
} | |
if (node instanceof IntegerLiteral) { | |
return new MInteger(node.value); | |
} | |
if (node instanceof InfixExpression) { | |
return ifNotError(evaluateNode(node.left, env), (left) => { | |
return ifNotError(evaluateNode(node.right, env), (right) => { | |
return evalInfixExpression(node.operator, left, right); | |
}); | |
}); | |
} | |
if (node instanceof BlockStatement) { | |
return evalBlockStatement(node, env); | |
} | |
if (node instanceof ExpressionStatement) { | |
return evaluateNode(node.expression, env); | |
} | |
if (node instanceof IfExpression) { | |
function isTruthy(condition) { | |
if (condition === NULL) { | |
return false; | |
} | |
if (condition === TRUE) { | |
return true; | |
} | |
return condition !== FALSE; | |
} | |
return ifNotError(evaluateNode(node.condition, env), (condition) => { | |
if (isTruthy(condition)) { | |
return evaluateNode(node.consequence, env); | |
} | |
if (node.alternative !== null) { | |
return evalBlockStatement(node.alternative, env); | |
} | |
return NULL; | |
}); | |
} | |
if (node instanceof CallExpression) { | |
return ifNotError(evaluateNode(node.fun, env), (fun) => { | |
const args = evalExpressions(node.args, env); | |
if (args.length === 1 && isError(args[0])) { | |
return args[0]; | |
} | |
return applyFunction(fun, args); | |
}); | |
} | |
if (node instanceof ReturnStatement) { | |
return ifNotError(evaluateNode(node.returnValue, env), (value) => { | |
return new MReturnValue(value); | |
}); | |
} | |
if (node instanceof PrefixExpression) { | |
return ifNotError(evaluateNode(node.right, env), (right) => { | |
switch (node.operator) { | |
case '!': | |
return evalBangOperatorExpression(right); | |
case '-': | |
return evalMinusPrefixOperatorExpression(right); | |
default: | |
return new MError(`Unknown operator: ${node.operator}${typeDesc(right)}`); | |
} | |
}); | |
} | |
if (node instanceof BooleanLiteral) { | |
return toMonkey(node.value); | |
} | |
if (node instanceof LetStatement) { | |
return ifNotError(evaluateNode(node.value, env), (value) => { | |
return env.put(node.name.value, value); | |
}); | |
} | |
if (node instanceof FunctionLiteral) { | |
return new MFunction(node.parameters, node.body, env); | |
} | |
if (node instanceof StringLiteral) { | |
return new MString(node.value); | |
} | |
if (node instanceof IndexExpression) { | |
const left = evaluateNode(node.left, env); | |
if (isError(left)) { | |
return left; | |
} | |
const index = evaluateNode(node.index, env); | |
if (isError(index)) { | |
return index; | |
} | |
if (left instanceof MArray && index instanceof MInteger) { | |
return evalArrayIndexExpression(left, index); | |
} | |
if (left instanceof MHash) { | |
return evalHashIndexExpression(left, index); | |
} | |
return new MError(`index operator not supported: ${typeDesc(left)}`); | |
} | |
if (node instanceof HashLiteral) { | |
const pairs = new Map(); | |
for (const [keyNode, valueNode] of node.pairs) { | |
const key = evaluateNode(keyNode, env); | |
if (isError(key)) { | |
return key; | |
} | |
if (key instanceof MValue) { | |
const value = evaluateNode(valueNode, env); | |
if (isError(value)) { | |
return value; | |
} | |
pairs.set(key.hashKey(), new HashPair(key, value)); | |
} | |
else { | |
return new MError(`unusable as hash key: ${typeDesc(key)}`); | |
} | |
} | |
return new MHash(pairs); | |
} | |
if (node instanceof ArrayLiteral) { | |
const elements = evalExpressions(node.elements, env); | |
if (elements.length == 1 && isError(elements[0])) { | |
return elements[0]; | |
} | |
return new MArray(elements); | |
} | |
throw new Error(`${node?.toString()} => ${node?.constructor.name}`); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment