Compiler

Yang Compiler — The generative half of Yin

If Yin is the continuation engine, the Yang compiler is its expression engine. Together they form a dual system—Yin for execution, reception, and introspection; Yang for generation, expression, and emission.

Yang transforms high-level intents into continuations that Yin can execute. It shapes the Universal AST (U-AST), seeds migrations, and ensures every emitted agent carries context for the runtime to honor.

Multi-language compiler collection

Yang is not a single compiler—it's a collection of compilers that transform code from different programming languages into the same Universal AST format. Each language compiler understands its source syntax and semantics, then produces the common intermediate representation that Yin executes.

Currently implemented:

  • yang.clojure — Compiles Clojure s-expressions to Universal AST
  • yang.python — Compiles Python syntax to Universal AST

This architecture enables true language interoperability —Python functions can call Clojure functions and vice versa, because both compile to the same Universal AST that Yin understands.

The Clojure compiler

The yang.clojure compiler transforms Clojure s-expressions into Universal AST. Written in .cljc format, it runs identically on both JVM and Node.js.

Compilation pipeline

  • Input: Clojure forms as data (s-expressions)
  • Dispatch: Pattern matching on form structure (literal, symbol, list, special form)
  • Transform: Map Clojure semantics to Universal AST nodes
  • Output: Universal AST maps ready for Yin execution

Supported features

  • Literals (numbers, strings, booleans, collections)
  • Variables (symbol lookup)
  • Lambda expressions (fn [x] (* x 2)){:type :lambda ...}
  • Function application (+ 1 2){:type :application ...}
  • Conditionals (if test then else){:type :if ...}
  • Let bindings (desugared to nested lambda applications)
  • Do blocks (sequential execution via lambdas)

Smart desugaring

The Clojure compiler transforms high-level constructs into simpler primitives:

(let [x 1 y 2] (+ x y))
 ;; Desugars to:
 ((fn [x] ((fn [y] (+ x y)) 2)) 1)

This transformation eliminates the need for a separate let construct in the Universal AST—everything becomes lambdas and applications.

The Python compiler

The yang.python compiler parses Python source text and compiles it to Universal AST. Unlike the Clojure compiler, which operates on already-parsed s-expressions, the Python compiler includes a complete tokenizer and recursive-descent parser .

Three-stage compilation

  • Tokenize: Python source → token stream
  • Parse: Tokens → Python-specific AST (with operator precedence)
  • Compile: Python AST → Universal AST

Tokenizer

The tokenizer breaks Python source into meaningful tokens using regex patterns:

"lambda x: x * 2"
 ;; Tokenizes to:
 [[:keyword "lambda"]
  [:identifier "x"]
  [:colon ":"]
  [:identifier "x"]
  [:operator "*"]
  [:number "2"]]

Parser

The recursive-descent parser constructs a Python-specific AST with proper operator precedence:

Python Python AST
2 + 3 * 4 {:py-type :binop, :op +, :left 2, :right {:py-type :binop, :op *, ...}}

Operator precedence ensures 3 * 4 evaluates before + 2 .

Supported Python features

  • Literals: 42 , "hello" , True , None
  • Variables: x , my_var
  • Lambda expressions: lambda x, y: x + y
  • Function definitions: def double(x): return x * 2
  • Function calls: f(1, 2) , (lambda x: x * 2)(21)
  • Binary operators with precedence: + , - , * , / , == , < , >
  • If expressions: 10 if x > 5 else 20
  • Higher-order functions: (lambda f: f(5))(lambda x: x * 2)

Language interoperability

Because both compilers produce the same Universal AST format, Python and Clojure code can be composed together :

;; Define a function in Python
 (def py-triple
   (yang.python/compile "lambda x: x * 3"))
 
 ;; Define a function in Clojure
 (def clj-add10
   (yang.clojure/compile '(fn [x] (+ x 10))))
 
 ;; Compose them!
 (def composed
   {:type :application
    :operator clj-add10
    :operands [{:type :application
                :operator py-triple
                :operands [{:type :literal :value 5}]}]})
 
 ;; Execute: add10(triple(5)) = add10(15) = 25
 (vm/run initial-state composed)
 ;; => {:value 25}

The Python lambda x: x * 3 and Clojure (fn [x] (+ x 10)) compile to identical Universal AST structures (both are :lambda nodes), so Yin can execute them interchangeably.

Universal AST as lingua franca

The Universal AST serves as the common language between all source languages and the Yin VM:

Source Language Universal AST
lambda x: x * 2 Python {:type :lambda, :params [x], :body {...}}
(fn [x] (* x 2)) Clojure {:type :lambda, :params [x], :body {...}}
x => x * 2 JavaScript (future) {:type :lambda, :params [x], :body {...}}

All three languages compile to the same Universal AST, enabling seamless cross-language function calls and data sharing.

Learn more about how the Universal AST enables cross-language semantic preservation in Yin.vm: Chinese Characters for Programming Languages , how different language semantics map to a unified representation in The Semantic Impedance Mismatch , and how ASTs are stored as queryable datom streams in AST as Higher Dimensional Construction of Datom Streams .

Cross-platform architecture

Both compilers are written in .cljc format— single source code that runs on both JVM and Node.js :

  • JVM: Full Clojure environment with Java interop
  • Node.js: ClojureScript compilation to JavaScript
  • Browser: (Future) In-browser compilation

The compilers use only portable Clojure/ClojureScript features— no platform-specific dependencies in the core logic. Platform-specific I/O (file reading) is isolated in separate yang.io modules.

Documentation & Source

Explore the Yang compiler implementation in depth:

  • Clojure Compiler Source — 226 lines of portable code
  • Python Compiler Source — 450+ lines including tokenizer and parser
  • Clojure Compiler Documentation — Usage examples and implementation details
  • Python Compiler Documentation — Tokenizer, parser, and compiler architecture
  • Multi-Language Architecture — How Yang enables cross-language composition

Where to go next

  • Revisit Yin to see how continuations are scheduled and migrated.
  • Explore DaoFlow to watch emitted continuations shape living interfaces.
  • Study Shibi to combine economic signaling with generated agents.