UNPKG

calcium-lang

Version:
165 lines 5.45 kB
import * as Cmd from "../command"; import createBuiltinFunction from "../factory/builtinFunction"; import Environment from "./environment"; import Namespace from "./namespace"; import Parser from "../parser"; import Status from "./status"; import * as Builtin from "../builtin"; import Index from "../indexes"; import { Result } from "./block"; import { FunctionCalled, InconsistentBlock } from "../error"; import * as Kw from "../keyword"; import { None } from "../factory"; export default class Runtime { /** * * @param code must be a string or a JSON array of Calcium statements. */ constructor(code, opt) { var _a; this.breakpoints = new Set(); /** * a utility flag to execute on a Worker */ this.isPaused = false; this.parser = (_a = opt === null || opt === void 0 ? void 0 : opt.parser) !== null && _a !== void 0 ? _a : new Parser(); // set up built-ins const builtin = new Namespace(); for (let name in Builtin.Functions) { const builtinFunc = createBuiltinFunction({ name, body: Builtin.Functions[name], }); builtin.register(name, builtinFunc); } const env = new Environment(code, builtin); this.env = env; } addBreakpoint(line) { this.breakpoints.add(line); } pause() { this.isPaused = true; } removeBreakpoint(line) { this.breakpoints.delete(line); } resume() { this.isPaused = false; } run() { if (this.env.address.line >= this.env.code.length) { return Status.Terminated; } while (true) { const result = this.step(); if (result !== Status.Running) { return result; } else { continue; } } } /** * * @param funcToOutput built-in function's body to output */ setOutputFunction(funcToOutput) { this.env.funcToOutput = funcToOutput; } skipToNextLine() { let nextIndex; outer: while (true) { nextIndex = this.env.address.line + 1; inner: while (true) { const nextStmt = this.env.code[nextIndex]; const nextIndent = nextStmt[Index.Statement.Indent]; const delta = this.env.address.indent - nextIndent; if (delta > 0) { // some blocks must be popped. for (let i = 0; i < delta; ++i) { const result = this.env.lastBlock.exit(this.env); if (result === Result.Invalid) { throw new InconsistentBlock(); } else if (result === Result.Jumpped) { continue outer; } } break outer; } else if (delta === 0) { break outer; } else { nextIndex += 1; continue inner; } } } this.env.address.line = nextIndex; } /** * execute one line. * * @returns the result of the execution */ step() { var _a; if (this.env.address.line >= this.env.code.length) { return Status.Terminated; } let stmt = this.currentStatement; let cmd = this.parser.read(stmt); if (cmd instanceof Cmd.End) { return Status.Terminated; } const callerAddr = this.env.address.clone(); const lastCommand = this.env.commandsWithCall[this.env.commandsWithCall.length - 1]; if (lastCommand && callerAddr.isAt(lastCommand.address)) { cmd = lastCommand.command; const returnedValue = (_a = this.env.commandsWithCall.pop()) === null || _a === void 0 ? void 0 : _a.returnedValue; if (returnedValue) { this.env.returnedValue = returnedValue; } } try { cmd.execute(this.env); } catch (e) { if (e instanceof FunctionCalled) { this.env.commandsWithCall.push({ address: callerAddr, command: cmd, returnedValue: this.env.returnedValue === None ? undefined : this.env.returnedValue, }); } else { throw e; } } if (this.isPaused) return Status.Paused; this.skipToNextLine(); stmt = this.currentStatement; let kw = stmt[Index.Statement.Keyword]; // pass through Ifs and Comment commands while (kw === Kw.Command.Ifs || kw === Kw.Command.Comment) { const cmd = this.parser.read(stmt); cmd.execute(this.env); this.skipToNextLine(); stmt = this.currentStatement; kw = stmt[Index.Statement.Keyword]; } if (this.breakpoints.has(this.env.address.line)) return Status.AtBreakpoint; return Status.Running; } get currentStatement() { return this.env.code[this.env.address.line]; } } //# sourceMappingURL=runtime.js.map