-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy patheagle-data.js
More file actions
134 lines (121 loc) · 5.78 KB
/
Copy patheagle-data.js
File metadata and controls
134 lines (121 loc) · 5.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/**
* Eagle language data loader - loads command/procedure docs for the LSP.
*/
'use strict';
const fs = require('fs');
const path = require('path');
const DATA_DIR = path.join(__dirname, 'data');
/**
* Load and prepare all Eagle language metadata used by the LSP server.
*
* This function reads the JSON files that ship under the sibling "data"
* directory (eagle_commands.json, eagle_procedures.json, and the optional
* eagle_command_options.json generated by the export_command_options.eagle
* tool) and turns them into the in-memory lookup structures the rest of the
* server consumes. It exists so the LSP can answer completion, hover, and
* signature-help queries quickly without re-reading or re-parsing JSON on
* every keystroke -- everything is loaded once at startup and then accessed
* via O(1) Map lookups or simple array iteration.
*
* How it works: the raw JSON arrays of command and procedure descriptors are
* each indexed by name into a Map for fast retrieval. A separate Map of
* subcommand lists is built from any command descriptor that exposes a
* non-empty "subcommands" property, so that the server can offer subcommand
* completion (for example, suggesting "bytelength", "cat", etc. after the
* user types "string "). Two flat arrays of just the names are precomputed
* for cheap completion enumeration. Finally, several hand-curated lists of
* well-known Eagle/Tcl identifiers -- control-flow keywords, expr math
* functions, "string is" classes, and expr string/list comparison operators
* -- are returned alongside the data-driven structures so callers can
* present them in completion lists even though they do not appear in the
* generated JSON.
*
* Tricky details: eagle_command_options.json is treated as optional; if the
* file is missing, an empty object is returned for commandOptions rather
* than raising an error, allowing the LSP to function (with reduced option
* awareness) on installations that have not yet generated the file. All
* file I/O is synchronous because this is intended to run exactly once at
* server startup. No validation is performed on the JSON contents beyond
* what JSON.parse itself enforces.
*
* Use cases: invoked from the LSP server bootstrap to populate the data
* caches; not intended to be called repeatedly during a session.
*
* @returns {Object} An object exposing the loaded data: "commands" (Map of
* command name to descriptor), "procedures" (Map of procedure name to
* descriptor), "subcommandMap" (Map of command name to array of
* subcommand names), "commandOptions" (plain object of per-command option
* metadata, possibly empty), "allCommandNames" and "allProcNames" (string
* arrays for completion), and the static lists "keywords",
* "mathFunctions", "stringIsClasses", and "exprOperators".
*/
function load() {
const cmdsRaw = JSON.parse(fs.readFileSync(path.join(DATA_DIR, 'eagle_commands.json'), 'utf8'));
const procsRaw = JSON.parse(fs.readFileSync(path.join(DATA_DIR, 'eagle_procedures.json'), 'utf8'));
// Load command option metadata (generated by export_command_options.eagle)
let commandOptions = {};
const optionsPath = path.join(DATA_DIR, 'eagle_command_options.json');
if (fs.existsSync(optionsPath)) {
commandOptions = JSON.parse(fs.readFileSync(optionsPath, 'utf8'));
}
// Build lookup maps
const commands = new Map();
for (const cmd of cmdsRaw) {
commands.set(cmd.name, cmd);
}
const procedures = new Map();
for (const proc of procsRaw) {
procedures.set(proc.name, proc);
}
// Build subcommand lookup: "string" -> ["bytelength", "cat", ...]
const subcommandMap = new Map();
for (const cmd of cmdsRaw) {
if (cmd.subcommands && cmd.subcommands.length > 0) {
subcommandMap.set(cmd.name, cmd.subcommands);
}
}
// All command names for fast completion
const allCommandNames = cmdsRaw.map(c => c.name);
const allProcNames = procsRaw.map(p => p.name);
// Known Eagle keywords / control flow
const keywords = [
'if', 'else', 'elseif', 'then', 'for', 'foreach', 'while', 'do',
'switch', 'break', 'continue', 'return', 'proc', 'set', 'unset',
'catch', 'try', 'throw', 'finally', 'error', 'downlevel',
'namespace', 'eval', 'uplevel', 'upvar', 'global', 'variable',
'expr', 'incr', 'append', 'lappend', 'source', 'package',
];
// Math functions available in expr
const mathFunctions = [
'acos', 'asin', 'atan', 'atan2', 'cos', 'cosh', 'sin', 'sinh',
'tan', 'tanh', 'exp', 'log', 'log10', 'log2', 'logx', 'pow',
'sqrt', 'ceil', 'floor', 'round', 'round2', 'round3', 'truncate',
'abs', 'fmod', 'hypot', 'sign', 'max', 'min',
'isfinite', 'isinf', 'isnan', 'isnormal', 'issubnormal', 'isunordered',
'rand', 'random', 'randstr', 'srand',
'bool', 'double', 'int', 'entier', 'wide', 'decimal',
'e', 'pi', 'epsilon', 'typeof', 'datetime', 'timespan', 'flags', 'list',
];
// Classes for "string is" command
const stringIsClasses = [
'alnum', 'alpha', 'ascii', 'control', 'digit', 'graph', 'lower',
'print', 'punct', 'space', 'upper', 'wordchar', 'xdigit',
'boolean', 'integer', 'wideinteger', 'entier', 'double', 'decimal',
'asciialnum', 'asciialpha', 'asciidigit', 'base64', 'byte', 'cidr',
'command', 'datetime', 'dict', 'directory', 'element', 'encoding',
'false', 'file', 'guid', 'hexadecimal', 'identifier', 'inetaddr',
'interpreter', 'list', 'none', 'number', 'numeric', 'object',
'path', 'real', 'single', 'timespan', 'true', 'type', 'uri',
'version', 'versionrange',
];
// String/list operators used in expr
const exprOperators = [
'eq', 'ne', 'lt', 'gt', 'le', 'ge', 'in', 'ni',
];
return {
commands, procedures, subcommandMap, commandOptions,
allCommandNames, allProcNames,
keywords, mathFunctions, stringIsClasses, exprOperators,
};
}
module.exports = { load };