Skip to content

Release v0.4.19#131

Merged
thiagoralves merged 2 commits into
mainfrom
development
May 29, 2026
Merged

Release v0.4.19#131
thiagoralves merged 2 commits into
mainfrom
development

Conversation

@thiagoralves
Copy link
Copy Markdown
Contributor

Promotes developmentmain for the v0.4.19 release.

Includes:

After merge: tag v0.4.19 on main to kick the release workflow (which builds the strucpp binary + bundles runtime headers + libs and publishes the GitHub release assets that openplc-editor/web pin via binary-versions.json).

🤖 Generated with Claude Code

thiagoralves and others added 2 commits May 28, 2026 21:55
…allable from generated code (#129)

User-reported bug on openplc-web: an ST program using `ADD_TIME` on
TIME variables failed at the arduino-cli stage with `'ADD_TIME' was
not declared in this scope` (the AVR cross compiler couldn't see
the symbol).  Same project compiled fine on the desktop editor —
but only by accident; it would have failed there too if the program
had ever made it to the arduino-cli step on that path.

Root cause is a two-layer dead-code problem in the runtime headers:

  1. `iec_std_lib.hpp` was the only header `codegen.ts` emitted into
     every `generated.hpp`, but it didn't transitively `#include
     "iec_time.hpp"` / `iec_date.hpp` / `iec_dt.hpp` / `iec_tod.hpp`.
     A generated POU calling `ADD_TIME` saw no declaration — hence
     the "not declared in this scope" error.

  2. Even with the includes restored, the functions in those four
     headers were templated on `TimeValue<T>` / `DateValue<T>` /
     `DateTimeValue<T>` / `TimeOfDayValue<T>` — a parallel value-class
     family the codegen never adopted.  TIME variables are emitted
     as `IEC_TIME` (= `IECVar<TIME_t>`); the templates couldn't
     deduce against an IECVar so the overload didn't bind either.

Strategy C — collapse the dead path:

  - The four headers are rewritten to operate on the canonical
    `IECVar<T>` aliases (`IEC_TIME`, `IEC_DATE`, `IEC_DT`, `IEC_TOD`)
    that codegen actually emits.  Functions take/return IECVars,
    extract the underlying integer via `iec_unwrap()`, and re-wrap
    the result — matching the existing IECVar-shaped helpers in
    `iec_std_lib.hpp` (`TO_TIME`, `TIME_FROM_MS`, `TIME_TO_MS`, …).

  - `iec_std_lib.hpp` now transitively `#include`s all four time-
    family headers so the single `#include "iec_std_lib.hpp"` that
    `generated.hpp` emits is enough for every standard function.

  - Deleted: `TimeValue<T>`, `IECTimeVar<T>`, `DateValue<T>`,
    `IECDateVar<T>`, `DateTimeValue<T>`, `IECDtVar<T>`,
    `TimeOfDayValue<T>`, `IECTodVar<T>`, plus the
    `IEC_*_Value` / `IEC_*_Var` aliases and the `MAKE_TIME_*` /
    `MAKE_LTIME_*` constructors that targeted them.  No call site
    in `src/`, in the libs, or in either downstream repo (openplc-
    editor, openplc-web) referenced any of these — `git grep`
    showed only the four headers themselves, this test file, and
    documentation comments.

  - Deleted: calendar component accessors (`YEAR`, `MONTH`, `DAY`,
    `DAY_OF_WEEK`, `DAY_OF_YEAR`, `HOUR`, `MINUTE`, `SECOND`,
    `MILLISECOND`, plus the `DT_*` variants).  These collided with
    OSCAT-imported user-side `FUNCTION DAY_OF_YEAR : INT` declarations
    in the OSCAT codesys-v23 stdlib (overload-by-return-type errors).
    They were never IEC 61131-3 standard free functions anyway — IEC
    component access is via OSCAT-style library imports.

  - Also `#undef`s AVR `<time.h>`'s `ONE_HOUR` / `ONE_DEGREE` /
    `ONE_DAY` / `UNIX_OFFSET` / `NTP_OFFSET` macros that `<chrono>`
    transitively pulls in.  Same class of macro-pollution bug as
    the existing `#undef OVERFLOW` codegen emits — without these
    undefs, an IEC variable named `one_hour` (upper-cased to
    `ONE_HOUR` by codegen) silently becomes the integer literal `3600`
    before the C++ parser sees the declaration, producing `expected
    unqualified-id before numeric constant`.

  - The dead `IEC_STRUCT_VALUE_FIELD` macro in `iec_struct.hpp`
    (referenced `IEC_TIME_Value` which is gone) is removed.  No
    callers; `IEC_STRUCT_FIELD` was already not in use either —
    codegen emits `IECVar<T>` struct fields directly without the
    macro.

Tests:
  - `runtime/tests/test_std_lib.cpp`: rewritten to exercise the
    IECVar surface (the only one codegen emits).  Old tests using
    `IEC_TIME_Var` / `IEC_TIME_Value` / accessor functions removed.
    Coverage of the surface that ships to users is now what's tested.

  - `tests/integration/cpp-compile.test.ts`: new regression case
    `compiles IEC TIME / DATE / DT / TOD standard arithmetic` that
    drives an FB using `ADD_TIME` / `ADD_DATE` / `ADD_DT` / `ADD_TOD`
    / `TIME_TO_S` through `compile(...)` + `compileWithGpp(...)`.
    Would have caught the original bug — the resulting C++ doesn't
    compile if `iec_time.hpp` isn't reachable from `generated.hpp`
    or if the function signatures don't match `IECVar` arguments.

End-to-end verification done locally:
  - Full suite: `npm run test` → 70/70 files, 1975 tests passing
  - Arduino-cli end-to-end: strucpp-emitted POU using ADD_TIME +
    ADD_DATE + ADD_DT + ADD_TOD + TIME_TO_S, compiled for
    arduino:avr:mega with the editor's bundled toolchain, produced a
    4136-byte .hex.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Patch release rolling up the IEC TIME/DATE/DT/TOD runtime-header fix
(#129):

  - `iec_std_lib.hpp` transitively pulls in `iec_time.hpp` / `iec_date.
    hpp` / `iec_dt.hpp` / `iec_tod.hpp` so generated POU code calling
    `ADD_TIME` et al. links cleanly.
  - The four time-family headers are rewritten to operate on `IECVar<T>`
    (the wrapper codegen actually emits) instead of the parallel
    `TimeValue<T>` / `IECTimeVar<T>` value-class design that was dead
    from generated code's perspective.
  - `TimeValue` / `IECTimeVar` / `DateValue` / `IECDateVar` /
    `DateTimeValue` / `IECDtVar` / `TimeOfDayValue` / `IECTodVar`
    deleted along with their aliases.  Calendar component accessors
    (YEAR / MONTH / DAY / DAY_OF_WEEK / HOUR / …) removed too — those
    are OSCAT-side responsibilities and were colliding with user-
    imported function bodies.
  - AVR `<time.h>` macro pollution (`ONE_HOUR`, `ONE_DAY`, etc.) now
    `#undef`d in `iec_std_lib.hpp` alongside the existing
    `#undef OVERFLOW` codegen.

End-to-end verification: strucpp + arduino-cli produced a working
.hex for an ATmega2560 sketch using `ADD_TIME` / `ADD_DATE` /
`ADD_DT` / `ADD_TOD` / `TIME_TO_S`.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@thiagoralves thiagoralves merged commit ab23bed into main May 29, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant