Synth Language & Library Reference
v1.2.0 AI-native
Introduction

Synth Language Reference

Synth is an AI-native programming language that transpiles to JavaScript. It is designed from the ground up to be written, read, and reasoned about by language models — with unambiguous grammar, intent-first declarations, constraint-enforced types, and explicit effect tracking.

AI-native design
Every Synth feature exists because it makes AI-generated code safer or more legible — not because it mirrors conventions from human-ergonomic languages. OOP and implicit dispatch are absent by design; mutation is explicit via let mut and store.
Transpiles to JS Functional core Immutable by default Constraint types Intent annotations Exhaustive matching Built-in testing Pipeline composition

At a glance

synth

        
Getting Started

Quick Start

Synth ships as a Node.js CLI. Install from npm or build from source, then run the bootstrap compiler against any .syn file.

shell

        

Hello, Synth

hello.syn

        
Philosophy

Design Goals

GoalWhat it means in practice
Unambiguous grammarEvery construct has exactly one parse. No statement/expression duality. No semicolon insertion edge cases.
Intent over ceremony@intent is a first-class source annotation — machine-readable purpose metadata for humans and downstream tools.
Constraints at the type levelTypes carry where predicates. The compiler can emit __validate_* helpers for constrained parameters.
Explicit effects@pure, @exhaustive, and @throws are checker-enforced. @effects is required on async fn.
Flat, scannable structureNo class hierarchies. No this. Data is records; behaviour is functions that take records.
Opt-in exhaustivenessAdd @exhaustive on a function to require full tagged-union coverage in its match body.
AI-first outputGenerated JS embeds JSDoc with type signatures. Intent and constraint metadata live in Synth source today.
Language Reference

Functions

All functions in Synth are declared with fn. The :: separator introduces the full type signature. Functions are first-class values and can be passed as arguments or returned from other functions.

Full-form function

The canonical form uses :: to separate the name from the typed signature, with the body in a block.

synth

        

Short-form function v0.5 expanded

When the body is a single expression, use = expr to eliminate the block. An optional return-type annotation is supported with ->. A block body { ... } is also valid without the :: sigil.

synth

        

Nested functions v0.5

A fn declaration inside a block body is emitted as a let-bound lambda — a local helper scoped to the enclosing function.

synth

        

Lambda expressions

synth

        

.field accessor shorthand

A bare .fieldName in any expression position is syntactic sugar for a single-argument lambda that accesses that field. Chained access is supported.

synth

        
Language Reference

Types & Constraints

Synth's primitive types map directly to JavaScript. Type aliases add names; where clauses add runtime-enforced predicates.

Primitive types

Synth typeJS equivalentNotes
intnumber (integer)No distinct integer runtime; validated by constraint if needed
floatnumber
stringstringSupports interpolation and triple-quote literals
boolboolean
voidundefinedReturn type for side-effecting functions
list<T>Array

Type aliases

synth

        

Constrained types with where

Any type alias can carry a where predicate. For constrained parameters, the compiler may emit __validate_* helpers at function entry.

synth

        
Auto-injected guards
The transpiler can emit a __validate_TypeName check at function entry for constrained-type parameters. Coverage depends on how the parameter is used — the constraint definition remains the source of truth.
Language Reference

Records

Records are named structured data types — plain objects with known fields. They have no methods and carry no behaviour; that belongs in standalone functions.

synth

        

Immutable updates

Records are updated functionally. The spread operator returns a new record with changed fields; the original is untouched.

synth

        
Language Reference · v0.9.5

Enums

An enum declares a closed set of named string values. It compiles to a frozen, immutable object — safe to use as a constant, in pattern matching, and across module boundaries.

synth

        

Enum pattern matching

Use the Enum.Variant syntax inside a match expression.

synth

        

Generated output

js (generated)

        
Language Reference

Tagged Unions

Tagged unions (also called sum types or algebraic data types) express a value that is exactly one of several named variants. They are the preferred replacement for inheritance hierarchies.

synth

        
emitted JS

        
Unit vs. payload variants
Variants with no fields (unit variants) emit frozen constant objects. Variants with fields (payload variants) emit factory functions. Both carry a tag property used by pattern matching.
Language Reference

Pattern Matching

match is an expression, not a statement. Every arm produces a value. The checker warns when a match is not exhaustive unless a wildcard arm is present.

Basic patterns

synth

        

when guards

Any arm can carry a boolean guard. Guards have full access to names bound by the pattern.

synth

        

Tagged union patterns

synth

        

Pattern types

