mirror of
				https://git.sfja.dk/Mikkel/slige.git
				synced 2025-10-31 03:48:16 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			102 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			102 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import * as path from "jsr:@std/path";
 | |
| import { Parser } from "./parser/parser.ts";
 | |
| import * as ast from "./ast/mod.ts";
 | |
| import { Ctx } from "./ctx.ts";
 | |
| import { File } from "./ctx.ts";
 | |
| 
 | |
| export type Pack = {
 | |
|     rootMod: Mod;
 | |
| };
 | |
| 
 | |
| export type Mod = null;
 | |
| 
 | |
| export interface PackEmitter {
 | |
|     emit(pack: Pack): void;
 | |
| }
 | |
| 
 | |
| export class PackCompiler {
 | |
|     private ctx = new Ctx();
 | |
| 
 | |
|     public constructor(
 | |
|         private entryFilePath: string,
 | |
|         private emitter: PackEmitter,
 | |
|     ) {}
 | |
| 
 | |
|     public compile() {
 | |
|         FileTreeAstCollector
 | |
|             .fromEntryFile(this.ctx, this.entryFilePath)
 | |
|             .collect();
 | |
|     }
 | |
| }
 | |
| 
 | |
| type _P = { file: File };
 | |
| export class FileTreeAstCollector implements ast.Visitor<[_P]> {
 | |
|     private subFilePromise = Promise.resolve();
 | |
| 
 | |
|     private constructor(
 | |
|         private ctx: Ctx,
 | |
|         private superFile: File | undefined,
 | |
|         private ident: string,
 | |
|         private absPath: string,
 | |
|         private relPath: string,
 | |
|     ) {}
 | |
| 
 | |
|     public static fromEntryFile(
 | |
|         ctx: Ctx,
 | |
|         entryFilePath: string,
 | |
|     ): FileTreeAstCollector {
 | |
|         return new FileTreeAstCollector(
 | |
|             ctx,
 | |
|             undefined,
 | |
|             "root",
 | |
|             entryFilePath,
 | |
|             entryFilePath,
 | |
|         );
 | |
|     }
 | |
| 
 | |
|     public async collect(): Promise<void> {
 | |
|         const text = await Deno.readTextFile(this.absPath);
 | |
|         const file = this.ctx.addFile(
 | |
|             this.ident,
 | |
|             this.absPath,
 | |
|             this.relPath,
 | |
|             this.superFile,
 | |
|             text,
 | |
|         );
 | |
|         const fileAst = new Parser(file, text).parse();
 | |
|         this.ctx.addFileAst(file, fileAst);
 | |
|         ast.visitFile(this, fileAst, { file });
 | |
|         await this.subFilePromise;
 | |
|     }
 | |
| 
 | |
|     visitModFileItem(
 | |
|         item: ast.Item,
 | |
|         kind: ast.ModFileItem,
 | |
|         { file }: _P,
 | |
|     ): ast.VisitRes {
 | |
|         const { ident: { text: ident }, filePath: relPath } = kind;
 | |
|         const absPath = path.join(path.dirname(this.absPath), relPath);
 | |
|         this.subFilePromise = this.subFilePromise
 | |
|             .then(() => {
 | |
|                 if (this.ctx.fileHasChildWithIdent(file, ident)) {
 | |
|                     this.ctx.report({
 | |
|                         severity: "fatal",
 | |
|                         msg: `module '${ident}' already declared`,
 | |
|                         file,
 | |
|                         span: item.span,
 | |
|                     });
 | |
|                     Deno.exit(1);
 | |
|                 }
 | |
|                 return new FileTreeAstCollector(
 | |
|                     this.ctx,
 | |
|                     file,
 | |
|                     ident,
 | |
|                     absPath,
 | |
|                     relPath,
 | |
|                 )
 | |
|                     .collect();
 | |
|             });
 | |
|         return "stop";
 | |
|     }
 | |
| }
 |