Keywords · NATIVE
NATIVE
The NATIVE keyword lets you specify platform-specific code for a particular target.
Format
The grammar of a single NATIVE line:
NATIVE ::= "NATIVE" target string
target ::= "dart" | "swift" | "js" | "nodejs" | "ts" | "go" | "rust" | "zig" | "glsl" | "php"
NATIVE keyword is followed by the target name and then a string of code in that target.Usage
A NATIVE keyword can live inside FUNCTION,
TYPE, and
MODULE keywords, or at the Root.
Inside a FUNCTION
Provides that function's platform-specific implementation for one target.
FUNCTION Text ToString
INPUT Code.Language.Json.Value input
NATIVE dart "return jsonEncode(Code_Language_Json_Value._unionToRaw({{input}}));"
NATIVE swift "return Code.Language.Json.Value.toJsonString({{input}})"
NATIVE js "return JSON.stringify(Code.Language.Json.Value._unionToRaw({{input}}));"
Each line is the function's body on that target, given verbatim in its own idiom — so the same
union is the dotted Code.Language.Json.Value in Swift and JavaScript but the
_-joined Code_Language_Json_Value in Dart. Anything the function provides
— its INPUT and
HOLE parameters, and any generic type — is
inserted into the native code wrapped in {{ }} around its name, as with the
{{input}} above, so the compiler can process it before splicing it in. A Program body, where
present, is the fallback for any target with no NATIVE line.
Inside a TYPE
Gives that type's native representation — the host type used in place of a Program record.
TYPE Dictionary<ValueType>
NATIVE dart "Map<String, {{ValueType}}>"
NATIVE swift "[String: {{ValueType}}]"
NATIVE js "Object"
Dictionary is generic over one type-checked argument, ValueType, with keys
always Text. Each NATIVE line inserts {{ValueType}} where the value
type belongs, and the compiler lowers it generically, substituting each target's own host type — so
Dictionary<Text> becomes Map<String, String> in Dart and
[String: String] in Swift. A type may also mix NATIVE lines with
FIELD or
OPTION members as the fallback.
Inside a MODULE
Runs per-target setup once, when the module is first used in a program.
MODULE Random
NATIVE dart "import 'dart:math';"
NATIVE swift "import Foundation"
NATIVE js "const _rng = Math.random;"
Tied to no single definition, it prepares the host environment — an import, a global — that the module's declarations rely on.
At the Root
Runs always, as part of the program itself — setup tied to no module.
NATIVE dart "final startedAt = DateTime.now();"
NATIVE swift "let startedAt = Date()"
NATIVE js "const startedAt = Date.now();"
With no enclosing definition, the line runs as part of the program itself, in source order.
In every case the dart, swift and js rows are required;
nodejs, ts, go, rust, zig,
glsl and php may follow. TypeScript needs no row of its own: the
js body is valid TypeScript, and is reused unless a ts row overrides it.
Can Contain
Nothing. A NATIVE is a leaf: a target name and a verbatim string. It has no body and
opens no indented lines — the whole line is one target's host code.
Targets
The same example, rendered to each target.
A function with only NATIVE lines renders to just the targets it gives a body for. This
ToString has no Program body to fall back on, so Go, Rust and Zig each need their own
NATIVE line before they can be built.
JavaScript
function ToString(input) {
return JSON.stringify(Code.Language.Json.Value._unionToRaw(input));
}
TypeScript
// no `ts` NATIVE row, so the `js` body is reused verbatim — JS is valid TS
function ToString(input: Code.Language.Json.Value): string {
return JSON.stringify(Code.Language.Json.Value._unionToRaw(input));
}
Dart
static String ToString(Object input) {
return jsonEncode(Code_Language_Json_Value._unionToRaw(input));
}
Swift
public static func ToString(_ input: Any) -> String {
return Code.Language.Json.Value.toJsonString(input)
}
Go
// no `go` NATIVE body, so ToString is not generated for Go;
// add a go NATIVE row before building for Go.
Rust
// no `rust` NATIVE body, so ToString is not generated for Rust;
// add a rust NATIVE row before building for Rust.
Zig
// no `zig` NATIVE body, so ToString is not generated for Zig;
// add a zig NATIVE row before building for Zig.
JSON
["N", "ToString", [], [["input", "Code.Language.Json.Value"]], [
["dart", "return jsonEncode(Code_Language_Json_Value._unionToRaw(input));"],
["swift", "return Code.Language.Json.Value.toJsonString(input)"],
["js", "return JSON.stringify(Code.Language.Json.Value._unionToRaw(input));"]
], "Text"]
Related
A NATIVE line is one target's body for a
FUNCTION; the function's parameters are
INPUT and HOLE.
A function written purely in Program has a body of LET
bindings instead, and one may mix the two — native lines with a Program body as the fallback. The
enclosing function lives at the Root or inside a
MODULE. Back to
the language.