time-to-botec

Benchmark sampling in different programming languages
Log | Files | Refs | README

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