Skip to content

cschoell/aion-agentic-language

Repository files navigation

Aion Language

A programming language designed to be optimal for AI agents to generate and reason about, while remaining readable for humans.

Version 0.7.0-dev — Tree-walking interpreter + bytecode compiler/VM · 231 passing tests � IntelliJ plugin · Multi-file imports · Pre-type-checker

Design Principles

1. Every construct starts with a unique keyword

An AI can predict the full syntactic shape from the first token alone:

First token Shape
fn function definition
let immutable binding / destructuring
mut mutable binding
type record / alias / newtype
enum sum type
match exhaustive pattern match
const module-level constant
import module import
for iteration / tuple destructuring loop
@pure @io @async effect annotation (precedes fn)
@tool @requires @ensures agent-contract annotation (precedes fn)
@on_fail structured failure hint for agent-callable tools
@test unit-test annotation (collected by aion test)

2. Effect annotations on every function

@pure  fn add(a: Int, b: Int) -> Int { ... }
@io    fn read_file(path: Str) -> Result[Str, Str] { ... }
@async fn fetch(url: Str) -> Result[Str, Str] { ... }

An AI can reason about what a function does without reading its body.

3. Agent-contract annotations

@tool
@pure
@requires(b != 0)
@ensures(result * b == a - a % b)
@on_fail("b must not be zero — retry with a non-zero divisor.")
fn safe_div(a: Int, b: Int) -> Int {
    describe "Divides a by b. Safe for agent use."
    return a / b
}

@tool marks an agent-callable function. @requires / @ensures are machine-checkable pre/post-conditions. @on_fail wraps any failure as err(ToolError { hint, cause }) so the agent loop can self-correct without unwrapping a Java stack trace.

4. No nulls — explicit Option and Result

@pure fn find(xs: List[Int], n: Int) -> Option[Int] { ... }
@pure fn divide(a: Float, b: Float) -> Result[Float, Str] { ... }

// Propagate errors with ?
let val = divide(a: x, b: y)?   // returns Err early if b == 0

5. Named arguments everywhere

greet(name: "Alice")
safe_divide(a: 10.0, b: 3.0)
User { name: "Bob", age: 25 }

No positional surprises. AI generates self-documenting call sites.

6. Pipeline operator >>

let result = 3 >> double >> increment >> str

Linear data flow — trivially verifiable left-to-right.

7. Exhaustive pattern matching with guards

match age {
    n if n < 13 => "child",
    n if n < 18 => "teenager",
    n if n < 65 => "adult",
    _           => "senior",
}

Every match must be exhaustive. Pattern guards allow inline conditions without nested if.

8. Types: records and enums only

No class hierarchies. No inheritance. No implicit interfaces.

type Point = { x: Float, y: Float }

enum Shape {
    Circle(Float),
    Rectangle { width: Float, height: Float },
}

Language Features

Numeric literal forms

All common bases and digit separators are supported for readability:

const MAX_BYTE:  Int = 0xFF          // hex
const FLAGS:     Int = 0b1111_0000   // binary with separator
const UNIX_RWX:  Int = 0o777         // octal
const MILLION:   Int = 1_000_000     // decimal with separator

Module imports

Split programs across files; import entire modules or select specific names:

import math_utils                    // import all declarations
import math_utils as mu              // import with alias
import math_utils { abs, clamp }     // selective import — only abs and clamp
import math_utils { abs, MAX_BYTE }  // mix functions and consts

Imports are resolved relative to the source file. Transitive imports and cycle detection are built in.

Range expressions

Produce a List[Int] inline — usable in for loops or as a value:

for i in 1..10  { print(i) }   // exclusive: 1 to 9
for i in 1..=10 { print(i) }   // inclusive: 1 to 10
let squares = (1..=5) >> map(fn(n: Int) -> Int { return n * n })

Destructuring let

Unpack record fields or tuple positions in a single binding:

type Point = { x: Int, y: Int }
let p = Point { x: 3, y: 4 }
let { x, y } = p                // record destructure

let pair = (10, 20)
let (a, b) = pair               // tuple destructure

Tuple for destructuring

Iterate over a list of tuples and unpack each element directly:

let pairs = [(1, "one"), (2, "two"), (3, "three")]
for (n, name) in pairs {
    print("${n} = ${name}")
}

Lambda expressions (first-class functions)

let double = fn(x: Int) -> Int { return x * 2 }
let evens  = numbers.filter(fn(x: Int) -> Bool { return x % 2 == 0 })
let result = numbers.map(fn(x: Int) -> Int { return x * 2 })

Refinement types

Constraints checked on every assignment:

type AgentID = Str where { self.starts_with("did:aion:") }
type Score   = Int where { self >= 0 and self <= 100 }

let id: AgentID = "did:aion:abc123"   // ok
// let bad: AgentID = "not-an-id"     // runtime error: constraint violated

Named return variables

