@m100/core 0.8.2 → 0.9.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.
- package/dist/data/keywordCategories.json +69 -0
- package/dist/data/keywordDataset.json +1935 -0
- package/dist/diagnostics/diagnostics.d.ts +15 -0
- package/dist/diagnostics/diagnostics.js +368 -0
- package/dist/diagnostics/diagnostics.js.map +1 -0
- package/dist/diagnostics/formatMessage.d.ts +19 -0
- package/dist/diagnostics/formatMessage.js +96 -0
- package/dist/diagnostics/formatMessage.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/dist/keywords.d.ts +28 -0
- package/dist/keywords.js +188 -0
- package/dist/keywords.js.map +1 -0
- package/dist/languageFeatures.d.ts +24 -0
- package/dist/languageFeatures.js +195 -0
- package/dist/languageFeatures.js.map +1 -0
- package/dist/utils/programAnalysis.d.ts +18 -6
- package/dist/utils/programAnalysis.js +102 -4
- package/dist/utils/programAnalysis.js.map +1 -1
- package/package.json +1 -1
package/dist/keywords.js
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
3
|
+
const require = createRequire(typeof import.meta !== 'undefined' && import.meta.url
|
|
4
|
+
? import.meta.url
|
|
5
|
+
: pathToFileURL(__filename).href);
|
|
6
|
+
const KEYWORD_DATASET = require('./data/keywordDataset.json');
|
|
7
|
+
const KEYWORD_CATEGORY_CONFIG = require('./data/keywordCategories.json');
|
|
8
|
+
const KEYWORD_DOCS_BY_NAME = new Map(KEYWORD_DATASET.keywords.map(entry => [entry.name.toUpperCase(), entry]));
|
|
9
|
+
const CONTROL_FLOW_KEYWORDS = new Set(KEYWORD_CATEGORY_CONFIG.control.map(value => value.toUpperCase()));
|
|
10
|
+
const VARIABLE_KEYWORDS = new Set(KEYWORD_CATEGORY_CONFIG.variables.map(value => value.toUpperCase()));
|
|
11
|
+
const OPERATOR_KEYWORDS = new Set(KEYWORD_CATEGORY_CONFIG.operators.map(value => value.toUpperCase()));
|
|
12
|
+
const FUNCTION_KEYWORDS = new Set(KEYWORD_CATEGORY_CONFIG.functions.map(value => value.toUpperCase()));
|
|
13
|
+
const INTEGER_RETURN_FUNCTIONS = new Set(KEYWORD_CATEGORY_CONFIG.integerFunctions.map(value => value.toUpperCase()));
|
|
14
|
+
const MANUAL_KEYWORDS = [
|
|
15
|
+
// Control Flow
|
|
16
|
+
{ name: 'IF', category: 'control', description: 'Tests a condition and executes code conditionally', syntax: 'IF condition THEN commands [ELSE commands]' },
|
|
17
|
+
{ name: 'THEN', category: 'control', description: 'Used with IF to specify true branch' },
|
|
18
|
+
{ name: 'ELSE', category: 'control', description: 'Used with IF to specify false branch' },
|
|
19
|
+
{ name: 'FOR', category: 'control', description: 'Starts a loop', syntax: 'FOR counter = start TO end [STEP increment]' },
|
|
20
|
+
{ name: 'NEXT', category: 'control', description: 'Ends a FOR loop' },
|
|
21
|
+
{ name: 'GOSUB', category: 'control', description: 'Calls a subroutine', syntax: 'GOSUB line_number' },
|
|
22
|
+
{ name: 'GOTO', category: 'control', description: 'Branches to a line', syntax: 'GOTO line_number' },
|
|
23
|
+
{ name: 'RETURN', category: 'control', description: 'Returns from a subroutine' },
|
|
24
|
+
{ name: 'ON', category: 'control', description: 'Branch based on expression value', syntax: 'ON expression GOTO/GOSUB line_list' },
|
|
25
|
+
// Program Control
|
|
26
|
+
{ name: 'RUN', category: 'statement', description: 'Runs the program', syntax: 'RUN [line_number]' },
|
|
27
|
+
{ name: 'NEW', category: 'statement', description: 'Clears the program and variables' },
|
|
28
|
+
{ name: 'STOP', category: 'statement', description: 'Halts program execution' },
|
|
29
|
+
{ name: 'END', category: 'statement', description: 'Ends the program' },
|
|
30
|
+
{ name: 'CONT', category: 'statement', description: 'Continues after BREAK or STOP' },
|
|
31
|
+
{ name: 'MENU', category: 'statement', description: 'Returns to Model 100 menu' },
|
|
32
|
+
{ name: 'EDIT', category: 'statement', description: 'Enters text editing mode', syntax: 'EDIT [line_range]' },
|
|
33
|
+
{ name: 'PRINT', category: 'statement', description: 'Outputs expressions to the screen', syntax: 'PRINT [expression][;|, expression]...', requiresParentheses: false },
|
|
34
|
+
{ name: 'INPUT', category: 'statement', description: 'Reads values from the user', syntax: 'INPUT [prompt;] variable_list', requiresParentheses: false },
|
|
35
|
+
{ name: 'CLS', category: 'statement', description: 'Clears the screen and resets the cursor', requiresParentheses: false },
|
|
36
|
+
// Error Handling
|
|
37
|
+
{ name: 'ERROR', category: 'statement', description: 'Simulates an error', syntax: 'ERROR error_number' },
|
|
38
|
+
{ name: 'ERR', category: 'variable', description: 'Returns the error number', returnType: 'integer' },
|
|
39
|
+
{ name: 'ERL', category: 'variable', description: 'Returns the line number of the error', returnType: 'integer' },
|
|
40
|
+
{ name: 'RESUME', category: 'statement', description: 'Resumes after an error', syntax: 'RESUME [line_number]' },
|
|
41
|
+
// Data & Variables
|
|
42
|
+
{ name: 'DIM', category: 'statement', description: 'Declares an array', syntax: 'DIM variable(dimensions)' },
|
|
43
|
+
{ name: 'LET', category: 'statement', description: 'Assigns a value to a variable (optional keyword)' },
|
|
44
|
+
{ name: 'CLEAR', category: 'statement', description: 'Clears variables and sets memory', syntax: 'CLEAR [string_space] [,high_memory]' },
|
|
45
|
+
{ name: 'DATA', category: 'statement', description: 'Defines constants for READ', syntax: 'DATA constant_list' },
|
|
46
|
+
{ name: 'READ', category: 'statement', description: 'Reads data from DATA statement', syntax: 'READ variable_list' },
|
|
47
|
+
{ name: 'RESTORE', category: 'statement', description: 'Resets DATA pointer', syntax: 'RESTORE [line_number]' },
|
|
48
|
+
// Comments
|
|
49
|
+
{ name: 'REM', category: 'statement', description: 'Comment (can use apostrophe instead)' },
|
|
50
|
+
// Numeric Functions
|
|
51
|
+
{ name: 'ABS', category: 'function', description: 'Absolute value', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'value', type: 'numeric' }] },
|
|
52
|
+
{ name: 'INT', category: 'function', description: 'Integer part of a number', requiresParentheses: true, returnType: 'integer', parameters: [{ name: 'value', type: 'numeric' }] },
|
|
53
|
+
{ name: 'FIX', category: 'function', description: 'Integer portion (truncate)', requiresParentheses: true, returnType: 'integer', parameters: [{ name: 'value', type: 'numeric' }] },
|
|
54
|
+
{ name: 'SQR', category: 'function', description: 'Square root', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'value', type: 'numeric' }] },
|
|
55
|
+
{ name: 'EXP', category: 'function', description: 'Exponential (e^x)', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'value', type: 'numeric' }] },
|
|
56
|
+
{ name: 'LOG', category: 'function', description: 'Natural logarithm', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'value', type: 'numeric' }] },
|
|
57
|
+
{ name: 'SIN', category: 'function', description: 'Sine (radians)', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'radians', type: 'numeric' }] },
|
|
58
|
+
{ name: 'COS', category: 'function', description: 'Cosine (radians)', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'radians', type: 'numeric' }] },
|
|
59
|
+
{ name: 'TAN', category: 'function', description: 'Tangent (radians)', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'radians', type: 'numeric' }] },
|
|
60
|
+
{ name: 'ATN', category: 'function', description: 'Arctangent (returns radians)', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'value', type: 'numeric' }] },
|
|
61
|
+
{ name: 'RND', category: 'function', description: 'Random number 0-1', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'seed', type: 'numeric', optional: true }] },
|
|
62
|
+
{ name: 'SGN', category: 'function', description: 'Sign (-1, 0, or 1)', requiresParentheses: true, returnType: 'integer', parameters: [{ name: 'value', type: 'numeric' }] },
|
|
63
|
+
// String Functions
|
|
64
|
+
{ name: 'CHR$', category: 'function', description: 'Character from ASCII code', requiresParentheses: true, returnType: 'string', parameters: [{ name: 'code', type: 'numeric' }] },
|
|
65
|
+
{ name: 'STR$', category: 'function', description: 'Convert number to string', requiresParentheses: true, returnType: 'string', parameters: [{ name: 'value', type: 'numeric' }] },
|
|
66
|
+
{ name: 'ASC', category: 'function', description: 'ASCII code of first character', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'text', type: 'string' }] },
|
|
67
|
+
{ name: 'VAL', category: 'function', description: 'Convert string to number', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'text', type: 'string' }] },
|
|
68
|
+
{ name: 'LEN', category: 'function', description: 'Length of string', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'text', type: 'string' }] },
|
|
69
|
+
{ name: 'LEFT$', category: 'function', description: 'Extract left characters', syntax: 'LEFT$(string, length)', requiresParentheses: true, returnType: 'string', parameters: [{ name: 'string', type: 'string' }, { name: 'length', type: 'numeric' }] },
|
|
70
|
+
{ name: 'RIGHT$', category: 'function', description: 'Extract right characters', syntax: 'RIGHT$(string, count)', requiresParentheses: true, returnType: 'string', parameters: [{ name: 'string', type: 'string' }, { name: 'count', type: 'numeric' }] },
|
|
71
|
+
{ name: 'MID$', category: 'function', description: 'Extract middle characters', syntax: 'MID$(string, start [, length])', requiresParentheses: true, returnType: 'string', parameters: [{ name: 'string', type: 'string' }, { name: 'start', type: 'numeric' }, { name: 'length', type: 'numeric', optional: true }] },
|
|
72
|
+
{ name: 'INSTR', category: 'function', description: 'Find substring position', syntax: 'INSTR(start, search_string, match_string)', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'start', type: 'numeric' }, { name: 'search', type: 'string' }, { name: 'match', type: 'string' }] },
|
|
73
|
+
{ name: 'SPACE$', category: 'function', description: 'Create string of spaces', syntax: 'SPACE$(length)', requiresParentheses: true, returnType: 'string', parameters: [{ name: 'length', type: 'numeric' }] },
|
|
74
|
+
{ name: 'STRING$', category: 'function', description: 'Repeat character', syntax: 'STRING$(length, character)', requiresParentheses: true, returnType: 'string', parameters: [{ name: 'length', type: 'numeric' }, { name: 'character', type: ['numeric', 'string'] }] },
|
|
75
|
+
// Type Conversion
|
|
76
|
+
{ name: 'CINT', category: 'function', description: 'Convert to integer', requiresParentheses: true, returnType: 'integer', parameters: [{ name: 'value', type: 'numeric' }] },
|
|
77
|
+
{ name: 'CSNG', category: 'function', description: 'Convert to single-precision', requiresParentheses: true, returnType: 'single', parameters: [{ name: 'value', type: 'numeric' }] },
|
|
78
|
+
{ name: 'CDBL', category: 'function', description: 'Convert to double-precision', requiresParentheses: true, returnType: 'double', parameters: [{ name: 'value', type: 'numeric' }] },
|
|
79
|
+
// Memory & Hardware
|
|
80
|
+
{ name: 'PEEK', category: 'function', description: 'Read byte from memory', syntax: 'PEEK(address)', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'address', type: 'numeric' }] },
|
|
81
|
+
{ name: 'POKE', category: 'statement', description: 'Write byte to memory', syntax: 'POKE address, byte', requiresParentheses: false },
|
|
82
|
+
{ name: 'CALL', category: 'statement', description: 'Call machine-level subroutine', syntax: 'CALL address [, expr1, expr2]', requiresParentheses: false },
|
|
83
|
+
{ name: 'VARPTR', category: 'function', description: 'Get variable memory address', syntax: 'VARPTR(variable)', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'variable', type: 'any' }] },
|
|
84
|
+
{ name: 'INP', category: 'function', description: 'Read from I/O port', syntax: 'INP(port)', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'port', type: 'numeric' }] },
|
|
85
|
+
{ name: 'OUT', category: 'statement', description: 'Write to I/O port', syntax: 'OUT port, byte', requiresParentheses: false },
|
|
86
|
+
{ name: 'FRE', category: 'function', description: 'Free memory', syntax: 'FRE(0) or FRE("")', requiresParentheses: true, returnType: 'numeric', parameters: [{ name: 'expression', type: ['numeric', 'string'], optional: true }] },
|
|
87
|
+
// Power Management
|
|
88
|
+
{ name: 'POWER', category: 'statement', description: 'Control power management', syntax: 'POWER auto_off_ticks', requiresParentheses: false },
|
|
89
|
+
// Built-in Variables
|
|
90
|
+
{ name: 'HIMEM', category: 'variable', description: 'Top of available memory', returnType: 'numeric' },
|
|
91
|
+
// Operators
|
|
92
|
+
{ name: 'AND', category: 'operator', description: 'Logical AND' },
|
|
93
|
+
{ name: 'OR', category: 'operator', description: 'Logical OR' },
|
|
94
|
+
{ name: 'NOT', category: 'operator', description: 'Logical NOT' },
|
|
95
|
+
{ name: 'XOR', category: 'operator', description: 'Logical XOR' },
|
|
96
|
+
{ name: 'MOD', category: 'operator', description: 'Modulo (remainder)' },
|
|
97
|
+
];
|
|
98
|
+
export const BASIC_KEYWORDS = buildKeywordList();
|
|
99
|
+
export function getKeywordByName(name) {
|
|
100
|
+
return BASIC_KEYWORDS.find(k => k.name.toUpperCase() === name.toUpperCase());
|
|
101
|
+
}
|
|
102
|
+
export function getKeywordsByCategory(category) {
|
|
103
|
+
return BASIC_KEYWORDS.filter(k => k.category === category);
|
|
104
|
+
}
|
|
105
|
+
export const KEYWORD_NAMES = BASIC_KEYWORDS.map(k => k.name);
|
|
106
|
+
function buildKeywordList() {
|
|
107
|
+
const merged = [];
|
|
108
|
+
const seen = new Set();
|
|
109
|
+
for (const keyword of MANUAL_KEYWORDS) {
|
|
110
|
+
const enriched = enrichKeywordFromDataset(keyword);
|
|
111
|
+
merged.push(enriched);
|
|
112
|
+
seen.add(enriched.name.toUpperCase());
|
|
113
|
+
}
|
|
114
|
+
const additional = [];
|
|
115
|
+
for (const entry of KEYWORD_DATASET.keywords) {
|
|
116
|
+
const nameKey = entry.name.toUpperCase();
|
|
117
|
+
if (seen.has(nameKey)) {
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
const doc = entry.documentation.find(d => d.description?.trim() || d.syntax?.trim()) ??
|
|
121
|
+
entry.documentation[0];
|
|
122
|
+
const category = inferCategory(entry.name);
|
|
123
|
+
additional.push({
|
|
124
|
+
name: entry.name,
|
|
125
|
+
category,
|
|
126
|
+
description: doc?.description || `Reserved keyword ${entry.name}`,
|
|
127
|
+
syntax: doc?.syntax || undefined,
|
|
128
|
+
requiresParentheses: category === 'function'
|
|
129
|
+
? true
|
|
130
|
+
: category === 'statement'
|
|
131
|
+
? false
|
|
132
|
+
: undefined,
|
|
133
|
+
returnType: inferReturnType(entry.name, category),
|
|
134
|
+
variants: entry.variants,
|
|
135
|
+
docEntries: entry.documentation,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
additional.sort((a, b) => a.name.localeCompare(b.name));
|
|
139
|
+
return [...merged, ...additional];
|
|
140
|
+
}
|
|
141
|
+
function enrichKeywordFromDataset(keyword) {
|
|
142
|
+
const entry = KEYWORD_DOCS_BY_NAME.get(keyword.name.toUpperCase());
|
|
143
|
+
if (!entry) {
|
|
144
|
+
return keyword;
|
|
145
|
+
}
|
|
146
|
+
const doc = entry.documentation.find(d => d.description?.trim() || d.syntax?.trim()) ??
|
|
147
|
+
entry.documentation[0];
|
|
148
|
+
return {
|
|
149
|
+
...keyword,
|
|
150
|
+
description: doc?.description || keyword.description,
|
|
151
|
+
syntax: doc?.syntax || keyword.syntax,
|
|
152
|
+
variants: entry.variants,
|
|
153
|
+
docEntries: entry.documentation,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
function inferCategory(name) {
|
|
157
|
+
const key = name.toUpperCase();
|
|
158
|
+
if (CONTROL_FLOW_KEYWORDS.has(key)) {
|
|
159
|
+
return 'control';
|
|
160
|
+
}
|
|
161
|
+
if (OPERATOR_KEYWORDS.has(key)) {
|
|
162
|
+
return 'operator';
|
|
163
|
+
}
|
|
164
|
+
if (VARIABLE_KEYWORDS.has(key)) {
|
|
165
|
+
return 'variable';
|
|
166
|
+
}
|
|
167
|
+
if (FUNCTION_KEYWORDS.has(key)) {
|
|
168
|
+
return 'function';
|
|
169
|
+
}
|
|
170
|
+
return 'statement';
|
|
171
|
+
}
|
|
172
|
+
function inferReturnType(name, category) {
|
|
173
|
+
if (category === 'function') {
|
|
174
|
+
const upper = name.toUpperCase();
|
|
175
|
+
if (upper.endsWith('$')) {
|
|
176
|
+
return 'string';
|
|
177
|
+
}
|
|
178
|
+
if (INTEGER_RETURN_FUNCTIONS.has(upper)) {
|
|
179
|
+
return 'integer';
|
|
180
|
+
}
|
|
181
|
+
return 'numeric';
|
|
182
|
+
}
|
|
183
|
+
if (category === 'variable') {
|
|
184
|
+
return name.endsWith('$') ? 'string' : 'numeric';
|
|
185
|
+
}
|
|
186
|
+
return undefined;
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=keywords.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keywords.js","sourceRoot":"","sources":["../src/keywords.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type BasicKeyword, type BasicType } from './keywords.js';
|
|
2
|
+
export declare const KEYWORDS_BY_NAME: Map<string, BasicKeyword>;
|
|
3
|
+
export declare function splitStatementsWithOffsets(line: string): Array<{
|
|
4
|
+
text: string;
|
|
5
|
+
start: number;
|
|
6
|
+
}>;
|
|
7
|
+
export declare function normalizeStatement(statement: string): {
|
|
8
|
+
text: string;
|
|
9
|
+
leadingOffset: number;
|
|
10
|
+
};
|
|
11
|
+
export declare function extractArguments(text: string, openParenIndex: number): {
|
|
12
|
+
args: string[];
|
|
13
|
+
ranges: Array<{
|
|
14
|
+
start: number;
|
|
15
|
+
end: number;
|
|
16
|
+
}>;
|
|
17
|
+
endIndex: number;
|
|
18
|
+
} | undefined;
|
|
19
|
+
export declare function inferVariableType(name: string): BasicType | undefined;
|
|
20
|
+
export declare function inferExpressionType(expression: string): BasicType | undefined;
|
|
21
|
+
export declare function typeMatches(expected: BasicType | BasicType[], actual?: BasicType): boolean;
|
|
22
|
+
export declare function formatType(type: BasicType): string;
|
|
23
|
+
export declare function formatExpectedType(type: BasicType | BasicType[]): string;
|
|
24
|
+
export type { BasicKeyword, BasicType };
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { BASIC_KEYWORDS } from './keywords.js';
|
|
2
|
+
export const KEYWORDS_BY_NAME = new Map(BASIC_KEYWORDS.map(keyword => [keyword.name.toUpperCase(), keyword]));
|
|
3
|
+
export function splitStatementsWithOffsets(line) {
|
|
4
|
+
const result = [];
|
|
5
|
+
let inString = false;
|
|
6
|
+
let lastSplit = 0;
|
|
7
|
+
for (let i = 0; i < line.length; i++) {
|
|
8
|
+
const char = line[i];
|
|
9
|
+
if (char === '"') {
|
|
10
|
+
inString = !inString;
|
|
11
|
+
}
|
|
12
|
+
if (!inString && char === ':') {
|
|
13
|
+
const segment = line.substring(lastSplit, i);
|
|
14
|
+
if (segment.trim()) {
|
|
15
|
+
result.push({ text: segment, start: lastSplit });
|
|
16
|
+
}
|
|
17
|
+
lastSplit = i + 1;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const finalSegment = line.substring(lastSplit);
|
|
21
|
+
if (finalSegment.trim()) {
|
|
22
|
+
result.push({ text: finalSegment, start: lastSplit });
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
export function normalizeStatement(statement) {
|
|
27
|
+
let text = statement;
|
|
28
|
+
let offset = 0;
|
|
29
|
+
const leading = text.length - text.trimStart().length;
|
|
30
|
+
if (leading) {
|
|
31
|
+
offset += leading;
|
|
32
|
+
text = text.trimStart();
|
|
33
|
+
}
|
|
34
|
+
const lineNumberMatch = text.match(/^\d+\s*/);
|
|
35
|
+
if (lineNumberMatch) {
|
|
36
|
+
offset += lineNumberMatch[0].length;
|
|
37
|
+
text = text.substring(lineNumberMatch[0].length);
|
|
38
|
+
}
|
|
39
|
+
return { text: text.trim(), leadingOffset: offset };
|
|
40
|
+
}
|
|
41
|
+
export function extractArguments(text, openParenIndex) {
|
|
42
|
+
const args = [];
|
|
43
|
+
const ranges = [];
|
|
44
|
+
let current = '';
|
|
45
|
+
let depth = 0;
|
|
46
|
+
let inString = false;
|
|
47
|
+
let argStart = openParenIndex + 1;
|
|
48
|
+
for (let i = openParenIndex + 1; i < text.length; i++) {
|
|
49
|
+
const char = text[i];
|
|
50
|
+
if (char === '"') {
|
|
51
|
+
inString = !inString;
|
|
52
|
+
}
|
|
53
|
+
else if (!inString) {
|
|
54
|
+
if (char === '(') {
|
|
55
|
+
depth += 1;
|
|
56
|
+
}
|
|
57
|
+
else if (char === ')') {
|
|
58
|
+
if (depth === 0) {
|
|
59
|
+
const trimmed = current.trim();
|
|
60
|
+
if (trimmed) {
|
|
61
|
+
const leading = current.length - current.trimStart().length;
|
|
62
|
+
const trailing = current.length - current.trimEnd().length;
|
|
63
|
+
args.push(trimmed);
|
|
64
|
+
ranges.push({ start: argStart + leading, end: i - trailing });
|
|
65
|
+
}
|
|
66
|
+
return { args, ranges, endIndex: i };
|
|
67
|
+
}
|
|
68
|
+
depth -= 1;
|
|
69
|
+
}
|
|
70
|
+
else if (char === ',' && depth === 0) {
|
|
71
|
+
const trimmed = current.trim();
|
|
72
|
+
if (trimmed) {
|
|
73
|
+
const leading = current.length - current.trimStart().length;
|
|
74
|
+
const trailing = current.length - current.trimEnd().length;
|
|
75
|
+
args.push(trimmed);
|
|
76
|
+
ranges.push({ start: argStart + leading, end: i - trailing });
|
|
77
|
+
}
|
|
78
|
+
current = '';
|
|
79
|
+
argStart = i + 1;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
current += char;
|
|
84
|
+
}
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
export function inferVariableType(name) {
|
|
88
|
+
const keyword = KEYWORDS_BY_NAME.get(name.toUpperCase());
|
|
89
|
+
if (keyword?.returnType) {
|
|
90
|
+
return keyword.returnType;
|
|
91
|
+
}
|
|
92
|
+
const suffix = name.slice(-1);
|
|
93
|
+
switch (suffix) {
|
|
94
|
+
case '$':
|
|
95
|
+
return 'string';
|
|
96
|
+
case '%':
|
|
97
|
+
return 'integer';
|
|
98
|
+
case '!':
|
|
99
|
+
return 'single';
|
|
100
|
+
case '#':
|
|
101
|
+
return 'double';
|
|
102
|
+
default:
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
export function inferExpressionType(expression) {
|
|
107
|
+
const trimmed = expression.trim();
|
|
108
|
+
if (!trimmed) {
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
if (/^".*"$/.test(trimmed)) {
|
|
112
|
+
return 'string';
|
|
113
|
+
}
|
|
114
|
+
if (/^-?\d+(\.\d+)?([eE][+-]?\d+)?([%!#])?$/.test(trimmed)) {
|
|
115
|
+
const suffix = trimmed.slice(-1);
|
|
116
|
+
switch (suffix) {
|
|
117
|
+
case '%':
|
|
118
|
+
return 'integer';
|
|
119
|
+
case '!':
|
|
120
|
+
return 'single';
|
|
121
|
+
case '#':
|
|
122
|
+
return 'double';
|
|
123
|
+
default:
|
|
124
|
+
return 'numeric';
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const variableMatch = /^([A-Za-z][A-Za-z0-9_$#!%]*)$/i.exec(trimmed);
|
|
128
|
+
if (variableMatch) {
|
|
129
|
+
return (KEYWORDS_BY_NAME.get(variableMatch[1].toUpperCase())?.returnType ??
|
|
130
|
+
inferVariableType(variableMatch[1]));
|
|
131
|
+
}
|
|
132
|
+
const functionMatch = /^([A-Za-z][A-Za-z0-9_$#!%]*)\s*\(/i.exec(trimmed);
|
|
133
|
+
if (functionMatch) {
|
|
134
|
+
return KEYWORDS_BY_NAME.get(functionMatch[1].toUpperCase())?.returnType;
|
|
135
|
+
}
|
|
136
|
+
return undefined;
|
|
137
|
+
}
|
|
138
|
+
export function typeMatches(expected, actual) {
|
|
139
|
+
if (!actual) {
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
const types = Array.isArray(expected) ? expected : [expected];
|
|
143
|
+
return types.some(type => compareType(type, actual));
|
|
144
|
+
}
|
|
145
|
+
function compareType(expected, actual) {
|
|
146
|
+
if (expected === 'any' || actual === 'any') {
|
|
147
|
+
return true;
|
|
148
|
+
}
|
|
149
|
+
if (expected === 'string') {
|
|
150
|
+
return actual === 'string';
|
|
151
|
+
}
|
|
152
|
+
if (expected === 'numeric') {
|
|
153
|
+
return isNumericType(actual);
|
|
154
|
+
}
|
|
155
|
+
if (expected === 'integer') {
|
|
156
|
+
return actual === 'integer' || actual === 'numeric';
|
|
157
|
+
}
|
|
158
|
+
if (expected === 'single') {
|
|
159
|
+
return actual === 'single' || actual === 'numeric';
|
|
160
|
+
}
|
|
161
|
+
if (expected === 'double') {
|
|
162
|
+
return actual === 'double' || actual === 'numeric';
|
|
163
|
+
}
|
|
164
|
+
return expected === actual;
|
|
165
|
+
}
|
|
166
|
+
export function formatType(type) {
|
|
167
|
+
switch (type) {
|
|
168
|
+
case 'string':
|
|
169
|
+
return 'string';
|
|
170
|
+
case 'integer':
|
|
171
|
+
return 'integer';
|
|
172
|
+
case 'single':
|
|
173
|
+
return 'single-precision';
|
|
174
|
+
case 'double':
|
|
175
|
+
return 'double-precision';
|
|
176
|
+
case 'numeric':
|
|
177
|
+
return 'numeric';
|
|
178
|
+
case 'any':
|
|
179
|
+
default:
|
|
180
|
+
return 'any';
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
export function formatExpectedType(type) {
|
|
184
|
+
if (Array.isArray(type)) {
|
|
185
|
+
return type.map(formatType).join(' or ');
|
|
186
|
+
}
|
|
187
|
+
return formatType(type);
|
|
188
|
+
}
|
|
189
|
+
function isNumericType(type) {
|
|
190
|
+
return (type === 'numeric' ||
|
|
191
|
+
type === 'integer' ||
|
|
192
|
+
type === 'single' ||
|
|
193
|
+
type === 'double');
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=languageFeatures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"languageFeatures.js","sourceRoot":"","sources":["../src/languageFeatures.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* This module provides the same analysis as src/programAnalysis.ts
|
|
5
|
-
* but works with plain strings instead of VS Code TextDocument.
|
|
2
|
+
* Program analysis utilities (VS Code-free).
|
|
6
3
|
*/
|
|
7
4
|
export type NumberedLineInfo = {
|
|
8
5
|
line: number;
|
|
@@ -11,6 +8,7 @@ export type NumberedLineInfo = {
|
|
|
11
8
|
numberEnd: number;
|
|
12
9
|
bodyOffset: number;
|
|
13
10
|
textBeforeComment: string;
|
|
11
|
+
controlInfo: LineControlInfo;
|
|
14
12
|
};
|
|
15
13
|
export type LineReference = {
|
|
16
14
|
lineIndex: number;
|
|
@@ -31,11 +29,25 @@ export type ReferenceSpan = {
|
|
|
31
29
|
keyword: ReferenceKeyword;
|
|
32
30
|
};
|
|
33
31
|
export type ReferenceKeyword = 'GOTO' | 'GOSUB' | 'THEN' | 'ELSE' | 'RUN' | 'RESUME' | 'RESTORE' | 'ON_GOTO' | 'ON_GOSUB' | 'ON_KEY_GOSUB';
|
|
32
|
+
export type LineControlInfo = {
|
|
33
|
+
hasIfThen: boolean;
|
|
34
|
+
containsGoto: boolean;
|
|
35
|
+
endsWithTerminal: boolean;
|
|
36
|
+
hasData: boolean;
|
|
37
|
+
};
|
|
38
|
+
export type LineSource = {
|
|
39
|
+
lineCount: number;
|
|
40
|
+
lineAt: (index: number) => string | {
|
|
41
|
+
text: string;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
34
44
|
/**
|
|
35
45
|
* Analyze BASIC program structure from plain text.
|
|
36
46
|
*
|
|
37
|
-
* @param basicCode - BASIC source code as a string
|
|
47
|
+
* @param basicCode - BASIC source code as a string, array of lines, or a line source
|
|
38
48
|
* @returns Program structure with numbered lines and references
|
|
39
49
|
*/
|
|
40
|
-
export declare function collectProgramStructure(basicCode: string): ProgramStructure;
|
|
50
|
+
export declare function collectProgramStructure(basicCode: string | string[] | LineSource): ProgramStructure;
|
|
41
51
|
export declare function findLineReferenceSpans(body: string): ReferenceSpan[];
|
|
52
|
+
export declare function extractLastStatement(code: string): string;
|
|
53
|
+
export declare function containsKeywordOutsideStrings(text: string, keyword: string): boolean;
|
|
@@ -2,16 +2,16 @@ import { findCommentStart } from '../commentUtils.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Analyze BASIC program structure from plain text.
|
|
4
4
|
*
|
|
5
|
-
* @param basicCode - BASIC source code as a string
|
|
5
|
+
* @param basicCode - BASIC source code as a string, array of lines, or a line source
|
|
6
6
|
* @returns Program structure with numbered lines and references
|
|
7
7
|
*/
|
|
8
8
|
export function collectProgramStructure(basicCode) {
|
|
9
|
-
const
|
|
9
|
+
const source = toLineSource(basicCode);
|
|
10
10
|
const numberedLines = [];
|
|
11
11
|
const references = [];
|
|
12
12
|
const referenceSpans = new Set();
|
|
13
|
-
for (let lineIndex = 0; lineIndex <
|
|
14
|
-
const sourceText =
|
|
13
|
+
for (let lineIndex = 0; lineIndex < source.lineCount; lineIndex++) {
|
|
14
|
+
const sourceText = readLine(source, lineIndex);
|
|
15
15
|
const commentStart = findCommentStart(sourceText);
|
|
16
16
|
const scanLimit = commentStart ?? sourceText.length;
|
|
17
17
|
const textBeforeComment = sourceText.slice(0, scanLimit);
|
|
@@ -45,6 +45,7 @@ export function collectProgramStructure(basicCode) {
|
|
|
45
45
|
numberEnd,
|
|
46
46
|
bodyOffset,
|
|
47
47
|
textBeforeComment,
|
|
48
|
+
controlInfo: analyzeControlFlow(body),
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
return { numberedLines, references };
|
|
@@ -149,4 +150,101 @@ function addReferenceIfValid(references, seen, lineIndex, fromNumber, position,
|
|
|
149
150
|
keyword,
|
|
150
151
|
});
|
|
151
152
|
}
|
|
153
|
+
function toLineSource(input) {
|
|
154
|
+
if (typeof input === 'string') {
|
|
155
|
+
const lines = input.split(/\r?\n/);
|
|
156
|
+
return {
|
|
157
|
+
lineCount: lines.length,
|
|
158
|
+
lineAt: (index) => lines[index] ?? '',
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
if (Array.isArray(input)) {
|
|
162
|
+
return {
|
|
163
|
+
lineCount: input.length,
|
|
164
|
+
lineAt: (index) => input[index] ?? '',
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
return input;
|
|
168
|
+
}
|
|
169
|
+
function readLine(source, index) {
|
|
170
|
+
const value = source.lineAt(index);
|
|
171
|
+
return typeof value === 'string' ? value : value.text ?? '';
|
|
172
|
+
}
|
|
173
|
+
function analyzeControlFlow(body) {
|
|
174
|
+
const text = body.trim();
|
|
175
|
+
if (!text) {
|
|
176
|
+
return {
|
|
177
|
+
hasIfThen: false,
|
|
178
|
+
containsGoto: false,
|
|
179
|
+
endsWithTerminal: false,
|
|
180
|
+
hasData: false,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
const hasIf = containsKeywordOutsideStrings(text, 'IF');
|
|
184
|
+
const hasThen = containsKeywordOutsideStrings(text, 'THEN');
|
|
185
|
+
const containsGoto = containsKeywordOutsideStrings(text, 'GOTO');
|
|
186
|
+
const hasData = containsKeywordOutsideStrings(text, 'DATA');
|
|
187
|
+
const lastStatement = extractLastStatement(text);
|
|
188
|
+
const upper = lastStatement.toUpperCase();
|
|
189
|
+
const endsWithTerminal = upper === 'RETURN' ||
|
|
190
|
+
upper === 'END' ||
|
|
191
|
+
upper === 'STOP' ||
|
|
192
|
+
/^\s*GOTO\s*\d+/i.test(lastStatement) ||
|
|
193
|
+
/^\s*RUN(?:\s+\d+)?\s*$/i.test(lastStatement);
|
|
194
|
+
return {
|
|
195
|
+
hasIfThen: hasIf && hasThen,
|
|
196
|
+
containsGoto,
|
|
197
|
+
endsWithTerminal,
|
|
198
|
+
hasData,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
export function extractLastStatement(code) {
|
|
202
|
+
let inString = false;
|
|
203
|
+
let lastSplit = 0;
|
|
204
|
+
for (let i = 0; i < code.length; i++) {
|
|
205
|
+
const char = code[i];
|
|
206
|
+
if (char === '"') {
|
|
207
|
+
if (inString && code[i + 1] === '"') {
|
|
208
|
+
i += 1;
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
inString = !inString;
|
|
212
|
+
continue;
|
|
213
|
+
}
|
|
214
|
+
if (!inString && char === ':') {
|
|
215
|
+
lastSplit = i + 1;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return code.slice(lastSplit).trim();
|
|
219
|
+
}
|
|
220
|
+
export function containsKeywordOutsideStrings(text, keyword) {
|
|
221
|
+
const upperKeyword = keyword.toUpperCase();
|
|
222
|
+
const keywordLength = upperKeyword.length;
|
|
223
|
+
let inString = false;
|
|
224
|
+
for (let i = 0; i < text.length; i++) {
|
|
225
|
+
const char = text[i];
|
|
226
|
+
if (char === '"') {
|
|
227
|
+
if (inString && text[i + 1] === '"') {
|
|
228
|
+
i += 1;
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
inString = !inString;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (inString) {
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
if (i + keywordLength > text.length) {
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
const slice = text.slice(i, i + keywordLength).toUpperCase();
|
|
241
|
+
if (slice === upperKeyword) {
|
|
242
|
+
const prev = i === 0 ? undefined : text[i - 1];
|
|
243
|
+
if (!prev || !/[A-Za-z]/.test(prev)) {
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
return false;
|
|
249
|
+
}
|
|
152
250
|
//# sourceMappingURL=programAnalysis.js.map
|