bds.js
Version: 
A simple interpreter written to simulate and run BDScript Language in JavaScript
178 lines (177 loc) • 5.36 kB
JavaScript
"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;