fn stats(xs: List[Int]) -> (Int, Int) return (min_val, max_val) {
    mut min_val = xs[0]
    mut max_val = xs[0]
    for x in xs { ... }
}

Built-in test runner

Annotate functions with @test and run them with aion test:

@test
fn test_add() {
    assert add(a: 2, b: 3) == 5
}
aion test src/main/resources/mymodule.aion
# PASS test_add
# 1 passed, 0 failed

Syntax Quick Reference

// Constants — all numeric literal forms
const PI:      Float = 3.14159
const MAX_U8:  Int   = 0xFF
const FLAGS:   Int   = 0b1010_1010
const PERMS:   Int   = 0o755
const MILLION: Int   = 1_000_000

// Immutable / mutable bindings
let x: Int = 42
mut counter = 0
counter = counter + 1

// Destructuring let
let { name, age } = user          // record fields
let (first, second) = my_tuple    // tuple positions

// String interpolation
let msg = "Hello, ${name}! You are ${age} years old."

// Function with agent contract
@tool
@pure
@requires(score >= 0 && score <= total)
@ensures(result >= score)
fn award_point(score: Int, total: Int, correct: Bool) -> Int {
    describe "Increments score if correct, bounded by total."
    return match correct {
        true  => score + 1,
        false => score,
    }
}

// Record type
type User = { name: Str, age: Int }

// Enum (sum type)
enum Shape {
    Circle(Float),
    Rectangle { width: Float, height: Float },
}

// Record / enum literals
let u = User { name: "Alice", age: 30 }
let s = Shape::Circle(5.0)

// Match with guard and enum record pattern
let area = match shape {
    Shape::Circle(r)                   => PI * r * r,
    Shape::Rectangle { width, height } => width * height,
}

// Option / Result
let maybe: Option[Int] = some(42)
let result: Result[Float, Str] = ok(3.14)
let val = risky_call()?     // propagate Err/None

// Pipeline
let out = input >> trim >> parse >> validate

// Range expressions
for i in 0..10  { print(i) }    // exclusive
for i in 0..=10 { print(i) }    // inclusive

// Tuple for-destructuring
for (k, v) in pairs { print("${k}: ${v}") }

// Lambda expressions (first-class functions)
let double = fn(x: Int) -> Int { return x * 2 }
let evens = numbers.filter(fn(x: Int) -> Bool { return x % 2 == 0 })
let doubled = numbers.map(fn(x: Int) -> Int { return x * 2 })

// Refinement types — constraint checked on every assignment
type AgentID = Str   where { self.starts_with("did:aion:") }
type Score   = Int   where { self >= 0 and self <= 100 }

let id: AgentID = "did:aion:abc123"   // ok
// let bad: AgentID = "not-an-id"    // runtime error: constraint violated

// Loops with break / continue
for item in list { ... }
while cond { if skip_condition { continue }  if done { break } }

// Module imports
import math_utils                    // all declarations
import math_utils as mu              // with alias
import math_utils { abs, clamp }     // selective

Execution Modes

Aion has two execution paths, selectable per invocation:

Mode Command How it works
Interpreter aion run <file> Tree-walking interpreter — instant startup, great for development
Bytecode VM aion compile <file> Compiles to a flat instruction list, runs on a stack-based VM
Test runner aion test <file> Collects @test functions, runs each, reports PASS/FAIL + summary
# Tree-walking interpreter
.\gradlew.bat :aion-lang:run --args="run src/main/resources/sample.aion"

# Bytecode compiler + VM
.\gradlew.bat :aion-lang:run --args="compile src/main/resources/sample.aion"

# Run built-in tests
.\gradlew.bat :aion-lang:run --args="test src/main/resources/sample.aion"

Agent Ecosystem

Aion is designed as the contract layer for autonomous AI-to-AI interaction.

Agent-to-Agent (A2A) protocol

type AgentID = Str where { self.starts_with("did:aion:") }

type ServiceRequest = {
    sender:       AgentID,
    action:       Str,
    payload:      Map[Str, Str],
    budget_limit: Int,
}

@tool
@untrusted
@requires(req.budget_limit > 0)
@ensures(result.status == "ACK" || result.status == "REJECT")
fn negotiate_service(req: ServiceRequest) -> Map[Str, Str] {
    describe "Formal entry point for external agent requests."
    return match req.action {
        "reserve" => handle_reservation(req.payload),
        _         => { status: "REJECT", reason: "Unknown action" },
    }
}

Automated arbitration

If an agent's response violates its own @ensures clause, the Aion runtime flags the breach and triggers an Arbiter Agent which audits the signed transaction and issues an automatic refund. Agents that breach are penalised in the global Registry.

See docs/Aion Agent Ecosystem Technical Breakdown.md for the full spec.


Project Structure

