UNPKG

bds.js

Version:

A simple interpreter written to simulate and run BDScript Language in JavaScript

178 lines (177 loc) 5.36 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Lexer = void 0; const SYNTAX = "[]\\;$"; const OPS = /[!=<>]+$/; const FN_DEF = /[a-z_]/i; class Lexer { constructor(input) { this.input = input; this.pos = 0; this.line = 0; this.col = 0; this.escape_c = false; if (typeof input !== "string" || !input) throw new Error("input arg must be non-empty and typeof string!"); } main() { const Tokens = []; while (true) { let res = this.advance(); if (res) Tokens.push(res); if (this.eof()) break; } return this.clean(Tokens); } peek(offset = 0) { return this.input[this.pos + offset]; } next() { let current = this.input[this.pos++]; if (this.peek() === "\n") { this.line += 1; this.col = 0; } else { this.col += 1; } return current; } eof() { return this.peek() === "" || this.peek() === undefined; } isOperator(x) { return OPS.test(x); } isSyntax(c) { return SYNTAX.indexOf(c) > -1; } isNumber(x) { return parseInt(x) === Number(x); } parseOperator(x) { switch (x) { case "==": case "!=": case ">=": case "<=": case ">": case "<": return { type: "operator", value: x, pos: this.col, line: this.line }; } return { type: "string", value: x, pos: this.col, line: this.line }; } validateCall(c) { return FN_DEF.test(c); } parseCall() { const fn = this.readInput(this.validateCall); if (!fn) return { type: "string", value: "$", pos: this.col, line: this.line }; return { type: "call", value: "$" + fn, child: [], pos: this.col, line: this.line }; } validateString(c) { return !(this.isSyntax(c) || this.isOperator(c)); } parseString() { const str = this.readInput(this.validateString); if (this.isNumber(str)) return { type: "number", value: Number(str), pos: this.col, line: this.line }; return { type: "string", value: str, pos: this.col, line: this.line }; } readInput(validator) { let str = ""; while (!this.eof() && validator.apply(this, [this.peek()])) { str += this.next(); } return str; } advance() { let c = this.peek(); if (this.escape_c) { this.escape_c = false; this.next(); if (this.isSyntax(c) || this.isOperator(c)) return { type: "string", value: c, pos: this.col, line: this.line }; return { type: "string", value: "\\" + c, pos: this.col, line: this.line }; } switch (c) { case "[": { this.next(); return { type: "open", pos: this.col, line: this.line }; } ; case "]": { this.next(); return { type: "close", pos: this.col, line: this.line }; } ; case ";": { this.next(); return { type: "newArg", pos: this.col, line: this.line }; } ; case "\\": { this.next(); this.escape_c = true; return void 0; } ; case "$": { this.next(); return this.parseCall(); } ; } if (this.isOperator(c)) { this.next(); if (this.isOperator(c + this.peek())) return this.parseOperator(c + this.next()); return this.parseOperator(c); } return this.parseString(); } clean(tokens) { let newArr = []; let token; let current; while (tokens.length > 0) { token = tokens.shift(); if (!current) { current = token; continue; } ; if (current.type === "string" && current.type === token.type) { current.value += token.value; continue; } else { if (current.type !== "string") { newArr.push(current); current = token; } else { if (token.type !== "string") { newArr.push(current); current = token; } else throw new Error("dunno wat to do"); } } } if (current) newArr.push(current); token = void 0; current = void 0; return newArr; } } exports.Lexer = Lexer;