Create Your Own Programming Language with Rust

repository·master·Indexed 21 days ago

https://github.com/ehsanmok/create-your-own-lang-with-rust

An educational resource for learning compiler fundamentals by building four languages: Calculator (arithmetic with Interpreter, VM, and JIT backends), Firstlang (dynamically typed interpreted language), Secondlang (statically typed compiled language with type inference), and Thirdlang (statically typed compiled language with OOP). The project demonstrates various execution strategies, including AST evaluation, stack-based bytecode VMs, and LLVM-based JIT compilation.

Tokens
62.4K
Snippets
223
Records
328
Agent score
72%

What's inside create-your-own-lang-with-rust

  1. Overview of the Create Your Own Programming Language with Rust book

    master

    This book provides a structured path for building programming languages using Rust, progressing through four distinct stages of complexity:

    1. Part I: Calculator - Focuses on the fundamentals: grammar, lexing, parsing, Abstract Syntax Trees (AST), interpreters, Virtual Machines (VM), bytecode, and JIT compilation using LLVM.
    2. Part II: Firstlang (Interpreted) - Transitions from a calculator to a real language with Python-like syntax, supporting variables, functions, control flow (if/else, while), and recursion via an interpreter.
    3. Part III: Secondlang (Compiled) - Evolves the language into a compiled language by adding type annotations, type inference, AST optimizations using the Visitor pattern, Intermediate Representation (IR), and LLVM code generation.
    4. Part IV: Thirdlang (Object-Oriented) - Adds object-oriented capabilities including class syntax, constructors, methods, self, and memory management, along with advanced LLVM IR optimization.

    The book also covers practical aspects like building a REPL, debugging, and testing your language.

  2. Overview of Firstlang

    master

    Firstlang is a dynamically typed, interpreted programming language featuring Python-like syntax. It is designed as a pure interpreter with no external dependencies, making it suitable for learning language implementation via a tree-walking interpreter.

    Key Features:

    • Variables and assignments
    • Functions with parameters
    • Control flow (if/else, while)
    • Recursion
    • Boolean and integer types
    • Comparison and arithmetic operators
    • REPL for interactive exploration
  3. Overview of the Calculator language

    master

    The Calculator is a simple arithmetic expression language designed to introduce fundamental compiler concepts. It supports integer arithmetic, unary operators, and parentheses for grouping.

    It features three distinct execution backends:

    1. Interpreter: Direct AST evaluation (Fast compilation, slower execution, uses stable Rust).
    2. VM: Bytecode compilation and stack-based execution (Compact bytecode, faster than interpreter, uses stable Rust).
    3. JIT: LLVM-based just-in-time compilation to native machine code (Slowest compilation, fastest execution, requires nightly Rust and LLVM).

    Supported syntax includes:

    • Basic arithmetic: 1 + 2, 10 - 5
    • Unary operators: -1, +5, -2 + 5
    • Parentheses: (1 + 2), -(5 - 2)
    • Multiple operations: 1 + 2 + 3
  4. Overview of the languages in Create Your Own Programming Language with Rust

    master

    This project teaches programming language implementation through four progressively complex languages. Each language focuses on different core concepts:

    • Calculator: Simple arithmetic expressions. Supports Interpreter, VM, and JIT execution backends.
    • Firstlang: A dynamically typed interpreted language featuring variables, functions, and recursion.
    • Secondlang: A statically typed compiled language featuring type inference and LLVM JIT execution.
    • Thirdlang: A statically typed compiled language featuring Object-Oriented Programming (OOP) with classes and methods using LLVM JIT.

    Project structure:

    create-your-own-lang-with-rust/
    ├── calculator/     # Simple arithmetic (interpreter, VM, JIT backends)
    ├── firstlang/      # Interpreted language with recursion
    ├── secondlang/     # Compiled language with type inference
    ├── thirdlang/      # Object-oriented with classes and methods
    └── book/           # mdbook source for createlang.rs
  5. Overview of Firstlang features and capabilities

    master

    Firstlang is a complete interpreted programming language built as a step up from a simple calculator. Unlike a calculator that only evaluates arithmetic expressions, Firstlang supports full programming constructs including variables, functions, and control flow.

    Key Features

    • Variables and assignment: e.g., x = 42
    • Functions with parameters: e.g., def add(a, b) { return a + b }
    • Conditionals: if (condition) { ... } else { ... }
    • Loops: while (condition) { ... }
    • Recursion: Functions can call themselves.

    Example: Recursive Fibonacci

    def fib(n) {
        if (n < 2) {
            return n
        } else {
            return fib(n - 1) + fib(n - 2)
        }
    }
    
    fib(10)  # Returns 55
  6. Overview of the language learning progression

    master

    The project builds four increasingly complex languages to teach compiler construction concepts:

    1. Calculator: Focuses on PEG basics, ASTs, and operators. Supports Interpreter, VM, and JIT execution.
    2. Firstlang: Introduces variables, functions, control flow, and recursion using a tree-walking interpreter.
    3. Secondlang: Adds static types, type inference, and optimization passes, compiling to native code via LLVM JIT.
    4. Thirdlang: Adds Object-Oriented Programming (classes, methods, constructors) and manual memory management (heap allocation) using LLVM JIT.
  7. What is LLVM IR and why use it?

    master

    LLVM IR (Intermediate Representation) is a low-level, typed, platform-independent representation that sits between your language's AST and machine assembly.

    By compiling your language to LLVM IR instead of direct machine code, you leverage the LLVM compiler infrastructure to handle:

    • Optimizations: World-class optimizations (like dead code elimination and constant propagation) are provided for free.
    • Code Generation: LLVM translates the IR into optimized machine code for various architectures (x86, ARM, WebAssembly, etc.).

    Think of it as a universal assembly language that allows you to write your compiler once and support many platforms automatically.

  8. Overview of the Secondlang compilation pipeline

    master

    Secondlang follows a multi-stage pipeline to transform source code into executable native code:

    1. Parser: Uses PEG grammar (pest) to convert source code into an Abstract Syntax Tree (AST).
    2. Type System: Performs type checking and inference to catch errors at compile time.
    3. Optimization: Uses the visitor pattern to perform passes that simplify the AST.
    4. Code Generation: Uses inkwell to generate LLVM IR from the typed AST.
    5. JIT Compilation: Compiles the LLVM IR into native machine code and executes it.
  9. What is an Abstract Syntax Tree (AST)?

    master

    An Abstract Syntax Tree (AST) is a data structure that captures the structure and meaning of source code, rather than just its text. While a parser (like pest) provides a generic tree of syntax pairs, the AST translates those pairs into domain-specific nodes that represent actual operations and values.

    In a calculator language:

    • Operators (e.g., +, -) are nodes that dictate actions.
    • Values (e.g., 1, 2) are nodes that provide data.

    This separation allows the program to move from a raw string like "1 + 2" to a manageable tree structure where nesting (like "-1 + (2 + 3)") is represented naturally.

  10. How local type inference works

    master

    The project implements local type inference (also known as "flow-based" inference). Unlike Hindley-Milner, which can infer polymorphic types without annotations, local type inference requires explicit type annotations at function boundaries (parameters and return types) but infers types for all variables and expressions within function bodies.

    Types "flow" forward from known sources (literals, parameters) through operations into variables. For example, in x = 1 + 2, the Int type of the literals flows through the + operator to the expression, and finally to the variable x.

  11. The Type Environment

    master

    The type environment (also called a symbol table or context) is a mapping of names to types. In this implementation, it is represented as:

    type TypeEnv = HashMap<String, Type>;

    Key characteristics:

    • Extension: New bindings are added when variables are declared or when entering a function scope.
    • Querying: Used to look up the type of a variable during expression typechecking.
    • Scoping: The environment is scoped; inner scopes can shadow outer bindings.
  12. Understand the transition from a Calculator to a Real Language

    master

    A calculator is a stateless system where each expression is independent and input produces output without persistence. A real programming language (like firstlang) is a state machine that maintains memory, allows branching, and supports repetition.

    Key Differences

    FeatureCalculatorReal Language
    StateNone - each expression is independentVariables persist across statements
    AbstractionNone - can't name computationsFunctions let you reuse code
    DecisionsNone - always evaluates everythingConditionals choose what to run
    RepetitionNone - runs onceLoops repeat until done

    Core Architectural Shifts

    To move from a calculator to a language like firstlang, you must implement the following:

    • State Management: Use a HashMap of name -> value to act as a variable environment.
    • Control Flow: Implement keywords like if, else, and while to allow the program to make decisions and loop.
    • Function Support: Implement a call stack using stack frames (where each frame is a HashMap) to handle recursion and local scope.
    • Statement Execution: Shift from single expression evaluation to executing a sequence of statements.