nodalis-compiler 1.0.17 → 1.0.19
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/CHANGELOG.md +3 -0
- package/package.json +1 -1
- package/src/compilers/iec-parser/parser.js +110 -7
- package/src/nodalis.js +24 -22
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.0.19] 2026-03-03
|
|
4
|
+
- Changed IEC parser to interpret Function Blocks that are actually standard functions to a formal function call.
|
|
5
|
+
|
|
3
6
|
## [1.0.17] 2026-02-25
|
|
4
7
|
- Added support for compilation of multiple ST files as a single project.
|
|
5
8
|
- Added support for formal parameters.
|
package/package.json
CHANGED
|
@@ -1845,6 +1845,35 @@ export class Rung extends Serializable {
|
|
|
1845
1845
|
return this.Objects.find((v) => v.ID == id);
|
|
1846
1846
|
}
|
|
1847
1847
|
|
|
1848
|
+
/**
|
|
1849
|
+
* Finds the object with the referenced output point ID.
|
|
1850
|
+
* @param {string} refID The ID of the output point to use in searching for the object.
|
|
1851
|
+
* @returns {FbdObject|LdObject} Returns the object with the output, or null if there is no object with that ID.
|
|
1852
|
+
*/
|
|
1853
|
+
findObjectWithOutput(refID) {
|
|
1854
|
+
return this.Objects.find(
|
|
1855
|
+
/**
|
|
1856
|
+
*
|
|
1857
|
+
* @param {FbdObject|LdObject|CommonObject} o
|
|
1858
|
+
*/
|
|
1859
|
+
(o) => {
|
|
1860
|
+
if (o.Type === "Block") {
|
|
1861
|
+
const v = o.OutputVariables.Variables.find(
|
|
1862
|
+
/**
|
|
1863
|
+
*
|
|
1864
|
+
* @param {OutputVariable} ov
|
|
1865
|
+
*/
|
|
1866
|
+
(ov) => {
|
|
1867
|
+
return ov.OutputPoint.ID === refID;
|
|
1868
|
+
});
|
|
1869
|
+
return typeof ov !== "undefined";
|
|
1870
|
+
}
|
|
1871
|
+
else if (o.Type !== "Comment") {
|
|
1872
|
+
return typeof o.Outputs.find(op => op.ID === refID) !== "undefined";
|
|
1873
|
+
}
|
|
1874
|
+
});
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1848
1877
|
/**
|
|
1849
1878
|
*
|
|
1850
1879
|
* @param {LdObject | FbdObject} obj The ladder logic object from which to find connections.
|
|
@@ -2084,19 +2113,65 @@ export class Rung extends Serializable {
|
|
|
2084
2113
|
if(expression.length > 0){
|
|
2085
2114
|
expression += " OR ";
|
|
2086
2115
|
}
|
|
2087
|
-
if(con instanceof FbdObject){
|
|
2088
|
-
|
|
2089
|
-
if(
|
|
2090
|
-
|
|
2116
|
+
if (con instanceof FbdObject) {
|
|
2117
|
+
const sb = FbdObject.getStandardBlock(con.TypeName);
|
|
2118
|
+
if (sb && sb.Style === "F") { //this is a function, not a function block.
|
|
2119
|
+
let fcall = con.TypeName + "(";
|
|
2120
|
+
forEachElem(con.InputVariables.Variables,
|
|
2121
|
+
/**
|
|
2122
|
+
*
|
|
2123
|
+
* @param {InputVariable} v
|
|
2124
|
+
*/
|
|
2125
|
+
(v) => {
|
|
2126
|
+
if (v.InputPoint.Connections.length > 0) {
|
|
2127
|
+
let assign = "";
|
|
2128
|
+
forEachElem(v.InputPoint.Connections,
|
|
2129
|
+
/**
|
|
2130
|
+
*
|
|
2131
|
+
* @param {Connection} c
|
|
2132
|
+
*/
|
|
2133
|
+
(c) => {
|
|
2134
|
+
const o = this.findObjectWithOutput(c.RefID);
|
|
2135
|
+
if (o) {
|
|
2136
|
+
if (assign.length > 0) {
|
|
2137
|
+
assign += " OR ";
|
|
2138
|
+
}
|
|
2139
|
+
assign += this.#buildExpression(o);
|
|
2140
|
+
}
|
|
2141
|
+
}
|
|
2142
|
+
);
|
|
2143
|
+
if (v.Negated === "true") {
|
|
2144
|
+
assign = "NOT " + assign;
|
|
2145
|
+
}
|
|
2146
|
+
if (!fcall.endsWith("(")) {
|
|
2147
|
+
fcall += ", ";
|
|
2148
|
+
}
|
|
2149
|
+
fcall += `${v.ParameterName} := ${assign}`;
|
|
2150
|
+
}
|
|
2151
|
+
});
|
|
2152
|
+
expression += `${fcall})`;
|
|
2091
2153
|
}
|
|
2154
|
+
else {
|
|
2155
|
+
var v = con.OutputVariables.Variables.find(iv => start.hasInput(iv.OutputPoint.ID));
|
|
2156
|
+
if (isValid(v)) {
|
|
2157
|
+
expression += con.toST(v.ParameterName);
|
|
2158
|
+
}
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2092
2161
|
}
|
|
2093
2162
|
else if(con.Type !== "LeftPowerRail"){
|
|
2094
2163
|
expression += `(${this.#buildExpression(con)})`;
|
|
2095
2164
|
}
|
|
2096
2165
|
}
|
|
2097
2166
|
);
|
|
2098
|
-
if(start.Type !== "Coil"){
|
|
2099
|
-
|
|
2167
|
+
if (start.Type !== "Coil") {
|
|
2168
|
+
if (start.Type === "DataSink") {
|
|
2169
|
+
expression = start.toST("", expression);
|
|
2170
|
+
}
|
|
2171
|
+
else {
|
|
2172
|
+
|
|
2173
|
+
expression = `${start.toST()}${expression.length > 0 ? " AND (" + expression + ")" : ""}`;
|
|
2174
|
+
}
|
|
2100
2175
|
}
|
|
2101
2176
|
return expression;
|
|
2102
2177
|
}
|
|
@@ -2124,6 +2199,34 @@ export class Rung extends Serializable {
|
|
|
2124
2199
|
(block) => {
|
|
2125
2200
|
if(done.includes(block.ID)) return;
|
|
2126
2201
|
done.push(block.ID);
|
|
2202
|
+
const sb = FbdObject.getStandardBlock(block.TypeName);
|
|
2203
|
+
if (typeof sb !== "undefined" && sb.Style === "F") {
|
|
2204
|
+
//if this is a function and connects with standard ladder logic, then we wait and deal with this in the next step.
|
|
2205
|
+
//If it doesn't connect with the rest of the rung, then we need to deal with it here.
|
|
2206
|
+
if (this.findConnections(block, true).find(o => o.Type === "Contact" || o.Type === "CompareContact" || o.Type === "Coil" || o.Type === "RightPowerRail")) {
|
|
2207
|
+
return;
|
|
2208
|
+
}
|
|
2209
|
+
else {
|
|
2210
|
+
forEachElem(block.OutputVariables.Variables,
|
|
2211
|
+
/**
|
|
2212
|
+
*
|
|
2213
|
+
* @param {OutputVariable} outvar
|
|
2214
|
+
*/
|
|
2215
|
+
(outvar) => {
|
|
2216
|
+
|
|
2217
|
+
|
|
2218
|
+
var inobj = this.Objects.find(o => o.hasInput(outvar.OutputPoint.ID));
|
|
2219
|
+
if (isValid(inobj)) {
|
|
2220
|
+
if (inobj.Type === "DataSink") {
|
|
2221
|
+
st += this.#buildExpression(inobj) + ";\n";
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
}
|
|
2226
|
+
);
|
|
2227
|
+
return;
|
|
2228
|
+
}
|
|
2229
|
+
}
|
|
2127
2230
|
forEachElem(block.InputVariables.Variables,
|
|
2128
2231
|
/**
|
|
2129
2232
|
*
|
|
@@ -2898,7 +3001,7 @@ export class Connection extends Serializable{
|
|
|
2898
3001
|
export class FbdObject extends Serializable {
|
|
2899
3002
|
|
|
2900
3003
|
/**
|
|
2901
|
-
* @type {{TypeName: string, InputVariables: string[], OutputVariables: string[]}[]}
|
|
3004
|
+
* @type {{TypeName: string, InputVariables: string[], OutputVariables: string[], Style: string}[]}
|
|
2902
3005
|
*/
|
|
2903
3006
|
static StandardBlocks = [
|
|
2904
3007
|
{
|
package/src/nodalis.js
CHANGED
|
@@ -128,11 +128,7 @@ export class Nodalis {
|
|
|
128
128
|
outputPath,
|
|
129
129
|
resourceName,
|
|
130
130
|
sourcePath,
|
|
131
|
-
language
|
|
132
|
-
codesysCommand,
|
|
133
|
-
codesysCommandTemplate,
|
|
134
|
-
codesysProjectFile,
|
|
135
|
-
codesysPouName
|
|
131
|
+
language
|
|
136
132
|
}) {
|
|
137
133
|
validateFileExtension(language, sourcePath, resourceName);
|
|
138
134
|
|
|
@@ -147,11 +143,7 @@ export class Nodalis {
|
|
|
147
143
|
resourceName,
|
|
148
144
|
target,
|
|
149
145
|
outputType,
|
|
150
|
-
language
|
|
151
|
-
codesysCommand,
|
|
152
|
-
codesysCommandTemplate,
|
|
153
|
-
codesysProjectFile,
|
|
154
|
-
codesysPouName
|
|
146
|
+
language
|
|
155
147
|
};
|
|
156
148
|
|
|
157
149
|
await compiler.compile();
|
|
@@ -182,8 +174,18 @@ export class Nodalis {
|
|
|
182
174
|
|
|
183
175
|
}
|
|
184
176
|
|
|
185
|
-
|
|
186
|
-
|
|
177
|
+
function isCliEntryPoint() {
|
|
178
|
+
try {
|
|
179
|
+
if (!process.argv[1]) return false;
|
|
180
|
+
const invokedPath = fs.realpathSync(process.argv[1]);
|
|
181
|
+
const modulePath = fs.realpathSync(fileURLToPath(import.meta.url));
|
|
182
|
+
return invokedPath === modulePath;
|
|
183
|
+
} catch {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (isCliEntryPoint()) {
|
|
187
189
|
|
|
188
190
|
if (process.argv.includes('--help') || process.argv.includes('-h')) {
|
|
189
191
|
console.log(`
|
|
@@ -193,6 +195,9 @@ Usage:
|
|
|
193
195
|
Actions:
|
|
194
196
|
--action list-compilers
|
|
195
197
|
Lists all available compilers and their supported targets, languages, protocols, and versions.
|
|
198
|
+
|
|
199
|
+
--action list-programmers
|
|
200
|
+
Lists all available programmers and their supported targets.
|
|
196
201
|
|
|
197
202
|
--action compile
|
|
198
203
|
Required options:
|
|
@@ -202,10 +207,6 @@ Actions:
|
|
|
202
207
|
--resourceName Resource name (used for .iec projects)
|
|
203
208
|
--sourcePath Path to source file (.st or .iec)
|
|
204
209
|
--language st (Structured Text) or ld (Ladder Diagram)
|
|
205
|
-
--codesysCommand Optional CODESYS executable/command for --target codesys
|
|
206
|
-
--codesysCommandTemplate Optional shell template for --target codesys executable builds
|
|
207
|
-
--codesysProjectFile Optional .project path for CODESYS automation (defaults to <output>/<resource>.project)
|
|
208
|
-
--codesysPouName Optional POU name to create/update in CODESYS project
|
|
209
210
|
|
|
210
211
|
--action deploy Programs a device based on a protocol.
|
|
211
212
|
--target The device/protocol targeted for programming.
|
|
@@ -251,6 +252,11 @@ Examples:
|
|
|
251
252
|
console.log(JSON.stringify(list, null, 2));
|
|
252
253
|
break;
|
|
253
254
|
}
|
|
255
|
+
case 'list-programmers': {
|
|
256
|
+
const list = app.listProgrammers();
|
|
257
|
+
console.log(JSON.stringify(list, null, 2));
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
254
260
|
|
|
255
261
|
case 'compile': {
|
|
256
262
|
app.compile({
|
|
@@ -259,11 +265,7 @@ Examples:
|
|
|
259
265
|
outputPath: argMap.outputPath,
|
|
260
266
|
resourceName: argMap.resourceName,
|
|
261
267
|
sourcePath: argMap.sourcePath,
|
|
262
|
-
language: argMap.language
|
|
263
|
-
codesysCommand: argMap.codesysCommand,
|
|
264
|
-
codesysCommandTemplate: argMap.codesysCommandTemplate,
|
|
265
|
-
codesysProjectFile: argMap.codesysProjectFile,
|
|
266
|
-
codesysPouName: argMap.codesysPouName
|
|
268
|
+
language: argMap.language
|
|
267
269
|
}).then(() => {
|
|
268
270
|
console.log('Compilation completed.');
|
|
269
271
|
}).catch(err => {
|
|
@@ -296,7 +298,7 @@ Examples:
|
|
|
296
298
|
|
|
297
299
|
default: {
|
|
298
300
|
console.error(`Unknown or missing action: ${argMap.action}`);
|
|
299
|
-
console.error(`Valid actions: list-compilers, compile, deploy`);
|
|
301
|
+
console.error(`Valid actions: list-compilers, list-programmers, compile, deploy`);
|
|
300
302
|
break;
|
|
301
303
|
}
|
|
302
304
|
}
|