UNPKG

rulescribe

Version:
406 lines (405 loc) 19.8 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const lexer_1 = require("./lexer"); const scope_1 = __importDefault(require("./scope")); const interfaces_1 = require("./interfaces"); const KEYWORD_WITH_END = new Set(['IF', 'FOR', 'WHILE', 'RULE', 'FUNCTION']); // Define the parser class Engine { constructor(lexer) { this.lexer = lexer; this.currentToken = null; this.lexer = lexer; this.currentToken = this.lexer.getNextToken(); } eat(tokenType) { var _a, _b; if (((_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.type) === tokenType) { this.currentToken = this.lexer.getNextToken(); } else { throw new Error(`Expected ${tokenType}, got ${(_b = this.currentToken) === null || _b === void 0 ? void 0 : _b.type}`); } } factor(engineScope) { return __awaiter(this, void 0, void 0, function* () { const token = this.currentToken; if ((token === null || token === void 0 ? void 0 : token.type) === 'CALL_FUNCTION') { const result = yield this.callFunction(engineScope); return (result === undefined) ? false : result; } else if ((token === null || token === void 0 ? void 0 : token.type) === 'NUMBER' || (token === null || token === void 0 ? void 0 : token.type) === 'FLOAT' || (token === null || token === void 0 ? void 0 : token.type) === 'BOOLEAN' || (token === null || token === void 0 ? void 0 : token.type) === 'STRING') { this.eat(token.type); return token.value; } else if ((token === null || token === void 0 ? void 0 : token.type) === 'IDENTIFIER') { const name = token.value; this.eat('IDENTIFIER'); const value = engineScope.lookup(name); if (value === undefined) { throw new Error(`Variable '${name}' is not defined`); } return value; } else if ((token === null || token === void 0 ? void 0 : token.type) === 'LPAREN') { this.eat('LPAREN'); const result = yield this.expr(engineScope); this.eat('RPAREN'); return result; } else if ((token === null || token === void 0 ? void 0 : token.type) === 'MINUS') { this.eat('MINUS'); return -(yield this.factor(engineScope)); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'NOT') { this.eat('NOT'); return !(yield this.factor(engineScope)); } throw new Error(`Unexpected token: ${token === null || token === void 0 ? void 0 : token.type}`); }); } term(engineScop) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c; let result = yield this.factor(engineScop); while (((_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.type) === 'MULTIPLY' || ((_b = this.currentToken) === null || _b === void 0 ? void 0 : _b.type) === 'DIVIDE' || ((_c = this.currentToken) === null || _c === void 0 ? void 0 : _c.type) === 'MODULO') { const token = this.currentToken; if ((token === null || token === void 0 ? void 0 : token.type) === 'MULTIPLY') { this.eat('MULTIPLY'); result *= (yield this.factor(engineScop)); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'DIVIDE') { this.eat('DIVIDE'); result /= (yield this.factor(engineScop)); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'MODULO') { this.eat('MODULO'); result %= (yield this.factor(engineScop)); } } return result; }); } expr(engineScop) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; const first = yield this.expr_math(engineScop); if (((_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.type) === 'AND') { this.eat('AND'); return (yield this.expr(engineScop)) && first; } else if (((_b = this.currentToken) === null || _b === void 0 ? void 0 : _b.type) === 'OR') { this.eat('OR'); return (yield this.expr(engineScop)) || first; } return first; }); } expr_math(engineScop) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k; let result = yield this.term(engineScop); while (((_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.type) === 'PLUS' || ((_b = this.currentToken) === null || _b === void 0 ? void 0 : _b.type) === 'MINUS' || ((_c = this.currentToken) === null || _c === void 0 ? void 0 : _c.type) === 'LESS_THAN' || ((_d = this.currentToken) === null || _d === void 0 ? void 0 : _d.type) === 'LESS_THAN_OR_EQUAL' || ((_e = this.currentToken) === null || _e === void 0 ? void 0 : _e.type) === 'GREATER_THAN' || ((_f = this.currentToken) === null || _f === void 0 ? void 0 : _f.type) === 'GREATER_THAN_OR_EQUAL' || ((_g = this.currentToken) === null || _g === void 0 ? void 0 : _g.type) === 'EQUALS' || ((_h = this.currentToken) === null || _h === void 0 ? void 0 : _h.type) === 'NOT_EQUALS' || ((_j = this.currentToken) === null || _j === void 0 ? void 0 : _j.type) === 'AND' || ((_k = this.currentToken) === null || _k === void 0 ? void 0 : _k.type) === 'OR') { const token = this.currentToken; if ((token === null || token === void 0 ? void 0 : token.type) === 'PLUS') { this.eat('PLUS'); result = result + (yield this.term(engineScop)); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'MINUS') { this.eat('MINUS'); result = result - (yield this.term(engineScop)); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'LESS_THAN') { this.eat('LESS_THAN'); return result < (yield this.expr_math(engineScop)); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'LESS_THAN_OR_EQUAL') { this.eat('LESS_THAN_OR_EQUAL'); return result <= (yield this.expr_math(engineScop)); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'GREATER_THAN') { this.eat('GREATER_THAN'); return result > (yield this.expr_math(engineScop)); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'GREATER_THAN_OR_EQUAL') { this.eat('GREATER_THAN_OR_EQUAL'); return result >= (yield this.expr_math(engineScop)); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'EQUALS') { this.eat('EQUALS'); return result === (yield this.expr_math(engineScop)); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'NOT_EQUALS') { this.eat('NOT_EQUALS'); return result != (yield this.expr_math(engineScop)); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'AND') { return result; } else if ((token === null || token === void 0 ? void 0 : token.type) === 'OR') { return result; } } return result; }); } assignment(engineScope) { return __awaiter(this, void 0, void 0, function* () { var _a; const name = (_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.value; this.eat('IDENTIFIER'); this.eat('ASSIGN'); const value = yield this.expr(engineScope); engineScope.define(name, value); }); } statement(engineScope) { return __awaiter(this, void 0, void 0, function* () { const token = this.currentToken; if ((token === null || token === void 0 ? void 0 : token.type) === 'IDENTIFIER') { yield this.assignment(engineScope); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'IF') { yield this.ifStatement(engineScope); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'WHILE') { yield this.whileLoop(engineScope); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'FOR') { yield this.forLoop(engineScope); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'RULE') { yield this.ruleDefenition(engineScope); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'FUNCTION') { this.functionDefinition(engineScope); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'CALL_FUNCTION') { yield this.callFunction(engineScope); } else if ((token === null || token === void 0 ? void 0 : token.type) === 'RETURN') { this.eat('RETURN'); engineScope.define('@RETURN_VALUE', yield this.expr(engineScope)); } else { throw new Error(`Unexpected token: ${token === null || token === void 0 ? void 0 : token.type}`); } }); } ifStatement(engineScop) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e, _f; this.eat('IF'); const condition = yield this.expr(engineScop); this.eat('THEN'); while (((_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.type) !== 'ELSE' && ((_b = this.currentToken) === null || _b === void 0 ? void 0 : _b.type) !== 'END') { if (condition) { yield this.statement(engineScop); } else { this.eat((_c = this.currentToken) === null || _c === void 0 ? void 0 : _c.type); } } if (((_d = this.currentToken) === null || _d === void 0 ? void 0 : _d.type) === 'ELSE') { this.eat('ELSE'); while (((_e = this.currentToken) === null || _e === void 0 ? void 0 : _e.type) !== 'END') { if (!condition) { yield this.statement(engineScop); } else { this.eat((_f = this.currentToken) === null || _f === void 0 ? void 0 : _f.type); } } } this.eat('END'); }); } forLoop(engineScope) { return __awaiter(this, void 0, void 0, function* () { var _a, _b; this.eat('FOR'); const name = (_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.value; this.eat('IDENTIFIER'); this.eat('FROM'); engineScope.define(name, yield this.expr(engineScope)); this.eat('TO'); const to = `@${name}_end`; engineScope.define(to, yield this.expr(engineScope)); const step = `@${name}_step`; if (((_b = this.currentToken) === null || _b === void 0 ? void 0 : _b.type) === 'STEP') { this.eat('STEP'); engineScope.define(step, yield this.expr(engineScope)); } else { engineScope.define(step, 1); } const body = this.getBody('DO'); const engine = new Engine(new lexer_1.CompiledLexer(body)); while (engineScope.lookup(name) <= engineScope.lookup(to)) { yield engine.parse(engineScope); engine.reset(); engineScope.define(name, engineScope.lookup(name) + engineScope.lookup(step)); } }); } whileLoop(engineScop) { return __awaiter(this, void 0, void 0, function* () { this.eat('WHILE'); const condition = this.getCondition('DO'); const body = this.getBody('DO'); const engine = new Engine(new lexer_1.CompiledLexer(body)); const condParser = new Engine(new lexer_1.CompiledLexer(condition)); let cond = yield condParser.expr(engineScop); while (cond) { yield engine.parse(engineScop); engine.reset(); condParser.reset(); cond = yield condParser.expr(engineScop); } }); } getCondition(end) { var _a, _b; const condition = []; while (((_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.type) !== end) { condition.push(this.currentToken); this.eat((_b = this.currentToken) === null || _b === void 0 ? void 0 : _b.type); } return condition; } getBody(start) { var _a, _b, _c, _d, _e; this.eat(start); const body = []; let end = 1; if (KEYWORD_WITH_END.has((_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.type)) { end += 1; } while ((end >= 1) || (((_b = this.currentToken) === null || _b === void 0 ? void 0 : _b.type) !== 'END')) { body.push(this.currentToken); this.eat((_c = this.currentToken) === null || _c === void 0 ? void 0 : _c.type); if (KEYWORD_WITH_END.has((_d = this.currentToken) === null || _d === void 0 ? void 0 : _d.type)) { end += 1; } else if (((_e = this.currentToken) === null || _e === void 0 ? void 0 : _e.type) === 'END') { end -= 1; } } this.eat('END'); return body; } callFunction(engineScope) { return __awaiter(this, void 0, void 0, function* () { var _a, _b, _c; const funcEngineScope = new scope_1.default(engineScope.builtinFunction); const funcName = (_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.value; const funcType = engineScope.functionType(funcName); const func = engineScope.getFunc(funcName); if (funcType === interfaces_1.FunctionType.UNDEFINED || func === undefined) { throw new Error(`'${funcName}' is not declared!`); } this.eat('CALL_FUNCTION'); this.eat('LPAREN'); let idx = 0; const args = []; while (((_b = this.currentToken) === null || _b === void 0 ? void 0 : _b.type) !== 'RPAREN') { const param = yield this.expr(engineScope); if (func.parameters !== undefined) { funcEngineScope.define(func.parameters[idx], param); } args.push(param); if (((_c = this.currentToken) === null || _c === void 0 ? void 0 : _c.type) === 'COMMA') { this.eat('COMMA'); } idx += 1; } this.eat('RPAREN'); if (funcType === interfaces_1.FunctionType.BUILTIN || funcType === interfaces_1.FunctionType.CLASS_METHOD) { return yield func.func.apply(func.thisArg, args); } else { const engine = new Engine(new lexer_1.CompiledLexer(func.func)); yield engine.parse(funcEngineScope); return funcEngineScope.lookup('@RETURN_VALUE'); } }); } ruleDefenition(engineScope) { var _a; this.eat('RULE'); const name = (_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.value; this.eat('STRING'); this.eat('WHEN'); const condition = this.getCondition('THEN'); const body = this.getBody('THEN'); engineScope.addRule(name, { condition, body }); } functionDefinition(engineScope) { var _a, _b, _c, _d; this.eat('FUNCTION'); const name = (_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.value; this.eat('IDENTIFIER'); this.eat('LPAREN'); const parameters = []; while (((_b = this.currentToken) === null || _b === void 0 ? void 0 : _b.type) !== 'RPAREN') { parameters.push((_c = this.currentToken) === null || _c === void 0 ? void 0 : _c.value); this.eat('IDENTIFIER'); if (((_d = this.currentToken) === null || _d === void 0 ? void 0 : _d.type) === 'COMMA') { this.eat('COMMA'); } } this.eat('RPAREN'); const body = this.getBody('DO'); engineScope.declare(name, parameters, body); } parse(engineScop) { return __awaiter(this, void 0, void 0, function* () { var _a; while (((_a = this.currentToken) === null || _a === void 0 ? void 0 : _a.type) !== 'EOF') { yield this.statement(engineScop); } }); } fire(engineScope) { return __awaiter(this, void 0, void 0, function* () { const rules = engineScope.getRuleNames().map((name) => __awaiter(this, void 0, void 0, function* () { const rule = engineScope.getRule(name); if (rule !== undefined) { const condEngine = new Engine(new lexer_1.CompiledLexer(rule.condition)); const cond = yield condEngine.expr(engineScope); if (cond) { const bodyEngine = new Engine(new lexer_1.CompiledLexer(rule.body)); yield bodyEngine.parse(engineScope); } } })); yield Promise.all(rules); }); } reset() { this.lexer.reset(); this.currentToken = this.lexer.getNextToken(); } } exports.default = Engine;