npm.io
1.4.4 • Published 8h agoCLI

@ball-lang/cli

Licence
MIT
Version
1.4.4
Deps
1
Size
104 kB
Vulns
0
Weekly
0

Ball Logo

Ball Programming Language

A polyglot programming language IR where every program is a Protocol Buffer message.

CI npm MIT License Buf

Website · Playground · Documentation · Examples


Why Ball?

Programs are structured data, not text. A Ball program is a protobuf message that can be serialized, transmitted, stored in a database, and compiled to any target language — with zero parsing ambiguity.

Capability Details
Programs are data Protobuf schema enforces structural validity. If it deserializes, it is syntactically valid. No parser, no syntax errors.
Provably complete security auditing ball audit statically reports every side effect. No eval, no FFI, no hidden capabilities — every I/O operation flows through a named base function.
Multi-language compilation Compile Ball to Dart, C++, and more. Encode Dart source back to Ball. Round-trip real-world code.
Self-hosted toolchain The Dart reference interpreter is itself encoded as Ball, then compiled back to Dart with byte-identical conformance output. A TS-native compiler (@ball-lang/compiler) uses ts-morph in-process — Dart fixtures round-trip to TS and execute byte-identical on Node, and the full engine.dart parses cleanly. The C++ compiler runs the conformance corpus end-to-end. Exact pass counts are CI-gated, never hand-maintained — see the conformance matrix.
Three runtime engines Dart (true async), C++ (native), TypeScript (runs in the browser).
Package management Import modules from pub, npm, and more registries with ball add pub:package@^1.0.0.
Web playground Try Ball in your browser at ball-lang.dev/playground.

Quick Start

Install the TypeScript engine (runs anywhere)
npm install @ball-lang/engine
import { BallEngine } from '@ball-lang/engine';

const program = JSON.parse(fs.readFileSync('hello_world.ball.json', 'utf-8'));
const engine = new BallEngine();
await engine.run(program);
Or use the Dart CLI
# The Dart pub-workspace + Melos root is the repo root; resolve from there.
dart pub get

# Run a program
dart run ball_cli:ball run examples/hello_world/hello_world.ball.json

# Compile Ball to Dart source
dart run ball_cli:ball compile examples/hello_world/hello_world.ball.json

# Encode Dart source back to Ball
dart run ball_cli:ball encode my_app.dart

# Security audit
dart run ball_cli:ball audit examples/hello_world/hello_world.ball.json

Hello World

Ball program (hello_world.ball.json):

{
  "@type": "type.googleapis.com/ball.v1.Program",
  "name": "hello_world",
  "version": "1.0.0",
  "modules": [
    {
      "name": "std",
      "functions": [{ "name": "print", "isBase": true }],
      "typeDefs": [{
        "name": "PrintInput",
        "descriptor": {
          "name": "PrintInput",
          "field": [{ "name": "message", "number": 1, "label": "LABEL_OPTIONAL", "type": "TYPE_STRING" }]
        }
      }]
    },
    {
      "name": "main",
      "moduleImports": [{ "name": "std" }],
      "functions": [{
        "name": "main",
        "outputType": "void",
        "body": {
          "call": {
            "module": "std", "function": "print",
            "input": { "messageCreation": { "typeName": "PrintInput", "fields": [
              { "name": "message", "value": { "literal": { "stringValue": "Hello, World!" } } }
            ]}}
          }
        }
      }]
    }
  ],
  "entryModule": "main",
  "entryFunction": "main"
}

Compiled Dart output:

void main() {
  print('Hello, World!');
}

Compiled C++ output:

#include <iostream>
int main() {
  std::cout << "Hello, World!" << std::endl;
  return 0;
}

Architecture

The 7 Expression Types

Every Ball computation is exactly one of these nodes:

Node Purpose Example
call Invoke a function std.add(left, right)
literal Constant value 42, "hello", true
reference Variable access input, x
fieldAccess Field of a message input.name
messageCreation Construct a message Point{x: 1, y: 2}
block Sequential statements let x = 1; x + 1
lambda Anonymous function (input) => input.x + 1
Modules and Base Functions

Every function takes one input message and returns one output message (gRPC-style). Base functions have no body — their implementation is provided per-platform:

  • std — arithmetic, comparison, logic, bitwise, strings, math, control flow, type ops, cascade, null-aware access, spread, invoke, record (see dart/shared/std.json for the canonical base-function inventory)
  • std_collections — list/map/set operations
  • std_io — console, process, time, random
  • std_memory — linear memory for C/C++ interop
  • std_convert — JSON / UTF-8 / base64 encode-decode
  • std_fs — file and directory operations
  • std_time — clock, timestamp formatting/parsing, duration arithmetic
  • std_concurrency — threads, mutexes, and atomics

