@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
JavaScript
"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;