Skip to content

Repository files navigation

Arith

CI

Arith is a small programming language that compiles simple arithmetic programs into executable .NET assemblies.

Rather than interpreting expressions one at a time, Arith type-checks the source code and translates it into an assembly containing .NET Common Intermediate Language (CIL, commonly called IL) and metadata. The .NET runtime executes the generated code and its JIT compiler translates the IL into machine code for the target CPU.

The goal of this project is to explore the fundamental stages of a compiler—lexing, parsing, type checking, and code generation—through a small, approachable language.

Note

The compiler implements all of language v0.1 (architecture in docs/compiler-design.md): arith build and arith run compile and execute every feature in LANGUAGE_SPEC.md.

Example

fn sum_range(start: i64, end: i64) -> i64 {
    let total = 0;

    for i in start..end {
        total += i;
    }

    return total;
}

fn main() -> i32 {
    let result = sum_range(1, 11);

    if result > 50 {
        print("large:");
        print(result);
    } else {
        print("small:");
        print(result);
    }

    return 0;
}

Expected output:

large:
55

Version 0.1 features

  • Primitive bool, i32, i64, f32, f64, and string types
  • Functions declared with fn, with support for return
  • Local variables declared with let, including reassignment
  • Arithmetic, comparison, and logical operators
  • if / else, while, and range-based for statements
  • break and continue
  • A built-in print function that prints one value per line
  • Typed main parameters that receive parsed command-line arguments
  • Explicit numeric conversions
  • Checked integer arithmetic
  • Generation of a .NET assembly with main as its entry point

See LANGUAGE_SPEC.md for the complete syntax and semantics.

Commands

arith build hello.arith [-o <dir>]   # compile into a .NET assembly
arith build hello.arith --aot        # compile into a single native executable
arith run hello.arith [args...]      # compile and run, forwarding the exit code

A main with parameters receives command-line arguments, parsed per parameter type before it runs (LANGUAGE_SPEC.md §5.1); on a wrong argument count or an unparsable value the program prints a usage line and exits with code 2. With arith run, put -- before values that start with -:

arith run greet.arith 3 hello        # fn main(count: i64, label: string)
arith run negate.arith -- -5

The source file must be named <program-name>.arith, where <program-name> starts with a letter or _ and contains only letters, digits, _, and - (a CLI rule, not part of the language); the outputs are named after it.

build produces framework-dependent artifacts:

hello.dll                  the compiled assembly
hello.runtimeconfig.json   names the shared framework for the dotnet host
hello / hello.cmd          convenience launchers

The generated program can also be run with the .NET CLI:

dotnet hello.dll

With --aot, the same emitted IL is instead compiled ahead-of-time by the official NativeAOT toolchain into one native executable that runs without the dotnet host (requires the platform's native linker, e.g. Xcode Command Line Tools on macOS; see docs/il-emission-notes.md).

On failure, diagnostics are printed as file:line:col: error ARITHxxxx: message; every code is listed in docs/diagnostics.md.

Compiler pipeline

Arith source
    ↓ lexing
token stream
    ↓ parsing
abstract syntax tree (AST)
    ↓ name resolution and type checking
typed syntax tree
    ↓ IL and metadata generation
.NET assembly

The stages are separate components of the Arith.Compiler library, and every stage reports errors with their source locations.

Development

Building the compiler requires the .NET 10 SDK.

dotnet build                                   # build all projects
dotnet test                                    # run the test suite
dotnet run --project src/Arith.Cli -- version  # run the CLI

The version command prints the CLI version:

0.1.0

The repository is laid out as follows:

  • examples/ — runnable example programs, from fizzbuzz to an ASCII Mandelbrot and a tail-call experiment (see examples/README.md)
  • src/Arith.Compiler — the compiler as a library (source text, diagnostics, lexer, parser, binder, and IL emitter; architecture in docs/compiler-design.md)
  • tests/Arith.Compiler.Tests — xUnit v3 unit tests for the compiler stages
  • src/Arith.Cli — the arith command-line tool (build, run, version), including the artifact writer and the NativeAOT packaging behind build --aot
  • tests/Arith.Cli.Tests — xUnit v3 tests
  • Directory.Build.props / Directory.Packages.props — shared build settings and centrally managed NuGet package versions
  • Build outputs are written to artifacts/

Roadmap

All stages of the original roadmap — lexer, parser, name resolution and type checking, IL generation for expressions and control flow, assembly emission and execution, and diagnostics with test coverage — are implemented; language v0.1 is complete.

Arrays, structs, classes, closures, generics, modules, and null are outside the scope of version 0.1 and are candidates for future versions (LANGUAGE_SPEC.md §13). Released versions are recorded in CHANGELOG.md.

License

The Arith compiler and this repository are released under the MIT License. Programs you write in Arith are your own; Arith claims no license over them or over the assemblies compiled from them. Note that a --aot executable embeds .NET runtime components, so distributing one must additionally comply with the applicable .NET licenses and notices — see the official .NET license information.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages