diff --git a/examples/0620-comptime-metatype-make-enum.sx b/examples/0620-comptime-metatype-make-enum.sx new file mode 100644 index 00000000..77a9e55f --- /dev/null +++ b/examples/0620-comptime-metatype-make-enum.sx @@ -0,0 +1,41 @@ +// make_enum — the GENERAL comptime enum constructor over declare/define: mint a +// nominal enum from a `[]EnumVariant` VALUE, rather than a hardcoded literal +// (the channel-result constructors hardcode theirs). The variant list is an +// ordinary comptime value, so a builder ASSEMBLES it in a local before minting — +// here `build_level` constructs `vs` (a local array, which could be filled +// conditionally / in a loop), then mints `Level` from it. +// +// This exercises `define` decoding a value-arg SLICE (`decodeVariantElements`'s +// slice-fat-pointer branch), as opposed to the inline `.[ … ]` array the +// 0614–0618 examples pass directly into `.enum(...)`. +#import "modules/std.sx"; +#import "modules/std/meta.sx"; + +build_level :: () -> Type { + // The variant list lives in a local (not inlined into `define`): a non- + // generic `() -> Type` builder has its whole body comptime-evaluated, so + // `vs` is in scope when `make_enum` mints from it. + vs := EnumVariant.[ + EnumVariant.{ name = "info", payload = void }, + EnumVariant.{ name = "warn", payload = void }, + EnumVariant.{ name = "fatal", payload = i64 }, // carries an exit code + ]; + return make_enum("Level", vs); +} + +Level :: build_level(); + +show :: (l: Level) { + if l == { + case .info: { print("info\n"); } + case .warn: { print("warn\n"); } + case .fatal: (c) { print("fatal code={}\n", c); } + } +} + +main :: () -> i32 { + show(.info); + show(.warn); + show(.fatal(70)); + return 0; +} diff --git a/examples/expected/0620-comptime-metatype-make-enum.exit b/examples/expected/0620-comptime-metatype-make-enum.exit new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/examples/expected/0620-comptime-metatype-make-enum.exit @@ -0,0 +1 @@ +0 diff --git a/examples/expected/0620-comptime-metatype-make-enum.stderr b/examples/expected/0620-comptime-metatype-make-enum.stderr new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/examples/expected/0620-comptime-metatype-make-enum.stderr @@ -0,0 +1 @@ + diff --git a/examples/expected/0620-comptime-metatype-make-enum.stdout b/examples/expected/0620-comptime-metatype-make-enum.stdout new file mode 100644 index 00000000..56eff2f8 --- /dev/null +++ b/examples/expected/0620-comptime-metatype-make-enum.stdout @@ -0,0 +1,3 @@ +info +warn +fatal code=70 diff --git a/library/modules/std/meta.sx b/library/modules/std/meta.sx index 69c481f3..f02a5c24 100644 --- a/library/modules/std/meta.sx +++ b/library/modules/std/meta.sx @@ -57,6 +57,23 @@ field_type :: ($T: Type, idx: i64) -> Type #builtin; // and is one nominal type across sites (the type-fn identity path). The channel // library (N3) consumes these once it lands. +// The GENERAL enum constructor: mint a nominal enum NAMED `name` from a variant +// list passed as a VALUE (a `[]EnumVariant`), rather than a hardcoded literal. +// Because `variants` is an ordinary comptime value, a caller can ASSEMBLE it in +// a local (conditionally, in a loop, from type args) before minting — see +// `examples/0620`. `define` decodes the slice via `decodeVariantElements`. The +// channel constructors above are the special-cased shapes; `make_enum` is the +// open-ended one every other constructor could be written over. +// +// Call it from a non-generic `() -> Type` builder (whose whole body is +// comptime-evaluated, so locals are in scope) or inline with a literal arg +// (`E :: make_enum("E", .[ … ])`). A *generic* type-fn comptime-evaluates only +// its return EXPRESSION, so build the list inline in the return there, not in a +// preceding local. +make_enum :: (name: string, variants: []EnumVariant) -> Type { + return define(declare(name), .enum(.{ variants = variants })); +} + // A blocking recv: a value, or the channel was closed (drained). RecvResult :: ($T: Type) -> Type { return define(declare("RecvResult"), .enum(.{ variants = .[