index.js (6656B)
1 import { parse } from "../ast/parse.js"; 2 import { defaultEnv } from "../dist/env.js"; 3 import { IRuntimeError, rethrowWithFrameStack, } from "../errors/IError.js"; 4 import { REExpectedType, RENotAFunction, REOther, } from "../errors/messages.js"; 5 import { compileAst } from "../expression/compile.js"; 6 import { getStdLib } from "../library/index.js"; 7 import { ImmutableMap } from "../utility/immutableMap.js"; 8 import * as Result from "../utility/result.js"; 9 import { Ok } from "../utility/result.js"; 10 import { annotationToDomain } from "../value/domain.js"; 11 import { vArray, vDict, vDomain, vLambda, vVoid, } from "../value/index.js"; 12 import * as Context from "./context.js"; 13 import { UserDefinedLambda } from "./lambda.js"; 14 function throwFrom(error, context, ast) { 15 throw IRuntimeError.fromMessageWithFrameStack(error, context.frameStack.extend(Context.currentFunctionName(context), ast.location)); 16 } 17 export const evaluate = (expression, context) => { 18 const ast = expression.ast; 19 switch (expression.type) { 20 case "Block": 21 return evaluateBlock(expression.value, context, ast); 22 case "Program": 23 return evaluateProgram(expression.value, context, ast); 24 case "Array": 25 return evaluateArray(expression.value, context, ast); 26 case "Dict": 27 return evaluateDict(expression.value, context, ast); 28 case "Assign": 29 return evaluateAssign(expression.value, context, ast); 30 case "ResolvedSymbol": 31 return evaluateResolvedSymbol(expression.value, context, ast); 32 case "Value": 33 return evaluateValue(expression.value, context, ast); 34 case "Ternary": 35 return evaluateTernary(expression.value, context, ast); 36 case "Lambda": 37 return evaluateLambda(expression.value, context, ast); 38 case "Call": 39 return evaluateCall(expression.value, context, ast); 40 default: 41 throw new Error(`Unreachable: ${expression}`); 42 } 43 }; 44 const evaluateBlock = (statements, context) => { 45 let currentContext = context; 46 let currentValue = vVoid(); 47 for (const statement of statements) { 48 [currentValue, currentContext] = context.evaluate(statement, currentContext); 49 } 50 return [currentValue, context]; 51 }; 52 const evaluateProgram = (expressionValue, context) => { 53 let currentContext = context; 54 let currentValue = vVoid(); 55 for (const statement of expressionValue.statements) { 56 [currentValue, currentContext] = context.evaluate(statement, currentContext); 57 } 58 return [currentValue, currentContext]; 59 }; 60 const evaluateArray = (expressionValue, context) => { 61 const values = expressionValue.map((element) => { 62 const [value] = context.evaluate(element, context); 63 return value; 64 }); 65 const value = vArray(values); 66 return [value, context]; 67 }; 68 const evaluateDict = (expressionValue, context, ast) => { 69 const value = vDict(ImmutableMap(expressionValue.map(([eKey, eValue]) => { 70 const [key] = context.evaluate(eKey, context); 71 if (key.type !== "String") { 72 return throwFrom(new REOther("Dict keys must be strings"), context, ast); 73 } 74 const keyString = key.value; 75 const [value] = context.evaluate(eValue, context); 76 return [keyString, value]; 77 }))); 78 return [value, context]; 79 }; 80 const evaluateAssign = (expressionValue, context) => { 81 const [result] = context.evaluate(expressionValue.right, context); 82 return [ 83 vVoid(), 84 { 85 stack: context.stack.push(expressionValue.left, result), 86 environment: context.environment, 87 frameStack: context.frameStack, 88 evaluate: context.evaluate, 89 inFunction: context.inFunction, 90 }, 91 ]; 92 }; 93 const evaluateResolvedSymbol = (expressionValue, context) => { 94 const value = context.stack.get(expressionValue.offset); 95 return [value, context]; 96 }; 97 const evaluateValue = (expressionValue, context) => { 98 return [expressionValue, context]; 99 }; 100 const evaluateTernary = (expressionValue, context, ast) => { 101 const [predicateResult] = context.evaluate(expressionValue.condition, context); 102 if (predicateResult.type !== "Bool") { 103 return throwFrom(new REExpectedType("Boolean", predicateResult.type), context, ast); 104 } 105 const [value] = context.evaluate(predicateResult.value ? expressionValue.ifTrue : expressionValue.ifFalse, context); 106 return [value, context]; 107 }; 108 const evaluateLambda = (expressionValue, context, ast) => { 109 const parameters = []; 110 for (const parameterExpression of expressionValue.parameters) { 111 let domain; 112 if (parameterExpression.annotation) { 113 const [annotationValue] = context.evaluate(parameterExpression.annotation, context); 114 try { 115 domain = vDomain(annotationToDomain(annotationValue)); 116 } 117 catch (e) { 118 rethrowWithFrameStack(e, context.frameStack.extend(Context.currentFunctionName(context), parameterExpression.annotation.ast.location)); 119 } 120 } 121 parameters.push({ 122 name: parameterExpression.name, 123 domain, 124 }); 125 } 126 const value = vLambda(new UserDefinedLambda(expressionValue.name, parameters, context.stack, expressionValue.body, ast.location)); 127 return [value, context]; 128 }; 129 const evaluateCall = (expressionValue, context, ast) => { 130 const [lambda] = context.evaluate(expressionValue.fn, context); 131 const argValues = expressionValue.args.map((arg) => { 132 const [argValue] = context.evaluate(arg, context); 133 return argValue; 134 }); 135 switch (lambda.type) { 136 case "Lambda": { 137 const result = lambda.value.callFrom(argValues, context, ast); 138 return [result, context]; 139 } 140 default: 141 return throwFrom(new RENotAFunction(lambda.toString()), context, ast); 142 } 143 }; 144 function createDefaultContext() { 145 return Context.createContext(defaultEnv); 146 } 147 export async function evaluateExpressionToResult(expression) { 148 const context = createDefaultContext(); 149 try { 150 const [value] = context.evaluate(expression, context); 151 return Ok(value); 152 } 153 catch (e) { 154 return Result.Err(IRuntimeError.fromException(e)); 155 } 156 } 157 export async function evaluateStringToResult(code) { 158 const exprR = Result.bind(parse(code, "main"), (ast) => compileAst(ast, getStdLib())); 159 if (exprR.ok) { 160 return await evaluateExpressionToResult(exprR.value); 161 } 162 else { 163 return Result.Err(exprR.value); 164 } 165 } 166 //# sourceMappingURL=index.js.map