diff --git a/language/README.md b/language/README.md index 23e4302..fec07b1 100644 --- a/language/README.md +++ b/language/README.md @@ -23,6 +23,7 @@ vsce package ``` ### 1.4 Publish CLI + NOTE: Previous versions have been published under the name `bcs-engineering-dsl` on my personal npm account. To avoid confusion, you might want to publish under a different name. ```bash @@ -75,3 +76,14 @@ In addition to the standard libraries provided by Beckhoff, the following librar - `Tc3_DALI`: Please note that this library integration is not fully tested. ## 4 Future Work +- Add support for more target platforms (e.g., Siemens, Codesys) +- Add and test support for more bus systems (e.g., EtherCAT, Profinet) +- Add a more sophisticated module system (e.g., support multiple files, packages, imports, etc.) +- Support structs of structs +- Support not only statefull FBs, but also stateless functions +- Support FB properties (besides inputs, outputs, locals, and logic) +- Support better scoping e.g. true block scoping for variables +- Support UseStmt within FB logic +- Look into debugging DSLs +- Look into moving the framework to a web-based solution (both the DSL and the deployment tool) +- Look into graphical modeling \ No newline at end of file diff --git a/language/bcs-engineering-dsl-0.0.24.vsix b/language/bcs-engineering-dsl-0.0.25.vsix similarity index 88% rename from language/bcs-engineering-dsl-0.0.24.vsix rename to language/bcs-engineering-dsl-0.0.25.vsix index 337145e..75bde8d 100644 Binary files a/language/bcs-engineering-dsl-0.0.24.vsix and b/language/bcs-engineering-dsl-0.0.25.vsix differ diff --git a/language/example/etherCAT/control.bcsctrl b/language/example/etherCAT/control.bcsctrl index eb12853..da75534 100644 --- a/language/example/etherCAT/control.bcsctrl +++ b/language/example/etherCAT/control.bcsctrl @@ -118,13 +118,13 @@ control EtherCATController { } unit AdjustLightLevelByMode { switch (mode){ - case OperatingMode.COMFORT: { + case OperatingMode.COMFORT { lightLevel = 100; } - case OperatingMode.ECO: { + case OperatingMode.ECO { lightLevel = 50; } - default: { + default { lightLevel = 0; } } diff --git a/language/example/exhaustive/exhaustive_control.bcsctrl b/language/example/exhaustive/exhaustive_control.bcsctrl index 279985f..fada58b 100644 --- a/language/example/exhaustive/exhaustive_control.bcsctrl +++ b/language/example/exhaustive/exhaustive_control.bcsctrl @@ -87,7 +87,7 @@ control ExhaustiveController { var extractedBool: BOOL = arr1[2]; var extractedInt: INT = arr2[3]; var extractedReal: REAL = arr3[4]; - var extractedBoolArray: BOOL[5] = arr4[2]; + var extractedBoolArray: BOOL[5] = arr4[2]; // Note: not supported in generator var extractedBoolArrayElement: BOOL = arr4[2][3]; var extractedMode: Mode = arr5[1]; @@ -100,8 +100,8 @@ control ExhaustiveController { arr2[0] = arr2[1] + arr2[2] - arr2[3] * arr2[4] / 2; arr3[0] = arr3[1] + arr3[2] - arr3[3] * arr3[4] / 2.0; arr4[0][0] = arr4[1][1] && arr4[2][2] || arr4[3][3] && arr4[4][4]; - arr4[1] = [true, false, true, false, true]; - arr4[1] = arr1; + arr4[1] = [true, false, true, false, true]; // Note: not supported in generator + arr4[1] = arr1; // Note: not supported in generator } struct Rectangle { @@ -149,7 +149,7 @@ control ExhaustiveController { // 6. Separate struct initialization after declaration var p: Point; - p = { x: 1.0, y: 2.0 }; + p = { x: 1.0, y: 2.0 }; // Note: not supported in generator // 7. Array element accessed and modified var tempX: REAL; @@ -160,7 +160,7 @@ control ExhaustiveController { // 8. Valid reassignment of structs var c1: Circle = { radius: 5.0 }; var c2: Circle; - c2 = { radius: 10.0 }; + c2 = { radius: 10.0 }; // Note: not supported in generator var newRadius: REAL = c2.radius; } diff --git a/language/package.json b/language/package.json index 822d4b2..0447446 100644 --- a/language/package.json +++ b/language/package.json @@ -1,5 +1,5 @@ { - "version": "0.0.24", + "version": "0.0.25", "name": "bcs-engineering-dsl", "displayName": "BCS Engineering DSL", "icon": "icon.png", diff --git a/language/railroad/svg/bcs-control/CaseOption.svg b/language/railroad/svg/bcs-control/CaseOption.svg index ccb0907..e09a5c8 100644 --- a/language/railroad/svg/bcs-control/CaseOption.svg +++ b/language/railroad/svg/bcs-control/CaseOption.svg @@ -1,4 +1,4 @@ - + diff --git a/language/railroad/svg/bcs-control/DefaultOption.svg b/language/railroad/svg/bcs-control/DefaultOption.svg index 5a08268..f92752e 100644 --- a/language/railroad/svg/bcs-control/DefaultOption.svg +++ b/language/railroad/svg/bcs-control/DefaultOption.svg @@ -1,4 +1,4 @@ - + diff --git a/language/src/language/bcs-control.langium b/language/src/language/bcs-control.langium index 52691d9..d90ca56 100644 --- a/language/src/language/bcs-control.langium +++ b/language/src/language/bcs-control.langium @@ -200,11 +200,11 @@ SwitchStmt: ; CaseOption: - 'case' (literals+=CaseLiteral (',' literals+=CaseLiteral)*) ':' Block + 'case' (literals+=CaseLiteral (',' literals+=CaseLiteral)*) Block ; DefaultOption: - 'default' ':' Block + 'default' Block ; ExpressionStmt: diff --git a/language/src/language/bcs-hardware.langium b/language/src/language/bcs-hardware.langium index c3b3d30..5c51092 100644 --- a/language/src/language/bcs-hardware.langium +++ b/language/src/language/bcs-hardware.langium @@ -58,7 +58,7 @@ Bus: Box: 'box' name=ID '{' - 'product:' product=ID // e.g. EK1100, CU1128 + 'product:' product=ID // e.g. EK1100, CU1128 ('revision:' rev=StringLiteral)? // optional explicit rev modules+=Module* '}' @@ -74,7 +74,7 @@ Module: NetworkSettings: 'network' '{' - 'hostname:' hostname=StringLiteral // e.g. "CX-301714" + 'hostname:' hostname=StringLiteral // e.g. "CX-301714" 'ipAddress:' ipAddress=StringLiteral // e.g. "192.168.1.100" TODO: IPLiteral '}' ; diff --git a/language/src/language/control/utils/type-inference-utils.ts b/language/src/language/control/utils/type-inference-utils.ts index c9b0bf3..13623d8 100644 --- a/language/src/language/control/utils/type-inference-utils.ts +++ b/language/src/language/control/utils/type-inference-utils.ts @@ -577,9 +577,9 @@ export class TypeInferenceUtils { accept: ValidationAcceptor, expr: any ): string | undefined { - const numericTypes = ["INT", "REAL"]; + const numericTypes = new Set(["INT", "REAL"]); - if (!numericTypes.includes(left) || !numericTypes.includes(right)) { + if (!numericTypes.has(left) || !numericTypes.has(right)) { accept( "error", `Arithmetic operator '${op}' requires numeric operands, but got '${left}' and '${right}'.`, @@ -588,11 +588,11 @@ export class TypeInferenceUtils { return undefined; } - // If either operand is REAL, result is REAL - if (left === "REAL" || right === "REAL") { - return "REAL"; + // If either operand is INT, result is INT + if (left === "INT" || right === "INT") { + return "INT"; } - return "INT"; + return "REAL"; } } diff --git a/language/test/generating/nested_control_test/input/nested_control_test.bcsctrl b/language/test/generating/nested_control_test/input/nested_control_test.bcsctrl index c5cb864..ed3753c 100644 --- a/language/test/generating/nested_control_test/input/nested_control_test.bcsctrl +++ b/language/test/generating/nested_control_test/input/nested_control_test.bcsctrl @@ -43,11 +43,11 @@ control NestedControlTestController { // Different processing based on state switch (iState) { - case ProcessState.INIT: { + case ProcessState.INIT { // Initialization processing tempSum = tempSum + iValues[i] * 0.8; } - case ProcessState.PROCESSING: { + case ProcessState.PROCESSING { // Normal processing - with nested if if (iValues[i] > iThreshold * 2.0) { tempSum = tempSum + iValues[i] * 1.5; @@ -55,7 +55,7 @@ control NestedControlTestController { tempSum = tempSum + iValues[i]; } } - default: { + default { // Should not happen, but handle anyway tempSum = tempSum + iValues[i] * 0.5; } diff --git a/language/test/generating/switch_test/input/switch_test.bcsctrl b/language/test/generating/switch_test/input/switch_test.bcsctrl index e1b2e80..7917b3b 100644 --- a/language/test/generating/switch_test/input/switch_test.bcsctrl +++ b/language/test/generating/switch_test/input/switch_test.bcsctrl @@ -24,22 +24,22 @@ control SwitchTestController { adjustedTemp = iTemperature * 1.05; switch (iMode) { - case OperationMode.IDLE: { + case OperationMode.IDLE { oHeatingValue = 0.0; oCoolingValue = 0.0; oStatusMessage = "System idle"; } - case OperationMode.HEATING: { + case OperationMode.HEATING { oHeatingValue = adjustedTemp; oCoolingValue = 0.0; oStatusMessage = "Heating active"; } - case OperationMode.COOLING: { + case OperationMode.COOLING { oHeatingValue = 0.0; oCoolingValue = adjustedTemp; oStatusMessage = "Cooling active"; } - default: { + default { oHeatingValue = 0.0; oCoolingValue = 0.0; oStatusMessage = "Error state"; diff --git a/language/test/validating/files/invalid/invalid_control.bcsctrl b/language/test/validating/files/invalid/invalid_control.bcsctrl index 9cf75d7..36f973a 100644 --- a/language/test/validating/files/invalid/invalid_control.bcsctrl +++ b/language/test/validating/files/invalid/invalid_control.bcsctrl @@ -9,6 +9,6 @@ control InvalidTestController { heater = 5.5; // Intentional type mismatch of sensor assign to local variable - temp = windowContact; + temp = WindowContact.value; } } diff --git a/language/test/validating/files/invalid/invalid_hardware.bcshw b/language/test/validating/files/invalid/invalid_hardware.bcshw index 6cbb5aa..c305425 100644 --- a/language/test/validating/files/invalid/invalid_hardware.bcshw +++ b/language/test/validating/files/invalid/invalid_hardware.bcshw @@ -32,7 +32,7 @@ controller InvalidTestController { channels: 8 } - datapoint windowContact { + datapoint WindowContact { portgroup: DigitalInputs channels: { channel value: BOOL link "Channel 1^Input" diff --git a/language/test/validating/files/invalid_switch/control_switch.bcsctrl b/language/test/validating/files/invalid_switch/control_switch.bcsctrl index a5b4839..c37c633 100644 --- a/language/test/validating/files/invalid_switch/control_switch.bcsctrl +++ b/language/test/validating/files/invalid_switch/control_switch.bcsctrl @@ -12,23 +12,23 @@ control InvalidSwitchTestController { unit TestUnit { var status_should_fail: Status; // Moved to unit level switch (mode_should_fail){ - case Status.OFF:{ + case Status.OFF{ // Nested variable declarations no longer allowed status_should_fail = Status.ON; } - case Mode.ECO:{ + case Mode.ECO{ // Nested variable declarations no longer allowed status_should_fail = Status.OFF; } - case Mode.ECO:{ + case Mode.ECO{ // Nested variable declarations no longer allowed status_should_fail = Status.ON; } - case true:{ + case true{ // Nested variable declarations no longer allowed status_should_fail = Status.OFF; } - default:{ + default{ // Nested variable declarations no longer allowed status_should_fail = Status.ON; } diff --git a/language/test/validating/validating.test.ts b/language/test/validating/validating.test.ts index adfea3a..621ecc0 100644 --- a/language/test/validating/validating.test.ts +++ b/language/test/validating/validating.test.ts @@ -202,7 +202,7 @@ describe("BCS Control Validation Tests", () => { expect(allDiagnostics.length).toBe(1); const expectedMessages = [ - "Condition in 'when (...)' of unit 'Test' must be of type BOOL, but got 'REAL'.", + "Condition in 'when (...)' of unit 'Test' must be of type BOOL, but got 'INT'.", ]; expectedMessages.forEach((msg) => {