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

Fault tolerant transformers #383

Merged
merged 16 commits into from
Sep 19, 2024

Conversation

ftomassetti
Copy link
Member

When we implement transformers we may have the case in which the transformation is missing and the case in which it is failing. It may be failing because we cover a certain subset of cases. For example, when transforming from RPG to Java, we may cover a field declaration if the field is a string or a number, but not if it is of type pointer. In these cases we may want to still produce a partial transformation, treating the failure similarly to what we do with missing transformations. So expand the strategy for missing transformation to cover also failing transformations.

In addition to this:

  • We ensure that generated IDs are compatible with LionWeb, removing illegal characters
  • We expand the logic to instantiate a dummy node, with the sole purpose of attaching an origin to it. Previously we were needing a default constructor. Now, if that is not present, we attempt to use other constructors, generating dummy values as needed

@ftomassetti ftomassetti changed the base branch from main to maintenance/kolasu15 September 17, 2024 14:15
Copy link
Member

@alessiostalla alessiostalla left a comment

Choose a reason for hiding this comment

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

Looks good!

(param.type.classifier as KClass<*>).isSubclassOf(Node::class) ->
(param.type.classifier as KClass<out Node>).dummyInstance()
param.type == String::class.createType() -> "DUMMY"
param.type.classifier == ReferenceByName::class -> ReferenceByName<PossiblyNamed>("UNKNOWN")
Copy link
Member

Choose a reason for hiding this comment

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

This is unlikely, but the reference could be "resolved" to a real element called "UNKNOWN". Is it possible to have a ReferenceByName subclass that can't possibly be resolved?

Copy link
Member Author

Choose a reason for hiding this comment

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

I see your point, but I would aim to solve it by never trying to resolve references belonging to "dummy nodes" or "dummy trees". So I would consider:

  1. Adding a flag val Node.isDummy that looks at the origin parameter and possibly also to the parent
  2. Adding a flag in walk and similar methods, to give the option to skip dummy nodes
  3. When resolving references use the walk method using the flag that skip dummy nodes
    In this way we never attempt to solve references. Alternatively we can also create subclass of ReferenceByName that explode if you attempt to mark it as solved.
    What do you think?

Copy link
Member

Choose a reason for hiding this comment

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

I'm not a fan of modifying walk, but the symbol resolver could apply a filter to the nodes it walks to exclude dummy ones, it makes sense

// We either find complex logic to find the ones that aren't or just pick one randomly.
// Eventually we will build a tree
val r = Random.Default
subclasses[r.nextInt(subclasses.size)].toInstantiableType()
Copy link
Member

Choose a reason for hiding this comment

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

I'm not a fan of random here because parsing the same file twice will likely give different results, which I think is undesirable (even if we can say that the behavior is unspecified for code that we don't yet support).
I would also consider a mechanism (marker interface or annotation) with which we can designate a specific subclass as the default/fallback node, because in my experience it's not uncommon to have classes such as UnsupportedStatement or ExpressionError already in use.

Copy link
Member Author

Choose a reason for hiding this comment

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

That is a good point. My goal is to avoid that we pick always the wrong one as ArrayType(ArrayType(ArrayType(...))), but perhaps what we can do is to pick a pseudo-random number, that actually depends on the depth of the "DummyNode". I will work on that. Adding an annotation could make our life easier here, but it would require extra work when building the language, so I would lean toward doing more work on this code to have to do less work on all the languages

Copy link
Member

Choose a reason for hiding this comment

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

I see. Anyway I guess this only applies to 1.5 because in 1.6 we'll have machine-generated error nodes to use.

@ftomassetti
Copy link
Member Author

Thank you @alessiostalla for the comments, I think the PR is now improved

@ftomassetti ftomassetti merged commit 173c4fd into maintenance/kolasu15 Sep 19, 2024
4 checks passed
@ftomassetti ftomassetti deleted the feature/faultTolerantTransformes branch September 19, 2024 06:38
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