Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

External tag #316

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ To be released.

- The `uri` type has completly gone; use `url` instead.
[[#126], [#281] by Jonghun Park]
- Support [external_tag][etag] via '@external-tag' annotation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changelogs should be the past tense. Also the following explanation does not have enough information:

external_tag via '@external-tag' annotation

[[#266], [#316] by JaeHyung Jang]

[etag]: https://serde.rs/enum-representations.html
[#266]: https://github.com/nirum-lang/nirum/issues/266
[#316]: https://github.com/nirum-lang/nirum/pull/316

### Docs target

Expand Down
21 changes: 21 additions & 0 deletions docs/serialization.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,27 @@ It's represented in JSON to:
In a similar way to a record type, undefined fields in a payload are ignored
by deserializer.

If '@external-tag' annotation is given on tag below example:

union name =
@external-tag
east-asian-name ( text family-name, text given-name )
| ...
;

It's representated in JSON to:

{
{
"east-asian-name": {
"_type": "name",
"_tag": "east-asian-name",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This field might be not necessary, because it already presented above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And, I think @external-tag should be associated on the whole union, not on its tag. If not, it loses the advantage that can be decide which tag should be parsed at once.

"family_name": "Hong",
"given_name": "Minhee"
}
}
}
}

Option type
-----------
Expand Down
3 changes: 2 additions & 1 deletion examples/shapes.nrm
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ union shape
point upper-left,
point lower-right
)
| circle (point origin, offset radius)
| @external-tag
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the @external-tag annotation be applied to tags, not union types? Does that mean some tags could be serialized as external-tag-style while some other tags are still serialized with "_tag" field at a time?

circle (point origin, offset radius)
;

// This is comment. Note that there are important differences between
Expand Down
16 changes: 14 additions & 2 deletions src/Nirum/Targets/Python.hs
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,8 @@ class $funcName(object):
|]

compileUnionTag :: Source -> Name -> Tag -> CodeGen Markup
compileUnionTag source parentname d@(Tag typename' fields' _) = do
compileUnionTag source parentname d@(Tag typename' fields' annotations') = do
let hasExternalTag = M.member "external-tag" $ AI.annotations annotations'
abc <- collectionsAbc
fieldCodes <- toFieldCodes source
(\ f -> [qq|value.get('{toBehindSnakeCaseText (fieldName f)}')|])
Expand Down Expand Up @@ -521,14 +522,18 @@ class #{className}(#{parentClass}):
%{ endcase }

def __nirum_serialize__(self):
return {
t = {
'_type': '#{behindParentTypename}',
'_tag': '#{behindTagName}',
%{ forall fc@FieldCode { fcField = Field { fieldType = fType } } <- fieldCodes }
'#{fcBehindName fc}':
#{compileSerializer' source fType $ T.append "self." $ fcAttributeName fc},
%{ endforall }
}
%{ if hasExternalTag }
t = {'#{behindTagName}': t}
%{ endif }
return t

@classmethod
%{ case pyVer }
Expand All @@ -544,6 +549,13 @@ class #{className}(#{parentClass}):
) -> typing.Optional['#{className}']:
%{ endcase }
handle_error = #{defaultErrorHandler}(on_error)
%{ if hasExternalTag }
try:
value = '#{toBehindSnakeCaseText typename'}'
except KeyError:
handle_error('.', 'Expected #{toBehindSnakeCaseText typename'} to exist.')
handle_error.raise_error()
%{ endif }
if isinstance(value, #{abc}.Mapping):
try:
tag = value['_tag']
Expand Down
5 changes: 5 additions & 0 deletions test/nirum_fixture/fixture/foo.nrm
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,8 @@ record name-shadowing-field-record (
union optional-union = foo ( int32? bar )
| baz ( int32 qux )
;

union external-tag-union = tag ( int32 tag )
| @external-tag
etag ( int32 etag)
;
18 changes: 18 additions & 0 deletions test/serialization/unions/external-tag.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"description": "Serialize into external tag when gives 'external-tag' annotation",
"type": "fixture.foo.etag",
"input": {
"etag": {
"_type": "external_tag_union",
"_tag": "etag",
"etag": 1
}
},
"normal": {
"etag": {
"_type": "external_tag_union",
"_tag": "etag",
"etag": 1
}
}
}