mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 13:06:30 +00:00
details, not trailing anno
This commit is contained in:
parent
94a57029c0
commit
f2b1323337
@ -10,6 +10,7 @@ export type Mod = {
|
|||||||
export type Stmt = {
|
export type Stmt = {
|
||||||
kind: StmtKind;
|
kind: StmtKind;
|
||||||
pos: Pos;
|
pos: Pos;
|
||||||
|
details?: StmtDetails;
|
||||||
id: number;
|
id: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,7 +28,6 @@ export type StmtKind =
|
|||||||
params: Param[];
|
params: Param[];
|
||||||
returnType?: EType;
|
returnType?: EType;
|
||||||
body: Expr;
|
body: Expr;
|
||||||
anno?: Anno;
|
|
||||||
vtype?: VType;
|
vtype?: VType;
|
||||||
}
|
}
|
||||||
| { type: "let"; param: Param; value: Expr }
|
| { type: "let"; param: Param; value: Expr }
|
||||||
@ -36,6 +36,11 @@ export type StmtKind =
|
|||||||
|
|
||||||
export type AssignType = "=" | "+=" | "-=";
|
export type AssignType = "=" | "+=" | "-=";
|
||||||
|
|
||||||
|
export type StmtDetails = {
|
||||||
|
pub: boolean;
|
||||||
|
annos: Anno[];
|
||||||
|
};
|
||||||
|
|
||||||
export type Expr = {
|
export type Expr = {
|
||||||
kind: ExprKind;
|
kind: ExprKind;
|
||||||
pos: Pos;
|
pos: Pos;
|
||||||
@ -147,17 +152,17 @@ export type GenericParam = {
|
|||||||
|
|
||||||
export type Anno = {
|
export type Anno = {
|
||||||
ident: string;
|
ident: string;
|
||||||
values: Expr[];
|
args: Expr[];
|
||||||
pos: Pos;
|
pos: Pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class AstCreator {
|
export class AstCreator {
|
||||||
private nextNodeId = 0;
|
private nextNodeId = 0;
|
||||||
|
|
||||||
public stmt(kind: StmtKind, pos: Pos): Stmt {
|
public stmt(kind: StmtKind, pos: Pos, details?: StmtDetails): Stmt {
|
||||||
const id = this.nextNodeId;
|
const id = this.nextNodeId;
|
||||||
this.nextNodeId += 1;
|
this.nextNodeId += 1;
|
||||||
return { kind, pos, id };
|
return { kind, pos, details, id };
|
||||||
}
|
}
|
||||||
|
|
||||||
public expr(kind: ExprKind, pos: Pos): Expr {
|
public expr(kind: ExprKind, pos: Pos): Expr {
|
||||||
@ -172,3 +177,21 @@ export class AstCreator {
|
|||||||
return { kind, pos, id };
|
return { kind, pos, id };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class AnnoView {
|
||||||
|
public constructor(private details?: StmtDetails) {}
|
||||||
|
|
||||||
|
public has(...idents: string[]): boolean {
|
||||||
|
return this.details?.annos.some((anno) =>
|
||||||
|
idents.some((ident) => anno.ident === ident)
|
||||||
|
) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get(ident: string): Anno {
|
||||||
|
const anno = this.details?.annos.find((anno) => anno.ident === ident);
|
||||||
|
if (!anno) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
return anno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { EType, Expr, Stmt, Sym } from "./ast.ts";
|
import { AnnoView, EType, Expr, Stmt, Sym } from "./ast.ts";
|
||||||
import { printStackTrace, Reporter } from "./info.ts";
|
import { printStackTrace, Reporter } from "./info.ts";
|
||||||
import { Pos } from "./token.ts";
|
import { Pos } from "./token.ts";
|
||||||
import {
|
import {
|
||||||
@ -162,12 +162,12 @@ export class Checker {
|
|||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
const annos = new AnnoView(stmt.details);
|
||||||
stmt.kind.anno?.ident === "remainder" ||
|
if (annos.has("builtin", "remainder")) {
|
||||||
stmt.kind.anno?.ident === "builtin"
|
// NOTE: handled in lowerer
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { returnType } = stmt.kind.vtype!;
|
const { returnType } = stmt.kind.vtype!;
|
||||||
if (returnType.type === "error") return returnType;
|
if (returnType.type === "error") return returnType;
|
||||||
this.fnReturnStack.push(returnType);
|
this.fnReturnStack.push(returnType);
|
||||||
|
@ -48,6 +48,8 @@ export class Lexer {
|
|||||||
"for",
|
"for",
|
||||||
"in",
|
"in",
|
||||||
"mod",
|
"mod",
|
||||||
|
"pub",
|
||||||
|
"use",
|
||||||
];
|
];
|
||||||
if (keywords.includes(value)) {
|
if (keywords.includes(value)) {
|
||||||
return this.token(value, pos);
|
return this.token(value, pos);
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Builtins, Ops } from "./arch.ts";
|
import { Builtins, Ops } from "./arch.ts";
|
||||||
import { Assembler, Label } from "./assembler.ts";
|
import { Assembler, Label } from "./assembler.ts";
|
||||||
import { Expr, Stmt } from "./ast.ts";
|
import { AnnoView, Expr, Stmt } from "./ast.ts";
|
||||||
import { LocalLeaf, Locals, LocalsFnRoot } from "./lowerer_locals.ts";
|
import { LocalLeaf, Locals, LocalsFnRoot } from "./lowerer_locals.ts";
|
||||||
import { MonoCallNameGenMap, MonoFn, MonoFnsMap } from "./mono.ts";
|
import { MonoCallNameGenMap, MonoFn, MonoFnsMap } from "./mono.ts";
|
||||||
import { Pos } from "./token.ts";
|
import { Pos } from "./token.ts";
|
||||||
@ -111,9 +111,15 @@ class MonoFnLowerer {
|
|||||||
for (const { ident } of stmt.kind.params) {
|
for (const { ident } of stmt.kind.params) {
|
||||||
this.locals.allocSym(ident);
|
this.locals.allocSym(ident);
|
||||||
}
|
}
|
||||||
if (stmt.kind.anno?.ident === "builtin") {
|
|
||||||
this.lowerFnBuiltinBody(stmt.kind.anno.values);
|
const annos = new AnnoView(stmt.details);
|
||||||
} else if (stmt.kind.anno?.ident === "remainder") {
|
if (annos.has("builtin")) {
|
||||||
|
const anno = annos.get("builtin");
|
||||||
|
if (!anno) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
this.lowerFnBuiltinBody(anno.args);
|
||||||
|
} else if (annos.has("remainder")) {
|
||||||
this.program.add(Ops.Remainder);
|
this.program.add(Ops.Remainder);
|
||||||
} else {
|
} else {
|
||||||
this.lowerExpr(stmt.kind.body);
|
this.lowerExpr(stmt.kind.body);
|
||||||
|
@ -10,6 +10,7 @@ import {
|
|||||||
GenericParam,
|
GenericParam,
|
||||||
Param,
|
Param,
|
||||||
Stmt,
|
Stmt,
|
||||||
|
StmtDetails,
|
||||||
StmtKind,
|
StmtKind,
|
||||||
UnaryType,
|
UnaryType,
|
||||||
} from "./ast.ts";
|
} from "./ast.ts";
|
||||||
@ -37,18 +38,18 @@ export class Parser {
|
|||||||
private parseStmts(): Stmt[] {
|
private parseStmts(): Stmt[] {
|
||||||
const stmts: Stmt[] = [];
|
const stmts: Stmt[] = [];
|
||||||
while (!this.done()) {
|
while (!this.done()) {
|
||||||
stmts.push(this.parseModStmt());
|
stmts.push(this.parseStmt());
|
||||||
}
|
}
|
||||||
return stmts;
|
return stmts;
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseModStmt(): Stmt {
|
private parseStmt(): Stmt {
|
||||||
if (this.test("mod")) {
|
if (
|
||||||
return (this.parseMod());
|
["#", "pub", "mod", "fn"].some((tt) => this.test(tt))
|
||||||
} else if (this.test("fn")) {
|
) {
|
||||||
return (this.parseFn());
|
return this.parseItemStmt();
|
||||||
} else if (
|
} else if (
|
||||||
this.test("let") || this.test("return") || this.test("break")
|
["let", "return", "break"].some((tt) => this.test(tt))
|
||||||
) {
|
) {
|
||||||
const expr = this.parseSingleLineBlockStmt();
|
const expr = this.parseSingleLineBlockStmt();
|
||||||
this.eatSemicolon();
|
this.eatSemicolon();
|
||||||
@ -65,42 +66,6 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseMod(): Stmt {
|
|
||||||
const pos = this.pos();
|
|
||||||
this.step();
|
|
||||||
if (!this.test("ident")) {
|
|
||||||
this.report("expected 'ident'");
|
|
||||||
return this.stmt({ type: "error" }, pos);
|
|
||||||
}
|
|
||||||
const ident = this.current().identValue!;
|
|
||||||
this.step();
|
|
||||||
if (this.test("string")) {
|
|
||||||
const filePath = this.current().stringValue!;
|
|
||||||
this.step();
|
|
||||||
this.eatSemicolon();
|
|
||||||
return this.stmt({ type: "mod_file", ident, filePath }, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.test("{")) {
|
|
||||||
this.report("expected '{' or 'string'");
|
|
||||||
return this.stmt({ type: "error" }, pos);
|
|
||||||
}
|
|
||||||
this.step();
|
|
||||||
|
|
||||||
const stmts: Stmt[] = [];
|
|
||||||
while (!this.done() && !this.test("}")) {
|
|
||||||
stmts.push(this.parseModStmt());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.test("}")) {
|
|
||||||
this.report("expected '}'");
|
|
||||||
return this.stmt({ type: "error" }, pos);
|
|
||||||
}
|
|
||||||
this.step();
|
|
||||||
|
|
||||||
return this.stmt({ type: "mod_block", ident, stmts }, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
private parseMultiLineBlockExpr(): Expr {
|
private parseMultiLineBlockExpr(): Expr {
|
||||||
const pos = this.pos();
|
const pos = this.pos();
|
||||||
if (this.test("{")) {
|
if (this.test("{")) {
|
||||||
@ -160,13 +125,14 @@ export class Parser {
|
|||||||
this.step();
|
this.step();
|
||||||
return this.expr({ type: "block", stmts }, pos);
|
return this.expr({ type: "block", stmts }, pos);
|
||||||
} else if (
|
} else if (
|
||||||
this.test("return") || this.test("break") || this.test("let")
|
["#", "pub", "mod", "fn"].some((tt) => this.test(tt))
|
||||||
|
) {
|
||||||
|
stmts.push(this.parseItemStmt());
|
||||||
|
} else if (
|
||||||
|
["let", "return", "break"].some((tt) => this.test(tt))
|
||||||
) {
|
) {
|
||||||
stmts.push(this.parseSingleLineBlockStmt());
|
stmts.push(this.parseSingleLineBlockStmt());
|
||||||
this.eatSemicolon();
|
this.eatSemicolon();
|
||||||
} else if (this.test("fn")) {
|
|
||||||
stmts.push(this.parseSingleLineBlockStmt());
|
|
||||||
stmts.push(this.parseFn());
|
|
||||||
} else if (
|
} else if (
|
||||||
["{", "if", "loop", "while", "for"].some((tt) => this.test(tt))
|
["{", "if", "loop", "while", "for"].some((tt) => this.test(tt))
|
||||||
) {
|
) {
|
||||||
@ -210,7 +176,103 @@ export class Parser {
|
|||||||
return this.expr({ type: "error" }, pos);
|
return this.expr({ type: "error" }, pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseFn(): Stmt {
|
private parseItemStmt(
|
||||||
|
pos = this.pos(),
|
||||||
|
details: StmtDetails = {
|
||||||
|
pub: false,
|
||||||
|
annos: [],
|
||||||
|
},
|
||||||
|
): Stmt {
|
||||||
|
const spos = this.pos();
|
||||||
|
if (this.test("#") && !details.pub) {
|
||||||
|
this.step();
|
||||||
|
if (!this.test("[")) {
|
||||||
|
this.report("expected '['");
|
||||||
|
return this.stmt({ type: "error" }, spos);
|
||||||
|
}
|
||||||
|
this.step();
|
||||||
|
if (!this.test("ident")) {
|
||||||
|
this.report("expected 'ident'");
|
||||||
|
return this.stmt({ type: "error" }, spos);
|
||||||
|
}
|
||||||
|
const ident = this.current().identValue!;
|
||||||
|
this.step();
|
||||||
|
const args: Expr[] = [];
|
||||||
|
if (this.test("(")) {
|
||||||
|
this.step();
|
||||||
|
if (!this.done() && !this.test(")")) {
|
||||||
|
args.push(this.parseExpr());
|
||||||
|
while (this.test(",")) {
|
||||||
|
this.step();
|
||||||
|
args.push(this.parseExpr());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.test(")")) {
|
||||||
|
this.report("expected ')'");
|
||||||
|
return this.stmt({ type: "error" }, spos);
|
||||||
|
}
|
||||||
|
this.step();
|
||||||
|
}
|
||||||
|
if (!this.test("]")) {
|
||||||
|
this.report("expected ']'");
|
||||||
|
return this.stmt({ type: "error" }, spos);
|
||||||
|
}
|
||||||
|
this.step();
|
||||||
|
const anno = { ident, args, pos: spos };
|
||||||
|
return this.parseItemStmt(pos, {
|
||||||
|
...details,
|
||||||
|
annos: [...details.annos, anno],
|
||||||
|
});
|
||||||
|
} else if (this.test("pub") && !details.pub) {
|
||||||
|
this.step();
|
||||||
|
return this.parseItemStmt(pos, { ...details, pub: true });
|
||||||
|
} else if (this.test("mod")) {
|
||||||
|
return this.parseMod(details);
|
||||||
|
} else if (this.test("fn")) {
|
||||||
|
return this.parseFn(details);
|
||||||
|
} else {
|
||||||
|
this.report("expected item statement");
|
||||||
|
return this.stmt({ type: "error" }, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseMod(details: StmtDetails): Stmt {
|
||||||
|
const pos = this.pos();
|
||||||
|
this.step();
|
||||||
|
if (!this.test("ident")) {
|
||||||
|
this.report("expected 'ident'");
|
||||||
|
return this.stmt({ type: "error" }, pos);
|
||||||
|
}
|
||||||
|
const ident = this.current().identValue!;
|
||||||
|
this.step();
|
||||||
|
if (this.test("string")) {
|
||||||
|
const filePath = this.current().stringValue!;
|
||||||
|
this.step();
|
||||||
|
this.eatSemicolon();
|
||||||
|
return this.stmt({ type: "mod_file", ident, filePath }, pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.test("{")) {
|
||||||
|
this.report("expected '{' or 'string'");
|
||||||
|
return this.stmt({ type: "error" }, pos);
|
||||||
|
}
|
||||||
|
this.step();
|
||||||
|
|
||||||
|
const stmts: Stmt[] = [];
|
||||||
|
while (!this.done() && !this.test("}")) {
|
||||||
|
stmts.push(this.parseStmt());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.test("}")) {
|
||||||
|
this.report("expected '}'");
|
||||||
|
return this.stmt({ type: "error" }, pos);
|
||||||
|
}
|
||||||
|
this.step();
|
||||||
|
|
||||||
|
return this.stmt({ type: "mod_block", ident, stmts }, pos, details);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseFn(details: StmtDetails): Stmt {
|
||||||
const pos = this.pos();
|
const pos = this.pos();
|
||||||
this.step();
|
this.step();
|
||||||
if (!this.test("ident")) {
|
if (!this.test("ident")) {
|
||||||
@ -234,14 +296,6 @@ export class Parser {
|
|||||||
returnType = this.parseEType();
|
returnType = this.parseEType();
|
||||||
}
|
}
|
||||||
|
|
||||||
let anno: Anno | undefined;
|
|
||||||
if (this.test("#")) {
|
|
||||||
const result = this.parseAnno();
|
|
||||||
if (!result.ok) {
|
|
||||||
return this.stmt({ type: "error" }, pos);
|
|
||||||
}
|
|
||||||
anno = result.value;
|
|
||||||
}
|
|
||||||
if (!this.test("{")) {
|
if (!this.test("{")) {
|
||||||
this.report("expected block");
|
this.report("expected block");
|
||||||
return this.stmt({ type: "error" }, pos);
|
return this.stmt({ type: "error" }, pos);
|
||||||
@ -255,60 +309,12 @@ export class Parser {
|
|||||||
params,
|
params,
|
||||||
returnType,
|
returnType,
|
||||||
body,
|
body,
|
||||||
anno,
|
|
||||||
},
|
},
|
||||||
pos,
|
pos,
|
||||||
|
details,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseAnnoArgs(): Expr[] {
|
|
||||||
this.step();
|
|
||||||
if (!this.test("(")) {
|
|
||||||
this.report("expected '('");
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
this.step();
|
|
||||||
const annoArgs: Expr[] = [];
|
|
||||||
if (!this.test(")")) {
|
|
||||||
annoArgs.push(this.parseExpr());
|
|
||||||
while (this.test(",")) {
|
|
||||||
this.step();
|
|
||||||
if (this.test(")")) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
annoArgs.push(this.parseExpr());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!this.test(")")) {
|
|
||||||
this.report("expected ')'");
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
this.step();
|
|
||||||
return annoArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private parseAnno(): Res<Anno> {
|
|
||||||
const pos = this.pos();
|
|
||||||
this.step();
|
|
||||||
if (!this.test("[")) {
|
|
||||||
this.report("expected '['");
|
|
||||||
return { ok: false };
|
|
||||||
}
|
|
||||||
this.step();
|
|
||||||
if (!this.test("ident")) {
|
|
||||||
this.report("expected identifier");
|
|
||||||
return { ok: false };
|
|
||||||
}
|
|
||||||
const ident = this.current().identValue!;
|
|
||||||
const values = this.parseAnnoArgs();
|
|
||||||
if (!this.test("]")) {
|
|
||||||
this.report("expected ']'");
|
|
||||||
return { ok: false };
|
|
||||||
}
|
|
||||||
this.step();
|
|
||||||
return { ok: true, value: { ident, pos, values } };
|
|
||||||
}
|
|
||||||
|
|
||||||
private parseFnETypeParams(): GenericParam[] {
|
private parseFnETypeParams(): GenericParam[] {
|
||||||
return this.parseDelimitedList(this.parseETypeParam, ">", ",");
|
return this.parseDelimitedList(this.parseETypeParam, ">", ",");
|
||||||
}
|
}
|
||||||
@ -920,8 +926,8 @@ export class Parser {
|
|||||||
printStackTrace();
|
printStackTrace();
|
||||||
}
|
}
|
||||||
|
|
||||||
private stmt(kind: StmtKind, pos: Pos): Stmt {
|
private stmt(kind: StmtKind, pos: Pos, details?: StmtDetails): Stmt {
|
||||||
return this.astCreator.stmt(kind, pos);
|
return this.astCreator.stmt(kind, pos, details);
|
||||||
}
|
}
|
||||||
|
|
||||||
private expr(kind: ExprKind, pos: Pos): Expr {
|
private expr(kind: ExprKind, pos: Pos): Expr {
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
fn print(msg: string) #[builtin(print)] {
|
//
|
||||||
|
|
||||||
|
#[builtin(Print)]
|
||||||
|
fn print(msg: string) {
|
||||||
"hello" + 0
|
"hello" + 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user