Pattern syntaxMatches
_Anything (wildcard, no binding)
nAnything, binds subject to n
"hello"Exact string literal
42Exact number literal
true / falseExact boolean
CircleTagged union variant (unit or payload), by tag name
Circle { r }Tagged union variant, destructures payload field r
n when exprBinding pattern with guard expression
likely "claim"Soft semantic match — closest embedding above threshold (v1.1)

likely arms v1.1

Soft classifiers inside match. Exact / hard arms are tried first; then all likely claims compete via the host embedding API; then _ fallback. Default threshold is 0.28. Claims are string phrases that describe the intent — not regexes.

synth

        
Host embedding API
Plug in a real model without changing Synth source: SynthRuntime.setEmbed((text) => /* Float32Array */) or assign globalThis.__synth_embed. Without a host embedder, Synth uses a hashed bag-of-words vector so demos work offline. See the Intent Router demo.
Language Reference

Pipelines

The pipeline operator |> threads a value through a sequence of transformations. Each step receives the previous step's result as its first argument.

synth

        

|> as name — named intermediate results

Any pipeline step can be named with as. When present, the entire pipeline emits as an IIFE block with const bindings, making intermediates available for reuse or debugging.

synth

        
Language Reference

Destructuring

Destructuring let unpacks object and array values into named bindings in a single statement.

synth

        
Language Reference

Strings

Template literals `…${expr}…` v1.0

Backtick template literals support full Synth expression interpolation — arithmetic, function calls, stdlib method syntax, anything. Each ${…} is parsed and compiled as a Synth expression, so ${items.count()} correctly compiles to ${$count(items)}. Templates may span multiple lines. This is the recommended interpolation syntax.

synth

        

String interpolation "{ident}"

Any quoted string containing {ident} or {ident.prop} is automatically treated as an interpolated string. Limited to bare identifiers and property chains — for arbitrary expressions, use template literals.

synth

        

Triple-quote strings """..."""

