this commit kinda sucks

This commit is contained in:
sfja 2024-12-30 21:12:28 +01:00
parent 852df09ac9
commit 7ca1ff1e25
12 changed files with 221 additions and 156 deletions

View File

@ -4,7 +4,14 @@ import { GenericArgsMap, VType } from "./vtype.ts";
export type Mod = { export type Mod = {
filePath: string; filePath: string;
ast: Stmt[]; items: Item[];
};
export type Item = {
stmt: Stmt;
pub: boolean;
annos?: Anno[];
pos: Pos;
}; };
export type Stmt = { export type Stmt = {
@ -15,9 +22,10 @@ export type Stmt = {
export type StmtKind = export type StmtKind =
| { type: "error" } | { 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_file"; ident: string; filePath: string }
| { type: "mod"; ident: string; mod: Mod } | { type: "mod"; ident: string; mod: Mod }
| { type: "item"; item: Item }
| { type: "break"; expr?: Expr } | { type: "break"; expr?: Expr }
| { type: "return"; expr?: Expr } | { type: "return"; expr?: Expr }
| { | {
@ -27,7 +35,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 }
@ -147,7 +154,7 @@ export type GenericParam = {
export type Anno = { export type Anno = {
ident: string; ident: string;
values: Expr[]; args: Expr[];
pos: Pos; pos: Pos;
}; };

View File

@ -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 type VisitRes = "stop" | void;
export interface AstVisitor<Args extends unknown[] = []> { export interface AstVisitor<Args extends unknown[] = []> {
visitItems?(items: Item[], ...args: Args): VisitRes;
visitItem?(item: Item, ...args: Args): VisitRes;
visitStmts?(stmts: Stmt[], ...args: Args): VisitRes; visitStmts?(stmts: Stmt[], ...args: Args): VisitRes;
visitStmt?(stmt: Stmt, ...args: Args): VisitRes; visitStmt?(stmt: Stmt, ...args: Args): VisitRes;
visitErrorStmt?(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; visitSymEType?(etype: EType, ...args: Args): VisitRes;
visitArrayEType?(etype: EType, ...args: Args): VisitRes; visitArrayEType?(etype: EType, ...args: Args): VisitRes;
visitStructEType?(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[] = []>( export function visitStmts<Args extends unknown[] = []>(
@ -75,11 +94,11 @@ export function visitStmt<Args extends unknown[] = []>(
break; break;
case "mod_block": case "mod_block":
if (v.visitModBlockStmt?.(stmt, ...args) == "stop") return; if (v.visitModBlockStmt?.(stmt, ...args) == "stop") return;
visitStmts(stmt.kind.stmts, v, ...args); visitItems(stmt.kind.items, v, ...args);
break; break;
case "mod": case "mod":
if (v.visitModStmt?.(stmt, ...args) == "stop") return; if (v.visitModStmt?.(stmt, ...args) == "stop") return;
visitStmts(stmt.kind.mod.ast, v, ...args); visitItems(stmt.kind.mod.items, v, ...args);
break; break;
case "break": case "break":
if (v.visitBreakStmt?.(stmt, ...args) == "stop") return; if (v.visitBreakStmt?.(stmt, ...args) == "stop") return;

View File

@ -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 { printStackTrace, Reporter } from "./info.ts";
import { Pos } from "./token.ts"; import { Pos } from "./token.ts";
import { import {
@ -19,15 +19,16 @@ export class Checker {
public constructor(private reporter: Reporter) {} public constructor(private reporter: Reporter) {}
public check(stmts: Stmt[]) { public check(items: Item[]) {
this.checkFnHeaders(stmts); this.scoutItems(items);
for (const stmt of stmts) { for (const item of items) {
this.checkStmt(stmt); this.checkItem(item);
} }
} }
private checkFnHeaders(stmts: Stmt[]) { private scoutItems(items: Item[]) {
for (const stmt of stmts) { for (const item of items) {
const { stmt } = item;
if (stmt.kind.type !== "fn") { if (stmt.kind.type !== "fn") {
continue; 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) { public checkStmt(stmt: Stmt) {
switch (stmt.kind.type) { switch (stmt.kind.type) {
case "error": case "error":
@ -79,7 +89,7 @@ export class Checker {
case "return": case "return":
return this.checkReturnStmt(stmt); return this.checkReturnStmt(stmt);
case "fn": case "fn":
return this.checkFnStmt(stmt); throw new Error("item, not stmt");
case "let": case "let":
return this.checkLetStmt(stmt); return this.checkLetStmt(stmt);
case "assign": case "assign":
@ -93,10 +103,10 @@ export class Checker {
if (stmt.kind.type !== "mod") { if (stmt.kind.type !== "mod") {
throw new Error(); throw new Error();
} }
const { ast } = stmt.kind.mod; const { items } = stmt.kind.mod;
this.checkFnHeaders(ast); this.scoutItems(items);
for (const stmt of ast) { for (const item of items) {
this.checkStmt(stmt); 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") { if (stmt.kind.type !== "fn") {
throw new Error(); throw new Error();
} }
@ -163,8 +174,9 @@ export class Checker {
} }
if ( if (
stmt.kind.anno?.ident === "remainder" || item.annos?.some((anno) =>
stmt.kind.anno?.ident === "builtin" ["remainder", "builtin"].includes(anno.ident)
) ?? false
) { ) {
return; return;
} }
@ -910,7 +922,14 @@ export class Checker {
if (expr.kind.type !== "block") { if (expr.kind.type !== "block") {
throw new Error(); 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) { for (const stmt of expr.kind.stmts) {
this.checkStmt(stmt); this.checkStmt(stmt);
} }

View File

@ -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 { Checker } from "./checker.ts";
import { CompoundAssignDesugarer } from "./desugar/compound_assign.ts"; import { CompoundAssignDesugarer } from "./desugar/compound_assign.ts";
import { SpecialLoopDesugarer } from "./desugar/special_loop.ts"; import { SpecialLoopDesugarer } from "./desugar/special_loop.ts";
@ -8,10 +8,10 @@ import { Monomorphizer } from "./mono.ts";
import { FnNamesMap, Lowerer } from "./lowerer.ts"; import { FnNamesMap, Lowerer } from "./lowerer.ts";
import { Parser } from "./parser.ts"; import { Parser } from "./parser.ts";
import { Resolver } from "./resolver.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 * as path from "jsr:@std/path";
import { Pos } from "./token.ts";
export type CompileResult = { export type CompileResult = {
program: number[]; program: number[];
@ -33,20 +33,21 @@ export class Compiler {
this.reporter, this.reporter,
).resolve(); ).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()) { if (this.reporter.errorOccured()) {
console.error("Errors occurred, stopping compilation."); console.error("Errors occurred, stopping compilation.");
Deno.exit(1); 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); const lastPos = await lastPosInTextFile(this.startFilePath);
@ -68,12 +69,12 @@ export class ModTree implements AstVisitor<[string]> {
public resolve(): Mod { public resolve(): Mod {
const entryAst = this.parseFile(this.entryFilePath); 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 text = Deno.readTextFileSync(filePath);
const lexer = new Lexer(text, this.reporter); const lexer = new Lexer(text, this.reporter);
@ -88,13 +89,13 @@ export class ModTree implements AstVisitor<[string]> {
if (stmt.kind.type !== "mod_block") { if (stmt.kind.type !== "mod_block") {
throw new Error(); throw new Error();
} }
const { ident, stmts: ast } = stmt.kind; const { ident, items } = stmt.kind;
stmt.kind = { stmt.kind = {
type: "mod", type: "mod",
ident, ident,
mod: { filePath, ast }, mod: { filePath, items },
}; };
visitStmts(ast, this, filePath); visitItems(items, this, filePath);
return "stop"; return "stop";
} }
@ -109,9 +110,9 @@ export class ModTree implements AstVisitor<[string]> {
stmt.kind = { stmt.kind = {
type: "mod", type: "mod",
ident, ident,
mod: { filePath, ast }, mod: { filePath, items: ast },
}; };
visitStmts(ast, this, filePath); visitItems(ast, this, filePath);
return "stop"; return "stop";
} }
} }

View File

@ -1,11 +1,11 @@
import { AstCreator, Stmt } from "../ast.ts"; import { AstCreator, Item, Stmt } from "../ast.ts";
import { AstVisitor, VisitRes, visitStmt, visitStmts } from "../ast_visitor.ts"; import { AstVisitor, visitItems, VisitRes, visitStmt } from "../ast_visitor.ts";
export class CompoundAssignDesugarer implements AstVisitor { export class CompoundAssignDesugarer implements AstVisitor {
public constructor(private astCreator: AstCreator) {} public constructor(private astCreator: AstCreator) {}
public desugar(stmts: Stmt[]) { public desugar(items: Item[]) {
visitStmts(stmts, this); visitItems(items, this);
} }
visitAssignStmt(stmt: Stmt): VisitRes { visitAssignStmt(stmt: Stmt): VisitRes {

View File

@ -1,5 +1,5 @@
import { AstCreator, Expr, ExprKind, Stmt, StmtKind } from "../ast.ts"; import { AstCreator, Expr, ExprKind, Item, StmtKind } from "../ast.ts";
import { AstVisitor, visitExpr, VisitRes, visitStmts } from "../ast_visitor.ts"; import { AstVisitor, visitExpr, visitItems, VisitRes } from "../ast_visitor.ts";
import { Pos } from "../token.ts"; import { Pos } from "../token.ts";
export class SpecialLoopDesugarer implements AstVisitor { export class SpecialLoopDesugarer implements AstVisitor {
@ -7,8 +7,8 @@ export class SpecialLoopDesugarer implements AstVisitor {
private astCreator: AstCreator, private astCreator: AstCreator,
) {} ) {}
public desugar(stmts: Stmt[]) { public desugar(items: Item[]) {
visitStmts(stmts, this); visitItems(items, this);
} }
visitWhileExpr(expr: Expr): VisitRes { visitWhileExpr(expr: Expr): VisitRes {

View File

@ -48,6 +48,7 @@ export class Lexer {
"for", "for",
"in", "in",
"mod", "mod",
"pub",
]; ];
if (keywords.includes(value)) { if (keywords.includes(value)) {
return this.token(value, pos); return this.token(value, pos);

View File

@ -1,15 +1,15 @@
import { Expr, Stmt } from "./ast.ts"; import { Expr, Item, Stmt } from "./ast.ts";
import { AstVisitor, visitExpr, VisitRes, visitStmts } from "./ast_visitor.ts"; import { AstVisitor, visitExpr, visitItems, VisitRes } from "./ast_visitor.ts";
import { GenericArgsMap, VType } from "./vtype.ts"; import { GenericArgsMap, VType } from "./vtype.ts";
export class Monomorphizer { export class Monomorphizer {
private fnIdCounter = 0; private fnIdCounter = 0;
private fns: MonoFnsMap = {}; private fns: MonoFnsMap = {};
private callMap: MonoCallNameGenMap = {}; private callMap: MonoCallNameGenMap = {};
private allFns: Map<number, Stmt>; private allFns: Map<number, Item>;
private entryFn: Stmt; private entryFn: Item;
constructor(private ast: Stmt[]) { constructor(private ast: Item[]) {
this.allFns = new AllFnsCollector().collect(this.ast); this.allFns = new AllFnsCollector().collect(this.ast);
this.entryFn = findMain(this.allFns); this.entryFn = findMain(this.allFns);
} }
@ -20,7 +20,7 @@ export class Monomorphizer {
} }
private monomorphizeFn( private monomorphizeFn(
stmt: Stmt, item: Item,
genericArgs?: GenericArgsMap, genericArgs?: GenericArgsMap,
): MonoFn { ): MonoFn {
const id = this.fnIdCounter; const id = this.fnIdCounter;
@ -29,7 +29,7 @@ export class Monomorphizer {
if (nameGen in this.fns) { if (nameGen in this.fns) {
return this.fns[nameGen]; return this.fns[nameGen];
} }
const monoFn = { id, nameGen, stmt, genericArgs }; const monoFn: MonoFn = { id, nameGen, stmt, genericArgs };
this.fns[nameGen] = monoFn; this.fns[nameGen] = monoFn;
const calls = new CallCollector().collect(stmt); const calls = new CallCollector().collect(stmt);
for (const call of calls) { for (const call of calls) {
@ -127,7 +127,7 @@ export type MonoFnsMap = { [nameGen: string]: MonoFn };
export type MonoFn = { export type MonoFn = {
id: number; id: number;
nameGen: string; nameGen: string;
stmt: Stmt; item: Item;
genericArgs?: GenericArgsMap; genericArgs?: GenericArgsMap;
}; };
@ -182,10 +182,10 @@ function vtypeNameGenPart(vtype: VType): string {
} }
class AllFnsCollector implements AstVisitor { class AllFnsCollector implements AstVisitor {
private allFns = new Map<number, Stmt>(); private allFns = new Map<number, Item>();
public collect(ast: Stmt[]): Map<number, Stmt> { public collect(ast: Item[]): Map<number, Item> {
visitStmts(ast, this); visitItems(ast, this);
return this.allFns; return this.allFns;
} }

View File

@ -8,6 +8,7 @@ import {
Expr, Expr,
ExprKind, ExprKind,
GenericParam, GenericParam,
Item,
Param, Param,
Stmt, Stmt,
StmtKind, StmtKind,
@ -30,39 +31,92 @@ export class Parser {
this.currentToken = lexer.next(); this.currentToken = lexer.next();
} }
public parse(): Stmt[] { public parse(): Item[] {
return this.parseStmts(); return this.parseItems();
} }
private parseStmts(): Stmt[] { private parseItems(): Item[] {
const stmts: Stmt[] = []; const items: Item[] = [];
while (!this.done()) { while (!this.done()) {
stmts.push(this.parseModStmt()); items.push(this.parseItem());
} }
return stmts; return items;
} }
private parseModStmt(): Stmt { private parseItem(): Item {
if (this.test("mod")) { const pos = this.pos();
return (this.parseMod()); return this.parseItemAnnos(pos, []);
} 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 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 { private parseMod(): Stmt {
@ -87,9 +141,9 @@ export class Parser {
} }
this.step(); this.step();
const stmts: Stmt[] = []; const items: Item[] = [];
while (!this.done() && !this.test("}")) { while (!this.done() && !this.test("}")) {
stmts.push(this.parseModStmt()); items.push(this.parseItem());
} }
if (!this.test("}")) { if (!this.test("}")) {
@ -98,7 +152,7 @@ export class Parser {
} }
this.step(); this.step();
return this.stmt({ type: "mod_block", ident, stmts }, pos); return this.stmt({ type: "mod_block", ident, items }, pos);
} }
private parseMultiLineBlockExpr(): Expr { private parseMultiLineBlockExpr(): Expr {
@ -234,14 +288,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 +301,11 @@ export class Parser {
params, params,
returnType, returnType,
body, body,
anno,
}, },
pos, 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[] { private parseFnETypeParams(): GenericParam[] {
return this.parseDelimitedList(this.parseETypeParam, ">", ","); return this.parseDelimitedList(this.parseETypeParam, ">", ",");
} }

View File

@ -1,8 +1,9 @@
import { EType, Expr, Stmt } from "./ast.ts"; import { EType, Expr, Item, Stmt } from "./ast.ts";
import { import {
AstVisitor, AstVisitor,
visitEType, visitEType,
visitExpr, visitExpr,
visitItems,
visitParam, visitParam,
VisitRes, VisitRes,
visitStmt, visitStmt,
@ -22,10 +23,10 @@ export class Resolver implements AstVisitor<[Syms]> {
public constructor(private reporter: Reporter) { public constructor(private reporter: Reporter) {
} }
public resolve(stmts: Stmt[]): VisitRes { public resolve(items: Item[]): VisitRes {
const syms = new EntryModSyms(); const syms = new EntryModSyms();
this.scoutFnStmts(stmts, syms); this.scoutItems(items, syms);
visitStmts(stmts, this, syms); visitItems(items, this, syms);
return "stop"; return "stop";
} }
@ -35,8 +36,8 @@ export class Resolver implements AstVisitor<[Syms]> {
} }
const modSyms = new ModSyms(syms); const modSyms = new ModSyms(syms);
const { mod, ident } = stmt.kind; const { mod, ident } = stmt.kind;
this.scoutFnStmts(mod.ast, modSyms); this.scoutItems(mod.items, modSyms);
visitStmts(mod.ast, this, modSyms); visitItems(mod.items, this, modSyms);
if (syms.definedLocally(ident)) { if (syms.definedLocally(ident)) {
this.reportAlreadyDefined(ident, stmt.pos, syms); this.reportAlreadyDefined(ident, stmt.pos, syms);
@ -72,8 +73,9 @@ export class Resolver implements AstVisitor<[Syms]> {
return "stop"; return "stop";
} }
private scoutFnStmts(stmts: Stmt[], syms: Syms) { private scoutItems(items: Item[], syms: Syms) {
for (const stmt of stmts) { for (const item of items) {
const { stmt } = item;
if (stmt.kind.type !== "fn") { if (stmt.kind.type !== "fn") {
continue; continue;
} }
@ -186,7 +188,15 @@ export class Resolver implements AstVisitor<[Syms]> {
throw new Error(); throw new Error();
} }
const childSyms = new LeafSyms(syms); 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); visitStmts(expr.kind.stmts, this, childSyms);
if (expr.kind.expr) { if (expr.kind.expr) {
visitExpr(expr.kind.expr, this, childSyms); visitExpr(expr.kind.expr, this, childSyms);

View File

@ -13,7 +13,13 @@ export interface Syms {
export class EntryModSyms implements Syms { export class EntryModSyms implements Syms {
private syms: SymMap = {}; private syms: SymMap = {};
public constructor() {} public constructor() {
this.syms["crate"] = {
type: "mod",
ident: "crate",
syms: this,
};
}
public define(ident: string, sym: Sym) { public define(ident: string, sym: Sym) {
if (sym.type === "let") { if (sym.type === "let") {
@ -65,6 +71,9 @@ export class ModSyms implements Syms {
} }
public get(ident: string): GetRes { public get(ident: string): GetRes {
if (ident === "crate") {
return this.parent.get(ident);
}
if (ident in this.syms) { if (ident in this.syms) {
return { ok: true, sym: this.syms[ident] }; return { ok: true, sym: this.syms[ident] };
} }

View File

@ -1,4 +1,6 @@
fn print(msg: string) #[builtin(print)] {
#[builtin(Print)]
fn print(msg: string) {
"hello" + 0 "hello" + 0
} }