commit b6669452679a49b3ff825daf266b546fbca08a7b
parent 0c2e8788cd86c23df960644b67e0543fc9519cf0
Author: Erik Loualiche <eloualic@umn.edu>
Date: Fri, 6 Feb 2026 11:10:55 -0600
Use Nickel std.enum.to_tag_and_arg format for enums
Change enum encoding to match Nickel standard library:
- Simple enum: { tag = "Name" }
- Enum with arg: { tag = "Name", arg = value }
Previously used _tag/_value, now uses tag/arg to be consistent
with std.enum.to_tag_and_arg.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat:
3 files changed, 27 insertions(+), 21 deletions(-)
diff --git a/docs/src/man/ffi.md b/docs/src/man/ffi.md
@@ -53,21 +53,27 @@ nickel_eval_ffi("{ a = 1 }", Dict{String, Int}) # Typed Dict
### Enums
-Nickel enums are converted to `Dict{String, Any}` with special fields:
+Nickel enums are converted to `Dict{String, Any}` matching the format of `std.enum.to_tag_and_arg`:
**Simple enum** (no argument):
```julia
nickel_eval_native("let x = 'Foo in x")
-# => Dict("_tag" => "Foo")
+# => Dict("tag" => "Foo")
```
**Enum with argument**:
```julia
nickel_eval_native("let x = 'Some 42 in x")
-# => Dict("_tag" => "Some", "_value" => 42)
+# => Dict("tag" => "Some", "arg" => 42)
nickel_eval_native("let x = 'Ok { value = 123 } in x")
-# => Dict("_tag" => "Ok", "_value" => Dict("value" => 123))
+# => Dict("tag" => "Ok", "arg" => Dict("value" => 123))
+```
+
+This matches Nickel's standard library convention:
+```nickel
+'Some 42 |> std.enum.to_tag_and_arg
+# => { tag = "Some", arg = 42 }
```
### Nested Structures
diff --git a/rust/nickel-jl/src/lib.rs b/rust/nickel-jl/src/lib.rs
@@ -206,12 +206,12 @@ fn encode_term(term: &RichTerm, buffer: &mut Vec<u8>) -> Result<(), String> {
}
}
Term::Enum(tag) => {
- // Simple enum without argument: encode as record with just _tag
+ // Simple enum: encode as { tag = "Name" } (matches std.enum.to_tag_and_arg)
buffer.push(TYPE_RECORD);
buffer.extend_from_slice(&1u32.to_le_bytes()); // 1 field
- // _tag field
- let tag_key = b"_tag";
+ // tag field
+ let tag_key = b"tag";
buffer.extend_from_slice(&(tag_key.len() as u32).to_le_bytes());
buffer.extend_from_slice(tag_key);
buffer.push(TYPE_STRING);
@@ -220,12 +220,12 @@ fn encode_term(term: &RichTerm, buffer: &mut Vec<u8>) -> Result<(), String> {
buffer.extend_from_slice(tag_bytes);
}
Term::EnumVariant { tag, arg, .. } => {
- // Enum variant with argument: encode as record with _tag and _value
+ // Enum with argument: encode as { tag = "Name", arg = value } (matches std.enum.to_tag_and_arg)
buffer.push(TYPE_RECORD);
buffer.extend_from_slice(&2u32.to_le_bytes()); // 2 fields
- // _tag field
- let tag_key = b"_tag";
+ // tag field
+ let tag_key = b"tag";
buffer.extend_from_slice(&(tag_key.len() as u32).to_le_bytes());
buffer.extend_from_slice(tag_key);
buffer.push(TYPE_STRING);
@@ -233,10 +233,10 @@ fn encode_term(term: &RichTerm, buffer: &mut Vec<u8>) -> Result<(), String> {
buffer.extend_from_slice(&(tag_bytes.len() as u32).to_le_bytes());
buffer.extend_from_slice(tag_bytes);
- // _value field
- let value_key = b"_value";
- buffer.extend_from_slice(&(value_key.len() as u32).to_le_bytes());
- buffer.extend_from_slice(value_key);
+ // arg field
+ let arg_key = b"arg";
+ buffer.extend_from_slice(&(arg_key.len() as u32).to_le_bytes());
+ buffer.extend_from_slice(arg_key);
encode_term(arg, buffer)?;
}
other => {
diff --git a/test/test_ffi.jl b/test/test_ffi.jl
@@ -84,21 +84,21 @@
end
@testset "Enums" begin
- # Simple enum (no argument)
+ # Simple enum (no argument) - matches std.enum.to_tag_and_arg format
result = nickel_eval_native("let x = 'Foo in x")
@test result isa Dict{String, Any}
- @test result["_tag"] == "Foo"
- @test !haskey(result, "_value")
+ @test result["tag"] == "Foo"
+ @test !haskey(result, "arg")
# Enum with integer argument
result = nickel_eval_native("let x = 'Some 42 in x")
- @test result["_tag"] == "Some"
- @test result["_value"] === Int64(42)
+ @test result["tag"] == "Some"
+ @test result["arg"] === Int64(42)
# Enum with record argument
result = nickel_eval_native("let x = 'Ok { value = 123 } in x")
- @test result["_tag"] == "Ok"
- @test result["_value"]["value"] === Int64(123)
+ @test result["tag"] == "Ok"
+ @test result["arg"]["value"] === Int64(123)
# Match expression
result = nickel_eval_native("let x = 'Success 42 in x |> match { 'Success v => v, 'Failure _ => 0 }")