@minduscript/compiler 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/.npmignore +2 -0
  2. package/dist/asm/gen-asm.d.ts +2 -0
  3. package/dist/asm/gen-asm.js +432 -0
  4. package/dist/counter.d.ts +5 -0
  5. package/dist/counter.js +13 -0
  6. package/dist/index.d.ts +1 -0
  7. package/dist/index.js +17 -0
  8. package/dist/ir/build-ir.d.ts +3 -0
  9. package/dist/ir/build-ir.js +1057 -0
  10. package/dist/ir/gather-macros.d.ts +8 -0
  11. package/dist/ir/gather-macros.js +204 -0
  12. package/dist/ir/ir.d.ts +478 -0
  13. package/dist/ir/ir.js +120 -0
  14. package/dist/ir/project.d.ts +24 -0
  15. package/dist/ir/project.js +339 -0
  16. package/dist/ir/symbol-table.d.ts +19 -0
  17. package/dist/ir/symbol-table.js +385 -0
  18. package/dist/macro/check-macro.d.ts +14 -0
  19. package/dist/macro/check-macro.js +136 -0
  20. package/dist/macro/expand-macros.d.ts +6 -0
  21. package/dist/macro/expand-macros.js +285 -0
  22. package/dist/optimizer/default-passes.d.ts +2 -0
  23. package/dist/optimizer/default-passes.js +20 -0
  24. package/dist/optimizer/merge-labels.d.ts +2 -0
  25. package/dist/optimizer/merge-labels.js +45 -0
  26. package/dist/optimizer/optimizer.d.ts +4 -0
  27. package/dist/optimizer/optimizer.js +26 -0
  28. package/dist/optimizer/passes/constant-folding.d.ts +2 -0
  29. package/dist/optimizer/passes/constant-folding.js +160 -0
  30. package/dist/optimizer/passes/control-flow.d.ts +5 -0
  31. package/dist/optimizer/passes/control-flow.js +138 -0
  32. package/dist/optimizer/passes/copy-propagation.d.ts +2 -0
  33. package/dist/optimizer/passes/copy-propagation.js +127 -0
  34. package/dist/optimizer/passes/dead-code.d.ts +2 -0
  35. package/dist/optimizer/passes/dead-code.js +200 -0
  36. package/dist/optimizer/passes/merge-labels-pass.d.ts +2 -0
  37. package/dist/optimizer/passes/merge-labels-pass.js +14 -0
  38. package/dist/optimizer/types.d.ts +10 -0
  39. package/dist/optimizer/types.js +3 -0
  40. package/dist/test.d.ts +1 -0
  41. package/dist/test.js +14 -0
  42. package/package.json +22 -0
