mirror of
				https://git.sfja.dk/Mikkel/slige.git
				synced 2025-11-04 02:38:17 +00:00 
			
		
		
		
	this commit kinda sucks
This commit is contained in:
		
							parent
							
								
									852df09ac9
								
							
						
					
					
						commit
						7ca1ff1e25
					
				@ -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;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -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";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -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 {
 | 
				
			||||||
 | 
				
			|||||||
@ -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 {
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
 | 
				
			|||||||
@ -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;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -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, ">", ",");
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -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);
 | 
				
			||||||
 | 
				
			|||||||
@ -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] };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,6 @@
 | 
				
			|||||||
fn print(msg: string) #[builtin(print)] {
 | 
					
 | 
				
			||||||
 | 
					#[builtin(Print)]
 | 
				
			||||||
 | 
					fn print(msg: string) {
 | 
				
			||||||
    "hello" + 0    
 | 
					    "hello" + 0    
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user