rems-project / sail

Sail architecture definition language
Other
563 stars 92 forks source link

Merge union into enum? #598

Closed Timmmm closed 4 days ago

Timmmm commented 1 week ago

I wonder if it makes sense to merge union into enum like Rust does, since enums are just a special case union where every member is : unit. I think the syntax changes this would require are:

  1. Allow the type to be omitted for variants, and default to : unit.
  2. Allow the () to be omitted on unit variants when pattern matching and constructing values.

Not exactly high priority but it might simplify the language a bit, and makes things closer to Rust which people may have familiarity with already.

Alasdair commented 1 week ago

We used to allow nullary union constructors, but the issue was it was a bit awkward from a namespacing perspective. Right now there are two namespaces, one for function-like things f() which has functions and constructors and another for identifier-like things id which has registers, enum members, local variables, etc. The intent was to simplify the implementation various Sail backends, so they can just look into E_app nodes for unions and E_id nodes for enumerations. The code is in a better state now, so maybe we could think of undoing that restriction in a sensible way.

The only issue I see is this would change the behavior of scattered definitions in the following sense: With a combined Rust-style enum keyword, you could do

scattered enum my_enum

enum clause my_enum = A

enum clause my_enum = B

then later you could write:

enum clause my_enum = C : T

which would promote the enum to what is currently a union, and change its runtime representation quite significantly.

Alasdair commented 1 week ago

I think there was also an issue with how when we had

union option('a : Type) = {
  Some : 'a,
  None
}

it was very awkward because it mean't the E_id AST node with the None had a forall 'a quantifier, and that was awkward for some reason with bits of code that were assuming that identifiers never had quantifiers. It's been so long I can't recall the details though.

Timmmm commented 4 days ago

Right now there are two namespaces, one for function-like things f() which has functions and constructors and another for identifier-like things id which has registers, enum members, local variables, etc.

Ah interesting. I was wondering about that... Probably worth adding to the manual. There must be another namespace for type names right? Because we have code like this:

type cap_size : Int = xlen_bytes * 2
let  cap_size = sizeof(cap_size)
...
function ...(ast : ast)

change its runtime representation quite significantly

Ah yeah interesting point. Ok maybe not worth the effort then. I'll close this.