Skip to content

Comments

Add Zig rewrite skeleton in zig/#5

Draft
Copilot wants to merge 2 commits intomasterfrom
copilot/add-getting-started-skeleton
Draft

Add Zig rewrite skeleton in zig/#5
Copilot wants to merge 2 commits intomasterfrom
copilot/add-getting-started-skeleton

Conversation

Copy link

Copilot AI commented Feb 21, 2026

Scaffolding for a potential Zig rewrite of sid, motivated by Zig's zero-boilerplate C interop (@cImport/@cInclude) as an alternative to Rust's bindgen + unsafe. Rust source is untouched; this is a proof-of-concept skeleton only.

New files (zig/)

  • build.zig — standard Zig 0.14 build script; sid executable + run step; links libc
  • src/main.zig — entry point; reads script path from argv, calls run() with TODO stubs for parse/render steps
  • src/types.zig — tagged unions mirroring src/types.rs (RealValue, DataValue, ProgramValue); std.ArrayList for Rust Vec, []const u8 for String; manual deinit per type
  • src/interpreter.zigExeState + interpret loop mirroring src/invoke/mod.rs; dispatches Invoke to invoke() which handles Substack, BuiltInFunction (stub), and Label scope lookup
  • src/ffi.zig — key motivating demo: C interop with no boilerplate:
    const c = @cImport({ @cInclude("math.h"); });
    pub fn callCFunction(x: f64) f64 { return c.cos(x); }
    Includes doc comments sketching std.DynLib.open/.lookup for runtime-loaded shared libraries and the "cos" built-in → C dispatch mapping
  • README.md — motivation, build instructions (zig build run -- path/to/script.sid), Rust→Zig module map, Zig vs Rust FFI comparison, skeleton status notice
Original prompt

Overview

This repository contains a Rust implementation of a custom Lisp-inspired reverse-polish-notation (RPN) stack-based language interpreter called sid. The author is considering a full rewrite in Zig, primarily to take advantage of Zig's zero-boilerplate, first-class C interop (@cImport / @cInclude).

The goal of this PR is to create a getting-started skeleton for a Zig rewrite alongside the existing Rust code — it should not remove or break anything that exists today. This is a proof-of-concept / scaffolding PR to suggest an approach.


What to create

Please create the following new files in a top-level zig/ directory. Do not touch the existing Rust source.


1. zig/build.zig

A standard Zig build script (build.zig) that:

  • Defines an executable target named sid
  • Sets the root source file to zig/src/main.zig
  • Adds a run step

2. zig/src/main.zig

The entry point. Should:

  • Read a source file path from std.os.argv (or std.process.args)
  • Read the file contents
  • Pass the source string to a run(source) function
  • Print a basic "sid (zig rewrite)" banner or usage message if no args are given

3. zig/src/types.zig

Define the core value types that mirror the existing Rust types in src/types.rs. The Rust types to mirror are:

pub enum RealValue {
  Bool(bool),
  Str(String),
  Char(String),
  Int(i64),
  Float(f64),
  Substack(Vec<ProgramValue>),
  List(Vec<DataValue>),
  BuiltInFunction(String),
}

pub enum DataValue {
  Real(RealValue),
  Label(String),
}

pub enum ProgramValue {
  Real(RealValue),
  Label(String),
  Invoke,
  // Template omitted for now
}

In Zig, represent these as tagged unions. Use std.ArrayList for dynamic arrays. Use []const u8 for strings. Add a // TODO: Template comment where templates would go.


4. zig/src/interpreter.zig

A minimal interpreter loop that mirrors the structure in src/invoke/mod.rs. It should:

  • Define an ExeState struct with program_stack, data_stack, and a scope (use std.StringHashMap)
  • Implement an interpret function that loops over the program stack and dispatches on ProgramValue
  • Handle the Invoke case by popping the top of the data stack and (for now) printing what was invoked
  • Add a stub/comment for where C FFI function dispatch would hook in

5. zig/src/ffi.zig

This is the key file demonstrating Zig's C interop story — the main reason for the rewrite. It should:

  • Show how to import a C standard library header using @cImport / @cInclude:
    const c = @cImport({
        @cInclude("math.h");
    });
  • Define a callCFunction demo function that calls c.cos with a f64 argument and returns a f64
  • Include a clear doc comment explaining that this is where dynamic C library loading (std.DynLib) would go for runtime-loaded libraries, with a brief code sketch of how std.DynLib.open and .lookup work
  • Add a comment stub showing how a sid built-in "cos" function would map to a C call

6. zig/README.md

A short markdown document explaining:

  • Why Zig was chosen (zero-cost C interop via @cImport, no bindgen, no unsafe blocks)
  • How to build and run: zig build run -- path/to/script.sid
  • The mapping between the Rust modules and the new Zig modules
  • A note that this is a work-in-progress skeleton and the Rust implementation remains authoritative
  • A brief example of what C FFI looks like in Zig vs Rust (the cos example from the conversation)

Context from existing Rust code

The existing architecture (for reference when writing the Zig skeleton):

  • Parser (src/parse/): Tokenises source into Vec<TemplateValue>
  • Renderer (src/render.rs): Resolves templates into Vec<ProgramValue>
  • Interpreter (src/invoke/mod.rs): Loops over program_stack, dispatches on each ProgramValue. On Invoke, pops the data stack and calls the appropriate BuiltInFunction.
  • Built-ins (src/built_in/mod.rs): Currently returns an empty HashMap — a stub
  • Entry point (src/bin/sid.rs): Reads a file, calls compile() then interpret()

The Zig skeleton should follow the same conceptual pipeline: parse → render → interpret, with C FFI hooks in the built-in/invoke layer.


Notes

  • Zig version: target Zig 0.14 (stable as of early 2026)
  • Do not add a zig-out/ or zig-cache/ gitignore entry — the existing .gitignore can be updated if needed, but it's not required for this PR
  • Keep the skeleton simple and well-commented — this is meant to be a readable starting point, not a complete implementation

This pull request was created from Copilot chat.


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.

Co-authored-by: sidju <13993607+sidju@users.noreply.github.com>
Copilot AI changed the title [WIP] Add getting started skeleton for Zig rewrite Add Zig rewrite skeleton in zig/ Feb 21, 2026
Copilot AI requested a review from sidju February 21, 2026 19:43
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