@igorivaniuk/tlb-parser
Version:
Parse TLB syntax into TypeScript objects
202 lines (201 loc) • 7.97 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (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.exprNodes = exports.combinatorNodes = exports.fieldNodes = exports.constructorNodes = exports.rootNodes = void 0;
const ast = __importStar(require("./ast/nodes"));
const locations_1 = require("./ast/locations");
exports.rootNodes = {
Program(node) {
return (0, locations_1.withLocations)(new ast.Program(node.children.map((child) => child['root']())), node);
},
SourceElement(node) {
return (0, locations_1.withLocations)(new ast.Declaration(node.child(0)['Constructor'](), node.child(1)['Field'](), node.child(3)['Combinator']()), node);
},
};
exports.constructorNodes = {
Constructor(name, tag) {
const nameValue = name.sourceString;
let tagValue = null;
if (tag.numChildren !== 0) {
tagValue = tag.child(0)['Constructor']();
}
return (0, locations_1.withLocations)(new ast.Constructor(nameValue, tagValue), name);
},
ConstructorTag(node) {
// This is a string-only node:
return node.sourceString;
},
};
exports.fieldNodes = {
Fields(node) {
return node.children.map((child) => child['Field']());
},
FieldDefinition(node) {
return node['Field'](); // just a wrapper node, unwrapping
},
FieldBuiltinDef(lpar, name, _sep, type, _rpar) {
// TODO: validate `type.sourceString` to be in allowed values.
return (0, locations_1.withLocations)(new ast.FieldBuiltinDef(name.sourceString, type.sourceString), lpar);
},
FieldCurlyExprDef(lpar, expr, _rpar) {
return (0, locations_1.withLocations)(new ast.FieldCurlyExprDef(expr['expr']()), lpar);
},
FieldAnonymousDef(node) {
const { name, isRef, fields } = node['Field']();
return (0, locations_1.withLocations)(new ast.FieldAnonymousDef(name, isRef, fields), node);
},
FieldNamedDef(name, _sep, expr) {
return (0, locations_1.withLocations)(new ast.FieldNamedDef(name.sourceString, expr['expr']()), name);
},
FieldExprDef(node) {
return (0, locations_1.withLocations)(new ast.FieldExprDef(node['expr']()), node);
},
// Helpers to parse complex anonymous fields:
// TODO: move out of this semantics
FieldAnonRef(ref, _lpar, fields, _rpar) {
return {
'name': null,
'isRef': ref.numChildren !== 0,
'fields': fields.children.map((field) => field['Field']()),
};
},
FieldNamedAnonRef(name, _sep, fields) {
return Object.assign(Object.assign({}, fields['Field']()), { 'name': name.sourceString });
},
};
exports.combinatorNodes = {
Combinator(name, exprs) {
return (0, locations_1.withLocations)(new ast.Combinator(name.sourceString, exprs.children.map((typeExpr) => typeExpr['expr']())), name);
},
};
exports.exprNodes = {
// Math
MathExpr(left, ops, rights) {
return parseMath(left, ops, rights);
},
MulExpr(left, ops, rights) {
return parseMath(left, ops, rights);
},
CompareExpr(node) {
return node['expr']();
},
CompareOperatorExpr(left, op, right) {
return (0, locations_1.withLocations)(new ast.CompareExpr(left['expr'](), op.sourceString, right['expr']()), op);
},
// Conditional types
CondExpr(expr) {
const { leftExpr, dotExpr, condExpr } = expr['expr']();
if (dotExpr === undefined && condExpr === undefined) {
return leftExpr;
}
return (0, locations_1.withLocations)(new ast.CondExpr(leftExpr, dotExpr, condExpr), expr);
},
// TODO: move out of this semantics
CondDotAndQuestionExpr(dotNode, _sep, condNode) {
return Object.assign(Object.assign({}, dotNode['expr']()), { 'condExpr': condNode['expr']() });
},
CondQuestionExpr(left, _sep, condNode) {
return {
'leftExpr': left['expr'](),
'dotExpr': null,
'condExpr': condNode['expr'](),
};
},
CondTypeExpr(node) {
return {
'leftExpr': node['expr'](),
};
},
CondDotted(left, _sep, number) {
return {
'leftExpr': left['expr'](),
'dotExpr': new Number(number.sourceString),
};
},
// TypeExpr
CombinatorExpr(lpar, name, args, _rpar) {
return (0, locations_1.withLocations)(new ast.CombinatorExpr(name.sourceString, args.children.map((arg) => arg['expr']())), lpar);
},
CellRefExpr(ref, node) {
return (0, locations_1.withLocations)(new ast.CellRefExpr(node['expr']()), ref);
},
BuiltinExpr(node) {
return (0, locations_1.withLocations)(node['expr'](), node);
},
NegateExpr(op, node) {
return (0, locations_1.withLocations)(new ast.NegateExpr(node['expr']()), op);
},
// Builtins
BuiltinOneArg(lpar, expr, arg, _rpar) {
// TODO: validate `expr` to be in allowed set of operators
return (0, locations_1.withLocations)(new ast.BuiltinOneArgExpr(expr.sourceString, arg['expr']()), lpar);
},
BuiltinZeroArgs(expr) {
// TODO: validate `expr` to be in allowed set of operators
return (0, locations_1.withLocations)(new ast.BuiltinZeroArgs(expr.sourceString), expr);
},
// Base rules
identifier(start, rest) {
return (0, locations_1.withLocations)(new ast.NameExpr(start.sourceString + rest.sourceString), start);
},
number(node) {
return (0, locations_1.withLocations)(new ast.NumberExpr(parseInt(node.sourceString)), node);
},
// Helpers
Parens(lpar, node, _rpar) {
// Just drop `()` around an expression, it should be fine
return (0, locations_1.withLocations)(node['expr'](), lpar);
},
};
function parseMath(left, ops, rights) {
const leftExpr = left['expr']();
const opsSigns = [];
for (let child of ops.children) {
// TODO: validate op is in ast.MathOperators
opsSigns.push(child.sourceString);
}
const rightExprs = [];
for (let child of rights.children) {
const rightExpr = child['expr']();
if (rightExpr !== undefined) {
rightExprs.push(rightExpr);
}
}
if (opsSigns.length !== rightExprs.length) {
throw new Error('Invalid math operation'); // should not happen
}
if (opsSigns.length === 0) {
// This is not a math expr, just the left part
return (0, locations_1.withLocations)(leftExpr, left);
}
// We always use the left part for all the math expressions,
// it should be fine for now.
let expr = (0, locations_1.withLocations)(new ast.MathExpr(leftExpr, opsSigns[0], rightExprs[0]), left);
for (let index = 1; index < opsSigns.length; index++) {
expr = (0, locations_1.withLocations)(new ast.MathExpr(expr, opsSigns[index], // validated earlier
rightExprs[index]), left);
}
return expr;
}