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"
A 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}}));"
A function that takes a JSON value and returns its stringified form.

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"
A string-keyed dictionary, generic over its value type.

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;"
A module whose setup pulls in each host's random-number facilities.

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();"
Root setup recording the program's start time on each target.

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.