circuitscript 0.1.4 → 0.1.7
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/cjs/BaseVisitor.js +149 -80
- package/dist/cjs/SemanticTokenVisitor.js +19 -13
- package/dist/cjs/antlr/CircuitScriptParser.js +711 -671
- package/dist/cjs/builtinMethods.js +48 -22
- package/dist/cjs/draw_symbols.js +4 -1
- package/dist/cjs/environment.js +118 -0
- package/dist/cjs/execute.js +98 -46
- package/dist/cjs/geometry.js +1 -0
- package/dist/cjs/globals.js +14 -7
- package/dist/cjs/helpers.js +142 -150
- package/dist/cjs/index.js +5 -0
- package/dist/cjs/layout.js +39 -14
- package/dist/cjs/main.js +34 -21
- package/dist/cjs/objects/ClassComponent.js +4 -1
- package/dist/cjs/objects/ExecutionScope.js +40 -2
- package/dist/cjs/objects/ParamDefinition.js +15 -15
- package/dist/cjs/parser.js +27 -21
- package/dist/cjs/regenerate-tests.js +9 -6
- package/dist/cjs/render.js +3 -1
- package/dist/cjs/sizing.js +10 -60
- package/dist/cjs/utils.js +148 -17
- package/dist/cjs/validate/SymbolTable.js +96 -0
- package/dist/cjs/validate/SymbolValidatorResolveVisitor.js +14 -0
- package/dist/cjs/validate/SymbolValidatorVisitor.js +170 -0
- package/dist/cjs/validate.js +52 -44
- package/dist/cjs/visitor.js +149 -31
- package/dist/esm/{BaseVisitor.mjs → BaseVisitor.js} +124 -56
- package/dist/esm/{SemanticTokenVisitor.mjs → SemanticTokenVisitor.js} +17 -11
- package/dist/esm/antlr/{CircuitScriptParser.mjs → CircuitScriptParser.js} +711 -671
- package/dist/esm/{builtinMethods.mjs → builtinMethods.js} +40 -14
- package/dist/esm/{draw_symbols.mjs → draw_symbols.js} +11 -8
- package/dist/esm/environment.js +110 -0
- package/dist/esm/{execute.mjs → execute.js} +111 -58
- package/dist/esm/{export.mjs → export.js} +2 -2
- package/dist/esm/{geometry.mjs → geometry.js} +6 -5
- package/dist/esm/{globals.mjs → globals.js} +9 -2
- package/dist/esm/helpers.js +377 -0
- package/dist/esm/index.js +20 -0
- package/dist/esm/{layout.mjs → layout.js} +44 -22
- package/dist/esm/{lexer.mjs → lexer.js} +2 -2
- package/dist/esm/{main.mjs → main.js} +36 -23
- package/dist/esm/objects/{ClassComponent.mjs → ClassComponent.js} +9 -5
- package/dist/esm/objects/{ExecutionScope.mjs → ExecutionScope.js} +40 -2
- package/dist/esm/objects/{Frame.mjs → Frame.js} +1 -1
- package/dist/esm/objects/{ParamDefinition.mjs → ParamDefinition.js} +1 -1
- package/dist/esm/objects/{PinDefinition.mjs → PinDefinition.js} +1 -1
- package/dist/esm/parser.js +71 -0
- package/dist/esm/{regenerate-tests.mjs → regenerate-tests.js} +10 -7
- package/dist/esm/{render.mjs → render.js} +11 -9
- package/dist/esm/{sizing.mjs → sizing.js} +11 -36
- package/dist/esm/utils.js +286 -0
- package/dist/esm/validate/SymbolTable.js +90 -0
- package/dist/esm/validate/SymbolValidatorResolveVisitor.js +10 -0
- package/dist/esm/validate/SymbolValidatorVisitor.js +163 -0
- package/dist/esm/validate.js +86 -0
- package/dist/esm/{visitor.mjs → visitor.js} +160 -42
- package/dist/fonts/Arial.ttf +0 -0
- package/dist/fonts/Inter-Bold.ttf +0 -0
- package/dist/fonts/Inter-Regular.ttf +0 -0
- package/dist/fonts/OpenSans-Regular.ttf +0 -0
- package/dist/fonts/Roboto-Regular.ttf +0 -0
- package/dist/libs/lib.cst +423 -0
- package/dist/types/BaseVisitor.d.ts +36 -22
- package/dist/types/SemanticTokenVisitor.d.ts +6 -5
- package/dist/types/antlr/CircuitScriptParser.d.ts +4 -2
- package/dist/types/builtinMethods.d.ts +3 -2
- package/dist/types/draw_symbols.d.ts +2 -6
- package/dist/types/environment.d.ts +31 -0
- package/dist/types/execute.d.ts +2 -3
- package/dist/types/globals.d.ts +7 -2
- package/dist/types/helpers.d.ts +12 -14
- package/dist/types/index.d.ts +5 -0
- package/dist/types/objects/ClassComponent.d.ts +2 -3
- package/dist/types/objects/ExecutionScope.d.ts +20 -6
- package/dist/types/objects/types.d.ts +6 -1
- package/dist/types/parser.d.ts +7 -11
- package/dist/types/sizing.d.ts +0 -3
- package/dist/types/utils.d.ts +33 -4
- package/dist/types/validate/SymbolTable.d.ts +40 -0
- package/dist/types/validate/SymbolValidatorResolveVisitor.d.ts +7 -0
- package/dist/types/validate/SymbolValidatorVisitor.d.ts +32 -0
- package/dist/types/validate.d.ts +1 -1
- package/libs/lib.cst +12 -22
- package/package.json +14 -13
- package/dist/cjs/SymbolValidatorVisitor.js +0 -233
- package/dist/esm/SymbolValidatorVisitor.mjs +0 -222
- package/dist/esm/helpers.mjs +0 -380
- package/dist/esm/index.mjs +0 -15
- package/dist/esm/parser.mjs +0 -64
- package/dist/esm/utils.mjs +0 -169
- package/dist/esm/validate.mjs +0 -74
- package/dist/types/SymbolValidatorVisitor.d.ts +0 -61
- package/dist/types/layout.d.ts +0 -148
- /package/dist/esm/antlr/{CircuitScriptLexer.mjs → CircuitScriptLexer.js} +0 -0
- /package/dist/esm/antlr/{CircuitScriptVisitor.mjs → CircuitScriptVisitor.js} +0 -0
- /package/dist/esm/{fonts.mjs → fonts.js} +0 -0
- /package/dist/esm/{logger.mjs → logger.js} +0 -0
- /package/dist/esm/objects/{Net.mjs → Net.js} +0 -0
- /package/dist/esm/objects/{PinTypes.mjs → PinTypes.js} +0 -0
- /package/dist/esm/objects/{Wire.mjs → Wire.js} +0 -0
- /package/dist/esm/objects/{types.mjs → types.js} +0 -0
- /package/dist/esm/{server.mjs → server.js} +0 -0
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import { writeFileSync, createWriteStream, existsSync, mkdirSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import PDFDocument from "pdfkit";
|
|
4
|
+
import { generateKiCADNetList, printTree } from "./export.js";
|
|
5
|
+
import { LayoutEngine } from "./layout.js";
|
|
6
|
+
import { parseFileWithVisitor } from "./parser.js";
|
|
7
|
+
import { generatePdfOutput, generateSvgOutput, renderSheetsToSVG } from "./render.js";
|
|
8
|
+
import { generateDebugSequenceAction, ParseError, ParseSyntaxError, RenderError, resolveToNumericValue, RuntimeExecutionError, sequenceActionString, SimpleStopwatch } from "./utils.js";
|
|
9
|
+
import { ParserVisitor } from "./visitor.js";
|
|
10
|
+
import { SymbolValidatorVisitor } from "./validate/SymbolValidatorVisitor.js";
|
|
11
|
+
import { SymbolValidatorResolveVisitor } from "./validate/SymbolValidatorResolveVisitor.js";
|
|
12
|
+
import { BaseErrorListener, CharStream, CommonTokenStream, DefaultErrorStrategy, RecognitionException } from "antlr4ng";
|
|
13
|
+
import { MainLexer } from "./lexer.js";
|
|
14
|
+
import { CircuitScriptParser } from "./antlr/CircuitScriptParser.js";
|
|
15
|
+
import { prepareTokens, SemanticTokensVisitor } from "./SemanticTokenVisitor.js";
|
|
16
|
+
import { defaultPageMarginMM, defaultZoomScale, LengthUnit, MilsToMM, PxToMM } from "./globals.js";
|
|
17
|
+
import { FrameParamKeys } from "./objects/Frame.js";
|
|
18
|
+
import Big from "big.js";
|
|
19
|
+
import { Logger } from "./logger.js";
|
|
20
|
+
export var JSModuleType;
|
|
21
|
+
(function (JSModuleType) {
|
|
22
|
+
JSModuleType["CommonJs"] = "cjs";
|
|
23
|
+
JSModuleType["ESM"] = "mjs";
|
|
24
|
+
})(JSModuleType || (JSModuleType = {}));
|
|
25
|
+
export function prepareFile(textData) {
|
|
26
|
+
const chars = CharStream.fromString(textData);
|
|
27
|
+
const lexer = new MainLexer(chars);
|
|
28
|
+
const lexerTimer = new SimpleStopwatch();
|
|
29
|
+
const tokens = new CommonTokenStream(lexer);
|
|
30
|
+
tokens.fill();
|
|
31
|
+
const lexerTimeTaken = lexerTimer.lap();
|
|
32
|
+
const parser = new CircuitScriptParser(tokens);
|
|
33
|
+
return {
|
|
34
|
+
parser,
|
|
35
|
+
lexer,
|
|
36
|
+
lexerTimeTaken,
|
|
37
|
+
tokens
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export async function getSemanticTokens(scriptData, options) {
|
|
41
|
+
const { parser, lexer, tokens } = prepareFile(scriptData);
|
|
42
|
+
const tree = parser.script();
|
|
43
|
+
const visitor = new SemanticTokensVisitor(true, null, options.environment, lexer, scriptData);
|
|
44
|
+
parser.removeErrorListeners();
|
|
45
|
+
visitor.onImportFile = async (visitor, filePath, textData) => {
|
|
46
|
+
let hasError = false;
|
|
47
|
+
let hasParseError = false;
|
|
48
|
+
if (textData !== null) {
|
|
49
|
+
const { parser } = prepareFile(textData);
|
|
50
|
+
const tree = parser.script();
|
|
51
|
+
try {
|
|
52
|
+
visitor.visit(tree);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
console.log('Error while parsing: ', err);
|
|
56
|
+
hasParseError = true;
|
|
57
|
+
hasError = true;
|
|
58
|
+
throw new ParseError(`Error parsing semantic tokens in imported file: ${err}`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
console.log('File does not exist');
|
|
63
|
+
hasError = true;
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
hasError, hasParseError
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
await visitor.visitAsync(tree);
|
|
70
|
+
const semanticTokens = visitor.getTokens();
|
|
71
|
+
const parsedTokens = prepareTokens(tokens.getTokens(), lexer, scriptData);
|
|
72
|
+
const finalParsedTokens = [];
|
|
73
|
+
parsedTokens.forEach(token => {
|
|
74
|
+
const location = `${token.line}_${token.column}`;
|
|
75
|
+
if (semanticTokens.has(location)) {
|
|
76
|
+
finalParsedTokens.push(semanticTokens.get(location));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
finalParsedTokens.push(token);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
visitor,
|
|
84
|
+
parsedTokens: finalParsedTokens
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
class TokenErrorListener extends BaseErrorListener {
|
|
88
|
+
syntaxError(recognizer, offendingSymbol, line, column, msg, e) {
|
|
89
|
+
console.log(msg);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
export class ParseErrorStrategy extends DefaultErrorStrategy {
|
|
93
|
+
reportUnwantedToken(recognizer) {
|
|
94
|
+
if (this.inErrorRecoveryMode(recognizer)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
this.beginErrorCondition(recognizer);
|
|
98
|
+
const t = recognizer.getCurrentToken();
|
|
99
|
+
const tokenName = this.getTokenErrorDisplay(t);
|
|
100
|
+
const msg = "extraneous input " + tokenName;
|
|
101
|
+
recognizer.notifyErrorListeners(msg, t, null);
|
|
102
|
+
this.endErrorCondition(recognizer);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
export async function validateScript(filePath, scriptData, options) {
|
|
106
|
+
const { parser } = prepareFile(scriptData);
|
|
107
|
+
parser.removeErrorListeners();
|
|
108
|
+
parser.errorHandler = new ParseErrorStrategy();
|
|
109
|
+
parser.addErrorListener(new TokenErrorListener());
|
|
110
|
+
const tree = parser.script();
|
|
111
|
+
const visitor = new SymbolValidatorVisitor(true, null, options.environment);
|
|
112
|
+
visitor.enterFile(filePath);
|
|
113
|
+
visitor.onImportFile = async (visitor, filePath, textData) => {
|
|
114
|
+
visitor.enterFile(filePath);
|
|
115
|
+
let hasError = false;
|
|
116
|
+
let hasParseError = false;
|
|
117
|
+
if (textData !== null) {
|
|
118
|
+
const { parser } = prepareFile(textData);
|
|
119
|
+
const tree = parser.script();
|
|
120
|
+
try {
|
|
121
|
+
await visitor.visitAsync(tree);
|
|
122
|
+
visitor.exitFile();
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
console.log('got an error while parsing tree: ', err);
|
|
126
|
+
hasParseError = true;
|
|
127
|
+
hasError = true;
|
|
128
|
+
throw new ParseError(`Error parsing validation in imported file: ${err}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
console.log('file does not exist!');
|
|
133
|
+
hasError = true;
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
hasError, hasParseError
|
|
137
|
+
};
|
|
138
|
+
};
|
|
139
|
+
await visitor.visitAsync(tree);
|
|
140
|
+
const symbolTable = visitor.getSymbols();
|
|
141
|
+
symbolTable.clearUndefined();
|
|
142
|
+
const visitorResolver = new SymbolValidatorResolveVisitor(true, null, options.environment);
|
|
143
|
+
visitorResolver.enterFile(filePath);
|
|
144
|
+
visitorResolver.setSymbols(visitor.getSymbols());
|
|
145
|
+
visitorResolver.onImportFile = visitor.onImportFile;
|
|
146
|
+
await visitorResolver.visitAsync(tree);
|
|
147
|
+
return visitorResolver;
|
|
148
|
+
}
|
|
149
|
+
export async function renderScript(scriptData, outputPath, options) {
|
|
150
|
+
const { dumpNets = false, dumpData = false, showStats = false, environment } = options;
|
|
151
|
+
const errors = [];
|
|
152
|
+
const onErrorHandler = (message, context, error) => {
|
|
153
|
+
if (error && error instanceof RuntimeExecutionError) {
|
|
154
|
+
errors.push(error);
|
|
155
|
+
}
|
|
156
|
+
else if (error && error instanceof RecognitionException) {
|
|
157
|
+
errors.push(new ParseSyntaxError(message, context.start, context.stop));
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
errors.push(new ParseError(message, context.start, context.stop));
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const visitor = new ParserVisitor(true, onErrorHandler, options.environment);
|
|
164
|
+
visitor.onImportFile = async (visitor, filePath, fileData) => {
|
|
165
|
+
const { hasError, hasParseError } = await parseFileWithVisitor(visitor, fileData);
|
|
166
|
+
if (hasError || hasParseError) {
|
|
167
|
+
throw new ParseError(`Error parsing imported file: ${filePath}`, undefined, undefined, filePath);
|
|
168
|
+
}
|
|
169
|
+
return { hasError, hasParseError };
|
|
170
|
+
};
|
|
171
|
+
visitor.log('reading file');
|
|
172
|
+
visitor.log('done reading file');
|
|
173
|
+
const { tree, parser, parserTimeTaken, lexerTimeTaken } = await parseFileWithVisitor(visitor, scriptData);
|
|
174
|
+
showStats && console.log('Lexing took:', lexerTimeTaken);
|
|
175
|
+
showStats && console.log('Parsing took:', parserTimeTaken);
|
|
176
|
+
if (dumpNets) {
|
|
177
|
+
const nets = visitor.dumpNets();
|
|
178
|
+
nets.forEach(item => console.log(item.join(" | ")));
|
|
179
|
+
}
|
|
180
|
+
const dumpDirectory = environment.getRelativeToModule('/dump/');
|
|
181
|
+
if (dumpData) {
|
|
182
|
+
console.log('Dump data to:', dumpDirectory);
|
|
183
|
+
if (!existsSync(dumpDirectory)) {
|
|
184
|
+
mkdirSync(dumpDirectory);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
dumpData && writeFileSync(dumpDirectory + 'tree.lisp', tree.toStringTree(null, parser));
|
|
188
|
+
dumpData && writeFileSync(dumpDirectory + 'raw-parser.txt', visitor.logger.dump());
|
|
189
|
+
let svgOutput = "";
|
|
190
|
+
if (errors.length === 0) {
|
|
191
|
+
const { frameComponent } = visitor.applySheetFrameComponent();
|
|
192
|
+
try {
|
|
193
|
+
visitor.annotateComponents();
|
|
194
|
+
}
|
|
195
|
+
catch (err) {
|
|
196
|
+
throw new RenderError(`Error during component annotation: ${err}`, 'annotation');
|
|
197
|
+
}
|
|
198
|
+
const { sequence, nets } = visitor.getGraph();
|
|
199
|
+
const tmpSequence = generateDebugSequenceAction(sequence).map(item => sequenceActionString(item));
|
|
200
|
+
dumpData && writeFileSync(dumpDirectory + 'raw-sequence.txt', tmpSequence.join('\n'));
|
|
201
|
+
try {
|
|
202
|
+
let fileExtension = null;
|
|
203
|
+
let outputDefaultZoom = defaultZoomScale;
|
|
204
|
+
if (outputPath) {
|
|
205
|
+
fileExtension = path.extname(outputPath).substring(1);
|
|
206
|
+
if (fileExtension === "pdf") {
|
|
207
|
+
outputDefaultZoom = 1;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
if (fileExtension === 'net') {
|
|
211
|
+
const { tree: kicadNetList, missingFootprints } = generateKiCADNetList(visitor.getNetList());
|
|
212
|
+
missingFootprints.forEach(entry => {
|
|
213
|
+
console.log(`${entry.refdes} (${entry.instanceName}) does not have footprint`);
|
|
214
|
+
});
|
|
215
|
+
writeFileSync(outputPath, printTree(kicadNetList));
|
|
216
|
+
console.log('Generated file', outputPath);
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const layoutEngine = new LayoutEngine();
|
|
220
|
+
const layoutTimer = new SimpleStopwatch();
|
|
221
|
+
let sheetFrames;
|
|
222
|
+
try {
|
|
223
|
+
sheetFrames = layoutEngine.runLayout(sequence, nets);
|
|
224
|
+
}
|
|
225
|
+
catch (err) {
|
|
226
|
+
throw new RenderError(`Error during layout generation: ${err}`, 'layout');
|
|
227
|
+
}
|
|
228
|
+
layoutEngine.printWarnings();
|
|
229
|
+
showStats && console.log('Layout took:', layoutTimer.lap());
|
|
230
|
+
dumpData && writeFileSync(dumpDirectory + 'raw-layout.txt', layoutEngine.logger.dump());
|
|
231
|
+
const generateSvgTimer = new SimpleStopwatch();
|
|
232
|
+
const renderLogger = new Logger();
|
|
233
|
+
let svgCanvas;
|
|
234
|
+
try {
|
|
235
|
+
svgCanvas = renderSheetsToSVG(sheetFrames, renderLogger);
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
throw new RenderError(`Error during SVG generation: ${err}`, 'svg_generation');
|
|
239
|
+
}
|
|
240
|
+
showStats && console.log('Render took:', generateSvgTimer.lap());
|
|
241
|
+
dumpData && writeFileSync(dumpDirectory + 'raw-render.txt', renderLogger.dump());
|
|
242
|
+
try {
|
|
243
|
+
svgOutput = generateSvgOutput(svgCanvas, outputDefaultZoom);
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
throw new RenderError(`Error generating SVG output: ${err}`, 'svg_output');
|
|
247
|
+
}
|
|
248
|
+
if (outputPath) {
|
|
249
|
+
if (fileExtension === 'svg') {
|
|
250
|
+
try {
|
|
251
|
+
writeFileSync(outputPath, svgOutput);
|
|
252
|
+
}
|
|
253
|
+
catch (err) {
|
|
254
|
+
throw new RenderError(`Error writing SVG file: ${err}`, 'file_output');
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
else if (fileExtension === 'pdf') {
|
|
258
|
+
let sheetSize = "A4";
|
|
259
|
+
let sheetSizeDefined = false;
|
|
260
|
+
if (frameComponent) {
|
|
261
|
+
sheetSize = frameComponent.getParam(FrameParamKeys.PaperSize);
|
|
262
|
+
sheetSizeDefined = true;
|
|
263
|
+
}
|
|
264
|
+
try {
|
|
265
|
+
const doc = new PDFDocument({
|
|
266
|
+
layout: 'landscape',
|
|
267
|
+
size: sheetSize
|
|
268
|
+
});
|
|
269
|
+
const outputStream = createWriteStream(outputPath);
|
|
270
|
+
generatePdfOutput(doc, svgCanvas, sheetSize, sheetSizeDefined, outputDefaultZoom);
|
|
271
|
+
doc.pipe(outputStream);
|
|
272
|
+
doc.end();
|
|
273
|
+
}
|
|
274
|
+
catch (err) {
|
|
275
|
+
throw new RenderError(`Error generating PDF file: ${err}`, 'pdf_output');
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
throw new RenderError(`Invalid output format: ${fileExtension}`, 'file_output');
|
|
280
|
+
}
|
|
281
|
+
console.log('Generated file', outputPath);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
catch (err) {
|
|
285
|
+
throw new RenderError(`Error during rendering: ${err}`, 'output_generation');
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
svgOutput,
|
|
290
|
+
errors
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
export function detectJSModuleType() {
|
|
294
|
+
if (typeof __filename === 'undefined' &&
|
|
295
|
+
typeof __dirname === 'undefined') {
|
|
296
|
+
return JSModuleType.ESM;
|
|
297
|
+
}
|
|
298
|
+
else {
|
|
299
|
+
return JSModuleType.CommonJs;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
export class UnitDimension {
|
|
303
|
+
type;
|
|
304
|
+
value;
|
|
305
|
+
constructor(value, type = LengthUnit.mils) {
|
|
306
|
+
this.value = value;
|
|
307
|
+
this.type = type;
|
|
308
|
+
}
|
|
309
|
+
getMM() {
|
|
310
|
+
switch (this.type) {
|
|
311
|
+
case LengthUnit.mm:
|
|
312
|
+
return this.value;
|
|
313
|
+
case LengthUnit.mils:
|
|
314
|
+
return this.value * MilsToMM;
|
|
315
|
+
case LengthUnit.px:
|
|
316
|
+
return this.value * PxToMM;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
static mm(value) {
|
|
320
|
+
return new UnitDimension(value, LengthUnit.mm);
|
|
321
|
+
}
|
|
322
|
+
static mils(value) {
|
|
323
|
+
return new UnitDimension(value, LengthUnit.mils);
|
|
324
|
+
}
|
|
325
|
+
static px(value) {
|
|
326
|
+
return new UnitDimension(value, LengthUnit.px);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
export function milsToMM(value) {
|
|
330
|
+
if (typeof value === 'number') {
|
|
331
|
+
value = resolveToNumericValue(new Big(value));
|
|
332
|
+
}
|
|
333
|
+
return resolveToNumericValue(value.toBigNumber().mul(new Big(MilsToMM)).round(6));
|
|
334
|
+
}
|
|
335
|
+
export function pxToMM(value) {
|
|
336
|
+
return value * PxToMM;
|
|
337
|
+
}
|
|
338
|
+
const PaperSizes = {
|
|
339
|
+
'A0': [1189, 841],
|
|
340
|
+
'A1': [841, 594],
|
|
341
|
+
'A2': [594, 420],
|
|
342
|
+
'A3': [420, 297],
|
|
343
|
+
'A4': [297, 210],
|
|
344
|
+
'A5': [210, 148],
|
|
345
|
+
'A6': [148, 105],
|
|
346
|
+
};
|
|
347
|
+
export const PaperGridReferences = {
|
|
348
|
+
'A0': [16, 24],
|
|
349
|
+
'A1': [12, 16],
|
|
350
|
+
'A2': [8, 12],
|
|
351
|
+
'A3': [6, 8],
|
|
352
|
+
'A4': [4, 6],
|
|
353
|
+
};
|
|
354
|
+
export function isSupportedPaperSize(type) {
|
|
355
|
+
if (PaperSizes[type]) {
|
|
356
|
+
return true;
|
|
357
|
+
}
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
export function getPaperSize(type, margin = defaultPageMarginMM) {
|
|
361
|
+
if (PaperSizes[type]) {
|
|
362
|
+
const [width, height] = PaperSizes[type];
|
|
363
|
+
const useWidth = width - margin * 2;
|
|
364
|
+
const useHeight = height - margin * 2;
|
|
365
|
+
return {
|
|
366
|
+
width: Math.floor(useWidth * (1 / MilsToMM)),
|
|
367
|
+
height: Math.floor(useHeight * (1 / MilsToMM)),
|
|
368
|
+
widthMM: useWidth,
|
|
369
|
+
heightMM: useHeight,
|
|
370
|
+
originalWidthMM: width,
|
|
371
|
+
originalHeightMM: height,
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
return getPaperSize('A4');
|
|
376
|
+
}
|
|
377
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export * from './draw_symbols.js';
|
|
2
|
+
export * from './execute.js';
|
|
3
|
+
export * from './export.js';
|
|
4
|
+
export * from './geometry.js';
|
|
5
|
+
export * from './globals.js';
|
|
6
|
+
export * from './helpers.js';
|
|
7
|
+
export * from './layout.js';
|
|
8
|
+
export * from './lexer.js';
|
|
9
|
+
export * from './logger.js';
|
|
10
|
+
export * from './parser.js';
|
|
11
|
+
export * from './render.js';
|
|
12
|
+
export * from './utils.js';
|
|
13
|
+
export * from './visitor.js';
|
|
14
|
+
export * from './sizing.js';
|
|
15
|
+
export * from './objects/types.js';
|
|
16
|
+
export * from './builtinMethods.js';
|
|
17
|
+
export * from './validate/SymbolTable.js';
|
|
18
|
+
export * from './validate/SymbolValidatorResolveVisitor.js';
|
|
19
|
+
export * from './validate/SymbolValidatorVisitor.js';
|
|
20
|
+
export * from './environment.js';
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
1
|
+
import pkg from '@dagrejs/graphlib';
|
|
2
|
+
const { Graph, alg } = pkg;
|
|
3
|
+
import { SymbolCustom, SymbolDrawing, SymbolCustomModule, SymbolPlaceholder, SymbolText, PlaceHolderCommands } from "./draw_symbols.js";
|
|
4
|
+
import { FrameAction, SequenceAction } from "./objects/ExecutionScope.js";
|
|
5
|
+
import { ComponentTypes, defaultFrameTitleTextSize, defaultGridSizeUnits, FrameType, ParamKeys, SymbolPinSide, WireAutoDirection } from './globals.js';
|
|
6
|
+
import { Geometry, HorizontalAlign, VerticalAlign } from './geometry.js';
|
|
7
|
+
import { Logger } from './logger.js';
|
|
8
|
+
import { FixedFrameIds, Frame, FrameParamKeys, FramePlotDirection } from './objects/Frame.js';
|
|
9
|
+
import { areasOverlap, combineMaps, getBoundsSize, printBounds, resizeBounds, resizeToNearestGrid, roundValue, toNearestGrid } from './utils.js';
|
|
10
|
+
import { Direction } from './objects/types.js';
|
|
11
|
+
import { milsToMM, UnitDimension } from './helpers.js';
|
|
12
|
+
import { numeric, NumericValue } from './objects/ParamDefinition.js';
|
|
12
13
|
export class LayoutEngine {
|
|
13
14
|
logger;
|
|
14
15
|
layoutWarnings = [];
|
|
@@ -109,6 +110,7 @@ export class LayoutEngine {
|
|
|
109
110
|
findJunctions(wireGroups) {
|
|
110
111
|
const junctions = [];
|
|
111
112
|
const mergedWires = [];
|
|
113
|
+
const debugSegments = false;
|
|
112
114
|
for (const [key, wires] of wireGroups) {
|
|
113
115
|
const allLines = wires.map(wire => {
|
|
114
116
|
return wire.points.map(pt => {
|
|
@@ -118,15 +120,35 @@ export class LayoutEngine {
|
|
|
118
120
|
};
|
|
119
121
|
});
|
|
120
122
|
});
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
123
|
+
if (debugSegments) {
|
|
124
|
+
const tmpSegments = [];
|
|
125
|
+
allLines.forEach(wire => {
|
|
126
|
+
for (let i = 1; i < wire.length; i++) {
|
|
127
|
+
const pt1 = wire[i - 1];
|
|
128
|
+
const pt2 = wire[i];
|
|
129
|
+
tmpSegments.push([
|
|
130
|
+
[pt1.x.toNumber(), pt1.y.toNumber()],
|
|
131
|
+
[pt2.x.toNumber(), pt2.y.toNumber()],
|
|
132
|
+
]);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
mergedWires.push({
|
|
136
|
+
netName: key,
|
|
137
|
+
segments: tmpSegments,
|
|
138
|
+
intersectPoints: [],
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
const { intersectPoints, segments } = Geometry.mergeWires(allLines);
|
|
143
|
+
mergedWires.push({
|
|
144
|
+
netName: key,
|
|
145
|
+
segments,
|
|
146
|
+
intersectPoints,
|
|
147
|
+
});
|
|
148
|
+
intersectPoints.forEach(([x, y]) => {
|
|
149
|
+
junctions.push(new RenderJunction(numeric(x), numeric(y)));
|
|
150
|
+
});
|
|
151
|
+
}
|
|
130
152
|
}
|
|
131
153
|
return {
|
|
132
154
|
junctions,
|
|
@@ -346,7 +368,7 @@ export class LayoutEngine {
|
|
|
346
368
|
const frameArea = [tmpX1, tmpY1, tmpX2, tmpY2];
|
|
347
369
|
const overlaps = avoidAreas.filter(area => areasOverlap(frameArea, area));
|
|
348
370
|
const doesOverlapAreasToAvoid = overlaps.length > 0;
|
|
349
|
-
if (doesExceedFrameHeight || doesOverlapAreasToAvoid) {
|
|
371
|
+
if (boundPoints.length > 0 && (doesExceedFrameHeight || doesOverlapAreasToAvoid)) {
|
|
350
372
|
innerFrameY = offsetY;
|
|
351
373
|
const nextX = numeric(xmax).sub(offsetX).add(frame.gap);
|
|
352
374
|
innerFrameX = offsetX.add(nextX);
|
|
@@ -376,7 +398,7 @@ export class LayoutEngine {
|
|
|
376
398
|
const frameArea = [tmpX1, tmpY1, tmpX2, tmpY2];
|
|
377
399
|
const overlaps = avoidAreas.filter(area => areasOverlap(frameArea, area));
|
|
378
400
|
const doesOverlapAreasToAvoid = overlaps.length > 0;
|
|
379
|
-
if (doesExceedFrameWidth || doesOverlapAreasToAvoid) {
|
|
401
|
+
if (boundPoints.length > 0 && (doesExceedFrameWidth || doesOverlapAreasToAvoid)) {
|
|
380
402
|
innerFrameX = offsetX.add(centeredOffsetX);
|
|
381
403
|
const { ymax } = getBoundsFromPoints(boundPoints);
|
|
382
404
|
const nextY = numeric(ymax).sub(offsetY).add(frame.gap);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CommonToken } from "antlr4ng";
|
|
2
|
-
import { CircuitScriptParser } from "./antlr/CircuitScriptParser.
|
|
3
|
-
import { CircuitScriptLexer } from "./antlr/CircuitScriptLexer.
|
|
2
|
+
import { CircuitScriptParser } from "./antlr/CircuitScriptParser.js";
|
|
3
|
+
import { CircuitScriptLexer } from "./antlr/CircuitScriptLexer.js";
|
|
4
4
|
export class MainLexer extends CircuitScriptLexer {
|
|
5
5
|
tokens;
|
|
6
6
|
indents;
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
2
|
import { program } from 'commander';
|
|
3
3
|
import figlet from 'figlet';
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import { getDefaultLibsPath, getFontsPath, getPackageVersion, renderScript } from './helpers.mjs';
|
|
4
|
+
import { watch } from 'fs';
|
|
5
|
+
import { renderScript } from './helpers.js';
|
|
6
|
+
import { NodeScriptEnvironment } from "./environment.js";
|
|
8
7
|
export default async function main() {
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
const version = getPackageVersion();
|
|
8
|
+
const env = new NodeScriptEnvironment();
|
|
9
|
+
NodeScriptEnvironment.setInstance(env);
|
|
10
|
+
const version = env.getPackageVersion();
|
|
12
11
|
program
|
|
13
12
|
.description('generate graphical output from circuitscript files')
|
|
14
13
|
.version(version)
|
|
@@ -19,7 +18,8 @@ export default async function main() {
|
|
|
19
18
|
.option('-w, --watch', 'Watch for file changes')
|
|
20
19
|
.option('-n, --dump-nets', 'Dump out net information')
|
|
21
20
|
.option('-d, --dump-data', 'Dump data during parsing')
|
|
22
|
-
.option('-s, --stats', 'Show stats during generation')
|
|
21
|
+
.option('-s, --stats', 'Show stats during generation')
|
|
22
|
+
.option('-x, --skip-output', 'Skip output generation');
|
|
23
23
|
program.addHelpText('before', figlet.textSync('circuitscript', {
|
|
24
24
|
font: 'Small Slant'
|
|
25
25
|
}));
|
|
@@ -32,11 +32,13 @@ export default async function main() {
|
|
|
32
32
|
const watchFileChanges = options.watch;
|
|
33
33
|
const dumpNets = options.dumpNets;
|
|
34
34
|
const dumpData = options.dumpData;
|
|
35
|
-
|
|
35
|
+
if (options.currentDirectory) {
|
|
36
|
+
throw "Parameter not supported yet";
|
|
37
|
+
}
|
|
36
38
|
if (watchFileChanges) {
|
|
37
39
|
console.log('watching for file changes...');
|
|
38
40
|
}
|
|
39
|
-
await prepareSVGEnvironment(
|
|
41
|
+
await env.prepareSVGEnvironment();
|
|
40
42
|
let inputFilePath = "";
|
|
41
43
|
if (args.length > 2) {
|
|
42
44
|
console.log("Error: Extra arguments passed");
|
|
@@ -45,11 +47,8 @@ export default async function main() {
|
|
|
45
47
|
let scriptData;
|
|
46
48
|
if (args.length > 0 && args[0]) {
|
|
47
49
|
inputFilePath = args[0];
|
|
48
|
-
if (
|
|
49
|
-
scriptData =
|
|
50
|
-
if (currentDirectory === null) {
|
|
51
|
-
currentDirectory = path.dirname(inputFilePath);
|
|
52
|
-
}
|
|
50
|
+
if ((await env.exists(inputFilePath))) {
|
|
51
|
+
scriptData = await env.readFile(inputFilePath, { encoding: 'utf-8' });
|
|
53
52
|
}
|
|
54
53
|
else {
|
|
55
54
|
console.error("Error: File could not be found");
|
|
@@ -64,28 +63,42 @@ export default async function main() {
|
|
|
64
63
|
return;
|
|
65
64
|
}
|
|
66
65
|
const scriptOptions = {
|
|
67
|
-
currentDirectory,
|
|
68
|
-
defaultLibsPath,
|
|
69
66
|
dumpNets,
|
|
70
67
|
dumpData,
|
|
71
68
|
showStats: options.stats,
|
|
69
|
+
environment: env,
|
|
72
70
|
};
|
|
73
71
|
let outputPath = null;
|
|
74
72
|
if (args.length > 0 && args[1]) {
|
|
75
73
|
outputPath = args[1];
|
|
76
74
|
}
|
|
77
|
-
const output =
|
|
78
|
-
if (outputPath === null && output) {
|
|
75
|
+
const output = await parseFile(scriptData, outputPath, scriptOptions);
|
|
76
|
+
if (outputPath === null && output && (options.skipOutput === undefined)) {
|
|
79
77
|
console.log(output);
|
|
80
78
|
}
|
|
81
79
|
if (watchFileChanges) {
|
|
82
|
-
watch(inputFilePath, event => {
|
|
80
|
+
watch(inputFilePath, async (event) => {
|
|
83
81
|
if (event === 'change') {
|
|
84
|
-
const scriptData =
|
|
85
|
-
|
|
86
|
-
console.log('done');
|
|
82
|
+
const scriptData = await env.readFile(inputFilePath, { encoding: 'utf-8' });
|
|
83
|
+
parseFile(scriptData, outputPath, scriptOptions);
|
|
87
84
|
}
|
|
88
85
|
});
|
|
89
86
|
}
|
|
90
87
|
}
|
|
88
|
+
async function parseFile(scriptData, outputPath, scriptOptions) {
|
|
89
|
+
try {
|
|
90
|
+
const { svgOutput: output, errors } = await renderScript(scriptData, outputPath, scriptOptions);
|
|
91
|
+
errors.forEach((err, index) => {
|
|
92
|
+
console.log(`[${index}] ${err}`);
|
|
93
|
+
});
|
|
94
|
+
if (errors.length > 0) {
|
|
95
|
+
console.log('Render failed due to syntax or parsing errors');
|
|
96
|
+
}
|
|
97
|
+
return output;
|
|
98
|
+
}
|
|
99
|
+
catch (error) {
|
|
100
|
+
console.error(`Unexpected Error: ${error}`);
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
91
104
|
main();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { SymbolDrawingCommands } from '../draw_symbols.
|
|
2
|
-
import { PinDefinition, PinIdType } from './PinDefinition.
|
|
3
|
-
import { PinTypes } from './PinTypes.
|
|
4
|
-
import { ParamKeys } from '../globals.
|
|
1
|
+
import { SymbolDrawingCommands } from '../draw_symbols.js';
|
|
2
|
+
import { PinDefinition, PinIdType } from './PinDefinition.js';
|
|
3
|
+
import { PinTypes } from './PinTypes.js';
|
|
4
|
+
import { ParamKeys } from '../globals.js';
|
|
5
5
|
export class ClassComponent {
|
|
6
6
|
instanceName;
|
|
7
7
|
numPins;
|
|
@@ -9,11 +9,12 @@ export class ClassComponent {
|
|
|
9
9
|
pins = new Map();
|
|
10
10
|
pinNets = new Map();
|
|
11
11
|
pinWires = new Map();
|
|
12
|
-
pinsMaxPositions =
|
|
12
|
+
pinsMaxPositions = new Map();
|
|
13
13
|
_cachedPins;
|
|
14
14
|
_cachedParams;
|
|
15
15
|
_copyID = null;
|
|
16
16
|
_copyFrom = null;
|
|
17
|
+
_pointLinkComponent;
|
|
17
18
|
arrangeProps = null;
|
|
18
19
|
displayProp = null;
|
|
19
20
|
widthProp = null;
|
|
@@ -145,6 +146,9 @@ export class ClassComponent {
|
|
|
145
146
|
for (const [key, value] of this.pins) {
|
|
146
147
|
component.pins.set(key, value);
|
|
147
148
|
}
|
|
149
|
+
for (const [key, value] of this.pinsMaxPositions) {
|
|
150
|
+
component.pinsMaxPositions.set(key, value);
|
|
151
|
+
}
|
|
148
152
|
component.refreshCache();
|
|
149
153
|
return component;
|
|
150
154
|
}
|