A VM bytecode interpreter for EduScript, an educational language

Hello, I started learning zig this weekend and I’m creating a VM bytecode interpreter as a practical exercise.

I’ve been wanting to improve my compilation skills for a while now. But doing C++ is too heavy for me (same for Rust), I’m not paid to work with these languages, so it’s hard to justify investing so much time in them. There are opportunities in transpilation with JS (like TypeScript, Babel, etc.), but I would like something more low level… C didn’t seem too bad, easy to grasp, but it’s very primitive, so I was pretty sure to make too much mistakes.

Then I discovered ZIG, and I think I’m falling in love with it. Really, everything seems simple, intuitive and it’s fun to work with. Plus the native test support, integrated build system, really, it’s great. Congratulations on this project :clap: I might even risk doing a bit of web work with it.

If you have any feedback on the code of my project, that would be really nice, because I’m sure I’m making a lot of obvious mistakes, low-level languages aren’t my specialty at all.

9 Likes

This is nice. Here’s a stylistic suggestion: since files are structs in Zig, you could declare some types, like Token at the top level of their own file, e.g:

// file: Token.zig

// fields can be declared at the top level:
type: Type,
lexeme: []const u8,
literal: ?LiteralValue,
line: u32,
pos: usize,

// Now you have `Token.Type` instead of `token.TokenType`.
pub const Type = enum {
    // It is convention for enum variants to be snake_case.
    dot,
    // ...

    // Variant names that clash with keywords can use @"identifer" syntax.
   @"if",
}

Also, in main you can remove the direct import of token by using enum literals, and therefore remove the direct import of token.zig:

        if (token.type == .eof) // ...
3 Likes

Welcome to Ziggit @jean-michelet! That’s a good introductory project for the language.

Seems so-far-so-good to me. One note: having separate test files isn’t really idiomatic in Zig. It’s not unheard of, but it’s more normal to put test blocks at the bottom of the file getting tested.

It can then be a bit tricky to make sure that the tests all get found and referenced, see std.testing.refAllDecls for a way to ensure this. Worth reading everything in std.testing in fact.

I look forward to seeing more.

2 Likes

Thanks!

I read about that, but I struggle with the idea to put all the tests in the same file, not used to. I think it might be simpler to have a program that recursively searches for all files with a certain extension, e.g. .test.zig.

But I’ll follow your advice and read the whole documentation about testing.

1 Like

Great suggestions, thanks!

Hi welcome to Ziggit, just a small suggestions for you. In your import statements you don’t need to use relative path syntax, files are aware of where they are so in your scanner_test.zig you can replace

-const Scanner = @import("../../src/scanner/scanner.zig");
+const Scanner = @import("scanner.zig");
-const Token = @import("../../src/scanner/token.zig");
+const Token = @import("token.zig");

same in scanner.zig

-const Token = @import("./token.zig");
+const Token = @import("token.zig");

and in main.zig

-const scanner = @import("./scanner/scanner.zig");
+const scanner = @import("scanner/scanner.zig");

as a last suggestion you might want to add a proper test step in your build.zig file just for the convenience.

    const eduscript_zig_unit_test = b.addTest(.{
        .name = "eduscript-zig",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    const run_unit_test = b.addRunArtifact(eduscript_zig_unit_test);
    const test_step = b.step("test", "Test the app");
    test_step.dependOn(&run_unit_test.step);

In any case your code looks really great for a first attempt. Good luck on your journey :slight_smile:

3 Likes

Hi!

Thanks your feedback :pray:

Yes, I realized that recently. It was mainly an error when I moved the files during the refactoring of my test architecture.

1 Like