UNPKG

cookeylang-ts

Version:
159 lines (158 loc) 4.87 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Resolver = void 0; const Stmt = __importStar(require("./expr/stmt")); const Expr = __importStar(require("./expr/expr")); const errors_1 = require("./errors"); const visitor_1 = require("./expr/visitor"); class Resolver extends visitor_1.Visitor { constructor(interpreter) { super(); this.scopes = []; this.hasError = false; this.interpreter = interpreter; } init(stmts) { try { for (const stmt of stmts) { stmt.visit(this); } } catch (e) { if (e instanceof errors_1.CookeyError) { console.log(`<${e.lineData.file}> [ ${e.lineData.line} : ${e.lineData.col} ] ${e.message}`); this.hasError = true; } } } Block(self) { this.beginScope(); this.resolve(self.stmts); this.endScope(); } VarDecl(self) { this.declare(self.name); if (self.value) this.resolve([self.value]); this.define(self.name); } Variable(self) { if (this.scopes.length != 0 && this.scopes[this.scopes.length - 1].get(self.name.value) == false) throw new errors_1.CookeyError(self.lineData, "Cannot set variable with itself as the value."); this.resolveLocal(self, self.name); } Assign(self) { this.resolve([self.value]); this.resolveLocal(self, self.name); } FuncDecl(self) { this.declare(self.name); this.define(self.name); this.resolveFunc(self); } Lambda(self) { this.resolveFunc(self); } ExprStmt(self) { this.resolve([self.expr]); } IfStmt(self) { this.resolve([self.condition]); this.resolve([self.thenBr]); if (self.elseBr) this.resolve([self.elseBr]); } ExitStmt(self) { this.resolve([self.exit]); } RetStmt(self) { if (self.value) this.resolve([self.value]); } WhileStmt(self) { this.resolve([self.condition]); this.resolve([self.body]); } Binary(self) { this.resolve([self.left]); this.resolve([self.right]); } Call(self) { this.resolve([self.callee]); for (const arg of self.args) { this.resolve([arg]); } } Grouping(self) { this.resolve([self.value]); } Literal(_) { } Logic(self) { this.resolve([self.left]); this.resolve([self.right]); } Unary(self) { this.resolve([self.right]); } resolve(stmts) { for (const stmt of stmts) { stmt.visit(this); } } resolveLocal(expr, name) { for (let i = this.scopes.length - 1; i >= 0; i--) { if (this.scopes[i].has(name.value)) { this.interpreter.resolve(expr, this.scopes.length - 1 - i); return; } } } resolveFunc(func) { if (func instanceof Stmt.FuncDecl || func instanceof Expr.Lambda) { this.beginScope(); for (const param of func.params) { this.declare(param); this.define(param); } this.resolve(func.body); this.endScope(); } } beginScope() { this.scopes.push(new Map()); } endScope() { this.scopes.pop(); } declare(name) { if (this.scopes.length == 0) return; let scope = this.scopes[this.scopes.length - 1]; scope.set(name.value, false); } define(name) { if (this.scopes.length == 0) return; this.scopes[this.scopes.length - 1].set(name.value, true); } } exports.Resolver = Resolver;