mframejs
Version:
simple framework
173 lines • 5.39 kB
JavaScript
import { SymbolTemplate } from './symbolTemplate';
export class AST {
constructor() {
this.currentStatement = null;
this.currentTokenIndex = 0;
this.assignment = function (id) {
const astInstance = this;
return this.infixr(id, 10, function (left) {
if (left.id !== '.' && left.id !== '[' &&
left.arity !== 'variable') {
left.error('Bad lvalue.');
}
this.first = left;
this.second = astInstance.expression(9);
this.assignment = true;
this.arity = 'binary';
return this;
});
};
}
start(tokens) {
this.tokens = tokens;
this.currentStatement = null;
this.currentTokenIndex = 0;
this.currentToken = null;
this.advance();
const ast = this.statements();
return ast;
}
addSymbolContainer(symbolContainer) {
this.symbolContainer = symbolContainer;
}
symbol(id, bp) {
let s = this.symbolContainer[id];
bp = bp || 0;
if (s) {
if (bp >= s.lbp) {
s.lbp = bp;
}
}
else {
s = new SymbolTemplate();
s.id = s.value = id;
s.lbp = bp;
this.symbolContainer[id] = s;
}
return s;
}
prefix(id, nud) {
const s = this.symbol(id);
const astInstance = this;
s.nud = nud || function () {
this.first = astInstance.expression(70);
this.arity = 'unary';
return this;
};
return s;
}
infix(id, bp, led) {
const s = this.symbol(id, bp);
const astInstance = this;
s.led = led || function (left) {
this.first = left;
this.second = astInstance.expression(bp);
this.arity = 'binary';
return this;
};
return s;
}
infixr(id, bp, led) {
const s = this.symbol(id, bp);
const astInstance = this;
s.led = led || function (left) {
this.first = left;
this.second = astInstance.expression(bp - 1);
this.arity = 'binary';
return this;
};
return s;
}
stmt(id, f) {
const x = this.symbol(id);
x.std = f;
return x;
}
statement() {
const n = this.currentToken;
let v;
if (n.std) {
this.advance();
return n.std();
}
v = this.expression(0);
return v;
}
statements() {
this.statementsArray = [];
let s;
while (true) {
if (this.currentToken.id === '}' || this.currentToken.id === '(end)') {
break;
}
s = this.statement();
if (s) {
this.statementsArray.push(s);
}
}
return this.statementsArray.length === 0 ? null : this.statementsArray.length === 1 ? this.statementsArray[0] : this.statementsArray;
}
advance(expected) {
let type, o, token, value;
token = this.tokens[this.currentTokenIndex];
if (token && expected) {
const nextToken = this.tokens[this.currentTokenIndex + 1];
if (expected === '}' && nextToken && (nextToken.value === '|' || nextToken.value === '&')) {
return;
}
const prevToken = this.tokens[this.currentTokenIndex - 1];
if (expected === '}' && prevToken && (prevToken.value === '|' || prevToken.value === '&')) {
return;
}
}
if (this.currentTokenIndex >= this.tokens.length) {
this.currentToken = this.symbolContainer['(end)'];
return;
}
this.currentTokenIndex += 1;
value = token.value;
type = token.type;
if (type === 'variable') {
type = 'variable';
o = this.symbolContainer['(variable)'];
}
else if (type === 'operator') {
o = this.symbolContainer[value];
if (!o) {
console.warn('Unknown operator.', token);
}
}
else if (type === 'string' || type === 'number') {
type = 'literal';
o = this.symbolContainer['(literal)'];
}
else {
console.warn('Unexpected token.', token);
}
this.currentToken = Object.create(o);
this.currentToken.value = value;
this.currentToken.arity = type;
if (token.root) {
this.currentToken.root = true;
}
return this.currentToken;
}
expression(rbp) {
let left;
let token = this.currentToken;
this.advance();
left = token.nud();
try {
while (rbp < this.currentToken.lbp) {
token = this.currentToken;
this.advance();
left = token.led(left);
}
}
catch (e) {
console.warn('parser fail');
}
return left;
}
}
//# sourceMappingURL=ast.js.map