@artemis-lang/parser
Version:
The artemis language parser
107 lines (87 loc) • 2.31 kB
text/typescript
import { Token } from 'moo';
import IParserPlugin from '../types/parser-plugin';
import NodeTypes from '../node/node-types';
import Program from '../types/program';
import error from '../error';
import plugins from '../plugins';
import Lexer from '@artemis-lang/lexer';
class Parser {
tokens: Token[];
current: number;
plugins: IParserPlugin[];
input: string;
constructor(lexer: Lexer) {
this.tokens = this.init(lexer.tokenize().tokens);
this.input = lexer.code;
this.current = 0;
this.plugins = plugins;
}
init(tokens: moo.Token[]) {
return tokens.filter(
(v) =>
v.type !== 'ws' &&
v.type !== 'nl' &&
v.type !== 'multilineComment' &&
v.type !== 'singlelineComment'
);
}
isAtEnd() {
return this.current >= this.tokens.length;
}
isAtStart() {
return this.current <= 0;
}
peek() {
return this.tokens[this.current];
}
previous() {
return this.tokens[this.current - 1];
}
advance() {
if (!this.isAtEnd()) this.current++;
return this.previous();
}
match(type: string, value?: string) {
if (this.isAtEnd()) return false;
if (value) return this.peek().type === type && this.peek().value === value;
return this.peek().type === type;
}
consume(type: string, message: string) {
if (this.match(type)) return this.advance();
throw error(message, this.peek(), this.input);
}
plugin(plugin: IParserPlugin) {
this.plugins.push(plugin);
}
add(...plugins: IParserPlugin[]) {
this.plugins.push(...plugins);
}
next() {
if (!this.isAtEnd()) return this.tokens[this.current++];
return this.tokens[this.current];
}
nextBy(n: number) {
if (!this.isAtEnd()) return this.tokens[this.current + n];
return this.tokens[this.current];
}
nextByType(n: number) {
return this.nextBy(n).type;
}
parse() {
const program: Program = {
type: NodeTypes.Program,
body: []
};
while (!this.isAtEnd()) {
program.body.push(this.parseExpression());
}
return program;
}
parseExpression() {
for (const plugin of this.plugins) {
if (plugin.matcher(this)) return plugin.handler(this);
}
throw error('Unexpected token', this.peek(), this.input);
}
}
export default Parser;