c-next 0.1.62 → 0.1.64
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/README.md +86 -63
- package/package.json +1 -1
- package/src/transpiler/Transpiler.ts +3 -2
- package/src/transpiler/__tests__/DualCodePaths.test.ts +1 -1
- package/src/transpiler/__tests__/Transpiler.coverage.test.ts +1 -1
- package/src/transpiler/__tests__/Transpiler.test.ts +0 -23
- package/src/transpiler/logic/symbols/cnext/collectors/StructCollector.ts +156 -70
- package/src/transpiler/logic/symbols/cnext/collectors/VariableCollector.ts +31 -6
- package/src/transpiler/logic/symbols/cnext/utils/TypeUtils.ts +43 -11
- package/src/transpiler/output/codegen/CodeGenState.ts +811 -0
- package/src/transpiler/output/codegen/CodeGenerator.ts +848 -1382
- package/src/transpiler/output/codegen/TypeResolver.ts +193 -149
- package/src/transpiler/output/codegen/TypeValidator.ts +148 -370
- package/src/transpiler/output/codegen/__tests__/CodeGenState.test.ts +446 -0
- package/src/transpiler/output/codegen/__tests__/CodeGenerator.test.ts +462 -60
- package/src/transpiler/output/codegen/__tests__/TrackVariableTypeHelpers.test.ts +1 -1
- package/src/transpiler/output/codegen/__tests__/TypeResolver.test.ts +435 -196
- package/src/transpiler/output/codegen/__tests__/TypeValidator.resolution.test.ts +51 -67
- package/src/transpiler/output/codegen/__tests__/TypeValidator.test.ts +495 -471
- package/src/transpiler/output/codegen/analysis/MemberChainAnalyzer.ts +39 -43
- package/src/transpiler/output/codegen/analysis/StringLengthCounter.ts +52 -55
- package/src/transpiler/output/codegen/analysis/__tests__/MemberChainAnalyzer.test.ts +122 -62
- package/src/transpiler/output/codegen/analysis/__tests__/StringLengthCounter.test.ts +101 -144
- package/src/transpiler/output/codegen/assignment/AssignmentClassifier.ts +143 -126
- package/src/transpiler/output/codegen/assignment/__tests__/AssignmentClassifier.test.ts +287 -320
- package/src/transpiler/output/codegen/generators/GeneratorRegistry.ts +12 -0
- package/src/transpiler/output/codegen/generators/__tests__/GeneratorRegistry.test.ts +28 -1
- package/src/transpiler/output/codegen/generators/declarationGenerators/ArrayDimensionUtils.ts +67 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/ScopeGenerator.ts +121 -51
- package/src/transpiler/output/codegen/generators/declarationGenerators/StructGenerator.ts +100 -23
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ArrayDimensionUtils.test.ts +125 -0
- package/src/transpiler/output/codegen/generators/declarationGenerators/__tests__/ScopeGenerator.test.ts +157 -4
- package/src/transpiler/output/codegen/generators/support/HelperGenerator.ts +23 -22
- package/src/transpiler/output/codegen/helpers/ArrayInitHelper.ts +54 -61
- package/src/transpiler/output/codegen/helpers/AssignmentExpectedTypeResolver.ts +21 -30
- package/src/transpiler/output/codegen/helpers/AssignmentValidator.ts +56 -53
- package/src/transpiler/output/codegen/helpers/CppModeHelper.ts +22 -30
- package/src/transpiler/output/codegen/helpers/EnumAssignmentValidator.ts +108 -50
- package/src/transpiler/output/codegen/helpers/FloatBitHelper.ts +16 -31
- package/src/transpiler/output/codegen/helpers/StringDeclHelper.ts +103 -96
- package/src/transpiler/output/codegen/helpers/TypeGenerationHelper.ts +9 -0
- package/src/transpiler/output/codegen/helpers/__tests__/ArrayInitHelper.test.ts +58 -103
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentExpectedTypeResolver.test.ts +97 -40
- package/src/transpiler/output/codegen/helpers/__tests__/AssignmentValidator.test.ts +223 -128
- package/src/transpiler/output/codegen/helpers/__tests__/CppModeHelper.test.ts +68 -41
- package/src/transpiler/output/codegen/helpers/__tests__/EnumAssignmentValidator.test.ts +198 -47
- package/src/transpiler/output/codegen/helpers/__tests__/FloatBitHelper.test.ts +39 -37
- package/src/transpiler/output/codegen/helpers/__tests__/StringDeclHelper.test.ts +191 -453
- package/src/transpiler/output/codegen/resolution/EnumTypeResolver.ts +229 -0
- package/src/transpiler/output/codegen/resolution/ScopeResolver.ts +60 -0
- package/src/transpiler/output/codegen/resolution/SizeofResolver.ts +177 -0
- package/src/transpiler/output/codegen/resolution/__tests__/EnumTypeResolver.test.ts +336 -0
- package/src/transpiler/output/codegen/resolution/__tests__/SizeofResolver.test.ts +201 -0
- package/src/transpiler/output/codegen/types/ITypeResolverDeps.ts +0 -23
- package/src/transpiler/output/codegen/types/ITypeValidatorDeps.ts +0 -53
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
A safer C for embedded systems development. Transpiles to clean, readable C.
|
|
11
11
|
|
|
12
|
-
**Status: Working Transpiler** — Verified on Teensy MicroMod hardware.
|
|
12
|
+
**Status: Working Transpiler** — Verified on Teensy MicroMod, 4.0, and stm32 hardware.
|
|
13
13
|
|
|
14
14
|
## Quick Example
|
|
15
15
|
|
|
@@ -104,7 +104,7 @@ The C-Next VS Code extension provides syntax highlighting, live C preview, Intel
|
|
|
104
104
|
|
|
105
105
|
## Getting Started with PlatformIO
|
|
106
106
|
|
|
107
|
-
C-Next integrates seamlessly with PlatformIO embedded projects. The transpiler automatically converts `.cnx` files to `.c` before each build.
|
|
107
|
+
C-Next integrates seamlessly with PlatformIO embedded projects. The transpiler automatically converts `.cnx` files to `.c`, `.h`, and `.cpp` as needed before each build.
|
|
108
108
|
|
|
109
109
|
### Quick Setup
|
|
110
110
|
|
|
@@ -145,11 +145,11 @@ Transpiling 2 c-next files...
|
|
|
145
145
|
Building...
|
|
146
146
|
```
|
|
147
147
|
|
|
148
|
-
3. **Commit both `.cnx` and generated `.c` files** to version control
|
|
148
|
+
3. **Commit both `.cnx` and generated `.c|.cpp|.h` files** to version control
|
|
149
149
|
|
|
150
150
|
### Why Commit Generated Files?
|
|
151
151
|
|
|
152
|
-
Generated `.c` files are **reviewable artifacts** in pull requests:
|
|
152
|
+
Generated `.c|.cpp|.h` files are **reviewable artifacts** in pull requests:
|
|
153
153
|
|
|
154
154
|
```diff
|
|
155
155
|
+ // ConfigStorage.cnx
|
|
@@ -165,7 +165,7 @@ Generated `.c` files are **reviewable artifacts** in pull requests:
|
|
|
165
165
|
|
|
166
166
|
**Benefits**:
|
|
167
167
|
|
|
168
|
-
- See exactly what C code the transpiler generates
|
|
168
|
+
- See exactly what C/CPP code the transpiler generates
|
|
169
169
|
- Review safety features (overflow protection, atomic operations)
|
|
170
170
|
- Verify transpiler behavior
|
|
171
171
|
- Build succeeds even if transpiler isn't available
|
|
@@ -181,9 +181,9 @@ my-teensy-project/
|
|
|
181
181
|
├── src/
|
|
182
182
|
│ ├── main.cpp # C++ entry point
|
|
183
183
|
│ ├── ConfigStorage.cnx # c-next source
|
|
184
|
-
│ ├── ConfigStorage.
|
|
184
|
+
│ ├── ConfigStorage.cpp # Generated (committed)
|
|
185
185
|
│ ├── SensorProcessor.cnx # c-next source
|
|
186
|
-
│ └── SensorProcessor.
|
|
186
|
+
│ └── SensorProcessor.cpp # Generated (committed)
|
|
187
187
|
└── include/
|
|
188
188
|
└── AppConfig.h # Shared types
|
|
189
189
|
```
|
|
@@ -201,7 +201,7 @@ This removes:
|
|
|
201
201
|
- `cnext_build.py` script
|
|
202
202
|
- `extra_scripts` reference from `platformio.ini`
|
|
203
203
|
|
|
204
|
-
Your `.cnx` files and generated `.c` files remain untouched.
|
|
204
|
+
Your `.cnx` files and generated `.c|.cpp|.h` files remain untouched.
|
|
205
205
|
|
|
206
206
|
### Manual Integration
|
|
207
207
|
|
|
@@ -262,7 +262,7 @@ Generated headers automatically include guards:
|
|
|
262
262
|
| Add concepts to catch errors | Remove the ability to make errors |
|
|
263
263
|
| Borrow checker complexity | Startup allocation = predictable memory |
|
|
264
264
|
| Lifetime annotations | Fixed runtime layout = clear lifetimes |
|
|
265
|
-
| `unsafe` escape hatch |
|
|
265
|
+
| `unsafe` escape hatch | No escape hatch needed! |
|
|
266
266
|
|
|
267
267
|
**Guiding Principle:** If Linus Torvalds wouldn't approve of the complexity, it doesn't ship. Safety through removal, not addition.
|
|
268
268
|
|
|
@@ -360,11 +360,13 @@ memcpy(&buffer[8], ×tamp, 8);
|
|
|
360
360
|
|
|
361
361
|
### Scopes (ADR-016)
|
|
362
362
|
|
|
363
|
-
Organize code with automatic name prefixing. Inside scopes, explicit qualification is
|
|
363
|
+
Organize code with automatic name prefixing. Inside scopes, explicit qualification is available to avoid naming collisions:
|
|
364
364
|
|
|
365
365
|
- `this.X` for scope-local members
|
|
366
366
|
- `global.X` for global variables, functions, and registers
|
|
367
367
|
|
|
368
|
+
If the same name exists in local, scope, and global levels, the precedence is local, scope, global just like you are used to in other languages.
|
|
369
|
+
|
|
368
370
|
```cnx
|
|
369
371
|
const u8 LED_BIT <- 3;
|
|
370
372
|
|
|
@@ -652,7 +654,7 @@ Allocate at startup, run with fixed memory. Per MISRA C:2023 Dir 4.12: all memor
|
|
|
652
654
|
|
|
653
655
|
## Hardware Testing
|
|
654
656
|
|
|
655
|
-
Verified on **Teensy MicroMod**
|
|
657
|
+
Verified on **Teensy MicroMod**, **Teensy 4.0**, and **STM32** hardware:
|
|
656
658
|
|
|
657
659
|
```bash
|
|
658
660
|
# Build and flash with PlatformIO
|
|
@@ -674,16 +676,20 @@ _Using C-Next in your project? Open an issue to get listed!_
|
|
|
674
676
|
|
|
675
677
|
```
|
|
676
678
|
c-next/
|
|
677
|
-
├── grammar/CNext.g4
|
|
679
|
+
├── grammar/CNext.g4 # ANTLR4 grammar definition
|
|
678
680
|
├── src/
|
|
679
|
-
│ ├──
|
|
680
|
-
│ ├──
|
|
681
|
-
│
|
|
681
|
+
│ ├── index.ts # CLI entry point
|
|
682
|
+
│ ├── transpiler/
|
|
683
|
+
│ │ ├── Transpiler.ts # Orchestrator
|
|
684
|
+
│ │ ├── data/ # Discovery layer (files, includes, deps)
|
|
685
|
+
│ │ ├── logic/ # Business logic (parser, symbols, analysis)
|
|
686
|
+
│ │ └── output/ # Generation (codegen, headers)
|
|
687
|
+
│ └── utils/ # Shared utilities
|
|
682
688
|
├── examples/
|
|
683
|
-
│ ├── blink.cnx
|
|
684
|
-
│ └── bit_test.cnx
|
|
685
|
-
├── test-teensy/
|
|
686
|
-
└── docs/decisions/
|
|
689
|
+
│ ├── blink.cnx # LED blink (Teensy verified)
|
|
690
|
+
│ └── bit_test.cnx # Bit manipulation tests
|
|
691
|
+
├── test-teensy/ # PlatformIO test project
|
|
692
|
+
└── docs/decisions/ # Architecture Decision Records
|
|
687
693
|
```
|
|
688
694
|
|
|
689
695
|
## Architecture Decision Records
|
|
@@ -692,53 +698,70 @@ Decisions are documented in `/docs/decisions/`:
|
|
|
692
698
|
|
|
693
699
|
### Implemented
|
|
694
700
|
|
|
695
|
-
| ADR | Title | Description
|
|
696
|
-
| --------------------------------------------------------------------- | ------------------------- |
|
|
697
|
-
| [ADR-001](docs/decisions/adr-001-assignment-operator.md) | Assignment Operator | `<-` for assignment, `=` for comparison
|
|
698
|
-
| [ADR-003](docs/decisions/adr-003-static-allocation.md) | Static Allocation | No dynamic memory after init
|
|
699
|
-
| [ADR-004](docs/decisions/adr-004-register-bindings.md) | Register Bindings | Type-safe hardware access
|
|
700
|
-
| [ADR-006](docs/decisions/adr-006-simplified-references.md) | Simplified References | Pass by reference, no pointer syntax
|
|
701
|
-
| [ADR-007](docs/decisions/adr-007-type-aware-bit-indexing.md) | Type-Aware Bit Indexing | Integers as bit arrays, `.length` property
|
|
702
|
-
| [ADR-010](docs/decisions/adr-010-c-interoperability.md) | C Interoperability | Unified ANTLR parser architecture
|
|
703
|
-
| [ADR-011](docs/decisions/adr-011-vscode-extension.md) | VS Code Extension | Live C preview with syntax highlighting
|
|
704
|
-
| [ADR-012](docs/decisions/adr-012-static-analysis.md) | Static Analysis | cppcheck integration for generated C
|
|
705
|
-
| [ADR-013](docs/decisions/adr-013-const-qualifier.md) | Const Qualifier | Compile-time const enforcement
|
|
706
|
-
| [ADR-014](docs/decisions/adr-014-structs.md) | Structs | Data containers without methods
|
|
707
|
-
| [ADR-015](docs/decisions/adr-015-null-state.md) | Null State | Zero initialization for all variables
|
|
708
|
-
| [ADR-016](docs/decisions/adr-016-scope.md) | Scope | `this.`/`global.` explicit qualification
|
|
709
|
-
| [ADR-017](docs/decisions/adr-017-enums.md) | Enums | Type-safe enums with C-style casting
|
|
710
|
-
| [ADR-030](docs/decisions/adr-030-forward-declarations.md) | Define-Before-Use | Functions must be defined before called
|
|
711
|
-
| [ADR-037](docs/decisions/adr-037-preprocessor.md) | Preprocessor | Flag-only defines, const for values
|
|
712
|
-
| [ADR-043](docs/decisions/adr-043-comments.md) | Comments | Comment preservation with MISRA compliance
|
|
713
|
-
| [ADR-044](docs/decisions/adr-044-primitive-types.md) | Primitive Types | Fixed-width types with `clamp`/`wrap` overflow
|
|
714
|
-
| [ADR-024](docs/decisions/adr-024-type-casting.md) | Type Casting | Widening implicit, narrowing uses bit indexing
|
|
715
|
-
| [ADR-022](docs/decisions/adr-022-conditional-expressions.md) | Conditional Expressions | Ternary with required parens, boolean condition, no nesting
|
|
716
|
-
| [ADR-025](docs/decisions/adr-025-switch-statements.md) | Switch Statements | Safe switch with braces, `\|\|` syntax, counted `default(n)`
|
|
717
|
-
| [ADR-029](docs/decisions/adr-029-function-pointers.md) | Callbacks | Function-as-Type pattern with nominal typing
|
|
718
|
-
| [ADR-045](docs/decisions/adr-045-string-type.md) | Bounded Strings | `string<N>` with compile-time safety
|
|
719
|
-
| [ADR-023](docs/decisions/adr-023-sizeof.md) | Sizeof | Type/value size queries with safety checks
|
|
720
|
-
| [ADR-027](docs/decisions/adr-027-do-while.md) | Do-While | `do { } while ()` with boolean condition (E0701)
|
|
721
|
-
| [ADR-032](docs/decisions/adr-032-nested-structs.md) | Nested Structs | Named nested structs only (no anonymous)
|
|
722
|
-
| [ADR-035](docs/decisions/adr-035-array-initializers.md) | Array Initializers | `[1, 2, 3]` syntax with `[0*]` fill-all
|
|
723
|
-
| [ADR-036](docs/decisions/adr-036-multidimensional-arrays.md) | Multi-dim Arrays | `arr[i][j]` with compile-time bounds enforcement
|
|
724
|
-
| [ADR-040](docs/decisions/adr-040-isr-declaration.md) | ISR Type | Built-in `ISR` type for `void(void)` function pointers
|
|
725
|
-
| [ADR-034](docs/decisions/adr-034-bit-fields.md) | Bitmap Types | `bitmap8`/`bitmap16`/`bitmap32` for portable bit-packed data
|
|
726
|
-
| [ADR-048](docs/decisions/adr-048-cli-executable.md) | CLI Executable | `cnext` command with smart defaults
|
|
727
|
-
| [ADR-049](docs/decisions/adr-049-atomic-types.md) | Atomic Types | `atomic` keyword with LDREX/STREX or PRIMASK fallback
|
|
728
|
-
| [ADR-050](docs/decisions/adr-050-critical-sections.md) | Critical Sections | `critical { }` blocks with PRIMASK save/restore
|
|
729
|
-
| [ADR-108](docs/decisions/adr-108-volatile-keyword.md) | Volatile Variables | `volatile` keyword prevents compiler optimization
|
|
730
|
-
| [ADR-046](docs/decisions/adr-046-nullable-c-interop.md) | Nullable C Interop | `c_` prefix for nullable C pointer types
|
|
731
|
-
| [ADR-
|
|
732
|
-
| [ADR-
|
|
733
|
-
|
|
734
|
-
|
|
701
|
+
| ADR | Title | Description |
|
|
702
|
+
| --------------------------------------------------------------------- | ------------------------- | ------------------------------------------------------------ |
|
|
703
|
+
| [ADR-001](docs/decisions/adr-001-assignment-operator.md) | Assignment Operator | `<-` for assignment, `=` for comparison |
|
|
704
|
+
| [ADR-003](docs/decisions/adr-003-static-allocation.md) | Static Allocation | No dynamic memory after init |
|
|
705
|
+
| [ADR-004](docs/decisions/adr-004-register-bindings.md) | Register Bindings | Type-safe hardware access |
|
|
706
|
+
| [ADR-006](docs/decisions/adr-006-simplified-references.md) | Simplified References | Pass by reference, no pointer syntax |
|
|
707
|
+
| [ADR-007](docs/decisions/adr-007-type-aware-bit-indexing.md) | Type-Aware Bit Indexing | Integers as bit arrays, `.length` property |
|
|
708
|
+
| [ADR-010](docs/decisions/adr-010-c-interoperability.md) | C Interoperability | Unified ANTLR parser architecture |
|
|
709
|
+
| [ADR-011](docs/decisions/adr-011-vscode-extension.md) | VS Code Extension | Live C preview with syntax highlighting |
|
|
710
|
+
| [ADR-012](docs/decisions/adr-012-static-analysis.md) | Static Analysis | cppcheck integration for generated C |
|
|
711
|
+
| [ADR-013](docs/decisions/adr-013-const-qualifier.md) | Const Qualifier | Compile-time const enforcement |
|
|
712
|
+
| [ADR-014](docs/decisions/adr-014-structs.md) | Structs | Data containers without methods |
|
|
713
|
+
| [ADR-015](docs/decisions/adr-015-null-state.md) | Null State | Zero initialization for all variables |
|
|
714
|
+
| [ADR-016](docs/decisions/adr-016-scope.md) | Scope | `this.`/`global.` explicit qualification |
|
|
715
|
+
| [ADR-017](docs/decisions/adr-017-enums.md) | Enums | Type-safe enums with C-style casting |
|
|
716
|
+
| [ADR-030](docs/decisions/adr-030-forward-declarations.md) | Define-Before-Use | Functions must be defined before called |
|
|
717
|
+
| [ADR-037](docs/decisions/adr-037-preprocessor.md) | Preprocessor | Flag-only defines, const for values |
|
|
718
|
+
| [ADR-043](docs/decisions/adr-043-comments.md) | Comments | Comment preservation with MISRA compliance |
|
|
719
|
+
| [ADR-044](docs/decisions/adr-044-primitive-types.md) | Primitive Types | Fixed-width types with `clamp`/`wrap` overflow |
|
|
720
|
+
| [ADR-024](docs/decisions/adr-024-type-casting.md) | Type Casting | Widening implicit, narrowing uses bit indexing |
|
|
721
|
+
| [ADR-022](docs/decisions/adr-022-conditional-expressions.md) | Conditional Expressions | Ternary with required parens, boolean condition, no nesting |
|
|
722
|
+
| [ADR-025](docs/decisions/adr-025-switch-statements.md) | Switch Statements | Safe switch with braces, `\|\|` syntax, counted `default(n)` |
|
|
723
|
+
| [ADR-029](docs/decisions/adr-029-function-pointers.md) | Callbacks | Function-as-Type pattern with nominal typing |
|
|
724
|
+
| [ADR-045](docs/decisions/adr-045-string-type.md) | Bounded Strings | `string<N>` with compile-time safety |
|
|
725
|
+
| [ADR-023](docs/decisions/adr-023-sizeof.md) | Sizeof | Type/value size queries with safety checks |
|
|
726
|
+
| [ADR-027](docs/decisions/adr-027-do-while.md) | Do-While | `do { } while ()` with boolean condition (E0701) |
|
|
727
|
+
| [ADR-032](docs/decisions/adr-032-nested-structs.md) | Nested Structs | Named nested structs only (no anonymous) |
|
|
728
|
+
| [ADR-035](docs/decisions/adr-035-array-initializers.md) | Array Initializers | `[1, 2, 3]` syntax with `[0*]` fill-all |
|
|
729
|
+
| [ADR-036](docs/decisions/adr-036-multidimensional-arrays.md) | Multi-dim Arrays | `arr[i][j]` with compile-time bounds enforcement |
|
|
730
|
+
| [ADR-040](docs/decisions/adr-040-isr-declaration.md) | ISR Type | Built-in `ISR` type for `void(void)` function pointers |
|
|
731
|
+
| [ADR-034](docs/decisions/adr-034-bit-fields.md) | Bitmap Types | `bitmap8`/`bitmap16`/`bitmap32` for portable bit-packed data |
|
|
732
|
+
| [ADR-048](docs/decisions/adr-048-cli-executable.md) | CLI Executable | `cnext` command with smart defaults |
|
|
733
|
+
| [ADR-049](docs/decisions/adr-049-atomic-types.md) | Atomic Types | `atomic` keyword with LDREX/STREX or PRIMASK fallback |
|
|
734
|
+
| [ADR-050](docs/decisions/adr-050-critical-sections.md) | Critical Sections | `critical { }` blocks with PRIMASK save/restore |
|
|
735
|
+
| [ADR-108](docs/decisions/adr-108-volatile-keyword.md) | Volatile Variables | `volatile` keyword prevents compiler optimization |
|
|
736
|
+
| [ADR-046](docs/decisions/adr-046-nullable-c-interop.md) | Nullable C Interop | `c_` prefix for nullable C pointer types |
|
|
737
|
+
| [ADR-053](docs/decisions/adr-053-transpiler-pipeline-architecture.md) | Transpiler Pipeline | Unified multi-pass pipeline with header symbol extraction |
|
|
738
|
+
| [ADR-057](docs/decisions/adr-057-implicit-scope-resolution.md) | Implicit Scope Resolution | Bare identifiers resolve local → scope → global |
|
|
739
|
+
|
|
740
|
+
### Accepted
|
|
741
|
+
|
|
742
|
+
| ADR | Title | Description |
|
|
743
|
+
| -------------------------------------------------------------------- | --------------------- | ----------------------------------------------------- |
|
|
744
|
+
| [ADR-051](docs/decisions/adr-051-division-by-zero.md) | Division by Zero | Compile-time and runtime division-by-zero detection |
|
|
745
|
+
| [ADR-052](docs/decisions/adr-052-safe-numeric-literal-generation.md) | Safe Numeric Literals | `type_MIN`/`type_MAX` constants + safe hex conversion |
|
|
746
|
+
|
|
747
|
+
### Superseded
|
|
748
|
+
|
|
749
|
+
| ADR | Title | Description |
|
|
750
|
+
| --------------------------------------------------- | ------------------ | ----------------------------------------------------------- |
|
|
751
|
+
| [ADR-047](docs/decisions/adr-047-nullable-types.md) | NULL for C Interop | `NULL` keyword for C stream functions (replaced by ADR-046) |
|
|
735
752
|
|
|
736
753
|
### Research (v1 Roadmap)
|
|
737
754
|
|
|
738
|
-
| ADR
|
|
739
|
-
|
|
|
740
|
-
| [ADR-008](docs/decisions/adr-008-language-bug-prevention.md)
|
|
741
|
-
| [ADR-009](docs/decisions/adr-009-isr-safety.md)
|
|
755
|
+
| ADR | Title | Description |
|
|
756
|
+
| ---------------------------------------------------------------- | ----------------------------- | --------------------------------------------------- |
|
|
757
|
+
| [ADR-008](docs/decisions/adr-008-language-bug-prevention.md) | Language-Level Bug Prevention | Top 15 embedded bugs and prevention |
|
|
758
|
+
| [ADR-009](docs/decisions/adr-009-isr-safety.md) | ISR Safety | Safe interrupts without `unsafe` blocks |
|
|
759
|
+
| [ADR-054](docs/decisions/adr-054-array-index-overflow.md) | Array Index Overflow | Overflow semantics for array index expressions |
|
|
760
|
+
| [ADR-055](docs/decisions/adr-055-symbol-parser-architecture.md) | Symbol Parser Architecture | Unified symbol resolution design |
|
|
761
|
+
| [ADR-056](docs/decisions/adr-056-cast-overflow-behavior.md) | Cast Overflow Behavior | Consistent overflow semantics for type casts |
|
|
762
|
+
| [ADR-060](docs/decisions/adr-060-vscode-extension-separation.md) | VS Code Extension Separation | Separate repository for VS Code extension |
|
|
763
|
+
| [ADR-058](docs/decisions/adr-058-explicit-length-properties.md) | Explicit Length Properties | Replace `.length` with `.bit_length`/`.byte_length` |
|
|
764
|
+
| [ADR-109](docs/decisions/adr-109-codegenerator-decomposition.md) | CodeGenerator Decomposition | Breaking down CodeGenerator into modules |
|
|
742
765
|
|
|
743
766
|
### Research (v2 Roadmap)
|
|
744
767
|
|
package/package.json
CHANGED
|
@@ -19,6 +19,7 @@ import CNextSourceParser from "./logic/parser/CNextSourceParser";
|
|
|
19
19
|
import HeaderParser from "./logic/parser/HeaderParser";
|
|
20
20
|
|
|
21
21
|
import CodeGenerator from "./output/codegen/CodeGenerator";
|
|
22
|
+
import CodeGenState from "./output/codegen/CodeGenState";
|
|
22
23
|
import HeaderGenerator from "./output/headers/HeaderGenerator";
|
|
23
24
|
import ExternalTypeHeaderBuilder from "./output/headers/ExternalTypeHeaderBuilder";
|
|
24
25
|
import ICodeGenSymbols from "./types/ICodeGenSymbols";
|
|
@@ -1289,8 +1290,8 @@ class Transpiler {
|
|
|
1289
1290
|
|
|
1290
1291
|
const headerName = basename(sourcePath).replace(/\.cnx$|\.cnext$/, ".h");
|
|
1291
1292
|
|
|
1292
|
-
// Get type input from
|
|
1293
|
-
const typeInput =
|
|
1293
|
+
// Get type input from CodeGenState (for struct/enum definitions)
|
|
1294
|
+
const typeInput = CodeGenState.symbols;
|
|
1294
1295
|
|
|
1295
1296
|
// Update auto-const info on symbol parameters
|
|
1296
1297
|
const unmodifiedParams = this.codeGenerator.getFunctionUnmodifiedParams();
|
|
@@ -356,29 +356,6 @@ describe("Transpiler", () => {
|
|
|
356
356
|
expect(hFile?.content).toContain("Math_add");
|
|
357
357
|
});
|
|
358
358
|
|
|
359
|
-
// Note: Directory discovery uses fast-glob which accesses the real filesystem.
|
|
360
|
-
// This test is skipped because fast-glob doesn't work with MockFileSystem.
|
|
361
|
-
// Directory discovery is tested in integration tests with the real filesystem.
|
|
362
|
-
it.skip("discovers files in a directory (uses fast-glob, needs real fs)", async () => {
|
|
363
|
-
mockFs.addDirectory("/project/src");
|
|
364
|
-
mockFs.addFile("/project/src/a.cnx", "void a() { }");
|
|
365
|
-
mockFs.addFile("/project/src/b.cnx", "void b() { }");
|
|
366
|
-
|
|
367
|
-
const transpiler = new Transpiler(
|
|
368
|
-
{
|
|
369
|
-
inputs: ["/project/src"],
|
|
370
|
-
outDir: "/project/build",
|
|
371
|
-
noCache: true,
|
|
372
|
-
},
|
|
373
|
-
mockFs,
|
|
374
|
-
);
|
|
375
|
-
|
|
376
|
-
const result = await transpiler.run();
|
|
377
|
-
|
|
378
|
-
expect(result.success).toBe(true);
|
|
379
|
-
expect(result.filesProcessed).toBe(2);
|
|
380
|
-
});
|
|
381
|
-
|
|
382
359
|
it("returns error for non-existent input", async () => {
|
|
383
360
|
const transpiler = new Transpiler(
|
|
384
361
|
{
|
|
@@ -11,29 +11,98 @@ import IFieldInfo from "../../types/IFieldInfo";
|
|
|
11
11
|
import TypeUtils from "../utils/TypeUtils";
|
|
12
12
|
import LiteralUtils from "../../../../../utils/LiteralUtils";
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Result of processing an arrayType syntax context.
|
|
16
|
+
*/
|
|
17
|
+
interface IArrayTypeResult {
|
|
18
|
+
isArray: boolean;
|
|
19
|
+
dimension: number | undefined;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Process arrayType syntax (e.g., Item[3] items) and return array info.
|
|
24
|
+
*/
|
|
25
|
+
function processArrayTypeSyntax(
|
|
26
|
+
arrayTypeCtx: Parser.ArrayTypeContext | null | undefined,
|
|
27
|
+
constValues?: Map<string, number>,
|
|
28
|
+
): IArrayTypeResult {
|
|
29
|
+
if (!arrayTypeCtx) {
|
|
30
|
+
return { isArray: false, dimension: undefined };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const sizeExpr = arrayTypeCtx.expression();
|
|
34
|
+
if (!sizeExpr) {
|
|
35
|
+
return { isArray: true, dimension: undefined };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const resolved = tryResolveExpressionDimension(sizeExpr, constValues);
|
|
39
|
+
return { isArray: true, dimension: resolved };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Process string type fields and update dimensions array.
|
|
44
|
+
*/
|
|
45
|
+
function processStringField(
|
|
46
|
+
stringCtx: Parser.StringTypeContext,
|
|
47
|
+
arrayDims: Parser.ArrayDimensionContext[],
|
|
48
|
+
dimensions: number[],
|
|
49
|
+
constValues?: Map<string, number>,
|
|
50
|
+
): boolean {
|
|
51
|
+
const intLiteral = stringCtx.INTEGER_LITERAL();
|
|
52
|
+
if (!intLiteral) {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const capacity = Number.parseInt(intLiteral.getText(), 10);
|
|
57
|
+
|
|
58
|
+
// If there are array dimensions, they come BEFORE string capacity
|
|
59
|
+
if (arrayDims.length > 0) {
|
|
60
|
+
parseArrayDimensions(arrayDims, dimensions, constValues);
|
|
61
|
+
}
|
|
62
|
+
// String capacity becomes final dimension (+1 for null terminator)
|
|
63
|
+
dimensions.push(capacity + 1);
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Try to resolve a single expression as a numeric dimension.
|
|
69
|
+
* Handles integer literals and const references.
|
|
70
|
+
*/
|
|
71
|
+
function tryResolveExpressionDimension(
|
|
72
|
+
sizeExpr: Parser.ExpressionContext,
|
|
73
|
+
constValues?: Map<string, number>,
|
|
74
|
+
): number | undefined {
|
|
75
|
+
const dimText = sizeExpr.getText();
|
|
76
|
+
const literalSize = LiteralUtils.parseIntegerLiteral(dimText);
|
|
77
|
+
if (literalSize !== undefined) {
|
|
78
|
+
return literalSize;
|
|
79
|
+
}
|
|
80
|
+
if (constValues?.has(dimText)) {
|
|
81
|
+
return constValues.get(dimText);
|
|
82
|
+
}
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Parse array dimension expressions and append resolved sizes to dimensions array.
|
|
88
|
+
*/
|
|
89
|
+
function parseArrayDimensions(
|
|
90
|
+
arrayDims: Parser.ArrayDimensionContext[],
|
|
91
|
+
dimensions: number[],
|
|
92
|
+
constValues?: Map<string, number>,
|
|
93
|
+
): void {
|
|
94
|
+
for (const dim of arrayDims) {
|
|
95
|
+
const sizeExpr = dim.expression();
|
|
96
|
+
if (sizeExpr) {
|
|
97
|
+
const resolved = tryResolveExpressionDimension(sizeExpr, constValues);
|
|
98
|
+
if (resolved !== undefined) {
|
|
99
|
+
dimensions.push(resolved);
|
|
33
100
|
}
|
|
34
101
|
}
|
|
35
102
|
}
|
|
103
|
+
}
|
|
36
104
|
|
|
105
|
+
class StructCollector {
|
|
37
106
|
/**
|
|
38
107
|
* Collect a struct declaration and return an IStructSymbol.
|
|
39
108
|
*
|
|
@@ -56,57 +125,12 @@ class StructCollector {
|
|
|
56
125
|
const fields = new Map<string, IFieldInfo>();
|
|
57
126
|
|
|
58
127
|
for (const member of ctx.structMember()) {
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const arrayDims = member.arrayDimension();
|
|
66
|
-
const dimensions: number[] = [];
|
|
67
|
-
let isArray = false;
|
|
68
|
-
|
|
69
|
-
// Handle string types specially
|
|
70
|
-
if (typeCtx.stringType()) {
|
|
71
|
-
const stringCtx = typeCtx.stringType()!;
|
|
72
|
-
const intLiteral = stringCtx.INTEGER_LITERAL();
|
|
73
|
-
|
|
74
|
-
if (intLiteral) {
|
|
75
|
-
const capacity = Number.parseInt(intLiteral.getText(), 10);
|
|
76
|
-
|
|
77
|
-
// If there are array dimensions, they come BEFORE string capacity
|
|
78
|
-
if (arrayDims.length > 0) {
|
|
79
|
-
StructCollector.parseArrayDimensions(
|
|
80
|
-
arrayDims,
|
|
81
|
-
dimensions,
|
|
82
|
-
constValues,
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
// String capacity becomes final dimension (+1 for null terminator)
|
|
86
|
-
dimensions.push(capacity + 1);
|
|
87
|
-
isArray = true;
|
|
88
|
-
}
|
|
89
|
-
} else if (arrayDims.length > 0) {
|
|
90
|
-
// Non-string array
|
|
91
|
-
isArray = true;
|
|
92
|
-
StructCollector.parseArrayDimensions(
|
|
93
|
-
arrayDims,
|
|
94
|
-
dimensions,
|
|
95
|
-
constValues,
|
|
96
|
-
);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const fieldInfo: IFieldInfo = {
|
|
100
|
-
type: fieldType,
|
|
101
|
-
isArray,
|
|
102
|
-
isConst,
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
if (dimensions.length > 0) {
|
|
106
|
-
fieldInfo.dimensions = dimensions;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
fields.set(fieldName, fieldInfo);
|
|
128
|
+
const fieldInfo = StructCollector.collectField(
|
|
129
|
+
member,
|
|
130
|
+
scopeName,
|
|
131
|
+
constValues,
|
|
132
|
+
);
|
|
133
|
+
fields.set(member.IDENTIFIER().getText(), fieldInfo);
|
|
110
134
|
}
|
|
111
135
|
|
|
112
136
|
return {
|
|
@@ -120,6 +144,68 @@ class StructCollector {
|
|
|
120
144
|
fields,
|
|
121
145
|
};
|
|
122
146
|
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Collect a single struct field and return its IFieldInfo.
|
|
150
|
+
*/
|
|
151
|
+
private static collectField(
|
|
152
|
+
member: Parser.StructMemberContext,
|
|
153
|
+
scopeName?: string,
|
|
154
|
+
constValues?: Map<string, number>,
|
|
155
|
+
): IFieldInfo {
|
|
156
|
+
const typeCtx = member.type();
|
|
157
|
+
const fieldType = TypeUtils.getTypeName(typeCtx, scopeName);
|
|
158
|
+
// Note: C-Next struct members don't have const modifier in grammar
|
|
159
|
+
const isConst = false;
|
|
160
|
+
|
|
161
|
+
const arrayDims = member.arrayDimension();
|
|
162
|
+
const dimensions: number[] = [];
|
|
163
|
+
let isArray = false;
|
|
164
|
+
|
|
165
|
+
// Check for C-Next style arrayType syntax: Item[3] items -> typeCtx.arrayType()
|
|
166
|
+
const arrayTypeResult = processArrayTypeSyntax(
|
|
167
|
+
typeCtx.arrayType(),
|
|
168
|
+
constValues,
|
|
169
|
+
);
|
|
170
|
+
if (arrayTypeResult.isArray) {
|
|
171
|
+
isArray = true;
|
|
172
|
+
if (arrayTypeResult.dimension !== undefined) {
|
|
173
|
+
dimensions.push(arrayTypeResult.dimension);
|
|
174
|
+
}
|
|
175
|
+
// Note: non-literal, non-const expressions (like global.EnumName.COUNT)
|
|
176
|
+
// won't be resolvable at symbol collection time - dimensions stays empty
|
|
177
|
+
// but isArray is still true so the field is tracked as an array
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Handle string types specially
|
|
181
|
+
if (typeCtx.stringType()) {
|
|
182
|
+
const stringHandled = processStringField(
|
|
183
|
+
typeCtx.stringType()!,
|
|
184
|
+
arrayDims,
|
|
185
|
+
dimensions,
|
|
186
|
+
constValues,
|
|
187
|
+
);
|
|
188
|
+
if (stringHandled) {
|
|
189
|
+
isArray = true;
|
|
190
|
+
}
|
|
191
|
+
} else if (arrayDims.length > 0) {
|
|
192
|
+
// Non-string array
|
|
193
|
+
isArray = true;
|
|
194
|
+
parseArrayDimensions(arrayDims, dimensions, constValues);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const fieldInfo: IFieldInfo = {
|
|
198
|
+
type: fieldType,
|
|
199
|
+
isArray,
|
|
200
|
+
isConst,
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
if (dimensions.length > 0) {
|
|
204
|
+
fieldInfo.dimensions = dimensions;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return fieldInfo;
|
|
208
|
+
}
|
|
123
209
|
}
|
|
124
210
|
|
|
125
211
|
export default StructCollector;
|
|
@@ -9,6 +9,7 @@ import ESymbolKind from "../../../../../utils/types/ESymbolKind";
|
|
|
9
9
|
import IVariableSymbol from "../../types/IVariableSymbol";
|
|
10
10
|
import ArrayInitializerUtils from "../utils/ArrayInitializerUtils";
|
|
11
11
|
import TypeUtils from "../utils/TypeUtils";
|
|
12
|
+
import LiteralUtils from "../../../../../utils/LiteralUtils";
|
|
12
13
|
|
|
13
14
|
class VariableCollector {
|
|
14
15
|
/**
|
|
@@ -101,17 +102,41 @@ class VariableCollector {
|
|
|
101
102
|
// Issue #468: Check for atomic modifier
|
|
102
103
|
const isAtomic = ctx.atomicModifier() !== null;
|
|
103
104
|
|
|
104
|
-
// Check for array dimensions
|
|
105
|
+
// Check for array dimensions - both C-style (arrayDimension) and C-Next style (arrayType)
|
|
105
106
|
const arrayDims = ctx.arrayDimension();
|
|
106
|
-
const
|
|
107
|
+
const arrayTypeCtx = typeCtx.arrayType();
|
|
108
|
+
const hasArrayTypeSyntax = arrayTypeCtx !== null;
|
|
109
|
+
const isArray = arrayDims.length > 0 || hasArrayTypeSyntax;
|
|
107
110
|
const initExpr = ctx.expression();
|
|
108
|
-
const arrayDimensions =
|
|
109
|
-
|
|
111
|
+
const arrayDimensions: (number | string)[] = [];
|
|
112
|
+
|
|
113
|
+
// Collect dimension from arrayType syntax (u16[8] arr)
|
|
114
|
+
if (hasArrayTypeSyntax) {
|
|
115
|
+
const sizeExpr = arrayTypeCtx.expression();
|
|
116
|
+
if (sizeExpr) {
|
|
117
|
+
const dimText = sizeExpr.getText();
|
|
118
|
+
const literalSize = LiteralUtils.parseIntegerLiteral(dimText);
|
|
119
|
+
if (literalSize !== undefined) {
|
|
120
|
+
arrayDimensions.push(literalSize);
|
|
121
|
+
} else if (constValues?.has(dimText)) {
|
|
122
|
+
arrayDimensions.push(constValues.get(dimText)!);
|
|
123
|
+
} else {
|
|
124
|
+
// Keep as string for macro/enum references
|
|
125
|
+
arrayDimensions.push(dimText);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Collect additional dimensions from arrayDimension syntax
|
|
131
|
+
if (arrayDims.length > 0) {
|
|
132
|
+
arrayDimensions.push(
|
|
133
|
+
...VariableCollector.collectArrayDimensions(
|
|
110
134
|
arrayDims,
|
|
111
135
|
constValues,
|
|
112
136
|
initExpr,
|
|
113
|
-
)
|
|
114
|
-
|
|
137
|
+
),
|
|
138
|
+
);
|
|
139
|
+
}
|
|
115
140
|
|
|
116
141
|
// Issue #282: Capture initial value for const inlining
|
|
117
142
|
const initialValue = initExpr?.getText();
|