123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- import Error, { isError } from "./error";
- import Token, { TokenKind } from "./token";
-
- export default class Lexer {
- public source: string;
- public position: number;
- public line: number;
-
- constructor(source: string) {
- this.source = source;
- this.position = 0;
- this.line = 1;
- }
- public scan(): Token[] | Error {
- const tokens = [];
-
- while (!this.atEnd()) {
- const result = this.getToken();
- if (isError(result)) {
- return result;
- } else if (result) {
- tokens.push(result);
- }
- }
-
- tokens.push(new Token(TokenKind.EOF, null, this.line));
-
- return tokens;
- }
-
- private getToken(): Token | Error | null {
- const source = this.source.slice(this.position);
-
- if (source.match(/^select/i)) {
- this.advance(6);
- return new Token(TokenKind.SELECT, null, this.line);
- } else if (source.match(/^where/i)) {
- this.advance(5);
- return new Token(TokenKind.WHERE, null, this.line);
- } else if (source.match(/^from/i)) {
- this.advance(4);
- return new Token(TokenKind.FROM, null, this.line);
- } else if (source.match(/^as/i)) {
- this.advance(2);
- return new Token(TokenKind.AS, null, this.line);
- } else if (source.match(/^and/i)) {
- this.advance(3);
- return new Token(TokenKind.AND, null, this.line);
- } else if (source.match(/^or/i)) {
- this.advance(2);
- return new Token(TokenKind.OR, null, this.line);
- } else if (source.match(/^\+/)) {
- this.advance();
- return new Token(TokenKind.PLUS, null, this.line);
- } else if (source.match(/^-/)) {
- this.advance();
- return new Token(TokenKind.MINUS, null, this.line);
- } else if (source.match(/^\*/)) {
- this.advance();
- return new Token(TokenKind.STAR, null, this.line);
- } else if (source.match(/^\//)) {
- this.advance();
- return new Token(TokenKind.SLASH, null, this.line);
- } else if (source.match(/^=/)) {
- this.advance();
- return new Token(TokenKind.EQUALS, null, this.line);
- } else if (source.match(/^,/)) {
- this.advance();
- return new Token(TokenKind.COMMA, null, this.line);
- } else if (source.match(/^`/)) {
- this.advance();
- return new Token(TokenKind.BACKTICK, null, this.line);
- } else if (source.match(/^\.([^0-9]|$)/)) {
- this.advance();
- return new Token(TokenKind.DOT, null, this.line);
- } else if (source.match(/^;/)) {
- this.advance();
- return new Token(TokenKind.SEMICOLON, null, this.line);
- } else if (source.match(/^\(/)) {
- this.advance();
- return new Token(TokenKind.LPAREN, null, this.line);
- } else if (source.match(/^\)/)) {
- this.advance();
- return new Token(TokenKind.RPAREN, null, this.line);
- } else if (source.match(/^[0-9]+(\.[0-9]+)?/)) {
- const match = source.match(/^[0-9]+(\.[0-9]+)?/);
- if (match) {
- const numeric = match[0];
- this.advance(numeric.length);
- return new Token(TokenKind.NUMBER, numeric, this.line);
- }
- } else if (source.match(/^\.[0-9]+/)) {
- const match = source.match(/^\.[0-9]+/);
- if (match) {
- const numeric = match[0];
- this.advance(numeric.length);
- return new Token(TokenKind.NUMBER, numeric, this.line);
- }
- } else if (source.match(/^[a-zA-Z_][a-zA-Z0-9_]*/)) {
- const match = source.match(/^[a-zA-Z_][a-zA-Z0-9_]*/);
- if (match) {
- const identifier = match[0];
- this.advance(identifier.length);
- return new Token(TokenKind.IDENTIFIER, identifier, this.line);
- }
- } else if (source.match(/^\n/)) {
- this.advance();
- this.nextLine();
- return null;
- } else if (source.match(/^\s/)) {
- this.advance();
- return null;
- }
-
- return new Error(`Unrecognized character ${source[0]}`, this.line);
- }
-
- private advance(step: number = 1) {
- this.position += step;
- }
-
- private nextLine() {
- this.line += 1;
- }
-
- private atEnd(): boolean {
- return this.position === this.source.length;
- }
- }
|