package/dist/ir/ir.js ADDED
@@ -0,0 +1,120 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JumpCondition = exports.IRNodeType = void 0;
4
+ var IRNodeType;
5
+ (function (IRNodeType) {
6
+ // 控制指令
7
+ IRNodeType[IRNodeType["READ"] = 0] = "READ";
8
+ IRNodeType[IRNodeType["WRITE"] = 1] = "WRITE";
9
+ IRNodeType[IRNodeType["DRAW_CLEAR"] = 2] = "DRAW_CLEAR";
10
+ IRNodeType[IRNodeType["DRAW_COLOR"] = 3] = "DRAW_COLOR";
11
+ IRNodeType[IRNodeType["DRAW_COL"] = 4] = "DRAW_COL";
12
+ IRNodeType[IRNodeType["DRAW_STROKE"] = 5] = "DRAW_STROKE";
13
+ IRNodeType[IRNodeType["DRAW_LINE"] = 6] = "DRAW_LINE";
14
+ IRNodeType[IRNodeType["DRAW_RECT"] = 7] = "DRAW_RECT";
15
+ IRNodeType[IRNodeType["DRAW_LINE_RECT"] = 8] = "DRAW_LINE_RECT";
16
+ IRNodeType[IRNodeType["DRAW_POLY"] = 9] = "DRAW_POLY";
17
+ IRNodeType[IRNodeType["DRAW_LINE_POLY"] = 10] = "DRAW_LINE_POLY";
18
+ IRNodeType[IRNodeType["DRAW_TRIANGLE"] = 11] = "DRAW_TRIANGLE";
19
+ IRNodeType[IRNodeType["DRAW_IMAGE"] = 12] = "DRAW_IMAGE";
20
+ IRNodeType[IRNodeType["PRINT"] = 13] = "PRINT";
21
+ IRNodeType[IRNodeType["DRAW_FLUSH"] = 14] = "DRAW_FLUSH";
22
+ IRNodeType[IRNodeType["PRINT_FLUSH"] = 15] = "PRINT_FLUSH";
23
+ IRNodeType[IRNodeType["GET_LINK"] = 16] = "GET_LINK";
24
+ IRNodeType[IRNodeType["SET_ENABLED"] = 17] = "SET_ENABLED";
25
+ IRNodeType[IRNodeType["SET_SHOOT"] = 18] = "SET_SHOOT";
26
+ IRNodeType[IRNodeType["SET_SHOOT_P"] = 19] = "SET_SHOOT_P";
27
+ IRNodeType[IRNodeType["SET_CONFIG"] = 20] = "SET_CONFIG";
28
+ IRNodeType[IRNodeType["SET_COLOR"] = 21] = "SET_COLOR";
29
+ IRNodeType[IRNodeType["RADAR"] = 22] = "RADAR";
30
+ IRNodeType[IRNodeType["SENSOR"] = 23] = "SENSOR";
31
+ IRNodeType[IRNodeType["PACK_COLOR"] = 24] = "PACK_COLOR";
32
+ IRNodeType[IRNodeType["WAIT"] = 25] = "WAIT";
33
+ IRNodeType[IRNodeType["CPU_STOP"] = 26] = "CPU_STOP";
34
+ IRNodeType[IRNodeType["UNIT_BIND"] = 27] = "UNIT_BIND";
35
+ IRNodeType[IRNodeType["UNIT_RADAR"] = 28] = "UNIT_RADAR";
36
+ IRNodeType[IRNodeType["UNIT_LOCATE_ORE"] = 29] = "UNIT_LOCATE_ORE";
37
+ IRNodeType[IRNodeType["UNIT_LOCATE_BUILDING"] = 30] = "UNIT_LOCATE_BUILDING";
38
+ IRNodeType[IRNodeType["UNIT_LOCATE_SPAWN"] = 31] = "UNIT_LOCATE_SPAWN";
39
+ IRNodeType[IRNodeType["UNIT_LOCATE_DAMAGED"] = 32] = "UNIT_LOCATE_DAMAGED";
40
+ IRNodeType[IRNodeType["IDLE"] = 33] = "IDLE";
41
+ IRNodeType[IRNodeType["STOP"] = 34] = "STOP";
42
+ IRNodeType[IRNodeType["MOVE"] = 35] = "MOVE";
43
+ IRNodeType[IRNodeType["APPROACH"] = 36] = "APPROACH";
44
+ IRNodeType[IRNodeType["PATH_FIND"] = 37] = "PATH_FIND";
45
+ IRNodeType[IRNodeType["AUTO_PATH_FIND"] = 38] = "AUTO_PATH_FIND";
46
+ IRNodeType[IRNodeType["BOOST"] = 39] = "BOOST";
47
+ IRNodeType[IRNodeType["TARGET"] = 40] = "TARGET";
48
+ IRNodeType[IRNodeType["TARGET_P"] = 41] = "TARGET_P";
49
+ IRNodeType[IRNodeType["ITEM_DROP"] = 42] = "ITEM_DROP";
50
+ IRNodeType[IRNodeType["ITEM_TAKE"] = 43] = "ITEM_TAKE";
51
+ IRNodeType[IRNodeType["PAY_DROP"] = 44] = "PAY_DROP";
52
+ IRNodeType[IRNodeType["PAY_TAKE"] = 45] = "PAY_TAKE";
53
+ IRNodeType[IRNodeType["PAY_ENTER"] = 46] = "PAY_ENTER";
54
+ IRNodeType[IRNodeType["MINE"] = 47] = "MINE";
55
+ IRNodeType[IRNodeType["FLAG"] = 48] = "FLAG";
56
+ IRNodeType[IRNodeType["BUILD"] = 49] = "BUILD";
57
+ IRNodeType[IRNodeType["GET_BLOCK"] = 50] = "GET_BLOCK";
58
+ IRNodeType[IRNodeType["WITHIN"] = 51] = "WITHIN";
59
+ IRNodeType[IRNodeType["UNBIND"] = 52] = "UNBIND";
60
+ // 运算指令
61
+ IRNodeType[IRNodeType["ASSIGN"] = 53] = "ASSIGN";
62
+ IRNodeType[IRNodeType["FLIP"] = 54] = "FLIP";
63
+ IRNodeType[IRNodeType["AND"] = 55] = "AND";
64
+ IRNodeType[IRNodeType["EQ"] = 56] = "EQ";
65
+ IRNodeType[IRNodeType["NE"] = 57] = "NE";
66
+ IRNodeType[IRNodeType["LESS"] = 58] = "LESS";
67
+ IRNodeType[IRNodeType["LE"] = 59] = "LE";
68
+ IRNodeType[IRNodeType["GREATER"] = 60] = "GREATER";
69
+ IRNodeType[IRNodeType["GE"] = 61] = "GE";
70
+ IRNodeType[IRNodeType["STRICT_EQ"] = 62] = "STRICT_EQ";
71
+ IRNodeType[IRNodeType["BITOR"] = 63] = "BITOR";
72
+ IRNodeType[IRNodeType["XOR"] = 64] = "XOR";
73
+ IRNodeType[IRNodeType["BITAND"] = 65] = "BITAND";
74
+ IRNodeType[IRNodeType["SHL"] = 66] = "SHL";
75
+ IRNodeType[IRNodeType["SHR"] = 67] = "SHR";
76
+ IRNodeType[IRNodeType["ADD"] = 68] = "ADD";
77
+ IRNodeType[IRNodeType["SUB"] = 69] = "SUB";
78
+ IRNodeType[IRNodeType["MUL"] = 70] = "MUL";
79
+ IRNodeType[IRNodeType["DIV"] = 71] = "DIV";
80
+ IRNodeType[IRNodeType["IDIV"] = 72] = "IDIV";
81
+ IRNodeType[IRNodeType["MOD"] = 73] = "MOD";
82
+ IRNodeType[IRNodeType["POW"] = 74] = "POW";
83
+ IRNodeType[IRNodeType["MAX"] = 75] = "MAX";
84
+ IRNodeType[IRNodeType["MIN"] = 76] = "MIN";
85
+ IRNodeType[IRNodeType["ANGLE"] = 77] = "ANGLE";
86
+ IRNodeType[IRNodeType["ANGLE_DIFF"] = 78] = "ANGLE_DIFF";
87
+ IRNodeType[IRNodeType["LEN"] = 79] = "LEN";
88
+ IRNodeType[IRNodeType["NOISE"] = 80] = "NOISE";
89
+ IRNodeType[IRNodeType["ABS"] = 81] = "ABS";
90
+ IRNodeType[IRNodeType["LOG"] = 82] = "LOG";
91
+ IRNodeType[IRNodeType["LOG10"] = 83] = "LOG10";
92
+ IRNodeType[IRNodeType["FLOOR"] = 84] = "FLOOR";
93
+ IRNodeType[IRNodeType["CEIL"] = 85] = "CEIL";
94
+ IRNodeType[IRNodeType["SQRT"] = 86] = "SQRT";
95
+ IRNodeType[IRNodeType["RAND"] = 87] = "RAND";
96
+ IRNodeType[IRNodeType["SIN"] = 88] = "SIN";
97
+ IRNodeType[IRNodeType["COS"] = 89] = "COS";
98
+ IRNodeType[IRNodeType["TAN"] = 90] = "TAN";
99
+ IRNodeType[IRNodeType["ASIN"] = 91] = "ASIN";
100
+ IRNodeType[IRNodeType["ACOS"] = 92] = "ACOS";
101
+ IRNodeType[IRNodeType["ATAN"] = 93] = "ATAN";
102
+ // 其他指令
103
+ IRNodeType[IRNodeType["LABEL"] = 94] = "LABEL";
104
+ IRNodeType[IRNodeType["JUMP"] = 95] = "JUMP";
105
+ IRNodeType[IRNodeType["CONDITIONAL_JUMP"] = 96] = "CONDITIONAL_JUMP";
106
+ IRNodeType[IRNodeType["MACRO_CALL"] = 97] = "MACRO_CALL";
107
+ IRNodeType[IRNodeType["MACRO_CALL_ASSIGN"] = 98] = "MACRO_CALL_ASSIGN";
108
+ IRNodeType[IRNodeType["BIND"] = 99] = "BIND";
109
+ })(IRNodeType || (exports.IRNodeType = IRNodeType = {}));
110
+ var JumpCondition;
111
+ (function (JumpCondition) {
112
+ JumpCondition[JumpCondition["EQ"] = 0] = "EQ";
113
+ JumpCondition[JumpCondition["NE"] = 1] = "NE";
114
+ JumpCondition[JumpCondition["LESS"] = 2] = "LESS";
115
+ JumpCondition[JumpCondition["LE"] = 3] = "LE";
116
+ JumpCondition[JumpCondition["GREATER"] = 4] = "GREATER";
117
+ JumpCondition[JumpCondition["GE"] = 5] = "GE";
118
+ JumpCondition[JumpCondition["STRICT_EQ"] = 6] = "STRICT_EQ";
119
+ })(JumpCondition || (exports.JumpCondition = JumpCondition = {}));
120
+ //# sourceMappingURL=ir.js.map
@@ -0,0 +1,24 @@
1
+ import type { DocumentNode, MacroDefineStatementNode } from '@minduscript/parser';
2
+ import type { WithSymbolTable } from './symbol-table';
3
+ export type Source = {
4
+ path: string;
5
+ ast: WithSymbolTable<DocumentNode>;
6
+ macros: MacroDefineStatementNode[];
7
+ internalMacros: MacroDefineStatementNode[];
8
+ };
9
+ export type Project = {
10
+ rootPath: string;
11
+ entryPath: string;
12
+ sources: Record<string, Source>;
13
+ };
14
+ export declare class MacroRecursionError extends Error {
15
+ readonly chain: {
16
+ macroName: string;
17
+ sourceFile: string;
18
+ }[];
19
+ constructor(chain: {
20
+ macroName: string;
21
+ sourceFile: string;
22
+ }[]);
23
+ }
24
+ export declare const parseProject: (entryPath: string, rootPath?: string) => Project;
@@ -0,0 +1,339 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseProject = exports.MacroRecursionError = void 0;
7
+ const lexer_1 = require("@minduscript/lexer");
8
+ const lexer_2 = require("@minduscript/lexer");
9
+ const parser_1 = require("@minduscript/parser");
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const symbol_table_1 = require("./symbol-table");
13
+ class MacroRecursionError extends Error {
14
+ chain;
15
+ constructor(chain) {
16
+ super(`发生宏递归调用:${chain.map((item) => item.macroName).join('->')}`);
17
+ this.chain = chain;
18
+ }
19
+ }
20
+ exports.MacroRecursionError = MacroRecursionError;
21
+ const hasOwn = (record, name) => Object.prototype.hasOwnProperty.call(record, name);
22
+ const tryResolveFile = (candidatePath) => {
23
+ const normalizedPath = path_1.default.normalize(candidatePath);
24
+ const candidates = path_1.default.extname(normalizedPath)
25
+ ? [normalizedPath]
26
+ : [normalizedPath, `${normalizedPath}.minduscript`];
27
+ for (const current of candidates) {
28
+ if (!fs_1.default.existsSync(current)) {
29
+ continue;
30
+ }
31
+ if (!fs_1.default.statSync(current).isFile()) {
32
+ continue;
33
+ }
34
+ return current;
35
+ }
36
+ return undefined;
37
+ };
38
+ const resolveImportPath = (importStatement, importerPath, rootPath) => {
39
+ const { from } = importStatement;
40
+ const basePath = path_1.default.dirname(importerPath);
41
+ const candidate = path_1.default.isAbsolute(from)
42
+ ? from
43
+ : from.startsWith('.')
44
+ ? path_1.default.resolve(basePath, from)
45
+ : rootPath
46
+ ? path_1.default.resolve(rootPath, from)
47
+ : undefined;
48
+ if (!candidate) {
49
+ throw new Error(`Import "${from}" in "${importerPath}" requires an explicit project root path`);
50
+ }
51
+ const resolvedPath = tryResolveFile(candidate);
52
+ if (!resolvedPath) {
53
+ throw new Error(`Cannot resolve import "${from}" in "${importerPath}"`);
54
+ }
55
+ return resolvedPath;
56
+ };
57
+ const getGlobalVariableNames = (ast) => {
58
+ return new Set([...Object.keys(ast.symbolTable.vars), ...Object.keys(ast.symbolTable.consts)]);
59
+ };
60
+ const isIdentifierUsingGlobalVariable = (identifier, globalVariableNames) => {
61
+ return (!identifier.isMindustry &&
62
+ identifier.identifierType === parser_1.IdentifierType.SIMPLE &&
63
+ globalVariableNames.has(identifier.value));
64
+ };
65
+ const expressionUsesGlobalVariable = (expression, globalVariableNames, macroCallUsesGlobalVariable) => {
66
+ const childUsesGlobalVariable = (child) => {
67
+ switch (child.type) {
68
+ case parser_1.NodeType.UNARY_OP_EXPRESSION:
69
+ return childUsesGlobalVariable(child.child);
70
+ case parser_1.NodeType.BINARY_OP_EXPRESSION:
71
+ return childUsesGlobalVariable(child.lChild) || childUsesGlobalVariable(child.rChild);
72
+ case parser_1.NodeType.FUNCTION_CALL_EXPRESSION:
73
+ return child.args.some(childUsesGlobalVariable);
74
+ case parser_1.NodeType.MACRO_CALL_EXPRESSION:
75
+ return (macroCallUsesGlobalVariable(child.name) ||
76
+ child.inputArgs.some(childUsesGlobalVariable) ||
77
+ child.outputArgs.some((identifier) => isIdentifierUsingGlobalVariable(identifier, globalVariableNames)));
78
+ case parser_1.NodeType.IDENTIFIER_EXPRESSION:
79
+ return isIdentifierUsingGlobalVariable(child, globalVariableNames);
80
+ case parser_1.NodeType.LITERAL_EXPRESSION:
81
+ return false;
82
+ default:
83
+ return child;
84
+ }
85
+ };
86
+ return childUsesGlobalVariable(expression.child);
87
+ };
88
+ const statementUsesGlobalVariable = (statement, globalVariableNames, macroCallUsesGlobalVariable) => {
89
+ switch (statement.statementType) {
90
+ case parser_1.StatementType.EMPTY:
91
+ return false;
92
+ case parser_1.StatementType.VARIABLE_DEFINE:
93
+ return expressionUsesGlobalVariable(statement.expression, globalVariableNames, macroCallUsesGlobalVariable);
94
+ case parser_1.StatementType.ASSIGN:
95
+ return (expressionUsesGlobalVariable(statement.expression, globalVariableNames, macroCallUsesGlobalVariable) ||
96
+ (statement.tokens[0]?.type !== lexer_2.TokenType.MINDUSTRY_IDENTIFIER &&
97
+ globalVariableNames.has(statement.variableName)));
98
+ case parser_1.StatementType.CONTROL:
99
+ return Object.values(statement).some((value) => {
100
+ if (!value || typeof value !== 'object') {
101
+ return false;
102
+ }
103
+ const maybeNode = value;
104
+ if (maybeNode.type === parser_1.NodeType.EXPRESSION) {
105
+ return expressionUsesGlobalVariable(maybeNode, globalVariableNames, macroCallUsesGlobalVariable);
106
+ }
107
+ if (maybeNode.type === parser_1.NodeType.IDENTIFIER_EXPRESSION) {
108
+ return isIdentifierUsingGlobalVariable(maybeNode, globalVariableNames);
109
+ }
110
+ return false;
111
+ });
112
+ case parser_1.StatementType.MACRO_CALL:
113
+ return (macroCallUsesGlobalVariable(statement.name) ||
114
+ statement.inputArgs.some((expression) => expressionUsesGlobalVariable(expression, globalVariableNames, macroCallUsesGlobalVariable)) ||
115
+ statement.outputArgs.some((identifier) => isIdentifierUsingGlobalVariable(identifier, globalVariableNames)));
116
+ case parser_1.StatementType.MACRO_DEFINE:
117
+ return statement.body.some((child) => statementUsesGlobalVariable(child, globalVariableNames, macroCallUsesGlobalVariable));
118
+ case parser_1.StatementType.IF:
119
+ return (expressionUsesGlobalVariable(statement.condition, globalVariableNames, macroCallUsesGlobalVariable) ||
120
+ statement.ifBody.some((child) => statementUsesGlobalVariable(child, globalVariableNames, macroCallUsesGlobalVariable)));
121
+ case parser_1.StatementType.IF_ELSE:
122
+ return (expressionUsesGlobalVariable(statement.condition, globalVariableNames, macroCallUsesGlobalVariable) ||
123
+ statement.ifBody.some((child) => statementUsesGlobalVariable(child, globalVariableNames, macroCallUsesGlobalVariable)) ||
124
+ statement.elseBody.some((child) => statementUsesGlobalVariable(child, globalVariableNames, macroCallUsesGlobalVariable)));
125
+ case parser_1.StatementType.FOR:
126
+ return (statementUsesGlobalVariable(statement.init, globalVariableNames, macroCallUsesGlobalVariable) ||
127
+ expressionUsesGlobalVariable(statement.condition, globalVariableNames, macroCallUsesGlobalVariable) ||
128
+ (statement.increment
129
+ ? statementUsesGlobalVariable(statement.increment, globalVariableNames, macroCallUsesGlobalVariable)
130
+ : false) ||
131
+ statement.body.some((child) => statementUsesGlobalVariable(child, globalVariableNames, macroCallUsesGlobalVariable)));
132
+ case parser_1.StatementType.WHILE:
133
+ return (expressionUsesGlobalVariable(statement.condition, globalVariableNames, macroCallUsesGlobalVariable) ||
134
+ statement.body.some((child) => statementUsesGlobalVariable(child, globalVariableNames, macroCallUsesGlobalVariable)));
135
+ case parser_1.StatementType.LOOP_CONTROL:
136
+ return false;
137
+ case parser_1.StatementType.RETURN:
138
+ return expressionUsesGlobalVariable(statement.expression, globalVariableNames, macroCallUsesGlobalVariable);
139
+ default:
140
+ return statement;
141
+ }
142
+ };
143
+ const collectLocalMacroMap = (ast) => {
144
+ const macroMap = {};
145
+ for (const statement of ast.statementList) {
146
+ if (statement.statementType !== parser_1.StatementType.MACRO_DEFINE) {
147
+ continue;
148
+ }
149
+ macroMap[statement.name] = statement;
150
+ }
151
+ return macroMap;
152
+ };
153
+ const createReExportedMacro = (macro, exportName) => {
154
+ if (macro.name === exportName) {
155
+ return macro;
156
+ }
157
+ return {
158
+ ...macro,
159
+ name: exportName,
160
+ };
161
+ };
162
+ const parseProject = (entryPath, rootPath) => {
163
+ const resolvedEntryPath = tryResolveFile(path_1.default.resolve(entryPath));
164
+ if (!resolvedEntryPath) {
165
+ throw new Error(`Entry file "${entryPath}" does not exist`);
166
+ }
167
+ const resolvedRootPath = rootPath ? path_1.default.resolve(rootPath) : path_1.default.dirname(resolvedEntryPath);
168
+ const sourceMap = {};
169
+ const visitingStack = [];
170
+ const loadSource = (filePath) => {
171
+ if (hasOwn(sourceMap, filePath)) {
172
+ return sourceMap[filePath];
173
+ }
174
+ const cycleStartIndex = visitingStack.indexOf(filePath);
175
+ if (cycleStartIndex >= 0) {
176
+ const cyclePath = [...visitingStack.slice(cycleStartIndex), filePath].join(' -> ');
177
+ throw new Error(`Circular dependency detected: ${cyclePath}`);
178
+ }
179
+ visitingStack.push(filePath);
180
+ try {
181
+ const tokens = lexer_1.lexer.lexFile(filePath);
182
+ const ast = (0, symbol_table_1.buildSymbolTable)(parser_1.parser.parse(tokens));
183
+ const source = {
184
+ path: filePath,
185
+ ast,
186
+ macros: [],
187
+ internalMacros: [],
188
+ exportMap: {},
189
+ localMacroMap: collectLocalMacroMap(ast),
190
+ importAliasMap: {},
191
+ resolvedImports: [],
192
+ globalVariableNames: getGlobalVariableNames(ast),
193
+ };
194
+ sourceMap[filePath] = source;
195
+ for (const importStatement of ast.importList) {
196
+ const importedPath = resolveImportPath(importStatement, filePath, rootPath ? resolvedRootPath : undefined);
197
+ loadSource(importedPath);
198
+ const resolvedImport = {
199
+ sourcePath: importedPath,
200
+ macroName: importStatement.name,
201
+ asName: importStatement.asName,
202
+ };
203
+ source.resolvedImports.push(resolvedImport);
204
+ source.importAliasMap[importStatement.asName] = resolvedImport;
205
+ }
206
+ return source;
207
+ }
208
+ finally {
209
+ visitingStack.pop();
210
+ }
211
+ };
212
+ loadSource(resolvedEntryPath);
213
+ const resolveMacroDefinition = (sourcePath, macroName, aliasChain = []) => {
214
+ const source = sourceMap[sourcePath];
215
+ if (!source) {
216
+ return undefined;
217
+ }
218
+ const nextAliasChain = [...aliasChain, { sourcePath, macroName }];
219
+ const localMacro = source.localMacroMap[macroName];
220
+ if (localMacro) {
221
+ return {
222
+ sourcePath,
223
+ macroName,
224
+ macro: localMacro,
225
+ aliases: nextAliasChain,
226
+ };
227
+ }
228
+ const imported = source.importAliasMap[macroName];
229
+ if (!imported) {
230
+ return undefined;
231
+ }
232
+ return resolveMacroDefinition(imported.sourcePath, imported.macroName, nextAliasChain);
233
+ };
234
+ const toMacroKey = (sourcePath, macroName) => `${sourcePath}\u0000${macroName}`;
235
+ const parseMacroKey = (key) => {
236
+ const separator = key.indexOf('\u0000');
237
+ return {
238
+ sourcePath: key.slice(0, separator),
239
+ macroName: key.slice(separator + 1),
240
+ };
241
+ };
242
+ const macroState = new Map();
243
+ const macroUsesGlobalVariableMap = new Map();
244
+ const macroStack = [];
245
+ const analyzeMacroUsesGlobalVariable = (sourcePath, macroName) => {
246
+ const resolved = resolveMacroDefinition(sourcePath, macroName);
247
+ if (!resolved) {
248
+ return false;
249
+ }
250
+ const key = toMacroKey(resolved.sourcePath, resolved.macroName);
251
+ const currentState = macroState.get(key);
252
+ if (currentState === 'done') {
253
+ return macroUsesGlobalVariableMap.get(key) ?? false;
254
+ }
255
+ if (currentState === 'visiting') {
256
+ const cycleStart = macroStack.indexOf(key);
257
+ const cycleKeys = [...macroStack.slice(cycleStart), key];
258
+ throw new MacroRecursionError(cycleKeys.map((item) => {
259
+ const parsed = parseMacroKey(item);
260
+ return {
261
+ macroName: parsed.macroName,
262
+ sourceFile: parsed.sourcePath,
263
+ };
264
+ }));
265
+ }
266
+ const ownerSource = sourceMap[resolved.sourcePath];
267
+ macroState.set(key, 'visiting');
268
+ macroStack.push(key);
269
+ try {
270
+ const usesGlobalVariable = resolved.macro.body.some((statement) => statementUsesGlobalVariable(statement, ownerSource.globalVariableNames, (calledMacroName) => analyzeMacroUsesGlobalVariable(resolved.sourcePath, calledMacroName)));
271
+ macroUsesGlobalVariableMap.set(key, usesGlobalVariable);
272
+ macroState.set(key, 'done');
273
+ return usesGlobalVariable;
274
+ }
275
+ finally {
276
+ macroStack.pop();
277
+ }
278
+ };
279
+ const localExportMapBySource = {};
280
+ for (const source of Object.values(sourceMap)) {
281
+ const localExportMap = {};
282
+ const internalMacros = [];
283
+ for (const [macroName, macroNode] of Object.entries(source.localMacroMap)) {
284
+ if (analyzeMacroUsesGlobalVariable(source.path, macroName)) {
285
+ internalMacros.push(macroNode);
286
+ continue;
287
+ }
288
+ localExportMap[macroName] = macroNode;
289
+ }
290
+ localExportMapBySource[source.path] = localExportMap;
291
+ source.internalMacros = internalMacros;
292
+ }
293
+ const sourceExportState = new Map();
294
+ const buildSourceExportMap = (sourcePath) => {
295
+ const source = sourceMap[sourcePath];
296
+ const currentState = sourceExportState.get(sourcePath);
297
+ if (currentState === 'done') {
298
+ return source.exportMap;
299
+ }
300
+ if (currentState === 'visiting') {
301
+ throw new Error(`Unexpected import cycle while building exports: ${sourcePath}`);
302
+ }
303
+ sourceExportState.set(sourcePath, 'visiting');
304
+ const exportMap = {
305
+ ...localExportMapBySource[sourcePath],
306
+ };
307
+ for (const resolvedImport of source.resolvedImports) {
308
+ const importedExportMap = buildSourceExportMap(resolvedImport.sourcePath);
309
+ const importedMacro = importedExportMap[resolvedImport.macroName];
310
+ if (!importedMacro) {
311
+ throw new Error(`Macro "${resolvedImport.macroName}" imported by "${sourcePath}" was not exported from "${resolvedImport.sourcePath}"`);
312
+ }
313
+ exportMap[resolvedImport.asName] = createReExportedMacro(importedMacro, resolvedImport.asName);
314
+ }
315
+ source.exportMap = exportMap;
316
+ source.macros = Object.values(exportMap);
317
+ sourceExportState.set(sourcePath, 'done');
318
+ return exportMap;
319
+ };
320
+ for (const sourcePath of Object.keys(sourceMap)) {
321
+ buildSourceExportMap(sourcePath);
322
+ }
323
+ const sources = {};
324
+ for (const [filePath, source] of Object.entries(sourceMap)) {
325
+ sources[filePath] = {
326
+ path: source.path,
327
+ ast: source.ast,
328
+ macros: source.macros,
329
+ internalMacros: source.internalMacros,
330
+ };
331
+ }
332
+ return {
333
+ rootPath: resolvedRootPath,
334
+ entryPath: resolvedEntryPath,
335
+ sources,
336
+ };
337
+ };
338
+ exports.parseProject = parseProject;
339
+ //# sourceMappingURL=project.js.map
@@ -0,0 +1,19 @@
1
+ import type { ASTNode, BindStatementNode, DocumentNode, ImportStatementNode, MacroDefineStatementNode, MinduscriptIdentifierExpressionNode, VariableDefineStatementNode } from '@minduscript/parser';
2
+ export type VarSymbolSource = VariableDefineStatementNode | BindStatementNode | MinduscriptIdentifierExpressionNode;
3
+ export type MacroSymbolSource = MacroDefineStatementNode | ImportStatementNode;
4
+ export type SymbolTable = {
5
+ vars: Record<string, VarSymbolSource>;
6
+ consts: Record<string, VarSymbolSource>;
7
+ macros: Record<string, MacroSymbolSource>;
8
+ };
9
+ export type WithSymbolTable<T extends ASTNode> = T extends ASTNode ? {
10
+ [K in keyof T]: T[K] extends ASTNode ? WithSymbolTable<T[K]> : T[K] extends (infer N extends ASTNode)[] ? WithSymbolTable<N>[] : T[K];
11
+ } & {
12
+ symbolTable: SymbolTable;
13
+ } : never;
14
+ export declare class BuildSymbolTableError extends Error {
15
+ readonly node: ASTNode;
16
+ constructor(node: ASTNode, message: string);
17
+ }
18
+ declare const buildSymbolTable: (document: DocumentNode) => WithSymbolTable<DocumentNode>;
19
+ export { buildSymbolTable };