import { syntaxError } from '../error/syntaxError';
import { Token } from './ast';
import { isNameStart } from './characterClasses';
import type { LexerInterface } from './lexer';
import { createToken, printCodePointAt, readName } from './lexer';
import type { Source } from './source';
import { TokenKind } from './tokenKind';
export class SchemaCoordinateLexer implements LexerInterface {
source: Source;
lastToken: Token;
token: Token;
line: 1 = 1 as const;
lineStart: 0 = 0 as const;
constructor(source: Source) {
const startOfFileToken = new Token(TokenKind.SOF, 0, 0, 0, 0);
this.source = source;
this.lastToken = startOfFileToken;
this.token = startOfFileToken;
}
get [Symbol.toStringTag]() {
return 'SchemaCoordinateLexer';
}
advance(): Token {
this.lastToken = this.token;
const token = (this.token = this.lookahead());
return token;
}
lookahead(): Token {
let token = this.token;
if (token.kind !== TokenKind.EOF) {
const nextToken = readNextToken(this, token.end);
token.next = nextToken;
nextToken.prev = token;
token = nextToken;
}
return token;
}
}
function readNextToken(lexer: SchemaCoordinateLexer, start: number): Token {
const body = lexer.source.body;
const bodyLength = body.length;
const position = start;
if (position < bodyLength) {
const code = body.charCodeAt(position);
switch (code) {
case 0x002e:
return createToken(lexer, TokenKind.DOT, position, position + 1);
case 0x0028:
return createToken(lexer, TokenKind.PAREN_L, position, position + 1);
case 0x0029:
return createToken(lexer, TokenKind.PAREN_R, position, position + 1);
case 0x003a:
return createToken(lexer, TokenKind.COLON, position, position + 1);
case 0x0040:
return createToken(lexer, TokenKind.AT, position, position + 1);
}
if (isNameStart(code)) {
return readName(lexer, position);
}
throw syntaxError(
lexer.source,
position,
`Invalid character: ${printCodePointAt(lexer, position)}.`,
);
}
return createToken(lexer, TokenKind.EOF, bodyLength, bodyLength);
}