aion-lang/
├── build-logic/                          # Gradle convention plugin
├── docs/
│   ├── missing-features.md               # Gap analysis (18 items, rated by impact)
│   └── Aion Agent Ecosystem Technical Breakdown.md
├── aion-lang/
│   ├── src/main/antlr4/com/aion/parser/
│   │   ├── AionLexer.g4                  # Lexer grammar
│   │   └── AionParser.g4                 # Parser grammar
│   └── src/main/java/com/aion/
│       ├── ast/Node.java                 # Sealed AST node hierarchy
│       ├── parser/
│       │   ├── AstBuilder.java           # ANTLR tree → AST
│       │   ├── AionFrontend.java         # Public parse API + import resolution
│       │   └── AionParseException.java
│       ├── interpreter/
│       │   ├── AionValue.java            # Runtime value types (sealed)
│       │   ├── Environment.java          # Lexical scope
│       │   └── Interpreter.java          # Tree-walking interpreter
│       ├── bytecode/
│       │   ├── Instruction.java          # Sealed instruction hierarchy (70+ variants)
│       │   ├── Bytecode.java             # Compiled program (instructions + fn table)
│       │   ├── BytecodeCompiler.java     # AST → instruction list
│       │   ├── BytecodeVM.java           # Stack machine executor
│       │   └── VmValue.java              # VM runtime value types
│       └── cli/AionCli.java              # CLI (picocli): run, compile, test, check
├── aion-lang-intellij/                   # IntelliJ Platform plugin
│   └── src/main/kotlin/com/aion/intellij/
│       ├── AionLanguage.kt               # Language singleton
│       ├── AionFileType.kt               # .aion file type
│       ├── AionLexer.kt                  # Hand-written highlighting lexer
│       ├── AionSyntaxHighlighter.kt      # Token → color mapping
│       ├── AionColorSettingsPage.kt      # Settings → Color Scheme → Aion
│       ├── AionCommenter.kt              # Line/block comment actions
│       ├── AionBraceMatcher.kt           # {} [] () matching
│       ├── AionParserDefinition.kt       # PSI registration
│       └── AionFile.kt                   # PSI file node
└── aion-lang/src/main/resources/
    ├── sample.aion                       # Full feature demo
    ├── bytecode-demo.aion                # Bytecode compiler demo
    ├── import-demo.aion                  # Module import + numeric literals demo
    └── math_utils.aion                   # Shared utility module (imported by demos)

IntelliJ Plugin

The aion-lang-intellij module is a full IntelliJ Platform plugin providing:

Feature Details
Syntax highlighting Keywords, built-ins, annotations, type names, numbers (hex/bin/oct), strings, comments, operators
Color scheme page Settings → Editor → Color Scheme → Aion — 14 customisable token categories
Brace matching {}, [], () — structural pair for {} enables smart indent
Line/block commenting // line comment · /* … */ block comment via standard IDE actions
File type .aion extension registered; recognised in Project view and editor tabs

Build & install the plugin

# Build the installable ZIP
.\gradlew.bat :aion-lang-intellij:buildPlugin
# Output: aion-lang-intellij/build/distributions/aion-lang-intellij-0.12.0.zip

# Install: Settings → Plugins → ⚙ → Install Plugin from Disk → select the ZIP

Build & Run

# Build
.\gradlew.bat :aion-lang:build

# Run the sample (tree-walking interpreter)
.\gradlew.bat :aion-lang:run --args="run src/main/resources/sample.aion"

# Run via bytecode compiler + VM
.\gradlew.bat :aion-lang:run --args="compile src/main/resources/sample.aion"

# Run the import demo (multi-file, numeric literals, selective imports)
.\gradlew.bat :aion-lang:run --args="compile src/main/resources/import-demo.aion"

# Run built-in tests in a source file
.\gradlew.bat :aion-lang:run --args="test src/main/resources/sample.aion"

# Parse-check only
.\gradlew.bat :aion-lang:run --args="check src/main/resources/sample.aion"

# Run all unit tests
.\gradlew.bat :aion-lang:test

# Install distribution (then run directly without Gradle)
.\gradlew.bat :aion-lang:installDist
.\aion-lang\build\install\aion-lang\bin\aion-lang.bat compile src/main/resources/sample.aion

Why Aion for AI?

Problem in existing languages Aion's answer
AI must read entire function body to know side effects @pure / @io / @async declared in signature
No machine-checkable API contracts @requires / @ensures are language-level, not comments
Positional args cause silent bugs when AI reorders them All call sites use named args
Null reference errors are invisible at the call site No nulls — Option[T] everywhere
Unhandled error paths Result[T, E] + ? propagation — explicit at every call site
Complex inheritance hierarchies confuse generation Records + enums only — flat, composable
Non-exhaustive match/switch causes runtime surprises All match expressions must be exhaustive
Implicit type conversions produce wrong types Zero implicit coercions
Long expression chains are hard to generate correctly >> pipeline makes data flow linear and verifiable
AI agents cannot verify each other's behaviour @tool + registry + arbiter agent — pay-on-success economy
Magic numbers obscure intent Hex/binary/octal literals + digit separators built in
Multi-file programs require build tooling import with transitive resolution and cycle detection

See Also

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors