Skip to content

Initial Oxide language implementation with parser, type checker, and VM - #1

Open
zagdrath wants to merge 8 commits into
mainfrom
claude/oxide-language-design-lk7ytz
Open

Initial Oxide language implementation with parser, type checker, and VM#1
zagdrath wants to merge 8 commits into
mainfrom
claude/oxide-language-design-lk7ytz

Conversation

@zagdrath

Copy link
Copy Markdown
Member

This PR introduces the complete initial implementation of the Oxide programming language, a Rust-inspired language designed to maintain memory safety while reducing learning complexity.

Summary

This is the foundational commit establishing the Oxide language toolchain: a full pipeline from source code through lexing, parsing, type checking, and bytecode compilation to a stack-based VM execution. The implementation covers the v1 language specification with support for variables, functions, classes, control flow, and ownership/borrowing semantics.

Key Components

Language Design & Documentation

  • docs/design.md: Comprehensive v1 language specification covering philosophy, syntax, types, ownership model, and roadmap
  • README.md: Project overview and feature summary
  • Example programs (examples/tour.ox, examples/hello.ox) demonstrating language capabilities

Compiler Pipeline

  • src/lexer.rs: Hand-written lexer supporting all v1 tokens, string interpolation with expression holes, nested block comments, and reserved keyword detection
  • src/parser.rs: Recursive-descent parser with Pratt-style expression parsing, class-literal context restrictions, and comprehensive error recovery
  • src/ast.rs: Complete AST node definitions for programs, items, statements, expressions, types, and class definitions
  • src/check.rs: Type checker implementing the milestone-2 subset (single func main with variables, expressions, if-statements, lists, and built-ins)
  • src/compile.rs: Bytecode compiler with jump patching for control flow and short-circuit boolean operators
  • src/vm.rs: Stack-based VM with checked arithmetic, runtime error handling, and source span tracking for diagnostics

Supporting Infrastructure

  • src/token.rs: Token definitions and descriptions for all v1 grammar elements
  • src/bytecode.rs: Bytecode instruction set with parallel span tracking for runtime error reporting
  • src/tir.rs: Typed intermediate representation (checker output, compiler input)
  • src/ty.rs: Semantic type system distinct from surface syntax
  • src/value.rs: Runtime value representation
  • src/span.rs: Byte-offset source spans for precise error locations
  • src/diagnostics.rs: Diagnostic rendering with line/column mapping and source context
  • src/pretty.rs: AST pretty-printer for oxide ast command
  • src/main.rs: CLI with run, build, check, and ast subcommands

Testing

  • tests/run_programs.rs: End-to-end integration tests covering arithmetic, string interpolation, control flow, lists, and built-in functions
  • tests/parse_examples.rs: Parser validation tests for example programs

Notable Implementation Details

  • String interpolation: Lexer captures expression holes as raw source text with byte offsets, allowing re-parsing by the parser while keeping the lexer expression-grammar-agnostic
  • Class literal context: Parser tracks allow_class_literal flag to disambiguate Name { ... } syntax in control flow conditions
  • Type inference: Checker infers types from context (e.g., empty list literals with type annotations) while maintaining explicit int→float widening
  • Error-first diagnostics: Parser and checker implement "first error wins" strategy with helpful context messages
  • Runtime safety: VM includes checked arithmetic, bounds checking, and division-by-zero detection with source span reporting
  • Milestone gating: Constructs from future milestones (user functions, classes, traits) are explicitly rejected with messages indicating when they arrive

The implementation establishes a solid foundation for the language while maintaining clear separation of concerns across the compilation pipeline.

https://claude.ai/code/session_01LYnXK6V7AZgX7r6ayfQhXx

claude added 8 commits July 23, 2026 16:59
Specifies the core language: ownership + borrow checking with fully
inferred lifetimes, classes (struct+impl merged, no inheritance),
simple types (int/float/bool/string), string interpolation, panic-only
errors, and a bytecode VM implementation plan with milestone order.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LYnXK6V7AZgX7r6ayfQhXx
Function values are now produced only by 'return expr;' — Rust's
tail-expression return is removed for function bodies. 'if' remains
usable as an expression; 'fn' is reserved so the compiler can suggest
'func'. All examples updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LYnXK6V7AZgX7r6ayfQhXx
Covers the full v1 grammar from docs/design.md:
- Hand-written lexer with interpolated strings ({expr} holes re-parsed
  with correct source offsets), nested block comments, hex/binary/
  exponent literals, fused &mut, and friendly rejections for Rust-isms
  (fn, ||, !, i32, String) per the reserved-keyword plan
- Recursive-descent parser with Pratt-style precedence, if-expressions
  (else required in expression position), non-chaining comparisons,
  class-literal restriction in conditions, place-checked assignments,
  and the no-reference-fields rule from design doc 8.3
