UNPKG

mframejs

Version:
173 lines 5.39 kB
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