My penguin avatar

Kiesel Devlog #2: Iterators, more math, and a bug in the Zig stdlib

Published on 2023-09-15.

Welcome to the second devlog for the Kiesel JS engine! It hasn't been long since the last one, but I worked on a couple of fun things since then :^)

Iterators

Quoting myself from last week:

[…] two major features needed to unlock a bunch of runtime functionality are promises and iterators, so I'll likely work on those soon.

And that's what I did the next day. Turns out iterators are much simpler than I remembered — the entire implementation is less than 300 lines!

As expected this unlocked a few more builtins which I did next:

More Math Functions

I only implemented about half of the Math object, so a bunch of functions were still missing. I picked mostly trigonometric and logarithmic functions next, all of which have an equivalent in Zig's std.math library (or even compiler intrinsics) and thus were easy to implement.

Conveniently they are directly mirroring their equivalents from the standard C library in terms of behavior for "special" inputs (NaN, infinity, negative zero), as do the ones in ECMAScript.

This means that most steps can be folded into a single function call, e.g. for Math.sin():

/// 21.3.2.30 Math.sin ( x )
/// https://tc39.es/ecma262/#sec-math.sin
fn sin(agent: *Agent, _: Value, arguments: ArgumentsList) !Value {
    const x = arguments.get(0);

    // 1. Let n be ? ToNumber(x).
    const n = try x.toNumber(agent);

    // 2. If n is one of NaN, +0𝔽, or -0𝔽, return n.
    // 3. If n is either +∞𝔽 or -∞𝔽, return NaN.
    // 4. Return an implementation-approximated Number value representing the result of the
    //    sine of ℝ(n).
    return Value.from(@sin(n.asFloat()));
}

While doing this I noticed two functions misbehaving in a subtle way: both std.math.asinh() and std.math.cbrt() would return 0 for -0 even though they are supposed to preserve the sign. I filed issues #17111 and #17112, which promptly got fixed in PRs #17120 and #17121 🎉

This is of course much less likely to happen in mature language and library implementations, but I'm more than happy to be an "early adopter" and improve the language for everyone by reporting/fixing such issues :^)

Pretty-Printing in Scripts

The Kiesel REPL already implements basic pretty-printing, generally trying to print relevant internal object state instead of just serializing (enumerable) properties.

I decided to expose this functionality to scripts — similar to pprint.pprint() in Python — by adding an optional second argument for options to the non-standard Kiesel.print() builtin:

Kiesel.print(value, { pretty: true });

Summary

test262 went up exactly 1%, now at 26%. CanadaHonk also prepared data collection for making a graph of progress over time for each engine, which I'm really looking forward to!

Expand to see the full list of newly implemented builtins 📝

There also were a couple of people reaching out about how to file issues or contribute after the previous devlog ended up on Lobsters. The short version is that I'm treating this as a read-only open source project for the moment — the source code is freely available, and everyone is welcome to use and modify it. However I want to avoid falling back into a mode where I spend more time reviewing PRs and handling issues than making actual progress myself.

There are plenty of issues that I'm aware of right now, and more that I'm not currently aware of, but this isn't the time for a backlog. Feel free to reach out directly if you have any questions/suggestions/fixes for obvious mistakes (example). :^)


Loading posts...