- Span-carrying diagnostics rendered with source line, caret, and a
  concrete help suggestion
- oxide CLI with check/ast subcommands, examples/tour.ox exercising
  every construct, 29 passing tests

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LYnXK6V7AZgX7r6ayfQhXx
Adds the back half of the pipeline from docs/design.md section 13:
- Type checker (check.rs) lowering the AST to a typed IR (tir.rs):
  name resolution to local slots, let/let-mut mutability enforcement,
  implicit int->float widening as explicit nodes, interpolation
  printability, if-expression branch unification, list element typing,
  and built-ins (println, str, int, float, assert, panic). Constructs
  from later milestones error with the milestone that delivers them.
- Bytecode compiler (compile.rs) with jump patching for if and
  short-circuit and/or; constants dedupe; disassembler for oxide build
- Stack VM (vm.rs) with checked integer arithmetic (overflow, division
  by zero), index bounds checks, and runtime panics carrying the source
  span of the faulting instruction (rendered with caret + exit 101)
- CLI: oxide run and oxide build now work; examples/hello.ox shows
  everything executable today; 23 new end-to-end tests (52 total)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LYnXK6V7AZgX7r6ayfQhXx
- Checker: two-pass signature collection (call order doesn't matter,
  mutual recursion works), per-function checking with immutable params
  (dedicated 'copy it first' diagnostic), return-type coercion, and
  all-paths-return analysis where panic and breakless loops count as
  diverging. while/for/loop with break/continue bound to the innermost
  loop; for iterates lists and int ranges with hidden slot temporaries.
- Compiler: chunk-per-function CompiledProgram, Call/Return/Unit ops,
  loop codegen with break/continue jump patching.
- VM: call-frame stack with per-frame locals, 10k-frame recursion guard,
  and panic stack traces (call-site spans rendered as 'called from ...'
  lines by the CLI). Broken-pipe writes now end execution quietly.
- examples/functions.ox (fib, fizzbuzz, primes); 15 new tests (67 total)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LYnXK6V7AZgX7r6ayfQhXx
- Checker: three-pass lowering (class names -> signatures -> bodies).
  Methods become plain functions named Class::method with self in slot
  0; field access compiles to indexed access in declaration order.
  Class literals require every field exactly once with per-field type
  errors; receiver mutability for &mut self calls and field assignment
  is enforced by walking place expressions to their root (local, self,
  or temporary), with &self methods barred from writing fields.
- to_str(&self) -> string makes a class printable: interpolation,
  println, and str() all route through it.
- Runtime: Value::Object is Rc<RefCell<fields>> so &mut self methods
  mutate the real instance; ops MakeObject/GetField/SetField. The
  sharing stands in for move semantics until the borrow checker
  (milestone 5) makes aliasing unobservable.
- examples/classes.ox (Point/Counter/Rect composition, Newton sqrt);
  15 new tests (82 total)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LYnXK6V7AZgX7r6ayfQhXx
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LYnXK6V7AZgX7r6ayfQhXx
Moves and borrows now work exactly as docs/design.md section 8
specifies, with zero lifetime annotations:

- References are real types: &T / &mut T in parameters and locals, with
  auto-deref on field access, indexing, and method calls, explicit *x
  for value reads, and &-iteration (for x in &xs). Structural limits
  keep inference annotation-free: no refs in lists or fields, no &&T,
  no &mut of Copy types, and returning references is rejected with a
  restructure hint.
- The checker lowers every variable access to a place (root +
  field/index/deref projections) with an access mode: read-only
  contexts (interpolation, ==, len(), &self receivers) borrow; value
  contexts copy or move by type; moving out of a field/element/
  reference errors with a .clone() hint. Mutation paths track &mut
  derefs, so xs[i] = v works through &mut [int] parameters.
- borrowck.rs flattens each function into an event stream, computes
  last-use liveness (borrows end at last use — non-lexical — extended
  through loops entered after the borrow), then enforces: no use after
  move, no move/assign/mutate while borrowed, aliasing XOR mutation.
  Branches merge conservatively; loop bodies are re-analyzed to catch
  iteration-carried moves. Errors show both conflicting sites via new
  related-location diagnostics plus a concrete fix.
- Runtime: strings and lists join objects as Rc-shared values, so a
  borrow is the same Rc and moves are pointer-cheap; .clone() deep-
  copies via a new CloneVal op; SetIndex replaces slot-based stores;
  float .sqrt() added as a built-in method.
- examples/borrow.ox showcases the rules; examples/tour.ox — the full
  v1 grammar — now runs end-to-end. 29 new tests (106 total).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LYnXK6V7AZgX7r6ayfQhXx
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants