| Summary: | [serializer] Serializer chooses first matching parser rule for local serialization | ||
|---|---|---|---|
| Product: | [Modeling] TMF | Reporter: | Jan Koehnlein <jan> |
| Component: | Xtext | Assignee: | Project Inbox <tmf.xtext-inbox> |
| Status: | CLOSED FIXED | QA Contact: | |
| Severity: | normal | ||
| Priority: | P3 | CC: | henrik.lindberg, moritz.eysholdt, sebastian.zarnekow |
| Version: | 1.0.0 | Flags: | jan:
indigo+
|
| Target Milestone: | SR1 | ||
| Hardware: | PC | ||
| OS: | Mac OS X - Carbon (unsup.) | ||
| Whiteboard: | |||
| Bug Depends on: | 333976, 352088 | ||
| Bug Blocks: | |||
what's your intended way of implementing this? I'll check the containment tree of the semantic model against the grammar if the to-be-serialized-token is a root token. by "root token" do you mean an EObject for which there is only one valid parser rule? that would work... By RootToken I mean org.eclipse.xtext.parsetree.reconstr.impl.AbstractParseTreeConstructor.RootToken (In reply to comment #4) > By RootToken I mean > org.eclipse.xtext.parsetree.reconstr.impl.AbstractParseTreeConstructor.RootToken hm... then I don't see what you're up to. (In reply to comment #2) > I'll check the containment tree of the semantic model against the grammar if > the to-be-serialized-token is a root token. because, with the current implementation, every to-be-serialized-EObject is a valid RootToken. On the one hand this is convenient to allow easy serialization for every sub-tree of a model. But on the other hand this is exactly the cause for this bug. The algorithm I was thinking of is: boolean exactlyOneParserRuleForObject(EObject) { There is exactly one parser rule in the grammar that could have instantiated this EObject. I.e., object.eClass() == rule.returnType || actionExists(object.eClass(), rule) || unassigendRuleCallExists(object.eClass(), rule) } extended_to_be_serialized = to_be_serialized; while(!exactlyOneParserRuleForObject(extended_to_be_serialized))) extended_to_be_serialized = extended_to_be_serialized.eContainer(); text = serialize(extended_to_be_serialized); text = trimToRegion(text, to_be_serialized); The main problem is that if there are multiple parser rules for an EObject the only algorithm that can select the right one is the serializer's backtracking algorithm. I'm on the following track:
InstanceDescription tryConsume() {
if (next == lastRuleCallOrigin && lastRuleCallOrigin instanceof RootToken) {
if (!isValidFor(getEObject()) {
return null;
}
}
if(getEObject().eClass() != grammarAccess....getClassifier())
return null;
return eObjectConsumer;
}
(In reply to comment #6) > I'm on the following track: > > InstanceDescription tryConsume() { > if (next == lastRuleCallOrigin && lastRuleCallOrigin instanceof RootToken) { > if (!isValidFor(getEObject()) { > return null; > } > } > if(getEObject().eClass() != grammarAccess....getClassifier()) > return null; > return eObjectConsumer; > } It has to read: IEObjectConsumer tryConsume() { .. } (In reply to comment #6) > I'm on the following track: > > InstanceDescription tryConsume() { > if (next == lastRuleCallOrigin && lastRuleCallOrigin instanceof RootToken) { > if (!isValidFor(getEObject()) { > return null; > } > } > if(getEObject().eClass() != grammarAccess....getClassifier()) > return null; > return eObjectConsumer; > } ok, I see. How do you want to implement isValidFor(getEObject()? Postponed. I think I may have been bitten by this bug.
I experienced an insertion of the string "@precondition" before an Expression, and a ';' after the expression as result of a SemanticModification of a SwitchExpression (derived from Expression).
I had the following...
Function : ... // other things omitted
(preCondition = PreCondition) ?
;
PreCondition returns Expression : "@precondition" Expression ';' ;
Changing this to:
Function : ... //
("@precondition preCondition = Expression ';' )
(and removing the PreCondition rule) worked around the issue.
bug 333976 proposes to solve this in the way that a "context" can be given to the serializer. The context can be a ParserRule or an AssignedAction. Furthermore, a component to find all valid contexts for a semantic object would come handy. --- interface GrammarContextFinder { Iterable<EObject> findValidContexts(EObject semanitcObject, boolean checkContainer, Iterable<EObject> contextsToConsider); } - if contextsToConsider is null, all contexts are considered. - this returns a list of all contexts that would be valid to serializes semanitcObject. - if checkContainer is true, this should also check if there is a context for semanticObject's container that has an assigned rule call/action to the returned context. The described MWE2 scenario works like a charm now. Resolved fixed. Closing all bugs that were set to RESOLVED before Neon.0 Closing all bugs that were set to RESOLVED before Neon.0 |
If a grammar contains to rules with the same return types, that both assign the features that are set in the object to be serialized (and maybe more optional ones) the serializer takes the first match, even though it might not be valid in the context of the element. MWE2 for example defines two rules with almost identical feature assignment. RootComponent returns Component: {Component} (type=[types::JvmType|FQN]| '@' module=[Module|FQN]) (':' name=FQN)? (autoInject?='auto-inject')? '{' assignment+=Assignment* '}'; Component: {Component} (type=[types::JvmType|FQN]| '@' module=[Module|FQN])? (':' name=FQN)? (autoInject?='auto-inject')? '{' assignment+=Assignment* '}'; While the RootComponent rule only matches the first occurrence, Components can be nested using the Component rule. Serializing a non root component will usually result in applying the RootComponent rule as it preceeds the Component rule. One consequence of this bug is that comments are changing positions when applying a quickfix (#302128).