this commit kinda sucks
This commit is contained in:
parent
5642e3fc5a
commit
7ffd2879d1
@ -4,7 +4,14 @@ import { GenericArgsMap, VType } from "./vtype.ts";
|
||||
|
||||
export type Mod = {
|
||||
filePath: string;
|
||||
ast: Stmt[];
|
||||
items: Item[];
|
||||
};
|
||||
|
||||
export type Item = {
|
||||
stmt: Stmt;
|
||||
pub: boolean;
|
||||
annos?: Anno[];
|
||||
pos: Pos;
|
||||
};
|
||||
|
||||
export type Stmt = {
|
||||
@ -15,9 +22,10 @@ export type Stmt = {
|
||||
|
||||
export type StmtKind =
|
||||
| { type: "error" }
|
||||
| { type: "mod_block"; ident: string; stmts: Stmt[] }
|
||||
| { type: "mod_block"; ident: string; items: Item[] }
|
||||
| { type: "mod_file"; ident: string; filePath: string }
|
||||
| { type: "mod"; ident: string; mod: Mod }
|
||||
| { type: "item"; item: Item }
|
||||
| { type: "break"; expr?: Expr }
|
||||
| { type: "return"; expr?: Expr }
|
||||
| {
|
||||
@ -27,7 +35,6 @@ export type StmtKind =
|
||||
params: Param[];
|
||||
returnType?: EType;
|
||||
body: Expr;
|
||||
anno?: Anno;
|
||||
vtype?: VType;
|
||||
}
|
||||
| { type: "let"; param: Param; value: Expr }
|
||||
@ -147,7 +154,7 @@ export type GenericParam = {
|
||||
|
||||
export type Anno = {
|
||||
ident: string;
|
||||
values: Expr[];
|
||||
args: Expr[];
|
||||
pos: Pos;
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { EType, Expr, Param, Stmt } from "./ast.ts";
|
||||
import { EType, Expr, Item, Param, Stmt } from "./ast.ts";
|
||||
|
||||
export type VisitRes = "stop" | void;
|
||||
|
||||
export interface AstVisitor<Args extends unknown[] = []> {
|
||||
visitItems?(items: Item[], ...args: Args): VisitRes;
|
||||
visitItem?(item: Item, ...args: Args): VisitRes;
|
||||
visitStmts?(stmts: Stmt[], ...args: Args): VisitRes;
|
||||
visitStmt?(stmt: Stmt, ...args: Args): VisitRes;
|
||||
visitErrorStmt?(stmt: Stmt, ...args: Args): VisitRes;
|
||||
@ -48,7 +50,24 @@ export interface AstVisitor<Args extends unknown[] = []> {
|
||||
visitSymEType?(etype: EType, ...args: Args): VisitRes;
|
||||
visitArrayEType?(etype: EType, ...args: Args): VisitRes;
|
||||
visitStructEType?(etype: EType, ...args: Args): VisitRes;
|
||||
visitAnno?(etype: EType, ...args: Args): VisitRes;
|
||||
}
|
||||
|
||||
export function visitItems<Args extends unknown[] = []>(
|
||||
items: Item[],
|
||||
v: AstVisitor<Args>,
|
||||
...args: Args
|
||||
) {
|
||||
if (v.visitItems?.(items, ...args) === "stop") return;
|
||||
items.map((item) => visitItem(item, v, ...args));
|
||||
}
|
||||
|
||||
export function visitItem<Args extends unknown[] = []>(
|
||||
item: Item,
|
||||
v: AstVisitor<Args>,
|
||||
...args: Args
|
||||
) {
|
||||
if (v.visitItem?.(item, ...args) == "stop") return;
|
||||
visitStmt(item.stmt, v, ...args);
|
||||
}
|
||||
|
||||
export function visitStmts<Args extends unknown[] = []>(
|
||||
@ -75,11 +94,11 @@ export function visitStmt<Args extends unknown[] = []>(
|
||||
break;
|
||||
case "mod_block":
|
||||
if (v.visitModBlockStmt?.(stmt, ...args) == "stop") return;
|
||||
visitStmts(stmt.kind.stmts, v, ...args);
|
||||
visitItems(stmt.kind.items, v, ...args);
|
||||
break;
|
||||
case "mod":
|
||||
if (v.visitModStmt?.(stmt, ...args) == "stop") return;
|
||||
visitStmts(stmt.kind.mod.ast, v, ...args);
|
||||
visitItems(stmt.kind.mod.items, v, ...args);
|
||||
break;
|
||||
case "break":
|
||||
if (v.visitBreakStmt?.(stmt, ...args) == "stop") return;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { EType, Expr, Stmt, Sym } from "./ast.ts";
|
||||
import { EType, Expr, Item, Stmt, Sym } from "./ast.ts";
|
||||
import { printStackTrace, Reporter } from "./info.ts";
|
||||
import { Pos } from "./token.ts";
|
||||
import {
|
||||
@ -19,15 +19,16 @@ export class Checker {
|
||||
|
||||
public constructor(private reporter: Reporter) {}
|
||||
|
||||
public check(stmts: Stmt[]) {
|
||||
this.checkFnHeaders(stmts);
|
||||
for (const stmt of stmts) {
|
||||
this.checkStmt(stmt);
|
||||
public check(items: Item[]) {
|
||||
this.scoutItems(items);
|
||||
for (const item of items) {
|
||||
this.checkItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
private checkFnHeaders(stmts: Stmt[]) {
|
||||
for (const stmt of stmts) {
|
||||
private scoutItems(items: Item[]) {
|
||||
for (const item of items) {
|
||||
const { stmt } = item;
|
||||
if (stmt.kind.type !== "fn") {
|
||||
continue;
|
||||
}
|
||||
@ -65,6 +66,15 @@ export class Checker {
|
||||
}
|
||||
}
|
||||
|
||||
private checkItem(item: Item) {
|
||||
switch (item.stmt.kind.type) {
|
||||
case "fn":
|
||||
return this.checkFnItem(item);
|
||||
default:
|
||||
return this.checkStmt(item.stmt);
|
||||
}
|
||||
}
|
||||
|
||||
public checkStmt(stmt: Stmt) {
|
||||
switch (stmt.kind.type) {
|
||||
case "error":
|
||||
@ -79,7 +89,7 @@ export class Checker {
|
||||
case "return":
|
||||
return this.checkReturnStmt(stmt);
|
||||
case "fn":
|
||||
return this.checkFnStmt(stmt);
|
||||
throw new Error("item, not stmt");
|
||||
case "let":
|
||||
return this.checkLetStmt(stmt);
|
||||
case "assign":
|
||||
@ -93,10 +103,10 @@ export class Checker {
|
||||
if (stmt.kind.type !== "mod") {
|
||||
throw new Error();
|
||||
}
|
||||
const { ast } = stmt.kind.mod;
|
||||
this.checkFnHeaders(ast);
|
||||
for (const stmt of ast) {
|
||||
this.checkStmt(stmt);
|
||||
const { items } = stmt.kind.mod;
|
||||
this.scoutItems(items);
|
||||
for (const item of items) {
|
||||
this.checkItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,7 +163,8 @@ export class Checker {
|
||||
}
|
||||
}
|
||||
|
||||
public checkFnStmt(stmt: Stmt) {
|
||||
public checkFnItem(item: Item) {
|
||||
const { stmt } = item;
|
||||
if (stmt.kind.type !== "fn") {
|
||||
throw new Error();
|
||||
}
|
||||
@ -163,8 +174,9 @@ export class Checker {
|
||||
}
|
||||
|
||||
if (
|
||||
stmt.kind.anno?.ident === "remainder" ||
|
||||
stmt.kind.anno?.ident === "builtin"
|
||||
item.annos?.some((anno) =>
|
||||
["remainder", "builtin"].includes(anno.ident)
|
||||
) ?? false
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@ -910,7 +922,14 @@ export class Checker {
|
||||
if (expr.kind.type !== "block") {
|
||||
throw new Error();
|
||||
}
|
||||
this.checkFnHeaders(expr.kind.stmts);
|
||||
this.scoutItems(
|
||||
expr.kind.stmts
|
||||
.filter((stmt) => stmt.kind.type === "item")
|
||||
.map((stmt) =>
|
||||
stmt.kind.type === "item" ? stmt.kind.item : undefined
|
||||
)
|
||||
.filter((item) => item !== undefined),
|
||||
);
|
||||
for (const stmt of expr.kind.stmts) {
|
||||
this.checkStmt(stmt);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { AstCreator, Mod, Stmt } from "./ast.ts";
|
||||
import { AstCreator, Item, Mod, Stmt } from "./ast.ts";
|
||||
import { Checker } from "./checker.ts";
|
||||
import { CompoundAssignDesugarer } from "./desugar/compound_assign.ts";
|
||||
import { SpecialLoopDesugarer } from "./desugar/special_loop.ts";
|
||||
@ -8,10 +8,10 @@ import { Monomorphizer } from "./mono.ts";
|
||||
import { FnNamesMap, Lowerer } from "./lowerer.ts";
|
||||
import { Parser } from "./parser.ts";
|
||||
import { Resolver } from "./resolver.ts";
|
||||
import { AstVisitor, VisitRes, visitStmts } from "./ast_visitor.ts";
|
||||
import { AstVisitor, visitItems, VisitRes } from "./ast_visitor.ts";
|
||||
import { Pos } from "./token.ts";
|
||||
|
||||
import * as path from "jsr:@std/path";
|
||||
import { Pos } from "./token.ts";
|
||||
|
||||
export type CompileResult = {
|
||||
program: number[];
|
||||
@ -33,20 +33,21 @@ export class Compiler {
|
||||
this.reporter,
|
||||
).resolve();
|
||||
|
||||
new SpecialLoopDesugarer(this.astCreator).desugar(mod.ast);
|
||||
new SpecialLoopDesugarer(this.astCreator).desugar(mod.items);
|
||||
|
||||
new Resolver(this.reporter).resolve(mod.ast);
|
||||
new Resolver(this.reporter).resolve(mod.items);
|
||||
|
||||
new CompoundAssignDesugarer(this.astCreator).desugar(mod.ast);
|
||||
new CompoundAssignDesugarer(this.astCreator).desugar(mod.items);
|
||||
|
||||
new Checker(this.reporter).check(mod.ast);
|
||||
new Checker(this.reporter).check(mod.items);
|
||||
|
||||
if (this.reporter.errorOccured()) {
|
||||
console.error("Errors occurred, stopping compilation.");
|
||||
Deno.exit(1);
|
||||
}
|
||||
|
||||
const { monoFns, callMap } = new Monomorphizer(mod.ast).monomorphize();
|
||||
const { monoFns, callMap } = new Monomorphizer(mod.items)
|
||||
.monomorphize();
|
||||
|
||||
const lastPos = await lastPosInTextFile(this.startFilePath);
|
||||
|
||||
@ -68,12 +69,12 @@ export class ModTree implements AstVisitor<[string]> {
|
||||
public resolve(): Mod {
|
||||
const entryAst = this.parseFile(this.entryFilePath);
|
||||
|
||||
visitStmts(entryAst, this, this.entryFilePath);
|
||||
visitItems(entryAst, this, this.entryFilePath);
|
||||
|
||||
return { filePath: this.entryFilePath, ast: entryAst };
|
||||
return { filePath: this.entryFilePath, items: entryAst };
|
||||
}
|
||||
|
||||
private parseFile(filePath: string): Stmt[] {
|
||||
private parseFile(filePath: string): Item[] {
|
||||
const text = Deno.readTextFileSync(filePath);
|
||||
|
||||
const lexer = new Lexer(text, this.reporter);
|
||||
@ -88,13 +89,13 @@ export class ModTree implements AstVisitor<[string]> {
|
||||
if (stmt.kind.type !== "mod_block") {
|
||||
throw new Error();
|
||||
}
|
||||
const { ident, stmts: ast } = stmt.kind;
|
||||
const { ident, items } = stmt.kind;
|
||||
stmt.kind = {
|
||||
type: "mod",
|
||||
ident,
|
||||
mod: { filePath, ast },
|
||||
mod: { filePath, items },
|
||||
};
|
||||
visitStmts(ast, this, filePath);
|
||||
visitItems(items, this, filePath);
|
||||
return "stop";
|
||||
}
|
||||
|
||||
@ -109,9 +110,9 @@ export class ModTree implements AstVisitor<[string]> {
|
||||
stmt.kind = {
|
||||
type: "mod",
|
||||
ident,
|
||||
mod: { filePath, ast },
|
||||
mod: { filePath, items: ast },
|
||||
};
|
||||
visitStmts(ast, this, filePath);
|
||||
visitItems(ast, this, filePath);
|
||||
return "stop";
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
import { AstCreator, Stmt } from "../ast.ts";
|
||||
import { AstVisitor, VisitRes, visitStmt, visitStmts } from "../ast_visitor.ts";
|
||||
import { AstCreator, Item, Stmt } from "../ast.ts";
|
||||
import { AstVisitor, visitItems, VisitRes, visitStmt } from "../ast_visitor.ts";
|
||||
|
||||
export class CompoundAssignDesugarer implements AstVisitor {
|
||||
public constructor(private astCreator: AstCreator) {}
|
||||
|
||||
public desugar(stmts: Stmt[]) {
|
||||
visitStmts(stmts, this);
|
||||
public desugar(items: Item[]) {
|
||||
visitItems(items, this);
|
||||
}
|
||||
|
||||
visitAssignStmt(stmt: Stmt): VisitRes {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { AstCreator, Expr, ExprKind, Stmt, StmtKind } from "../ast.ts";
|
||||
import { AstVisitor, visitExpr, VisitRes, visitStmts } from "../ast_visitor.ts";
|
||||
import { AstCreator, Expr, ExprKind, Item, StmtKind } from "../ast.ts";
|
||||
import { AstVisitor, visitExpr, visitItems, VisitRes } from "../ast_visitor.ts";
|
||||
import { Pos } from "../token.ts";
|
||||
|
||||
export class SpecialLoopDesugarer implements AstVisitor {
|
||||
@ -7,8 +7,8 @@ export class SpecialLoopDesugarer implements AstVisitor {
|
||||
private astCreator: AstCreator,
|
||||
) {}
|
||||
|
||||
public desugar(stmts: Stmt[]) {
|
||||
visitStmts(stmts, this);
|
||||
public desugar(items: Item[]) {
|
||||
visitItems(items, this);
|
||||
}
|
||||
|
||||
visitWhileExpr(expr: Expr): VisitRes {
|
||||
|
@ -48,6 +48,7 @@ export class Lexer {
|
||||
"for",
|
||||
"in",
|
||||
"mod",
|
||||
"pub",
|
||||
];
|
||||
if (keywords.includes(value)) {
|
||||
return this.token(value, pos);
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { Expr, Stmt } from "./ast.ts";
|
||||
import { AstVisitor, visitExpr, VisitRes, visitStmts } from "./ast_visitor.ts";
|
||||
import { Expr, Item, Stmt } from "./ast.ts";
|
||||
import { AstVisitor, visitExpr, visitItems, VisitRes } from "./ast_visitor.ts";
|
||||
import { GenericArgsMap, VType } from "./vtype.ts";
|
||||
|
||||
export class Monomorphizer {
|
||||
private fnIdCounter = 0;
|
||||
private fns: MonoFnsMap = {};
|
||||
private callMap: MonoCallNameGenMap = {};
|
||||
private allFns: Map<number, Stmt>;
|
||||
private entryFn: Stmt;
|
||||
private allFns: Map<number, Item>;
|
||||
private entryFn: Item;
|
||||
|
||||
constructor(private ast: Stmt[]) {
|
||||
constructor(private ast: Item[]) {
|
||||
this.allFns = new AllFnsCollector().collect(this.ast);
|
||||
this.entryFn = findMain(this.allFns);
|
||||
}
|
||||
@ -20,7 +20,7 @@ export class Monomorphizer {
|
||||
}
|
||||
|
||||
private monomorphizeFn(
|
||||
stmt: Stmt,
|
||||
item: Item,
|
||||
genericArgs?: GenericArgsMap,
|
||||
): MonoFn {
|
||||
const id = this.fnIdCounter;
|
||||
@ -29,7 +29,7 @@ export class Monomorphizer {
|
||||
if (nameGen in this.fns) {
|
||||
return this.fns[nameGen];
|
||||
}
|
||||
const monoFn = { id, nameGen, stmt, genericArgs };
|
||||
const monoFn: MonoFn = { id, nameGen, stmt, genericArgs };
|
||||
this.fns[nameGen] = monoFn;
|
||||
const calls = new CallCollector().collect(stmt);
|
||||
for (const call of calls) {
|
||||
@ -127,7 +127,7 @@ export type MonoFnsMap = { [nameGen: string]: MonoFn };
|
||||
export type MonoFn = {
|
||||
id: number;
|
||||
nameGen: string;
|
||||
stmt: Stmt;
|
||||
item: Item;
|
||||
genericArgs?: GenericArgsMap;
|
||||
};
|
||||
|
||||
@ -182,10 +182,10 @@ function vtypeNameGenPart(vtype: VType): string {
|
||||
}
|
||||
|
||||
class AllFnsCollector implements AstVisitor {
|
||||
private allFns = new Map<number, Stmt>();
|
||||
private allFns = new Map<number, Item>();
|
||||
|
||||
public collect(ast: Stmt[]): Map<number, Stmt> {
|
||||
visitStmts(ast, this);
|
||||
public collect(ast: Item[]): Map<number, Item> {
|
||||
visitItems(ast, this);
|
||||
return this.allFns;
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
Expr,
|
||||
ExprKind,
|
||||
GenericParam,
|
||||
Item,
|
||||
Param,
|
||||
Stmt,
|
||||
StmtKind,
|
||||
@ -30,39 +31,92 @@ export class Parser {
|
||||
this.currentToken = lexer.next();
|
||||
}
|
||||
|
||||
public parse(): Stmt[] {
|
||||
return this.parseStmts();
|
||||
public parse(): Item[] {
|
||||
return this.parseItems();
|
||||
}
|
||||
|
||||
private parseStmts(): Stmt[] {
|
||||
const stmts: Stmt[] = [];
|
||||
private parseItems(): Item[] {
|
||||
const items: Item[] = [];
|
||||
while (!this.done()) {
|
||||
stmts.push(this.parseModStmt());
|
||||
items.push(this.parseItem());
|
||||
}
|
||||
return stmts;
|
||||
return items;
|
||||
}
|
||||
|
||||
private parseModStmt(): Stmt {
|
||||
if (this.test("mod")) {
|
||||
return (this.parseMod());
|
||||
} else if (this.test("fn")) {
|
||||
return (this.parseFn());
|
||||
} else if (
|
||||
this.test("let") || this.test("return") || this.test("break")
|
||||
) {
|
||||
const expr = this.parseSingleLineBlockStmt();
|
||||
this.eatSemicolon();
|
||||
return expr;
|
||||
} else if (
|
||||
["{", "if", "loop", "while", "for"].some((tt) => this.test(tt))
|
||||
) {
|
||||
const expr = this.parseMultiLineBlockExpr();
|
||||
return (this.stmt({ type: "expr", expr }, expr.pos));
|
||||
} else {
|
||||
const expr = this.parseAssign();
|
||||
this.eatSemicolon();
|
||||
return expr;
|
||||
private parseItem(): Item {
|
||||
const pos = this.pos();
|
||||
return this.parseItemAnnos(pos, []);
|
||||
}
|
||||
|
||||
private parseItemAnnos(itemPos: Pos, annos: Anno[]): Item {
|
||||
const pos = this.pos();
|
||||
if (!this.test("#")) {
|
||||
return this.parseItemPub(itemPos, annos);
|
||||
}
|
||||
this.step();
|
||||
if (!this.test("[")) {
|
||||
this.report("expected '['");
|
||||
return this.errorItem(pos);
|
||||
}
|
||||
this.step();
|
||||
if (!this.test("ident")) {
|
||||
this.report("expected 'ident'");
|
||||
return this.errorItem(pos);
|
||||
}
|
||||
const ident = this.current().identValue!;
|
||||
this.step();
|
||||
if (!this.test("(")) {
|
||||
this.report("expected '('");
|
||||
return this.errorItem(pos);
|
||||
}
|
||||
this.step();
|
||||
const args: Expr[] = [];
|
||||
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.errorItem(pos);
|
||||
}
|
||||
this.step();
|
||||
return this.parseItemAnnos(itemPos, [...annos, { ident, args, pos }]);
|
||||
}
|
||||
|
||||
private parseItemPub(itemPos: Pos, annos: Anno[]): Item {
|
||||
if (!this.test("pub")) {
|
||||
return this.parseItemInner(itemPos, false, annos);
|
||||
}
|
||||
this.step();
|
||||
return this.parseItemInner(itemPos, true, annos);
|
||||
}
|
||||
|
||||
private parseItemInner(pos: Pos, pub: boolean, annos: Anno[]): Item {
|
||||
const stmt = this.parseItemStmt();
|
||||
return { stmt, pub, annos, pos };
|
||||
}
|
||||
|
||||
private parseItemStmt(): Stmt {
|
||||
const pos = this.pos();
|
||||
if (this.test("mod")) {
|
||||
return this.parseMod();
|
||||
} else if (this.test("fn")) {
|
||||
return this.parseFn();
|
||||
} else if (this.test("let")) {
|
||||
const stmt = this.parseLet();
|
||||
this.eatSemicolon();
|
||||
return stmt;
|
||||
} else {
|
||||
this.report("expected item");
|
||||
return this.stmt({ type: "error" }, pos);
|
||||
}
|
||||
}
|
||||
|
||||
private errorItem(pos: Pos): Item {
|
||||
return { stmt: this.stmt({ type: "error" }, pos), pub: false, pos };
|
||||
}
|
||||
|
||||
private parseMod(): Stmt {
|
||||
@ -87,9 +141,9 @@ export class Parser {
|
||||
}
|
||||
this.step();
|
||||
|
||||
const stmts: Stmt[] = [];
|
||||
const items: Item[] = [];
|
||||
while (!this.done() && !this.test("}")) {
|
||||
stmts.push(this.parseModStmt());
|
||||
items.push(this.parseItem());
|
||||
}
|
||||
|
||||
if (!this.test("}")) {
|
||||
@ -98,7 +152,7 @@ export class Parser {
|
||||
}
|
||||
this.step();
|
||||
|
||||
return this.stmt({ type: "mod_block", ident, stmts }, pos);
|
||||
return this.stmt({ type: "mod_block", ident, items }, pos);
|
||||
}
|
||||
|
||||
private parseMultiLineBlockExpr(): Expr {
|
||||
@ -234,14 +288,6 @@ export class Parser {
|
||||
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("{")) {
|
||||
this.report("expected block");
|
||||
return this.stmt({ type: "error" }, pos);
|
||||
@ -255,60 +301,11 @@ export class Parser {
|
||||
params,
|
||||
returnType,
|
||||
body,
|
||||
anno,
|
||||
},
|
||||
pos,
|
||||
);
|
||||
}
|
||||
|
||||
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[] {
|
||||
return this.parseDelimitedList(this.parseETypeParam, ">", ",");
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { EType, Expr, Stmt } from "./ast.ts";
|
||||
import { EType, Expr, Item, Stmt } from "./ast.ts";
|
||||
import {
|
||||
AstVisitor,
|
||||
visitEType,
|
||||
visitExpr,
|
||||
visitItems,
|
||||
visitParam,
|
||||
VisitRes,
|
||||
visitStmt,
|
||||
@ -22,10 +23,10 @@ export class Resolver implements AstVisitor<[Syms]> {
|
||||
public constructor(private reporter: Reporter) {
|
||||
}
|
||||
|
||||
public resolve(stmts: Stmt[]): VisitRes {
|
||||
public resolve(items: Item[]): VisitRes {
|
||||
const syms = new EntryModSyms();
|
||||
this.scoutFnStmts(stmts, syms);
|
||||
visitStmts(stmts, this, syms);
|
||||
this.scoutItems(items, syms);
|
||||
visitItems(items, this, syms);
|
||||
return "stop";
|
||||
}
|
||||
|
||||
@ -35,8 +36,8 @@ export class Resolver implements AstVisitor<[Syms]> {
|
||||
}
|
||||
const modSyms = new ModSyms(syms);
|
||||
const { mod, ident } = stmt.kind;
|
||||
this.scoutFnStmts(mod.ast, modSyms);
|
||||
visitStmts(mod.ast, this, modSyms);
|
||||
this.scoutItems(mod.items, modSyms);
|
||||
visitItems(mod.items, this, modSyms);
|
||||
|
||||
if (syms.definedLocally(ident)) {
|
||||
this.reportAlreadyDefined(ident, stmt.pos, syms);
|
||||
@ -72,8 +73,9 @@ export class Resolver implements AstVisitor<[Syms]> {
|
||||
return "stop";
|
||||
}
|
||||
|
||||
private scoutFnStmts(stmts: Stmt[], syms: Syms) {
|
||||
for (const stmt of stmts) {
|
||||
private scoutItems(items: Item[], syms: Syms) {
|
||||
for (const item of items) {
|
||||
const { stmt } = item;
|
||||
if (stmt.kind.type !== "fn") {
|
||||
continue;
|
||||
}
|
||||
@ -186,7 +188,15 @@ export class Resolver implements AstVisitor<[Syms]> {
|
||||
throw new Error();
|
||||
}
|
||||
const childSyms = new LeafSyms(syms);
|
||||
this.scoutFnStmts(expr.kind.stmts, childSyms);
|
||||
this.scoutItems(
|
||||
expr.kind.stmts
|
||||
.filter((stmt) => stmt.kind.type === "item")
|
||||
.map((stmt) =>
|
||||
stmt.kind.type === "item" ? stmt.kind.item : undefined
|
||||
)
|
||||
.filter((item) => item !== undefined),
|
||||
childSyms,
|
||||
);
|
||||
visitStmts(expr.kind.stmts, this, childSyms);
|
||||
if (expr.kind.expr) {
|
||||
visitExpr(expr.kind.expr, this, childSyms);
|
||||
|
@ -13,7 +13,13 @@ export interface Syms {
|
||||
export class EntryModSyms implements Syms {
|
||||
private syms: SymMap = {};
|
||||
|
||||
public constructor() {}
|
||||
public constructor() {
|
||||
this.syms["crate"] = {
|
||||
type: "mod",
|
||||
ident: "crate",
|
||||
syms: this,
|
||||
};
|
||||
}
|
||||
|
||||
public define(ident: string, sym: Sym) {
|
||||
if (sym.type === "let") {
|
||||
@ -65,6 +71,9 @@ export class ModSyms implements Syms {
|
||||
}
|
||||
|
||||
public get(ident: string): GetRes {
|
||||
if (ident === "crate") {
|
||||
return this.parent.get(ident);
|
||||
}
|
||||
if (ident in this.syms) {
|
||||
return { ok: true, sym: this.syms[ident] };
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
fn print(msg: string) #[builtin(print)] {
|
||||
|
||||
#[builtin(Print)]
|
||||
fn print(msg: string) {
|
||||
"hello" + 0
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user