UNPKG

calcium-lang

Version:
263 lines 10.2 kB
import * as Cmd from "../command"; import * as Err from "../error"; import * as Expr from "../expression"; import Index from "../indexes"; import * as Kw from "../keyword"; import { createBool, createDict, createInt, createList, createStr, None, } from "../factory"; /** * a default parser for Calcium language */ export default class Parser { /** * * @param table has default implementation when empty */ constructor(table = new Map()) { this.table = table; if (this.table.size === 0) { // an assignment this.table.set(Kw.Command.Assign, (stmt) => { const lhs = this.readRef(stmt[Index.Assign.Lhs]); const rhs = this.readExpr(stmt[Index.Assign.Rhs]); return new Cmd.Assign(lhs, rhs); }); this.table.set(Kw.Command.Break, (stmt) => { return new Cmd.Break(); }); this.table.set(Kw.Command.Class, (stmt) => { const className = stmt[Index.Class.Name]; const superclassName = stmt[Index.Class.SuperclassName]; if (superclassName === null) { return new Cmd.Class(className); } else { return new Cmd.Class(className, superclassName); } }); // a comment line this.table.set(Kw.Command.Comment, (stmt) => { const text = stmt[Index.Comment.Text]; if (typeof text === "string") { return new Cmd.Comment(text); } else { return new Cmd.Comment(null); } }); // compound assignment this.table.set(Kw.Command.CompoundAddition, (stmt) => { const lhs = this.readRef(stmt[Index.Assign.Lhs]); const rhs = this.readExpr(stmt[Index.Assign.Rhs]); return new Cmd.CompoundAssign(Kw.BinaryOperator.Addition, lhs, rhs); }); this.table.set(Kw.Command.CompoundMultiplication, (stmt) => { const lhs = this.readRef(stmt[Index.Assign.Lhs]); const rhs = this.readExpr(stmt[Index.Assign.Rhs]); return new Cmd.CompoundAssign(Kw.BinaryOperator.Multiplication, lhs, rhs); }); this.table.set(Kw.Command.Def, (stmt) => { const name = stmt[Index.FuncDef.Name]; const params = stmt[Index.FuncDef.Parameters]; return new Cmd.Def(name, params); }); this.table.set(Kw.Command.Elif, (stmt) => { const condition = this.readExpr(stmt[Index.Conditional.Expr]); return new Cmd.Elif(condition); }); this.table.set(Kw.Command.Else, (stmt) => { return new Cmd.Else(); }); // the end of program this.table.set(Kw.Command.End, (stmt) => { return new Cmd.End(); }); this.table.set(Kw.Command.ExprStmt, (stmt) => { const expr = this.readExpr(stmt[Index.ExprStmt.Value]); return new Cmd.ExprStmt(expr); }); this.table.set(Kw.Command.For, (stmt) => { const variables = stmt[Index.For.Variables]; let varRefs; if (variables[0] === Kw.Syntax.Comma) { varRefs = this.readExpr(variables); } else { varRefs = this.readRef(stmt[Index.For.Variables]); } const iterable = this.readExpr(stmt[Index.For.Iterable]); return new Cmd.For(varRefs, iterable); }); this.table.set(Kw.Command.If, (stmt) => { const condition = this.readExpr(stmt[Index.Conditional.Expr]); return new Cmd.If(condition); }); this.table.set(Kw.Command.Ifs, (stmt) => { return new Cmd.Ifs(); }); this.table.set(Kw.Command.Pass, (stmt) => { return new Cmd.Pass(); }); this.table.set(Kw.Command.Return, (stmt) => { if (stmt.length > Index.Return.Expr) { const expr = this.readExpr(stmt[Index.Return.Expr]); return new Cmd.Return(expr); } else { return new Cmd.Return(); } }); this.table.set(Kw.Command.While, (stmt) => { const condition = this.readExpr(stmt[Index.Conditional.Expr]); return new Cmd.While(condition); }); } } /** * used by `Call`. * @param args arguments given to a function * @returns converted objects that will be evaluated in runtime */ readArgs(args) { const convertedArgs = []; for (let a of args) { const arg = this.readExpr(a); convertedArgs.push(arg); } return convertedArgs; } /** * * @param stmt a JSON array that represents one line to execute * @returns a command object to be executed */ read(stmt) { var _a; const kw = stmt[Index.Statement.Keyword]; const cmd = (_a = this.table.get(kw)) === null || _a === void 0 ? void 0 : _a(stmt); if (cmd === undefined) { throw new Err.CommandNotFound(); } else { return cmd; } } readBinOp(operator, expr) { if (!Kw.BinaryOperatorsSet.has(operator)) { throw new Err.CannotConvertToExpression(); } const left = this.readExpr(expr[Index.BinaryOperator.Left]); const right = this.readExpr(expr[Index.BinaryOperator.Right]); return new Expr.BinaryOperation(operator, left, right); } /** * parse JSON element(s) and return `Expression`. * @param expr any JSON element * @returns an internal type or a reference */ readExpr(expr) { if (Array.isArray(expr)) { if (Array.isArray(expr[0])) { // expr is an array literal. const list = []; for (let elem of expr[0]) { list.push(this.readExpr(elem)); } return createList(list); } else if (expr[0] === Kw.Reference.Attribute || expr[0] === Kw.Reference.Subscript || expr[0] === Kw.Reference.Variable) { // expr is a reference. return this.readRef(expr); } else if (expr[0] === Kw.Reference.Call) { const func = this.readRef(expr[Index.Call.FuncRef]); const args = this.readArgs(expr[Index.Call.Args]); return new Expr.Call(func, args); } else if (expr[0] === Kw.Syntax.Comma) { const refs = []; for (let i = 1; i < expr.length; ++i) { refs.push(this.readRef(expr[i])); } return new Expr.Comma(refs); } else if (expr[0] === Kw.Syntax.KwArg) { const keyword = expr[1]; const value = this.readExpr(expr[2]); return new Expr.KwArg(keyword, value); } else if (expr[0] === Kw.UnaryOperator.BitwiseNot || expr[0] === Kw.UnaryOperator.Negative || expr[0] === Kw.UnaryOperator.Not) { return this.readUnOp(expr[0], expr); } else if (expr.length === 3) { // expr could be a binary operation return this.readBinOp(expr[0], expr); } else { throw new Err.CannotConvertToExpression(); } } else if (typeof expr === "number") { return createInt(expr); } else if (typeof expr === "string") { return createStr(expr); } else if (typeof expr === "boolean") { return createBool(expr); } else if (expr === null) { return None; } else if (typeof expr === "object") { // can generate an empty dict only return createDict({}); } else { throw new Err.CannotConvertToExpression(); } } /** * parse a reference array and return an reference object used in runtime. * @param expr a reference array such as `["var", "x"]` * @returns a reference object to be evaluated later */ readRef(expr) { const kw = expr[Index.Expression.Keyword]; if (kw === Kw.Reference.Variable) { return new Expr.Variable(expr[Index.Variable.Name]); } else if (kw === Kw.Reference.Attribute) { const attrsName = []; for (let i = Index.Attribute.FirstAttributeName; i < expr.length; ++i) { attrsName.push(expr[i]); } return new Expr.Attribute(expr[Index.Attribute.VarName], attrsName); } else if (kw === Kw.Reference.Subscript) { if (expr.length === 3) { const ref = this.readRef(expr[Index.Subscript.ReferredObj]); const index = this.readExpr(expr[Index.Subscript.IndexExpr]); return new Expr.Subscript(ref, index); } else if (expr.length >= 4) { // slice const ref = this.readRef(expr[Index.Subscript.ReferredObj]); const lower = this.readExpr(expr[Index.Subscript.SliceStart]); const upper = this.readExpr(expr[Index.Subscript.SliceEnd]); return new Expr.Subscript(ref, lower, upper); } throw new Err.FewerElement(); } else { throw new Err.UnsupportedKeyword(kw); } } readUnOp(operator, expr) { return new Expr.UnaryOperation(operator, None); // TODO change here } } //# sourceMappingURL=index.js.map