Skip to content

Commit

Permalink
Support record variannts with no fields
Browse files Browse the repository at this point in the history
  • Loading branch information
dusty-phillips committed Aug 20, 2024
1 parent be9779e commit 5ac853f
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 7 deletions.
10 changes: 6 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,10 @@ PRs are welcome.

### TODO

- custom types with no fields are probably not working
- custom types with unlabelled fields are probably not working
- most expressions aren't implemented yet
- panic should probably raise a custom/stdlib exception instead of BaseException
- custom types with unlabelled fields are not working
- Given that labelled and unlabelled fields can be mixed on one class, I have a feeling we have to ditch dataclasses. Probably a custom class with slots, a dict of names to indices, and a custom **match_args** that can handle tuple-like _or_ record-like syntax?
- some complex expressions aren't implemented yet
- haven't really tested with nesting of expressions
- need to print out nice errors when glance fails to parse
- No List or Result custom types yet
Expand All @@ -58,7 +59,8 @@ PRs are welcome.
- not currently generating python type hints (e.g. function arguments and return types), but gleam gives us that info so may as well use it
- no concept of a "project", gleam.toml, downloading dependencies
- only compiles one module at a time
- copies the prelude module blindly into the directory that contains that one module
- eliminate all todos in source code
- panic should probably raise a custom/stdlib exception
- generate **main** if a module has a main function
- I notice that the javascript doesn't generate the wrapping class for custom variants. Can we get away with not having them?
- flesh out this list
12 changes: 9 additions & 3 deletions src/generator.gleam
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ fn generate_type(type_: python.Type) -> StringBuilder {
}
}

fn generate_type_fields(field: python.Field(python.Type)) -> StringBuilder {
fn generate_type_field(field: python.Field(python.Type)) -> StringBuilder {
case field {
python.UnlabelledField(_) ->
todo as "not handling unlabeled fields in custom types yet"
Expand All @@ -203,7 +203,10 @@ fn generate_type_variant(variant: python.Variant) -> StringBuilder {
|> string_builder.append(variant.name)
|> string_builder.append(":\n")
|> string_builder.append_builder(
generate_plural(variant.fields, generate_type_fields, "\n")
case variant.fields {
[] -> string_builder.from_string("pass")
fields -> generate_plural(fields, generate_type_field, "\n")
}
|> generator_helpers.indent(4),
)
}
Expand All @@ -224,12 +227,15 @@ fn generate_variant_reassign(

fn generate_custom_type(custom_type: python.CustomType) -> StringBuilder {
case custom_type.variants {
[] -> todo as "Empty types not supported yet"
// empty types get discarded
[] -> string_builder.new()

// we just discard the outer class if there is only one variant
[one_variant] -> {
generate_type_variant(one_variant)
|> string_builder.append("\n\n\n")
}

variants -> {
string_builder.new()
|> string_builder.append("class ")
Expand Down
57 changes: 57 additions & 0 deletions test/custom_types_test.gleam
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
import gleeunit/should
import macabre

pub fn no_variant_custom_type_test() {
"pub type Foo {
}"
|> macabre.compile
|> should.be_ok
|> should.equal(
"from gleam_builtins import *
",
)
}

pub fn single_variant_custom_type_test() {
"pub type Foo {
Bar(a: Int)
Expand Down Expand Up @@ -42,6 +54,51 @@ Bar = Foo.Bar
Baz = Foo.Baz
",
)
}

pub fn single_variant_with_no_fields_test() {
"pub type Foo {
Bar
}"
|> macabre.compile
|> should.be_ok
|> should.equal(
"from gleam_builtins import *
@dataclasses.dataclass(frozen=True)
class Bar:
pass
",
)
}

pub fn multi_variant_with_no_fields_test() {
"pub type Foo {
Bar
Baz
}"
|> macabre.compile
|> should.be_ok
|> should.equal(
"from gleam_builtins import *
class Foo:
@dataclasses.dataclass(frozen=True)
class Bar:
pass
@dataclasses.dataclass(frozen=True)
class Baz:
pass
Bar = Foo.Bar
Baz = Foo.Baz
",
)
}

0 comments on commit 5ac853f

Please sign in to comment.