Compilation Targets¶
ll-lang supports multiple output targets. In 1.0, stable targets are F#, TypeScript, Python, Java, and C#. LLVM IR is available as an experimental subset backend.
See Release Contract 1.0 for compatibility guarantees.
Selecting a Target¶
Use the --target flag with lllc build:
lllc build --target fs file.lll # F# (default)
lllc build --target ts file.lll # TypeScript
lllc build --target py file.lll # Python
lllc build --target java file.lll # Java
lllc build --target cs file.lll # C#
lllc build --target llvm file.lll # LLVM IR (experimental subset)
Accepted aliases: fs / fsharp, ts / typescript, py / python, java / jvm, cs / csharp, llvm / ll.
Stability in 1.0¶
- Stable targets:
fs,ts,py,java,cs - Experimental target:
llvm
The output file uses the appropriate extension (.fs, .ts, .py, .java, .cs, .ll).
F# (default)¶
The F# backend is the primary target and the most complete. All language features are supported. The output is valid F# 8+ with discriminated unions, computation expressions, and [<EntryPoint>].
lllc build file.lll # emits file.fs
lllc build --target fs file.lll # same
F# stdlib helpers are emitted on demand. If a module does not reference ll-lang stdlib symbols, no prelude block is inserted.
TypeScript¶
The TypeScript backend emits ES2020+ TypeScript. Requires TypeScript 4.4+ for const assertions.
lllc build --target ts file.lll # emits file.ts
Type mapping¶
| ll-lang | TypeScript |
|---|---|
Int |
number |
Float |
number |
Str |
string |
Bool |
boolean |
Char |
string |
Unit |
void |
List[A] |
A[] |
Maybe[A] |
A \| null |
Sum types¶
Sum types become TypeScript discriminated unions:
Shape = Circle Float | Rect Float Float | Empty
Emits:
type Shape =
{ _tag: `Circle`; _0: number }
| { _tag: `Rect`; _0: number; _1: number }
| { _tag: `Empty` };
const Circle = (_0: number): Shape => ({ _tag: `Circle` as const, _0 });
const Rect = (_0: number, _1: number): Shape => ({ _tag: `Rect` as const, _0, _1 });
const Empty: Shape = { _tag: `Empty` as const };
Functions¶
Functions are curried arrow functions:
add(a Int)(b Int) = a + b
Emits:
const add = (a: number) => (b: number): number => a + b;
Pattern matching¶
Match expressions become switch-like if/else chains on ._tag.
Stdlib¶
The TypeScript backend emits a compact stdlib helper block on demand: only helpers that are actually referenced in the module/project are generated once as const bindings, then reused at call sites.
Python¶
The Python backend emits Python 3.10+ with from __future__ import annotations.
lllc build --target py file.lll # emits file.py
Type mapping¶
| ll-lang | Python |
|---|---|
Int |
int |
Float |
float |
Str |
str |
Bool |
bool |
Char |
str |
Unit |
None |
List[A] |
list[A] |
Maybe[A] |
Optional[A] |
Sum types¶
Sum types become immutable @dataclass(frozen=True) classes with a _tag field, collected into a Union type alias:
Shape = Circle Float | Rect Float Float | Empty
Emits:
@dataclass(frozen=True)
class Circle:
_tag: str = "Circle"
_0: float
@dataclass(frozen=True)
class Rect:
_tag: str = "Rect"
_0: float
_1: float
@dataclass(frozen=True)
class Empty:
_tag: str = "Empty"
pass
Shape = Union[Circle, Rect, Empty]
Functions¶
Curried functions become nested def statements with return:
add(a Int)(b Int) = a + b
Emits:
def add(a: int):
def _f_b(b: int):
return a + b
return _f_b
Pattern matching¶
Match expressions become ternary if/else chains (Python expressions, not statements).
Stdlib¶
The Python backend always emits typing/import headers, and emits runtime stdlib helpers on demand. Modules that do not reference stdlib helpers avoid runtime-prelude bloat.
External mappings¶
Python also maps external declarations to standard library functions. In this release JSON_parse is emitted as json.loads, and import json is added only when the module/project uses JSON_parse.
Java¶
The Java backend emits Java source with a static-class style runtime prelude, included on demand when stdlib helpers are referenced.
lllc build --target java file.lll # emits file.java
# CLI also prints SDK commands, e.g.:
# suggested compile: javac /.../Main.java
# suggested run: javac /.../Main.java && java Main
C¶
The C# backend emits idiomatic C# with platform types (List<T>, Func<...>), record/interface ADTs, and a compact runtime prelude.
The focus is low-boilerplate target code that still compiles cleanly in generated SDK projects, including self-hosted stdlib artifacts.
The runtime prelude is emitted on demand: modules that do not reference stdlib helpers avoid prelude bloat.
lllc build --target cs file.lll # emits file.cs
External mappings¶
The C# backend maps external declarations to runtime and base-library APIs. JSON_parse currently uses System.Text.Json.JsonSerializer.Deserialize<object>, and using System.Text.Json; is emitted only when needed.
LLVM IR (Experimental)¶
The LLVM backend emits typed LLVM IR with explicit control-flow lowering (if, match) and main lowering suitable for llvm-as validation.
Current supported subset includes integer/float arithmetic (add/sub/mul/div), integer comparisons, direct calls, let-style local bindings, ADT constructor allocation, and list literal/cons lowering via a compact runtime node ABI.
lllc build --target llvm file.lll # emits file.ll (experimental subset)
External mappings¶
LLVM currently supports external console_log(msg Str) Unit via direct symbol declaration/call (@console_log(ptr)).
Limitations¶
Known gaps:
- Trait impls are emitted as standalone functions with a type-name prefix.
- Tag types (
Str[UserId]) are erased to the base type at the target. - LLVM IR is still subset-based (full trait/ADT parity is not complete yet).
Running Multi-Target Output¶
TypeScript¶
lllc build --target ts hello.lll
# SDK run command mirrors CLI `run --target ts`:
npx tsc hello.ts --target es2022 --module esnext && node hello.js
Python¶
lllc build --target py hello.lll
python hello.py
Java / C¶
lllc build --target java hello.lll
## if module tail is Hello, class-aligned mirror is written as Hello.java
javac Hello.java && java Hello
lllc build --target cs hello.lll