initial commit
This commit is contained in:
commit
0298a062dd
39 changed files with 2448 additions and 0 deletions
71
src/compiler/parser.ts
Normal file
71
src/compiler/parser.ts
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
import type { ASTNode } from './ast';
|
||||
import type { Grammar } from './grammar';
|
||||
import type { Token, Tokenizer } from './tokenizer';
|
||||
|
||||
export class Parser {
|
||||
lookahead: Token | null = null;
|
||||
constructor(
|
||||
private tokenizer: Tokenizer,
|
||||
private grammar: Grammar,
|
||||
) {}
|
||||
|
||||
parse(source: string) {
|
||||
this.tokenizer.tokenize(source);
|
||||
this.nextToken();
|
||||
try {
|
||||
return this.parseExpr();
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
const token = this.lookahead;
|
||||
if (token) {
|
||||
throw new Error(
|
||||
`${error.message} at line ${token.line}, column ${token.col}`,
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
nextToken() {
|
||||
this.lookahead = this.tokenizer.nextToken();
|
||||
}
|
||||
|
||||
parseExpr(minBp = 0): ASTNode {
|
||||
const token = this.lookahead!;
|
||||
this.nextToken();
|
||||
|
||||
const prefixRule =
|
||||
this.grammar.prefixOperatorsByText.get(token.text) ??
|
||||
this.grammar.prefixOperatorsByKind.get(token.kind);
|
||||
if (!prefixRule) throw new Error(`Unexpected token ${token.text}`);
|
||||
let left = prefixRule.parse(this, token);
|
||||
|
||||
while (true) {
|
||||
const next = this.lookahead;
|
||||
if (!next) break;
|
||||
|
||||
// Check for postfix operators first
|
||||
const postfixRule =
|
||||
this.grammar.postfixOperatorsByText.get(next.text) ??
|
||||
this.grammar.postfixOperatorsByKind.get(next.kind);
|
||||
if (postfixRule) {
|
||||
this.nextToken();
|
||||
left = postfixRule.parse(this, next, left);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Then check for infix operators
|
||||
const infixRule =
|
||||
this.grammar.operatorsByText.get(next.text) ??
|
||||
this.grammar.operatorsByKind.get(next.kind);
|
||||
if (!infixRule || (infixRule.bp ?? 0) <= minBp) break;
|
||||
|
||||
this.nextToken();
|
||||
left = infixRule.parse(this, next, left);
|
||||
}
|
||||
|
||||
return left;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue