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