The core idea is allowing multiple execution profiles to coexist in a single source file:
- userland (default): indentation-based, Python-like syntax, safety by default - kernel: brace-based syntax, strict rules, no heap or runtime - baremetal: brace-based syntax, raw pointers, no safety net
At build time, a single profile is selected and all other code is erased at compile time — no runtime checks or overhead.
The compiler pipeline is lexer → parser → typed IR → LLVM backend, with profile rules enforced during IR validation rather than at runtime.
Roughly ~90% of the core language and compiler are implemented; I plan to open-source the project once the remaining pieces are finished.
This is still an experiment. I’m mainly curious: - does this model make sense? - are there obvious design pitfalls? - has anyone seen similar approaches succeed or fail?
I’d appreciate critical feedback.
platinumrad•7h ago
Can you expand on this?
JhonPork•6h ago
platinumrad•6h ago
I think I'm missing something really basic. The idea of three different subsets/dialects is interesting, but I would expect all three to be usable at the same time, like how unsafe blocks can be used in the performance-critical sections of a larger Rust program.
JhonPork•5h ago
Falcon’s profiles are not meant to be “dialects you mix freely” like Rust’s unsafe blocks. They represent different execution contracts, not different safety levels inside the same runtime.
In Rust, unsafe still lives inside one program with:
- one allocator - one runtime model - one ABI - one set of linking assumptions
In Falcon, each profile defines a different world:
- userland assumes a runtime: heap, panics, rich abstractions - kernel assumes no runtime: no heap, no panics, stricter aliasing - baremetal assumes no OS at all: raw pointers, direct memory, UB allowed
Mixing them at runtime would force the strongest constraints everywhere, or require dynamic checks — which defeats the goal.
Instead, Falcon treats profiles as compile-time execution modes, not scoped escape hatches.
The reason non-selected profiles are erased before IR is so:
- LLVM never sees incompatible assumptions - no dead-code elimination or guards are needed - profile-specific rules can be enforced structurally, not heuristically
You still share logic by compiling the same source multiple times:
Or: This produces multiple artifacts from one codebase, each valid by construction for its environment.So the comparison isn’t “why not Rust unsafe blocks”, but: “Should fundamentally different execution contracts coexist at runtime, or be selected at compile time?”
Falcon chooses the latter to avoid hidden coupling and runtime cost.