Initial Oxide language implementation with parser, type checker, and VM - #1
Open
zagdrath wants to merge 8 commits into
Open
Initial Oxide language implementation with parser, type checker, and VM#1zagdrath wants to merge 8 commits into
zagdrath wants to merge 8 commits into
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 roadmapREADME.md: Project overview and feature summaryexamples/tour.ox,examples/hello.ox) demonstrating language capabilitiesCompiler Pipeline
src/lexer.rs: Hand-written lexer supporting all v1 tokens, string interpolation with expression holes, nested block comments, and reserved keyword detectionsrc/parser.rs: Recursive-descent parser with Pratt-style expression parsing, class-literal context restrictions, and comprehensive error recoverysrc/ast.rs: Complete AST node definitions for programs, items, statements, expressions, types, and class definitionssrc/check.rs: Type checker implementing the milestone-2 subset (singlefunc mainwith variables, expressions, if-statements, lists, and built-ins)src/compile.rs: Bytecode compiler with jump patching for control flow and short-circuit boolean operatorssrc/vm.rs: Stack-based VM with checked arithmetic, runtime error handling, and source span tracking for diagnosticsSupporting Infrastructure
src/token.rs: Token definitions and descriptions for all v1 grammar elementssrc/bytecode.rs: Bytecode instruction set with parallel span tracking for runtime error reportingsrc/tir.rs: Typed intermediate representation (checker output, compiler input)src/ty.rs: Semantic type system distinct from surface syntaxsrc/value.rs: Runtime value representationsrc/span.rs: Byte-offset source spans for precise error locationssrc/diagnostics.rs: Diagnostic rendering with line/column mapping and source contextsrc/pretty.rs: AST pretty-printer foroxide astcommandsrc/main.rs: CLI withrun,build,check, andastsubcommandsTesting
tests/run_programs.rs: End-to-end integration tests covering arithmetic, string interpolation, control flow, lists, and built-in functionstests/parse_examples.rs: Parser validation tests for example programsNotable Implementation Details
allow_class_literalflag to disambiguateName { ... }syntax in control flow conditionsThe implementation establishes a solid foundation for the language while maintaining clear separation of concerns across the compilation pipeline.
https://claude.ai/code/session_01LYnXK6V7AZgX7r6ayfQhXx