ProjectItem.js (4624B)
1 import { parse } from "../../ast/parse.js"; 2 import { ICompileError, IRuntimeError } from "../../errors/IError.js"; 3 import { compileAst } from "../../expression/compile.js"; 4 import { evaluate } from "../../reducer/index.js"; 5 import * as Result from "../../utility/result.js"; 6 import { Ok } from "../../utility/result.js"; 7 import { SqCompileError, SqRuntimeError } from "../SqError.js"; 8 export class ProjectItem { 9 constructor(props) { 10 this.sourceId = props.sourceId; 11 this.source = props.source; 12 this.continues = []; 13 } 14 touchSource() { 15 this.ast = undefined; 16 this.imports = undefined; 17 this.output = undefined; 18 } 19 setSource(source) { 20 this.source = source; 21 this.touchSource(); 22 } 23 setAst(ast) { 24 this.ast = ast; 25 this.imports = undefined; 26 this.output = undefined; 27 } 28 setImports(imports) { 29 this.imports = imports; 30 this.output = undefined; 31 } 32 clean() { 33 this.output = undefined; 34 } 35 getDependencies() { 36 if (!this.imports?.ok) { 37 return this.continues; 38 } 39 return [...this.continues, ...this.imports.value.map((i) => i.sourceId)]; 40 } 41 getImplicitImports() { 42 const implicitImports = []; 43 for (const continueId of this.continues) { 44 implicitImports.push({ 45 type: "flat", 46 sourceId: continueId, 47 }); 48 } 49 return implicitImports; 50 } 51 setContinues(continues) { 52 this.continues = continues; 53 this.clean(); 54 } 55 parseImports(linker) { 56 if (this.imports) { 57 return; 58 } 59 this.buildAst(); 60 if (!this.ast) { 61 throw new Error("Internal logic error"); 62 } 63 if (!this.ast.ok) { 64 this.setImports(this.ast); 65 return; 66 } 67 const program = this.ast.value; 68 const resolvedImports = []; 69 for (const [file, variable] of program.imports) { 70 const location = file.location; 71 if (!linker) { 72 this.setImports(Result.Err(new SqCompileError(new ICompileError("Can't use imports when linker is not configured", location)))); 73 return; 74 } 75 try { 76 const sourceId = linker.resolve(file.value, this.sourceId); 77 resolvedImports.push({ 78 type: "named", 79 variable: variable.value, 80 sourceId, 81 }); 82 } 83 catch (e) { 84 this.setImports(Result.Err(new SqCompileError(new ICompileError(`SqLinker.resolve has failed to resolve ${file.value}`, location)))); 85 return; 86 } 87 } 88 this.setImports(Ok(resolvedImports)); 89 } 90 buildAst() { 91 if (this.ast) { 92 return; 93 } 94 const ast = Result.errMap(parse(this.source, this.sourceId), (e) => new SqCompileError(e)); 95 this.setAst(ast); 96 } 97 failRun(e) { 98 this.output = Result.Err(e); 99 } 100 async run(context, externals) { 101 if (this.output) { 102 return; 103 } 104 this.buildAst(); 105 if (!this.ast) { 106 throw new Error("Internal logic error"); 107 } 108 if (!this.ast.ok) { 109 this.failRun(this.ast.value); 110 return; 111 } 112 const expression = Result.errMap(compileAst(this.ast.value, externals), (e) => new SqCompileError(e)); 113 if (!expression.ok) { 114 this.failRun(expression.value); 115 return; 116 } 117 try { 118 const wrappedEvaluate = context.evaluate; 119 const asyncEvaluate = (expression, context) => { 120 return wrappedEvaluate(expression, context); 121 }; 122 if (expression.value.type !== "Program") { 123 throw new Error("Expected Program expression"); 124 } 125 const [result, contextAfterEvaluation] = evaluate(expression.value, { 126 ...context, 127 evaluate: asyncEvaluate, 128 }); 129 const bindings = contextAfterEvaluation.stack.asBindings(); 130 const exportNames = new Set(expression.value.value.exports); 131 const exports = bindings.filter((_, key) => exportNames.has(key)); 132 this.output = Ok({ 133 result, 134 bindings, 135 exports, 136 }); 137 } 138 catch (e) { 139 this.failRun(new SqRuntimeError(IRuntimeError.fromException(e))); 140 } 141 } 142 } 143 //# sourceMappingURL=ProjectItem.js.map