Skip to content

added generation of type specific 'MarshalJSON' & 'UnmarshalJSON' implementations#98

Open
sailingKieler wants to merge 14 commits into
mainfrom
cs/json-marshalling
Open

added generation of type specific 'MarshalJSON' & 'UnmarshalJSON' implementations#98
sailingKieler wants to merge 14 commits into
mainfrom
cs/json-marshalling

Conversation

@sailingKieler

@sailingKieler sailingKieler commented Jun 8, 2026

Copy link
Copy Markdown
Member

Contributes support for exporting and importing ASTs in Json.
Includes:

  • a generator component producing json_gen.go files

    • they contribute methods turning AstNodes into impls of json.Marshaler & json.Unmarshaler
  • generic MarshalJSON & UnmarshalJSON implementations for Reference

  • util/json/json.go demonstrates the procedure of importing an AST in json into a Fastbelt container

  • a simple round trip AST export and import test including cross references to other documents (circular) by means of the Arithmetics test language,

    • focus is on successfully resolving the (cross document) cross-references
  • a roundtrip AST export and import test (no external cross-refs by now) by means of the Grammar language,

    • focus is on completeness of feature processing and cardinalities:
      boolean, string, AstNode, Reference x 1, ?, *, +

Note:

  • Minor supplements in fixture.go
  • Fix of a potential nil pointer de-reference in symbol.go

There's one known potential issue:
During the import of an AST in json the Token instances are always initialized with token type Token_ID.
The leads to a compiler issue if there is no ID token type.

We could improve this by an analysis of the Parser rules, but that will never be complete.
Imagine the grammar defines interfaces of types that are never instantiated by parser rules, but the data are always imported vom Json snapshots.
To mitigate this we might offer an opportunity in the grammar to determine a token type for fields of type string or composite. To be discussed.

Comment thread reference.go Outdated
}
// We expect at this point that all references have been attempted to resolve.
if !r.resolved.Load() {
return nil, errors.New("reference not resolved")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is just preliminary, I don't know which context instance to rely on for calling Ref(...), yet
(since this function is called by json.Mashall(...), not by ourselves), and whether we should attempt to resolve here, at all.

AFAICS, r.resolved is true if resolution has been attempted, regardless of success or failure.
Hence, this guards stops the serialization, e.g., if the document hasn't been build until DocStateLinked at least.

Comment thread reference.go
RefText string `json:"refText"`
URI string `json:"uri,omitempty"`
Err string `json:"error,omitempty"`
}{

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This struct def should be exported. And I propose aligning this with Langium for cross-framework compatibility:

https://github.com/eclipse-langium/langium/blob/7ad7c76e85134185146e1a99bd352e7527ed1fec/packages/langium/src/serializer/json-serializer.ts#L96-L105

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This struct def should be exported.

Why?
It's purely technical and kind of a vehicle.
It might make sense to rely in the two (Un)Marshal methods on the same definition, though.

And I propose aligning this with Langium for cross-framework compatibility:

That's my plain, too.

Comment thread reference.go Outdated
Err string `json:"error,omitempty"`
}{
RefText: r.unit.String(),
URI: uri,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

In Langium, we omit the URI if the reference target is in the same document. This can reduce the size of generated JSON by a lot.

Thought: can we include something like a URI converter here as well? Exporting JSONs with absolute file URIs would be pretty useless in many cases.

https://github.com/eclipse-langium/langium/blob/7ad7c76e85134185146e1a99bd352e7527ed1fec/packages/langium/src/serializer/json-serializer.ts#L161-L167

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In Langium, we omit the URI if the reference target is in the same document. This can reduce the size of generated JSON by a lot.

That's achieved by the omitempty setting. Of course, the prop value shouldn't be set upfront.

Thought: can we include something like a URI converter here as well? Exporting JSONs with absolute file URIs would be pretty useless in many cases.

Yes, that's my plan.

@sailingKieler sailingKieler left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Thanks for the hints Miro.
This state is a very early one, it doesn't represent the one I have in mind already.

I also seek for a solution that is compatible with Langium, s.t. we could use it as an interface for data exchange

More changes are coming soon :-)

Comment thread reference.go Outdated
Err string `json:"error,omitempty"`
}{
RefText: r.unit.String(),
URI: uri,

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

In Langium, we omit the URI if the reference target is in the same document. This can reduce the size of generated JSON by a lot.

That's achieved by the omitempty setting. Of course, the prop value shouldn't be set upfront.

Thought: can we include something like a URI converter here as well? Exporting JSONs with absolute file URIs would be pretty useless in many cases.

Yes, that's my plan.

Comment thread reference.go
RefText string `json:"refText"`
URI string `json:"uri,omitempty"`
Err string `json:"error,omitempty"`
}{

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This struct def should be exported.

Why?
It's purely technical and kind of a vehicle.
It might make sense to rely in the two (Un)Marshal methods on the same definition, though.

And I propose aligning this with Langium for cross-framework compatibility:

That's my plain, too.

Comment thread reference.go Outdated
}
// We expect at this point that all references have been attempted to resolve.
if !r.resolved.Load() {
return nil, errors.New("reference not resolved")

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is just preliminary, I don't know which context instance to rely on for calling Ref(...), yet
(since this function is called by json.Mashall(...), not by ourselves), and whether we should attempt to resolve here, at all.

AFAICS, r.resolved is true if resolution has been attempted, regardless of success or failure.
Hence, this guards stops the serialization, e.g., if the document hasn't been build until DocStateLinked at least.

@sailingKieler sailingKieler force-pushed the cs/json-marshalling branch 2 times, most recently from 23336ec to 10ec511 Compare June 17, 2026 18:23
@sailingKieler sailingKieler force-pushed the cs/json-marshalling branch 3 times, most recently from 66a1bfa to f72abbc Compare July 3, 2026 13:29
@sailingKieler sailingKieler force-pushed the cs/json-marshalling branch from f72abbc to cc2a141 Compare July 9, 2026 13:08
@sailingKieler sailingKieler marked this pull request as ready for review July 9, 2026 13:30
@sailingKieler sailingKieler force-pushed the cs/json-marshalling branch from cc2a141 to 8ca6a6c Compare July 9, 2026 13:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants