start multiple file support
This commit is contained in:
parent
242d5b16eb
commit
ed279f7998
@ -1,6 +1,13 @@
|
||||
import { Pos } from "./token.ts";
|
||||
import { VType } from "./vtype.ts";
|
||||
|
||||
export type Ast = File[];
|
||||
|
||||
export type File = {
|
||||
path: string;
|
||||
stmts: Stmt[];
|
||||
};
|
||||
|
||||
export type UnaryType = "not";
|
||||
export type BinaryType =
|
||||
| "+"
|
||||
@ -31,6 +38,7 @@ export type Stmt = {
|
||||
|
||||
export type StmtKind =
|
||||
| { type: "error" }
|
||||
| { type: "import"; path: Expr }
|
||||
| { type: "break"; expr?: Expr }
|
||||
| { type: "return"; expr?: Expr }
|
||||
| {
|
||||
|
@ -43,6 +43,8 @@ export class Lexer {
|
||||
return this.token("else", pos);
|
||||
case "struct":
|
||||
return this.token("struct", pos);
|
||||
case "import":
|
||||
return this.token("import", pos);
|
||||
default:
|
||||
return { ...this.token("ident", pos), identValue: value };
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { Ast, File } from "./ast.ts";
|
||||
import { Checker } from "./checker.ts";
|
||||
import { Reporter } from "./info.ts";
|
||||
import { Lexer } from "./lexer.ts";
|
||||
@ -5,6 +6,16 @@ import { Lowerer } from "./lowerer.ts";
|
||||
import { Parser } from "./parser.ts";
|
||||
import { Resolver } from "./resolver.ts";
|
||||
|
||||
class Compilation {
|
||||
private files: File[] = [];
|
||||
|
||||
public constructor(private startFile: string) {}
|
||||
|
||||
public compile(): Ast {
|
||||
throw new Error();
|
||||
}
|
||||
}
|
||||
|
||||
//const text = await Deno.readTextFile("example.slg");
|
||||
const text = await Deno.readTextFile(Deno.args[0]);
|
||||
|
||||
@ -13,7 +24,7 @@ const reporter = new Reporter();
|
||||
const lexer = new Lexer(text, reporter);
|
||||
|
||||
const parser = new Parser(lexer, reporter);
|
||||
const ast = parser.parseStmts();
|
||||
const ast = parser.parse();
|
||||
|
||||
// console.log(JSON.stringify(ast, null, 4));
|
||||
|
||||
|
@ -21,51 +21,29 @@ export class Parser {
|
||||
this.currentToken = lexer.next();
|
||||
}
|
||||
|
||||
private step() {
|
||||
this.currentToken = this.lexer.next();
|
||||
}
|
||||
public done(): boolean {
|
||||
return this.currentToken == null;
|
||||
}
|
||||
private current(): Token {
|
||||
return this.currentToken!;
|
||||
}
|
||||
private pos(): Pos {
|
||||
if (this.done()) {
|
||||
return this.lexer.currentPos();
|
||||
}
|
||||
return this.current().pos;
|
||||
public parse(): Stmt[] {
|
||||
return this.parseStmts();
|
||||
}
|
||||
|
||||
private test(type: string): boolean {
|
||||
return !this.done() && this.current().type === type;
|
||||
private parseStmts(): Stmt[] {
|
||||
const stmts: Stmt[] = [];
|
||||
while (!this.done()) {
|
||||
if (this.test("fn")) {
|
||||
stmts.push(this.parseFn());
|
||||
} else if (
|
||||
this.test("let") || this.test("return") || this.test("break")
|
||||
) {
|
||||
stmts.push(this.parseSingleLineBlockStmt());
|
||||
this.eatSemicolon();
|
||||
} else if (this.test("{") || this.test("if") || this.test("loop")) {
|
||||
const expr = this.parseMultiLineBlockExpr();
|
||||
stmts.push(this.stmt({ type: "expr", expr }, expr.pos));
|
||||
} else {
|
||||
stmts.push(this.parseAssign());
|
||||
this.eatSemicolon();
|
||||
}
|
||||
|
||||
private report(msg: string, pos = this.pos()) {
|
||||
this.reporter.reportError({
|
||||
msg,
|
||||
pos,
|
||||
reporter: "Parser",
|
||||
});
|
||||
printStackTrace();
|
||||
}
|
||||
|
||||
private stmt(kind: StmtKind, pos: Pos): Stmt {
|
||||
const id = this.nextNodeId;
|
||||
this.nextNodeId += 1;
|
||||
return { kind, pos, id };
|
||||
}
|
||||
|
||||
private expr(kind: ExprKind, pos: Pos): Expr {
|
||||
const id = this.nextNodeId;
|
||||
this.nextNodeId += 1;
|
||||
return { kind, pos, id };
|
||||
}
|
||||
|
||||
private etype(kind: ETypeKind, pos: Pos): EType {
|
||||
const id = this.nextNodeId;
|
||||
this.nextNodeId += 1;
|
||||
return { kind, pos, id };
|
||||
return stmts;
|
||||
}
|
||||
|
||||
private parseMultiLineBlockExpr(): Expr {
|
||||
@ -108,11 +86,11 @@ export class Parser {
|
||||
this.step();
|
||||
}
|
||||
|
||||
public parseExpr(): Expr {
|
||||
private parseExpr(): Expr {
|
||||
return this.parsePrefix();
|
||||
}
|
||||
|
||||
public parseBlock(): Expr {
|
||||
private parseBlock(): Expr {
|
||||
const pos = this.pos();
|
||||
this.step();
|
||||
let stmts: Stmt[] = [];
|
||||
@ -163,28 +141,7 @@ export class Parser {
|
||||
return this.expr({ type: "error" }, pos);
|
||||
}
|
||||
|
||||
public parseStmts(): Stmt[] {
|
||||
let stmts: Stmt[] = [];
|
||||
while (!this.done()) {
|
||||
if (this.test("fn")) {
|
||||
stmts.push(this.parseFn());
|
||||
} else if (
|
||||
this.test("let") || this.test("return") || this.test("break")
|
||||
) {
|
||||
stmts.push(this.parseSingleLineBlockStmt());
|
||||
this.eatSemicolon();
|
||||
} else if (this.test("{") || this.test("if") || this.test("loop")) {
|
||||
const expr = this.parseMultiLineBlockExpr();
|
||||
stmts.push(this.stmt({ type: "expr", expr }, expr.pos));
|
||||
} else {
|
||||
stmts.push(this.parseAssign());
|
||||
this.eatSemicolon();
|
||||
}
|
||||
}
|
||||
return stmts;
|
||||
}
|
||||
|
||||
public parseFn(): Stmt {
|
||||
private parseFn(): Stmt {
|
||||
const pos = this.pos();
|
||||
this.step();
|
||||
if (!this.test("ident")) {
|
||||
@ -226,7 +183,7 @@ export class Parser {
|
||||
);
|
||||
}
|
||||
|
||||
public parseAnnoArgs(): Expr[] {
|
||||
private parseAnnoArgs(): Expr[] {
|
||||
this.step();
|
||||
if (!this.test("(")) {
|
||||
this.report("expected '('");
|
||||
@ -252,7 +209,7 @@ export class Parser {
|
||||
return annoArgs;
|
||||
}
|
||||
|
||||
public parseAnno(): Anno | null {
|
||||
private parseAnno(): Anno | null {
|
||||
const pos = this.pos();
|
||||
this.step();
|
||||
if (!this.test("[")) {
|
||||
@ -274,7 +231,7 @@ export class Parser {
|
||||
return { ident, pos, values };
|
||||
}
|
||||
|
||||
public parseFnParams(): Param[] {
|
||||
private parseFnParams(): Param[] {
|
||||
this.step();
|
||||
if (this.test(")")) {
|
||||
this.step();
|
||||
@ -305,7 +262,7 @@ export class Parser {
|
||||
return params;
|
||||
}
|
||||
|
||||
public parseParam(): { ok: true; value: Param } | { ok: false } {
|
||||
private parseParam(): { ok: true; value: Param } | { ok: false } {
|
||||
const pos = this.pos();
|
||||
if (this.test("ident")) {
|
||||
const ident = this.current().identValue!;
|
||||
@ -321,7 +278,7 @@ export class Parser {
|
||||
return { ok: false };
|
||||
}
|
||||
|
||||
public parseLet(): Stmt {
|
||||
private parseLet(): Stmt {
|
||||
const pos = this.pos();
|
||||
this.step();
|
||||
const paramResult = this.parseParam();
|
||||
@ -337,7 +294,7 @@ export class Parser {
|
||||
const value = this.parseExpr();
|
||||
return this.stmt({ type: "let", param, value }, pos);
|
||||
}
|
||||
public parseAssign(): Stmt {
|
||||
private parseAssign(): Stmt {
|
||||
const pos = this.pos();
|
||||
const subject = this.parseExpr();
|
||||
if (!this.test("=")) {
|
||||
@ -348,7 +305,7 @@ export class Parser {
|
||||
return this.stmt({ type: "assign", subject, value }, pos);
|
||||
}
|
||||
|
||||
public parseReturn(): Stmt {
|
||||
private parseReturn(): Stmt {
|
||||
const pos = this.pos();
|
||||
this.step();
|
||||
if (this.test(";")) {
|
||||
@ -358,7 +315,7 @@ export class Parser {
|
||||
return this.stmt({ type: "return", expr }, pos);
|
||||
}
|
||||
|
||||
public parseBreak(): Stmt {
|
||||
private parseBreak(): Stmt {
|
||||
const pos = this.pos();
|
||||
this.step();
|
||||
if (this.test(";")) {
|
||||
@ -368,7 +325,7 @@ export class Parser {
|
||||
return this.stmt({ type: "break", expr }, pos);
|
||||
}
|
||||
|
||||
public parseLoop(): Expr {
|
||||
private parseLoop(): Expr {
|
||||
const pos = this.pos();
|
||||
this.step();
|
||||
if (!this.test("{")) {
|
||||
@ -379,7 +336,7 @@ export class Parser {
|
||||
return this.expr({ type: "loop", body }, pos);
|
||||
}
|
||||
|
||||
public parseIf(): Expr {
|
||||
private parseIf(): Expr {
|
||||
const pos = this.pos();
|
||||
this.step();
|
||||
const cond = this.parseExpr();
|
||||
@ -404,7 +361,7 @@ export class Parser {
|
||||
return this.expr({ type: "if", cond, truthy, falsy }, pos);
|
||||
}
|
||||
|
||||
public parsePrefix(): Expr {
|
||||
private parsePrefix(): Expr {
|
||||
const pos = this.pos();
|
||||
if (this.test("not")) {
|
||||
this.step();
|
||||
@ -435,7 +392,7 @@ export class Parser {
|
||||
return this.parsePostfix();
|
||||
}
|
||||
|
||||
public parseBinary(binaryType: BinaryType, pos: Pos): Expr | null {
|
||||
private parseBinary(binaryType: BinaryType, pos: Pos): Expr | null {
|
||||
if (this.test(binaryType)) {
|
||||
this.step();
|
||||
const left = this.parsePrefix();
|
||||
@ -445,7 +402,7 @@ export class Parser {
|
||||
return null;
|
||||
}
|
||||
|
||||
public parsePostfix(): Expr {
|
||||
private parsePostfix(): Expr {
|
||||
let subject = this.parseOperand();
|
||||
while (true) {
|
||||
const pos = this.pos();
|
||||
@ -497,7 +454,7 @@ export class Parser {
|
||||
return subject;
|
||||
}
|
||||
|
||||
public parseOperand(): Expr {
|
||||
private parseOperand(): Expr {
|
||||
const pos = this.pos();
|
||||
if (this.test("ident")) {
|
||||
const value = this.current().identValue!;
|
||||
@ -551,7 +508,7 @@ export class Parser {
|
||||
return this.expr({ type: "error" }, pos);
|
||||
}
|
||||
|
||||
public parseEType(): EType {
|
||||
private parseEType(): EType {
|
||||
const pos = this.pos();
|
||||
if (this.test("ident")) {
|
||||
const ident = this.current().identValue!;
|
||||
@ -581,7 +538,7 @@ export class Parser {
|
||||
return this.etype({ type: "error" }, pos);
|
||||
}
|
||||
|
||||
public parseETypeStructFields(): Param[] {
|
||||
private parseETypeStructFields(): Param[] {
|
||||
this.step();
|
||||
if (this.test("}")) {
|
||||
this.step();
|
||||
@ -611,4 +568,52 @@ export class Parser {
|
||||
this.step();
|
||||
return params;
|
||||
}
|
||||
|
||||
private step() {
|
||||
this.currentToken = this.lexer.next();
|
||||
}
|
||||
private done(): boolean {
|
||||
return this.currentToken == null;
|
||||
}
|
||||
private current(): Token {
|
||||
return this.currentToken!;
|
||||
}
|
||||
private pos(): Pos {
|
||||
if (this.done()) {
|
||||
return this.lexer.currentPos();
|
||||
}
|
||||
return this.current().pos;
|
||||
}
|
||||
|
||||
private test(type: string): boolean {
|
||||
return !this.done() && this.current().type === type;
|
||||
}
|
||||
|
||||
private report(msg: string, pos = this.pos()) {
|
||||
console.log(`Parser: ${msg} at ${pos.line}:${pos.col}`);
|
||||
this.reporter.reportError({
|
||||
msg,
|
||||
pos,
|
||||
reporter: "Parser",
|
||||
});
|
||||
printStackTrace();
|
||||
}
|
||||
|
||||
private stmt(kind: StmtKind, pos: Pos): Stmt {
|
||||
const id = this.nextNodeId;
|
||||
this.nextNodeId += 1;
|
||||
return { kind, pos, id };
|
||||
}
|
||||
|
||||
private expr(kind: ExprKind, pos: Pos): Expr {
|
||||
const id = this.nextNodeId;
|
||||
this.nextNodeId += 1;
|
||||
return { kind, pos, id };
|
||||
}
|
||||
|
||||
private etype(kind: ETypeKind, pos: Pos): EType {
|
||||
const id = this.nextNodeId;
|
||||
this.nextNodeId += 1;
|
||||
return { kind, pos, id };
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user