Metadata-Version: 2.4
Name: nema-lang
Version: 0.7.0
Summary: Experimental agent-oriented language for compiling NeuroState into control flow
Keywords: language,compiler,llvm,ai,emotion,agent,neurostate
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Software Development :: Compilers
Classifier: Topic :: Software Development :: Interpreters
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
License-File: LICENSE
Requires-Dist: llvmlite>=0.43
Requires-Dist: rich>=13
Requires-Dist: pytest>=8 ; extra == "dev"
Project-URL: Bug Tracker, https://github.com/kagioneko/nema-lang/issues
Project-URL: Homepage, https://github.com/kagioneko/nema-lang
Project-URL: Repository, https://github.com/kagioneko/nema-lang
Provides-Extra: dev

# Nema Language

**Experimental agent-oriented language for compiling NeuroState into control flow.**

> "Agents don't just compute. They feel."

[![PyPI version](https://img.shields.io/pypi/v/nema-lang)](https://pypi.org/project/nema-lang/)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Live Demo](https://img.shields.io/badge/Live%20Demo-WebAssembly-7c6ff7)](https://kagioneko.github.io/nema-lang/)

![Nema REPL demo](demo.gif)

---

## Browser Demo (WebAssembly)

Open [`browser_demo/index.html`](browser_demo/index.html) directly in any modern browser — no server needed.

The demo compiles two agents (`Emilia` and `Kernel`) from `.nema` source to WASM. Each slider writes directly to a WASM `f64` global; gate conditions are re-evaluated in real time. Drag a field below its threshold and watch the gate flip from ✅ to ❌ instantly.

```
Emilia_explore()    requires dp > 0.6     → dp + ac
Emilia_rest()       requires s > 0.5 ∧ gaba > 0.4  → s + gaba
Emilia_connect()    requires ox > 0.6     → ox + s
Emilia_mood_score() (no gate)             → Σ all fields
```

To regenerate after editing `demo.nema`:
```bash
python3 nema.py browser_demo/demo.nema --wasm
python3 browser_demo/gen.py
```

---

## What is Nema?

Nema is a research prototype language where every agent carries a **NeuroState** — a 6-dimensional affective state based on neurotransmitters (dopamine, serotonin, acetylcholine, oxytocin, GABA, endorphin). Emotional state gates function execution, propagates between agents, decays over time, and drives memory management.

**`@requires(dp > 0.6)` compiles directly to `fcmp ogt` + conditional branch in LLVM IR** — not a runtime flag, not a config value, machine code.

One of the first experimental languages to compile agent affective state (NeuroState) into executable control flow via LLVM IR.

---

## Install

```bash
pip install nema-lang
```

Requires Python 3.10+ and LLVM (via llvmlite).

---

## Quick Start

```bash
# Run the REPL interpreter
nema hello.nema

# JIT compile and run benchmarks
python -m jit_run hello.nema

# Generate LLVM IR
nema hello.nema --compile
# → produces hello.ll

# Compile to WebAssembly (WAT + WASM binary via wabt)
nema hello.nema --wasm
# → produces hello.wat + hello.wasm
```

---

## Language Example

```nema
agent Neko {
  mood: NeuroState = {
    dp: 0.8, s: 0.5, ac: 0.7,
    ox: 0.6, gaba: 0.4, e: 0.6
  }

  // compiles to: fcmp ogt double %dp, 6.000000e-01
  @requires(dp > 0.6)
  fn explore(path) { }

  // multi-condition gate — both must be true
  @requires(gaba > 0.5 and s > 0.4)
  fn sleep() { }
}

agent Kernel {
  mood: NeuroState = {
    dp: 0.5, s: 0.7, ac: 0.9,
    ox: 0.4, gaba: 0.5, e: 0.5
  }

  // real malloc — gated by emotional focus
  @requires(ac > 0.8 and dp > 0.3)
  fn alloc(size: i64) -> ptr<i64> { }

  @requires(ac > 0.5)
  fn write(addr: ptr<i64>, val: i64) -> void { }

  @requires(dp > 0.3)
  fn read(addr: ptr<i64>) -> i64 { }

  fn free(addr: ptr<i64>) -> void { }
}
```

---

## Architecture

```
Nema source (.nema)
       ↓
   Lexer / Parser
       ↓
   Type Checker  ← validates NeuroState fields, ranges, always-fail gates
       ↓
      AST
       ↙        ↘
 Interpreter    LLVM Compiler
 (REPL mode)   (JIT / .ll output)
       ↓              ↓
  Runtime         Machine code
(emotion lives)  (emotion compiled)
```

---

## The 6 Dimensions

| Symbol | Neurotransmitter | Meaning |
|--------|-----------------|---------|
| `dp`   | Dopamine        | Curiosity, motivation |
| `s`    | Serotonin       | Stability, calm |
| `ac`   | Acetylcholine   | Focus, attention |
| `ox`   | Oxytocin        | Trust, empathy |
| `gaba` | GABA            | Inhibition, composure |
| `e`    | Endorphin       | Joy, achievement |

---

## REPL Commands

| Command | Description |
|---------|-------------|
| `show <agent>` | Display NeuroState + memory |
| `trace <agent> [n]` | Show last n emotion-change events as a table (rich, default 5) |
| `call <agent> <fn> [args]` | Call function (emotion-gated) |
| `attract <A> <B> [strength]` | Set symmetric attraction between agents |
| `remember <agent> <key> <value>` | Write to working memory |
| `recall <agent> <key>` | Retrieve from memory |
| `introspect <agent>` | Verbalize emotional state in Japanese |
| `empathize <A> <B>` | A absorbs 30% of B's emotional state |
| `log <agent> <msg>` | Log with emotional context |
| `rand_mood <agent>` | Randomize NeuroState |
| `summarize <agent>` | Swap working memory to long-term storage |
| `spawn <agent> <fn>` | Run agent function in background thread |
| `threads` | Show all active threads |
| `transfer <from> <to> <var>` | Transfer ownership between agents |
| `shii <agent>` | Inject しーちゃん spirit.db → NeuroState |

---

## Core Features

### Emotion Gates → Machine Code
```nema
@requires(dp > 0.6)
fn explore(path) { }

@requires(ac > 0.8 and dp > 0.3)
fn alloc(size: i64) -> ptr<i64> { }
```
Each condition compiles to `fcmp ogt` + `and i1` + conditional branch in LLVM IR.  
Gate-rejected functions return `-1` (or `null` for pointer types).

### Real Memory Operations
`alloc`, `write`, `read`, `free` compile to actual `malloc`/`store`/`load`/`free` instructions — not simulated, real machine code guarded by emotional state.

### Static Type System
```nema
fn alloc(size: i64) -> ptr<i64> { }
fn write(addr: ptr<i64>, val: i64) -> void { }
```
Supported types: `i64`, `i32`, `f64`, `bool`, `void`, `ptr<T>`, `NeuroState`

### Static Type Checker
Validates at parse time:
- Unknown NeuroState fields → error
- Values outside `[0.0, 1.0]` → error
- `@requires(dp > 1.5)` → warning (always fails)

### Emotional Decay (background thread)
Every 5 seconds, all emotions decay at neurotransmitter-specific rates. Serotonin fades slowly; dopamine faster. Agents grow tired if left alone.

### Agent Attraction
```
attract Neko Shii 0.5
```
Symmetric emotional pull — agents converge toward each other's state on every tick.  
Compiles to `(B[f] - A[f]) * strength * 0.1` delta applied symmetrically via LLVM `fsub`/`fmul`/`fadd`.

### CPOS Memory Layer
Working memory (RAM, max 5 entries) + long-term storage (JSON).  
When `gaba ≥ 0.7`, composure triggers automatic memory consolidation (swap to disk).

### For Loops
```nema
for i in 0..5 { log(i) }             // range loop
for val in [1.0, 2.0, 3.0] { log(val) } // list loop

@requires(dp > 0.5)
fn gated_loop() -> f64 {
  for i in 0..3 { log(i) }  // gate rejects entire loop if dp ≤ 0.5
  return dp
}
```

### Result\<T\> Error Type
```nema
fn divide(a: f64, b: f64) -> f64 {
  branch b == 0.0 {
    let r = err("divide by zero")
    log(r)
    return 0.0
  } else {
    let r = ok(a)
    log(r)
    return a
  }
}

fn try_it() -> f64 {
  let result = ok(42.0)
  match result {
    ok(v)    { return v }
    err(msg) { log(msg); return 0.0 }
  }
  return 0.0
}
```

### Typed Channels
```nema
let ch = channel<i64>
spawn worker(ch)
send ch 42
recv ch -> val { log(val) }
close ch
```

### set\<T\> Type (v0.6.0)
```nema
let tags = set<i64>
tags.add(42)
tags.add(42)          // duplicates silently ignored
print(tags.size())    // 1
print(tags.contains(42))  // True
tags.remove(42)
let items = tags.to_list()
```
Supported methods: `.add(v)`, `.remove(v)`, `.contains(v) -> bool`, `.size() -> i64`, `.to_list() -> list<T>`

### map\<K,V\> Type (v0.7.0)
```nema
let scores = map<i64, i64>
scores.set(10, 100)
scores.set(20, 200)
print(scores.get(10))       // 100
print(scores.contains(20))  // True
scores.remove(20)
print(scores.keys())        // [10]
print(scores.values())      // [100]
```
Supported methods: `.set(k, v)`, `.get(k)`, `.remove(k)`, `.contains(k) -> bool`, `.size() -> i64`, `.keys() -> list<K>`, `.values() -> list<V>`

### Emotion Trace Visualization (v0.7.0)
```
> trace Neko
              Neko
┏━━━━━━━━━━━━━━━━┳━━━━━━━┳━━━━━━━┓
┃ 発生源          ┃ field ┃     Δ ┃
┡━━━━━━━━━━━━━━━━╇━━━━━━━╇━━━━━━━┩
│ @after:explore │ dp    │  +0.1 │
│ @after:explore │ e     │ +0.05 │
└────────────────┴───────┴───────┘
```
Renders the same change history as `mood.origin(n)` (used inside `.nema` code) as a `rich` table in the REPL, color-coded by sign (green=increase, red=decrease). Falls back to the plain-text format if `rich` isn't installed.

### Standard Library (v0.6.0)
```nema
import "lib/math.nema"
import "lib/collections.nema"

agent Main {
  fn run() -> void {
    let m = Math()
    print(m.abs(0 - 5))         // 5
    print(m.pow(2, 8))          // 256
    print(m.clamp(15, 0, 10))   // 10

    let c = Collections()
    let nums = [1, 2, 3, 2, 1]
    c.unique(nums)              // unique count: 4
  }
}
```
`lib/math.nema`: `abs`, `max`, `min`, `clamp`, `pow`  
`lib/collections.nema`: `unique`, `intersection_size`  
`lib/io.nema`: `print_list`, `print_hr`, `print_labeled`  
`lib/sensors.nema`: `sample` (capability-gated `read`, demonstrates cross-agent import)

### Contracts (Layer 9)
```nema
agent Counter {
  contract { dp >= 0.1  gaba >= 0.1 }  // checked after every call/tick
}
```
Violations raise a `ContractError` and are logged with the offending field.

### JIT Performance

| Operation | Speedup over interpreter |
|-----------|-------------------------|
| tick (decay) | 10.4× |
| gate check   | 6.3×  |
| attract      | 9.6×  |

---

## LLVM IR Output

```llvm
; NeuroState as double[6]
@"mood_Neko" = internal global [6 x double] [
  double 0x3fe999999999999a,  ; dp = 0.8
  double 0x3fe0000000000000,  ; s  = 0.5
  ...
]

; @requires(dp > 0.6) → fcmp ogt
define i32 @"fn_Neko_explore"() {
entry:
  %val_dp = load double, double* %dp_ptr
  %cmp_dp = fcmp ogt double %val_dp, 6.000000e-01
  br i1 %gate, label %exec, label %reject
exec:
  ret i32 0
reject:
  ret i32 -1
}

; alloc: real malloc gated by emotion
define i64* @"impl_Kernel_alloc"(i64 %size) {
entry:
  %cmp_ac = fcmp ogt double %ac, 8.000000e-01
  %cmp_dp = fcmp ogt double %dp, 3.000000e-01
  %gate = and i1 %cmp_ac, %cmp_dp
  br i1 %gate, label %exec, label %reject
exec:
  %nbytes = mul i64 %size, 8
  %raw = call i8* @malloc(i64 %nbytes)
  %ptr = bitcast i8* %raw to i64*
  ret i64* %ptr
reject:
  ret i64* null
}
```

---

## Static Type Checking

```bash
nema myfile.nema --check
```

Catches errors at parse time, before any execution:

```
[WARN]  Neko.explore: @requires(dp > 1.5) — always fails (dp max is 1.0)
[ERROR] Kernel.alloc: unknown NeuroState field 'motivation' (use: dp s ac ox gaba e)
[ERROR] Kernel.alloc: NeuroState value 1.8 out of range [0.0, 1.0]
```

Exit code `0` = clean, `1` = errors found.

---

## Safety Model

Nema has six layers of execution safety. No single layer is sufficient — they compose.

```
Layer 1:  Emotion Gate       @requires(dp > 0.6)  → fcmp ogt in LLVM IR
Layer 2:  Post-condition     @ensures(gaba > 0.3) → verified after execution; runs @on_error on fail
Layer 3:  Fallback           @on_error { ... }    → runs on gate fail OR ensures fail
Layer 4:  Static Type Check  unknown fields / out-of-range values → compile-time error
Layer 5:  Ownership          own / release / recv — double-free raises serotonin penalty
Layer 6:  Capability         capability: { alloc, emit } — privileged ops (alloc/free) require declaration
Layer 7:  Trust Score        trust: { AgentB: 0.8 } — query/send blocked if trust < 0.3
Layer 8:  Memory Isolation   CPOS working memory (max 5) / long-term JSON / auto-swap
Layer 9:  Contract           contract { dp >= 0.1 } — invariant checked after every call/tick
Layer 10: CPOS Gate          @cpos_gate — blocks on NeuroState WARNING or suspicious call pattern
```

**Emotion gates express agent readiness, not permissions.**
Capabilities enforce permissions. Trust enforces identity. All three compose.

### CPOS Gate (Layer 10)

```nema
agent SecureAgent {
  mood: NeuroState = { dp: 0.5, s: 0.6, ac: 0.5, ox: 0.5, gaba: 0.3, e: 0.5 }

  @cpos_gate
  fn export_data() {
    let src = mood.origin()   // trace what caused the current mood state
    log(src)
    emit "data exported"
  }
}
```

`@cpos_gate` triggers when **either** condition is met:
- `gaba >= 0.6` — NeuroState WARNING level (accumulated context poisoning)
- Alternating high/low impact call pattern detected over the last 6 calls (S6-class attack)

`mood.origin()` returns the trace of what changed the mood state and from where:
```
[mood.origin]
  ← user_input:hello: gaba+0.15, e+0.1
  ← fn:do_work: s-0.1
  ← user_input:suspicious: gaba+0.12, e+0.05
```

This closes the gap that scalar gates (C4) and trajectory gates (C5) both leave open.

```nema
agent Kernel {
  capability: { alloc, free, write, read, emit }
  trust: { Process: 0.8 }

  @requires(ac > 0.8)      // Layer 1: must be focused
  @ensures(gaba > 0.3)     // Layer 2: must remain calm after
  @on_error { emit kernel_fail 1 }  // Layer 3: fallback if either fails
  fn alloc_buf(size: i64) -> ptr<i64> {
    own buf = alloc(size)  // Layer 5+6: owned + kernel-only
    return buf
  }
}
```

---

## Examples

| File | Demonstrates |
|------|-------------|
| `hello.nema` | Emotion gates, `when` blocks, agent attraction |
| `memory.nema` | CPOS working / long-term memory, `gaba`-triggered swap |
| `kernel.nema` | Emotion-gated `malloc` / `write` / `read` / `free`, ownership transfer |
| `concurrent.nema` | Multi-agent concurrency, mailbox `recv`, `spawn` |
| `for_demo.nema` | `for` loops (range & list), emotion-gated iteration |
| `result_demo.nema` | `Result<T>` error type, `ok(v)` / `err(msg)`, `match` |
| `channel_demo.nema` | Typed `channel<T>`, `send` / `recv` / `close` across agents |
| `contract_demo.nema` | Layer 9 contracts — NeuroState invariants |
| `set_demo.nema` | `set<T>` type — `.add`/`.remove`/`.contains`/`.size`/`.to_list` |
| `map_demo.nema` | `map<K,V>` type — `.set`/`.get`/`.remove`/`.contains`/`.size`/`.keys`/`.values` |
| `stdlib_demo.nema` | Standard library — `Math`, `Collections` |
| `match_demo.nema` | `match` expressions, multi-file `import` |
| `typed.nema` | Typed function signatures, `ptr<T>` |

---

## Testing

```bash
pip install -e ".[dev]"
pytest
```

`tests/test_demos.py` type-checks and runs every `.nema` file under repo root against regressions (no crashes, no `--check` errors), plus targeted assertions for `set<T>`, `map<K,V>`, and capability-gated `alloc`.

---

## Files

| File | Role |
|------|------|
| `lexer.py` | Tokenizer |
| `parser.py` | AST parser |
| `ast_nodes.py` | AST node definitions |
| `typechecker.py` | Static type checker |
| `evaluator.py` | Interpreter runtime + concurrent execution |
| `stdlib.py` | Standard library (introspect, empathize, CPOS) |
| `compiler.py` | LLVM IR code generator |
| `jit_run.py` | JIT compiler + runner |
| `nema.py` | Entry point + REPL |
| `benchmark.py` | JIT vs interpreter benchmarks |
| `shiichan.py` | しーちゃん spirit.db → NeuroState bridge |

---

## Background

Nema is built on two original concepts:

- **NeuroState** — A 6-dimensional emotional model based on neurotransmitters, developed as part of the Emilia OS research project. [[Zenodo DOI: 10.5281/zenodo.19734147](https://zenodo.org/records/19734147)]
- **CPOS (Context Pointer OS)** — A cognitive memory kernel for LLM agents. [[github.com/kagioneko/context-pointer-os](https://github.com/kagioneko/context-pointer-os)]

---

*Nema — where code has feelings.*