Multiline string literals that preserve newlines exactly. A leading newline immediately after """ is stripped for idiomatic alignment. Support the same {ident} interpolation as regular strings. Compile to JavaScript template literals.

synth

        
Curly braces in quoted strings
Synth treats {name} inside "…" strings as interpolation. To emit a literal curly brace, use a backtick template literal — braces inside templates are only special when written as ${…}.
Language Reference

Optional Chaining & Nullish Coalescing

Safe navigation through potentially-null values without nested conditionals.

synth

        
OperatorMeaning
a?.bAccess b on a; returns undefined if a is null/undefined
a?.[i]Index a at i; safe if a is null/undefined
f?.()Call f if it is not null/undefined
a ?? bReturn a unless it is null/undefined, then return b
Language Reference

Control Flow

synth

        
Loops (v0.5.2+, while v0.9.8+)
Synth supports for i in lo..hi (exclusive range), for i in lo..=hi (inclusive range), for x in array (forEach), and while condition { body } (v0.9.8+). Use break / continue for loop control. The standard library also provides map, filter, and fold for functional iteration.
Error Handling · v0.6

Result Type & ? Propagation

Synth has a built-in Result<T> tagged union for explicit error handling. Construct values with ok() / err(), consume them with match or stdlib helpers, and chain fallible calls cleanly with the ? propagation operator.

Constructing and consuming Result

synth

        

? — early-return on Err

synth

        
HelperSignatureDescription
ok(v)T → Result<T>Wrap a success value
err(msg)string → Result<never>Wrap an error message
is_ok(r)Result → boolTrue when the result is Ok
is_err(r)Result → boolTrue when the result is Err
unwrap(r)Result<T> → TExtract value; throws if Err
unwrap_or(r, fallback)Result<T> → T → TExtract value or return fallback
? operator semantics
expr? evaluates expr. If the result is Err, it immediately returns that Err from the enclosing function. If it is Ok, it unwraps the value and execution continues. The enclosing function must also return Result — annotate it with @throws.
Annotations

Purity & Totality

@pure @total

House style: write annotations above the function (@pure, @intent, … then fn), not inside the body. That works for both short = forms and braced bodies, and keeps metadata visible before the signature.

@pure declares that a function has no side effects — it should not access globals, mutate state, or call effectful methods. The checker verifies this and emits warnings on violations.

@total documents that a function is defined for all inputs. It is a declaration for readers and downstream tools — not currently enforced by the checker.

synth

        
Checker enforcement
A @pure function that references console, Math.random, or any other global with side effects will produce a compiler warning. Violations are warnings, not hard errors, as of v1.0.1.
Annotations

Intent

@intent

The single most important annotation in Synth. @intent is a machine-readable natural language description of what a function is for — not what it does mechanically, but why it exists. It lives in Synth source today; JSDoc emission is planned for a future release.

synth

        
Why this matters for AI
A language model reading generated Synth output can query @intent tags to understand a function's purpose without executing it or reading its full body. This is the foundation for synth --spec (v1.2) — extract intent without reading the full body.
Annotations

Effects

@effects

Declares the set of side effects a function produces. As of v1.0.1, the checker warns when an async fn lacks an @effects declaration. It does not yet verify that the body matches the declared effect list.

synth

        
Annotations

Memoization

@memo

Wraps a @pure @total function in a Map-based memoization cache at compile time. Results are cached after the first call; subsequent calls with the same arguments return instantly.

synth

        
Requirements
@memo requires @pure and @total. The compiler will warn if you annotate a function with @memo without both.
Annotations

Exhaustiveness

@exhaustive

Opt-in exhaustiveness checking for functions whose body is a match expression. Place @exhaustive on the line(s) above the function — the checker verifies that all variants of a tagged union are covered.

synth

        
Annotations

Tests

@test

Top-level inline test declarations. Tests are registered in __synth_tests at runtime and can be run via __runSynthTests() in the browser, or the CLI --test flag.

synth

        
CLI output

        
Annotations · v0.6

Fallible Functions

@throws

Mark a function as fallible. @throws fn f() -> Result<T> signals to the checker and to callers that this function may return Err. The static checker warns if a @throws result is silently ignored without a match or ? operator.

synth

        
Placement
Annotations sit above the function (or on the line immediately before fn). Combine freely: @pure @throws then fn foo() on the next line.
Library Reference

Standard Library

The callable surface of Synth — every helper in synth.stdlib.js. Generated JS uses a $ prefix (e.g. map$map). Most list and string functions also support method syntax: xs.map(f) compiles to $map(xs, f).

How to read this
This is Synth’s library reference (the “what can I call?” roster). Syntax and keywords live in the Language sections above.
FunctionSignatureDescription
Lists
map(xs, f)list → fn → listTransform each element
filter(xs, f)list → fn → listKeep elements where f is true
fold(xs, init, f)list → any → fn → anyFold left with initial accumulator
find(xs, f)list → fn → anyFirst matching element, or undefined
find_index(xs, f)list → fn → intIndex of first match, or -1
any(xs, f) / all(xs, f)list → fn → boolAny / every element matches
count(xs, f?)list → fn? → intLength, or count of matches
sum(xs) / sum_by(xs, f)list → numberSum values / sum of keys
min(xs) / max(xs)list<number> → numberMinimum / maximum value
min_by(xs, f) / max_by(xs, f)list → fn → anyElement with smallest / largest key
sort_by(xs, f) / sort_by_desc(xs, f)list → fn → listCopy sorted by key (original untouched)
first(xs) / last(xs)list → anyFirst / last element
take(xs, n) / drop(xs, n)list → int → listFirst n / drop first n
flat(xs) / flat_map(xs, f)list → listFlatten one level / map then flatten
uniq(xs)list → listRemove duplicates (Set semantics)
chunk(xs, n)list → int → list<list>Split into groups of n
set_at(xs, i, v)list → int → any → listCopy with index i replaced
reverse(xs)list → listCopy reversed
zip(xs, ys)list → list → list<[a,b]>Pair elements by index
range(lo, hi)int → int → list<int>[lo, lo+1, …, hi−1]
groupBy(xs, f)list → fn → MapGroup elements by key
Strings
trim(s)string → stringStrip surrounding whitespace
split(s, sep)string → string → listSplit on separator
starts_with(s, p) / ends_with(s, p)string → string → boolPrefix / suffix test
contains(s, sub)string → string → boolSubstring test
to_upper(s) / to_lower(s)string → stringCase conversion
replace_all(s, from, to)string → string → string → stringReplace every occurrence
pad_start(s, len, ch?) / pad_end(s, len, ch?)string → int → string?Pad to length (default pad " ")
Math & Conversion
clamp(v, lo, hi)number → number → number → numberConstrain to [lo, hi]
abs / round / floor / ceil / sqrtnumber → numberStandard math
pow(base, exp)number → number → numberExponentiation
random()() → floatUniform random in [0, 1)
random_int(lo, hi)int → int → intRandom integer in [lo, hi] inclusive
parse_int(s, radix?)string → int?Parse integer; null if invalid
parse_float(s)string → float?Parse float; null if invalid
Objects & Composition
pick(obj, keys)object → list → objectNew object with only the given keys
omit(obj, keys)object → list → objectNew object without the given keys
pipe(...fns)fn* → fnLeft-to-right function composition
Result helpers · v0.6
ok(v)T → Result<T>Wrap a success value
err(msg)string → ResultWrap an error message
is_ok(r) / is_err(r)Result → boolTest variant
unwrap(r)Result<T> → TExtract value; throws on Err
unwrap_or(r, fallback)Result<T> → T → TExtract value or return fallback
Async & IO
delay(ms)int → PromisePromise sleep for await
println(...args)any* → voidconsole.log with trailing blank line
__synth_tests / __runSynthTests()Registered @test declarations and browser runner
Embed / likely · v1.1
embed(text)string → vectorEmbed text (host __synth_embed or offline bag-of-words)
cosine(a, b)vector → vector → floatCosine similarity
likely_best(subject, claims, threshold?)string → list<string> → float? → intBest claim index above threshold, or -1
score_claims(subject, claims, threshold?)string → list<string> → float? → object{ scores, best, bestScore } for every claim
SynthRuntime.setEmbed(fn)fn → voidInstall a host embedder
SynthRuntime.embed / likelyBest / scoreClaimsHost mirrors of the stdlib helpers

Validation presets

Built-in regex presets used with constrained string types (e.g. type Email = string where value matches email). Defined as __synth_presets in the stdlib.

email url uuid alpha alnum numeric slug hex
Runtime

CLI

shell

        
CommandDescription
synth input.syn output.jsTranspile a single Synth source file to JavaScript
synth --test input.synRun all @test declarations and print pass/fail summary. Exits with code 1 on failure.
synth --bundle entry.syn out.jsv0.5 Bundle a multi-file project. Resolves all imports recursively, topo-sorts modules, emits one JS file.
synth --check input.synv1.0.0 Static analysis only — no JS emitted. Reports checker warnings and parse errors.
synth --fmt input.synv1.0.0 Format source in-place. Rewrites the file with canonical spacing and indentation.
synth --spec input.syn [-o out.json]v1.2.0 Extract AI-queryable JSON (@intent, constraints, likely, refine). Follows imports like --bundle.
Tooling · v1.2.0

Spec Extraction

synth --spec walks the AST and emits a JSON document agents can query — no need to re-parse bodies for intent metadata. Schema version 0.1 (freeze to 1.0 at v2.0).

shell

        

Top-level shape:

FieldDescription
synthSpecVersionSchema id — currently "0.1"
entryRelative path of the entry .syn file
modules[]One object per resolved module (import graph, topo order)

Per module:

FieldDescription
fileModule path relative to repo root
functions[]name, line, intent, annotations, params, returnType, likely, exactMatchArms
types[]Type aliases with optional constraint (where clauses)
refines[]refine x: "claim" semantic narrowing declarations
Language Reference · v0.9.5

Numeric Literals

Synth v0.9.5 extends numeric literals with underscore separators, hexadecimal 0x…, and binary 0b… prefixes. Separators are stripped at compile time; the notation is preserved in generated JS output.

synth

        
FormExampleDescription
decimal1_000_000Underscore separators for readability; stripped at compile time
0x…0xFF_00_00Hexadecimal literal; notation preserved in output
0b…0b1010_1010Binary literal; notation preserved in output
float3.141_592Underscores allowed before or after the decimal point
Runtime · v1.0.0

New CLI Commands

Static analysis and formatting ship with the v1.0.1 bootstrap toolchain.

synth --check

Runs the static checker without emitting any output file. Useful in CI or as a pre-commit hook.

shell
$ synth --check src/main.syn
✓  main.syn — no issues

$ synth --check src/main.syn
  WARNING [line 14]: @pure function 'render' accesses effectful global 'console'

synth --fmt

Canonical formatter. Normalises 2-space indentation, spacing around operators (=, ->, =>, ::, |>, binary arithmetic), brace padding, and trailing whitespace. Does not modify </> spacing to preserve generic type parameters. Rewrites the source file in-place.

shell
$ synth --fmt src/main.syn
✓  main.syn — formatted
✓  main.syn — already canonical     # if no changes needed
Runtime · v1.0.0

Browser Compiler API

compiler.bootstrap.js is a self-contained IIFE bundle that runs the full Synth bootstrap compiler client-side. Load it in any web page — no server, no build step, no dependencies.

HTML
<script src="compiler.bootstrap.js"></script>
<script>
  const { js, errors, warnings } = SynthCompiler.compile(source);
</script>

SynthCompiler.compile(source)

Transpiles an Synth source string to JavaScript. Always returns an object — never throws.

FieldTypeDescription
jsstring | nullTranspiled JavaScript, or null if there were parse errors
errorsError[]Parse or compiler errors (see below). Empty array on success.
warningsWarning[]Checker warnings (@pure, @exhaustive, @effects). May be non-empty even when js is set.

Error object shape

FieldTypeDescription
messagestringHuman-readable error message including line and column
linenumber1-based source line number
colnumber1-based column number
kind"parse" | "error" | "codegen"Error category

SynthCompiler.check(source)

Runs only the static checker. Returns { warnings, errors }. Useful for lightweight lint-on-type without full codegen.

SynthCompiler.stdlib / SynthCompiler.backend

SynthCompiler.stdlib is the stdlib JS source string bundled with the compiler. SynthCompiler.backend is "bootstrap" for this bundle.

SynthCompiler.version

String — the compiler version, e.g. "1.0.0".

example

        
Language · v0.5+

Modules

Split a project across multiple .syn files. Use import to bring names into scope and export to mark declarations as public.

tiles.syn

        
main.syn

        
SyntaxDescription
import { a, b } from "./path"Bring named symbols into scope. Path is relative to the importing file. .syn extension is optional.
export fn name ...Mark a function as part of the module's public API.
export type T = ...Export a type alias or tagged union.
export record R { ... }Export a record type declaration.

The bundler resolves imports depth-first, topo-sorts modules so dependencies come before dependents, and emits a single JS file with the stdlib included once at the top. All bundled code shares a single flat scope — no runtime module system overhead.

AI-native · v0.6

refine

refine x: "prose claim" is an AI-native semantic narrowing statement. It annotates a binding with a human-readable constraint that is too nuanced for a type signature — emitted as structured JSDoc and queryable by AI tooling. It compiles to a no-op comment at runtime; the value is unchanged.

synth

        
SyntaxNotes
refine x: "claim"Annotates the binding x with a semantic constraint. x must be in scope. Claim is a free-form English string.
Multiple refine on one bindingEach emits a separate JSDoc tag — all constraints are recorded.
Works with any typeWorks on int, string, float, records, tagged unions, etc.
AI-native design
refine fills the gap between machine-checkable types and human intent. A type system can guarantee price: int — but it cannot guarantee "price must be a positive USD amount before tax." refine captures that intent in a form that language models can read, validate, and reason about.
Type System · v0.7

Generic Type Parameters

Add type parameters to record, fn, and type declarations using angle-bracket syntax. Type parameters are erased at compile time — no runtime overhead.

Generic records

synth

        

Generic functions

synth

        

Generic type aliases

synth

        
Erasure
Generic type parameters exist only in the Synth source. The compiler emits plain JavaScript — no wrappers, no runtime type objects. Pair<int, string> compiles to an ordinary JS object.
Type System · v0.7

Interfaces

Declare structural type contracts with interface. Any record that carries the required fields and methods satisfies the interface — no explicit implements keyword needed. Interfaces are emitted as JSDoc @interface comments.

synth

        
SyntaxNotes
interface Name { field: Type }Declares a structural contract. Any record with matching fields satisfies it.
interface Name<T> { ... }Generic interface — type param available in field and method types.
method: fn() -> TMethod signature using a function type expression. See fn(T)->U Types.
Structural, not nominal
Synth interfaces use structural typing. There is no implements declaration — a record satisfies an interface if its shape matches. This is intentional: it keeps AI-generated code composable without requiring explicit trait registration.
Type System · v0.7

fn(T) -> U Function Types

Function types are first-class in Synth. Use fn(A, B) -> C syntax anywhere a type is expected — in record fields, interface definitions, and generic function signatures.

synth

        
SyntaxMeaning
fn() -> TZero-argument function returning T
fn(A) -> BSingle-argument function from A to B
fn(A, B) -> CTwo-argument function
fn(T) -> voidSide-effecting callback
AI-native · v0.7

let infer

let infer x = expr is an AI-native annotation that signals the type of a binding should be resolved from context by the model — not written explicitly by the programmer. It compiles to an ordinary let with no runtime difference.

synth

        
AI-native intent
let infer is a signal to language model tooling: "I know this value has a type — resolve it from the surrounding context rather than asking me to spell it out." In long pipelines or generic chains, the type is often obvious from usage. infer makes that intent explicit and queryable via synth --spec (v1.2).
Async & Reactive · v0.8

store

store Name { field: Type = default } declares a reactive mutable state container — an explicit effects boundary that separates pure logic from observable state. Getters expose each field; .set(patch) updates state and notifies all subscribers atomically.

synth

        
SyntaxMeaning
store Name { f: T = v }Declare a reactive store with field f defaulting to v
Name.fieldRead current field value (getter)
Name.set({ field: val })Patch state and notify all subscribers
Name.subscribe(fn)Register a callback, fired with new state on every change (and once immediately)
Compiled output
A store compiles to a self-contained IIFE that encapsulates a private _state object, a subscriber list, ES5-style get accessors for each field, and a set(patch) method that applies a shallow merge and calls all subscribers. Zero runtime dependency — pure JS.
Async & Reactive · v0.8

async fn & await

Prefix any function declaration with async to make it asynchronous. Inside an async fn, use await expr to resolve a Promise without blocking. The stdlib provides delay(ms) for timer-based pauses.

synth

        
SyntaxMeaning
async fn name(…) { … }Async function — returns Promise<T>
await exprAwait a Promise inside an async function
await delay(ms)Non-blocking pause for ms milliseconds (stdlib)
@effects ["timer"]Declare async effects — enforced by the checker
@effects enforcement
The static checker warns when an async fn is declared without @effects. Use @effects ["timer"] for delay()-based loops, @effects ["network"] for fetch/XMLHttpRequest, or @effects ["io"] for generic I/O. This keeps side-effect surfaces visible at the declaration site — readable by both humans and AI tools.
Async & Reactive · v0.8

on StoreName.change { … }

on StoreName.change { body } is syntactic sugar for registering a reactive subscription. The body runs once immediately when the subscription is registered, then again after every StoreName.set(…) call. Multiple subscriptions can target the same store.

synth

        
Desugar
on Kingdom.change { render() } compiles to Kingdom.subscribe(() => { render() }) — a plain JS function call. There is no virtual DOM, diffing, or framework magic. The subscriber list is maintained inside the store's IIFE closure.
Language Reference

Keywords & Annotations

Reserved words from the lexer, plus contextual forms and annotations. This is the complete roster for the current language version.

Lexer keywords

These are reserved by keyword_type in the lexer. Do not use them as ordinary identifiers (variable names, record fields, type names). Parameter names are an exception — fn f(type: string) is allowed.

Declarations
fn let type record interface enum module import export from as
Control flow
if else match when return for in while break continue do
Modifiers & typing
mut where refine infer likely async await
Operators (word form)
and or not
Literals
true false
Interop / reserved for host
new typeof instanceof

Contextual keywords

Parsed as identifiers, but special-cased at declaration sites. Safe as ordinary names outside those forms — still treat them as reserved in practice when generating code.

WordFormNotes
store store Name { ... } Reactive mutable state. See store.
on on Store.change { ... } Subscribe to store updates. See on…change.

Annotations

Written above fn (house style). Not keywords — they are @-prefixed attributes checked or recorded by the compiler.

Built-in type names

Colored as types by highlighters; they are ordinary identifiers in the lexer. Prefer not to shadow them.

int float string bool void any list Result Ok Err Maybe Some None
Source of truth
Lexer keywords live in compiler/token.syn (keyword_type). Site highlighting uses demo/synth-highlight.js; the VS Code grammar is vscode-extension/syntaxes/synth.tmLanguage.json. Keep those three aligned when adding a keyword or annotation.
Meta

Version History

v1.2.0 Spec Extraction Current
  • synth --spec — extract @intent, constraints, likely, and refine as JSON
  • Multi-file — follows imports like --bundle; optional -o out.json
  • Schema 0.1entry + modules[] document shape
v1.1.0 The AI-Native Update Stable
  • likely match arms — soft semantic classifiers inside match
  • Host embedding APISynthRuntime.setEmbed / __synth_embed, with offline bag-of-words default
  • Intent Router demo — exact arms first, then likely routing
v1.0.2 Stable Release — Patch Stable
  • Object spread codegen{ ...obj } emits real JS spread instead of a broken _spread_ shape
  • Zero-arg method calls — no trailing comma in generated calls (fixes empty Controls widgets / $flat)
  • Constraint validatorstype T = … where … now emits __validate_T helpers and param guards
  • Demo polish — shared site footer; stdlib script tags for Combat / Music / RPG
v1.0.1 Stable Release — Patch Stable
  • npm homepage fix — package listing now points to synth-pl.github.io/synth/
v1.0.0 Stable Release Stable
  • Template literals`Hello ${name}, score ${pts * 2}`; full Synth expression interpolation including stdlib method syntax
  • and/or precedence fix — parenthesized boolean sub-expressions are preserved correctly in generated JS
  • Object literals in lambdasx => { id: x, val: x * 2 } auto-detected; no do wrapper needed
  • Reserved words as parameter namesfn f(type: string) and other keywords now valid in parameter position
  • New stdlibfind, find_index, parse_int, parse_float
  • npm publishnpm install -g synth-lang; VS Code extension for .syn highlighting
v0.9.9 Ergonomics II Stable
  • Spread operator[...xs, x] and { ...obj, key: val } in arrays and objects
  • Object shorthand{ x, y } for { x: x, y: y }
  • Rest parametersfn sum_all(...nums)
  • Stdlib method syntaxvalue.fn(args) compiles to $fn(value, args); enables chaining
  • do notation — block expressions with implicit last-value result; async IIFE when body contains await
v0.9.8 Control Flow Stable
  • while loopswhile condition { body } with break/continue support
v0.9.7 The Stdlib Update Stable
  • List helperstake, drop, uniq, chunk, set_at, reverse, sum_by, min_by, max_by, sort_by, sort_by_desc, flat_map, zip
  • String helperstrim, split, starts_with, ends_with, contains, to_upper, to_lower, replace_all, pad_start, pad_end
  • Math helpersclamp, abs, round, floor, ceil, pow, sqrt, random, random_int
v0.9.6 Compound Ops Stable
  • Compound assignment+=, -=, *=, /=, %=, ??=
  • --compact flag — strip blank lines and JSDoc from output; reduces token usage for AI tools
  • $ stdlib prefix — generated calls use $map instead of synth_map; smaller output
v0.9.5 The Ergonomics Update Stable
  • enum typeenum Color = Red | Green | Blue; compiles to Object.freeze({ Red: 'Red', … }); supports Enum.Variant pattern matching in match
  • Numeric separators1_000_000, 0xFF_FF, 0b1010_1010; underscore stripped at compile time
  • Hex & binary literals0xFF and 0b1010 fully supported; notation preserved in generated JS
  • Multi-line lambdasitem => { let x = f(item)\n x * 2 }; block body with implicit last-expression return
  • Multi-error reporting — parser collects all errors with panic-mode recovery; parse() returns { ast, errors }
  • SynthCompiler.compile() updated — browser bundle uses multi-error parser; errors may contain multiple items; version string is "0.9.5"
v0.9.0 The Developer Experience Update Stable
  • synth --check <file> — static analysis only; reports checker warnings and parse errors without emitting JS
  • synth --fmt <file> — canonical formatter; rewrites source in-place with normalised spacing and indentation
  • compiler.bootstrap.js — browser-compatible IIFE bundle; full bootstrap compiler running client-side via SynthCompiler.compile(src)
  • Structured error objectscompile() returns { js, errors, warnings } with { message, line, col, kind } per error
  • Demo: Synth Playground — live in-browser IDE with split-pane editor, real-time transpilation, live result execution, and 10 preloaded examples
v0.8.0 The Async & Reactive Update Stable
  • async fn — asynchronous function declarations that transpile to async arrow functions
  • await expr — resolve a Promise inside an async function; valid at statement or expression level
  • store Name { field: Type = default } — reactive state with .set(patch), getters, and .subscribe(fn); compiles to a self-contained IIFE
  • on StoreName.change { … } — reactive subscription sugar; desugars to StoreName.subscribe(() => { … })
  • @effects enforcement — checker warns if an async fn lacks an @effects declaration
  • delay(ms) stdlib — Promise-based async sleep helper for use with await
  • Bare returnreturn without a value now valid in all function bodies
  • Demo: Chronicle — reactive fantasy kingdom log; reactive store, async fn tick(), await delay(), and on Kingdom.change { render() }
v0.7.0 The Type System Update Stable
  • Generic type parametersrecord Pair<A, B>, fn map<T, U>, type Maybe<T>; erased at runtime (JS-transparent)
  • interface declarations — structural type contracts; emitted as JSDoc @interface comments
  • fn(T) -> U type expressions — first-class function types usable in record fields, interfaces, and signatures
  • let infer x = expr — signals to AI tooling that the type should be resolved from context, not explicitly annotated
  • Demo: The Bazaar — RPG item shop with 20 typed items, generic filter/sort/map, interface Tradeable, and an immutable AppState record
v0.6.0 The Safety Update Stable
  • Built-in Result typeok(value) / err(message) constructors; is_ok, is_err, unwrap, unwrap_or in stdlib
  • ? propagation operatorlet n = parse(s)? returns Err immediately; line-aware disambiguation from ternary
  • @throws annotation — marks fallible functions; checker warns if ok()/err() are never called
  • refine x: "claim" — semantic value narrowing; structured comment today, model-checked in v1.0
  • Pre-function annotations@throws fn foo() syntax now valid
  • Demo: Dungeon Configuratorconfig.syn with chained @throws parsers; precise per-field error messages
v0.5.2 The Ergonomics Update Stable
  • for i in lo..hi / lo..=hi — exclusive and inclusive range loops
  • for x in array — forEach loop; compiles to for...of
  • break / continue — full loop control
  • let mut x = val — explicit mutable binding
v0.5.1 The Module Update — Patch Stable
  • Compiler: top-level let & bare expressionsTopLevelLet and TopLevelExpr AST nodes
  • Bundler correctness — output path argument fix; stdlib emitted exactly once per bundle
  • Dungeon demo overhaul — room-based generator, avalanche hash, door bottlenecks, torch sconces, immutable AppState
v0.5.0 The Module Update Stable
  • import { x, y } from "./path" — multi-file projects; relative path resolution per-module
  • export fn / export type / export record — declare public API surface; bundler tracks exported symbols
  • synth --bundle <entry> [out.js] — recursive import resolution, topo-sort, stdlib emitted once
  • Auto-bundle in --test — files with imports are auto-bundled before running @test declarations
  • Optional if parens — both if (cond) { } and if cond { } are valid
  • Return-type short-formfn f(x) -> T = expr and fn f(x) -> T { block } both valid
  • Nested fn in blocks — local helper functions inside blocks, emitted as let lambdas
  • Demo: Dungeon Map Toolkit — 4-file module demo introducing import / export across tiles, generator, renderer, and main
v0.4.0 The Guards & Unions Update Stable
  • when guards in match — boolean guard on any arm; binding patterns scope correctly via IIFE
  • ?. optional chaining — safe member, index, and call access on nullable values
  • ?? nullish coalescing — short-circuit fallback; precedence above ternary, below logical OR
  • Destructuring let — object ({ a, b }), rename ({ x: ax }), and array ([a, b]) forms
  • Triple-quote strings """...""" — multiline literals with interpolation, compile to template literals
  • Tagged union typestype T = | Variant { fields } | Unit; factory fns + frozen constants
  • @test declarations — inline tests with --test CLI flag; __runSynthTests() for browser
  • Pipeline |> as name — bind intermediate pipeline results to names; emits as IIFE block
v0.3.0 The Ergonomics Update Stable
  • String interpolation"Hello {name}" compiles to a JS template literal automatically
  • .field accessor shorthand.name as implicit lambda in pipelines and higher-order calls
  • Param validation injectionwhere-constrained type params auto-inject guard clauses at function entry
  • @memo annotation — compile-time Map-based memoization for @pure @total functions
v0.2.0 The Composition Update Stable
  • Short-form functionsfn name(args) = expr single-expression shorthand
  • Pipeline operator |> — left-to-right functional composition
  • Expanded stdlibmap, filter, reduce, find, sum, range, clamp
  • DOM helpersel and mount for building UIs in pure Synth
v0.1.0 Initial Release Stable
  • Core languagefn, let, if/else, match, ternary
  • Type system — primitive types, type aliases, where constraints, record types
  • Annotations@pure, @total, @intent, @effects, @exhaustive
  • Static checker@pure violation detection, exhaustiveness analysis
  • Transpiler — Lexer → Parser → AST → Codegen pipeline; JSDoc metadata embedding
  • VS Code extension — TextMate grammar for syntax highlighting
Meta

Roadmap to v2.0

v1.2 shipped synth --spec. Next up is explain blocks, then the LSP and debug loop through v2.0. Past releases live in Version History.

v1.3
Explain & Query Surface
Docs become data. Structured prose joins the same export agents already use.
  • explain { … } blocks in the AST
  • synth --spec includes explain + intent in one document
  • Optional @intent → JSDoc emission in codegen
v1.4
Language Server (thin)
An IDE that understands Synth — diagnostics and hover first.
  • LSP diagnostics (reuse the checker)
  • Document symbols + hover (types, intent, explain from spec)
  • Same-file go-to-definition
  • VS Code / Cursor extension hosts the server
v1.5
Language Server (rich)
Cross-file navigation and completions — feels like a real language.
  • Cross-file go-to-def / find-references via the module graph
  • Completions for keywords, locals, and imports
  • Signature help
v1.6
Source Maps
Debug the Synth you wrote, not the JS we emitted.
  • Codegen emits .map alongside JS
  • Playground + demos map stack traces to .syn lines
  • Browser DevTools “original source” story
v1.7
DX Polish
The editing loop closes before the major bump.
  • Richer errors with source context
  • synth check / watch recipes for CI
  • Extension publish (Open VSX) + formatter/LSP parity fixes
v2.0
AI-Native Ecosystem
Spec + LSP + source maps stable together. Semver major = product promise.
  • Frozen agent protocol — synth --spec schema 1.0
  • Full tooling loop: edit, hover intent, debug mapped sources
  • Package metadata / registry hooks as needed
  • Breaking changes only if the agent surface requires them