Control flow (if, for, while, for_each) is implemented as base function calls with lazy evaluation — keeping the language completely uniform.

Schema

The single source of truth is proto/ball/v1/ball.proto. All implementations deserialize from this schema. Metadata fields are cosmetic — stripping all metadata never changes what a program computes.

CLI Commands

Command Description
ball run <program> Execute a Ball program
ball compile <program> Compile to target language source code
ball encode <source> Encode source code into a Ball program
ball round-trip <source> Encode then compile, show diff
ball audit <program> Static capability analysis (security)
ball info <program> Inspect program structure
ball validate <program> Check program validity
ball build <program> Resolve imports into self-contained program
ball init Create ball.yaml in current directory
ball add <spec> Add dependency (pub:pkg@^1.0.0)
ball resolve Resolve dependencies into ball.lock.json
ball tree Print dependency tree

Ecosystem

Implementation Status
Language Proto Bindings Compiler Encoder Engine
Dart Yes Full Full Full (true async)
TypeScript Yes Full Full Full (self-hosted, browser + Node)
C++ Yes Full Full Full (self-hosted)
Go Yes -- -- --
Python Yes -- -- --
Java Yes -- -- --
C# Yes -- -- --

Statuses drift — the authoritative source is CI (.github/workflows/ci.yml, conformance-matrix.yml), not this table. The TS pipeline is a full CI-gated compiler + self-hosted engine + encoder (the engine passes the conformance corpus; the encoder round-trips TS→Ball→target through universal std). C++ has a compiler, encoder (Clang AST → Ball), and self-hosted engine that passes every conformance fixture.

flowchart LR
    BP["Ball Program\n(protobuf)"] -- compiler --> SRC["Source Code"]
    SRC -- encoder --> BP
    BP -- engine --> RT["Runtime\nExecution"]
Extending Ball

Define custom base modules for any platform (Flutter, Unity, embedded):

{
  "name": "flutter",
  "functions": [
    { "name": "text", "inputType": "TextInput", "outputType": "Widget", "isBase": true }
  ]
}

Then implement the base function in your target compiler or engine. See docs/IMPLEMENTING_A_COMPILER.md for a complete guide.

Security Model

Ball programs have provably complete capability analysis because:

  1. No eval — programs are data, not text. There is no way to construct and execute arbitrary code at runtime.
  2. No FFI — the only way to perform side effects is through base function calls with known names.
  3. Static analysis is exhaustiveball audit walks the expression tree and reports every base function call, categorized by capability (I/O, network, filesystem, process, memory).

The ball-audit GitHub Action runs automatically on PRs that modify .ball.json files, blocking merges that introduce unauthorized capabilities.

Contributing

Build Commands
# Dart (the pub-workspace + Melos root is the repo root)
dart pub get
cd dart/engine && dart test
cd dart/encoder && dart test

# C++
cd cpp && mkdir -p build && cd build && cmake .. && cmake --build .

# TypeScript
cd ts/engine && npm install && npm test

# Proto (regenerate all bindings)
buf lint && buf generate
Workflow
  1. Schema changes: edit proto/ball/v1/ball.proto then buf lint / buf generate
  2. New std functions: edit dart/shared/lib/std.dart then dart run bin/gen_std.dart
  3. Implement in compiler, engine, or both
  4. Add tests alongside changes
  5. If C++ is in scope, mirror changes in cpp/

See the issues board for planned work and issue #135 (std coverage inventory; dart/shared/std.json is the canonical source of truth) for standard library coverage.

Project Structure

ball/
├── proto/ball/v1/ball.proto       # Language schema (single source of truth)
├── dart/                           # Dart implementation (reference)
│   ├── shared/                     # Protobuf types, std module, capability analyzer
│   ├── compiler/                   # Ball -> Dart
│   ├── encoder/                    # Dart -> Ball
│   ├── engine/                     # Interpreter (true async)
│   ├── resolver/                   # Package manager (pub/npm adapters)
│   └── cli/                        # ball CLI
├── cpp/                            # C++ implementation (compiler + encoder + self-hosted engine)
├── ts/                             # TypeScript implementation (compiler + encoder + self-hosted engine, browser + Node)
├── go/, python/, java/, csharp/    # Proto bindings
├── examples/                       # Example Ball programs
├── tests/conformance/              # Cross-implementation conformance tests
├── website/                        # ball-lang.dev + playground
└── docs/                           # Specs and guides

License

MIT

Keywords