UNPKG

@abdullah2993/expression-parser

Version:

An expression evaluator written in typescript with the goal to support SQL like WHERE clauses.

193 lines (192 loc) 7.16 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Lexer = void 0; var token_1 = require("./token"); var Lexer = /** @class */ (function () { function Lexer(text) { this.text = text; this.position = 0; this.readPosition = 0; this.currentChar = '\0'; this.readChar(); } Lexer.prototype.next = function () { var token; this.skipWhiteSpace(); switch (this.currentChar) { case '=': token = this.getToken(token_1.TokenType.Eq); break; case '<': if (this.peekChar() === '>') { this.readChar(); token = this.getToken(token_1.TokenType.Neq); } else if (this.peekChar() === '=') { this.readChar(); token = this.getToken(token_1.TokenType.Lte); } else { token = this.getToken(token_1.TokenType.Lt); } break; case '>': if (this.peekChar() === '=') { this.readChar(); token = this.getToken(token_1.TokenType.Gte); } else { token = this.getToken(token_1.TokenType.Gt); } break; case '"': case "'": { var unquotedValue = this.readString(this.currentChar); token = this.getToken(token_1.TokenType.String, unquotedValue); break; } case '+': token = this.getToken(token_1.TokenType.Plus); break; case '-': token = this.getToken(token_1.TokenType.Minus); break; case '*': token = this.getToken(token_1.TokenType.Mul); break; case '/': token = this.getToken(token_1.TokenType.Div); break; case '(': token = this.getToken(token_1.TokenType.Lparn); break; case ')': token = this.getToken(token_1.TokenType.Rparn); break; case ',': token = this.getToken(token_1.TokenType.Comma); break; case '\0': token = this.getToken(token_1.TokenType.EOF, '\0'); break; default: if (Lexer.isLetter(this.currentChar)) { var ident = this.readIdentifier(); var identType = Lexer.resolveIdentifier(ident); if (identType === token_1.TokenType.Identifier) { token = this.getToken(token_1.TokenType.Identifier, ident); } else { token = this.getToken(identType); } } else if (Lexer.isNumber(this.currentChar) || Lexer.isDot(this.currentChar)) { var num = this.readNumber(); token = this.getToken(token_1.TokenType.Numeric, num); } else { token = this.getToken(token_1.TokenType.Illegal, this.currentChar); } } this.readChar(); return token; }; Lexer.prototype.readChar = function () { if (this.readPosition >= this.text.length) { this.currentChar = '\0'; } else { this.currentChar = this.text[this.readPosition]; } this.position = this.readPosition; this.readPosition++; }; Lexer.prototype.peekChar = function () { if (this.readPosition >= this.text.length) { return '\0'; } return this.text[this.readPosition]; }; Lexer.prototype.skipWhiteSpace = function () { while (Lexer.isWhiteSpace(this.currentChar)) { this.readChar(); } }; Lexer.prototype.readString = function (quote) { var start = this.position + 1; do { this.readChar(); } while (this.currentChar !== quote && this.currentChar !== '\0'); return this.text.substring(start, this.position); }; Lexer.prototype.readIdentifier = function () { var start = this.position; while (Lexer.isLetter(this.peekChar())) { this.readChar(); } return this.text.substring(start, this.position + 1); }; Lexer.prototype.readNumber = function () { var start = this.position; var haveDecimal = Lexer.isDot(this.currentChar); while (Lexer.isNumber(this.peekChar()) || (Lexer.isDot(this.peekChar()) && !haveDecimal)) { if (Lexer.isDot(this.currentChar)) { haveDecimal = true; } this.readChar(); } return this.text.substring(start, this.position + 1); }; Lexer.prototype.getToken = function (type, literal) { var exactLiteral = literal !== null && literal !== void 0 ? literal : type; var adjustment = type === token_1.TokenType.String ? 0 : 1; var postion = this.position + adjustment - exactLiteral.length; return new token_1.Token(type, exactLiteral, postion); }; Lexer.isWhiteSpace = function (charStr) { var charCode = charStr.charCodeAt(0); return (charCode === 0x09 // '\t' || charCode === 0x0a // '\n' || charCode === 0x0d // '\r' || charCode === 0x20 // ' ' ); }; Lexer.isNumber = function (charStr) { var charCode = charStr.charCodeAt(0); return charCode >= 0x30 && charCode <= 0x39; // '0'-'9' }; Lexer.isLetter = function (charStr) { var charCode = charStr.charCodeAt(0); return ((charCode >= 0x41 && charCode <= 0x5a) // A-Z || (charCode >= 0x61 && charCode <= 0x7a) // a-z || charCode === 0x5f // '_' ); }; Lexer.isDot = function (charStr) { return charStr === '.'; }; Lexer.resolveIdentifier = function (ident) { var tokenType = Lexer.keywords[ident.toLowerCase()]; if (tokenType) { return tokenType; } return token_1.TokenType.Identifier; }; Lexer.keywords = { and: token_1.TokenType.And, or: token_1.TokenType.Or, not: token_1.TokenType.Not, true: token_1.TokenType.True, false: token_1.TokenType.False, is: token_1.TokenType.Is, between: token_1.TokenType.Between, null: token_1.TokenType.Null, case: token_1.TokenType.Case, when: token_1.TokenType.When, else: token_1.TokenType.Else, end: token_1.TokenType.End, then: token_1.TokenType.Then, }; return Lexer; }()); exports.Lexer = Lexer;