cookeylang-ts
Version:
A dynamic, interpreted language.
159 lines (158 loc) • 4.87 kB
JavaScript
"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;