Home » Modeling » OCL » Programatically Accessing OCL Comments
Programatically Accessing OCL Comments [message #515831] |
Sun, 21 February 2010 15:28 |
Alan McMorran Messages: 55 Registered: July 2009 |
Member |
|
|
Hi,
First of all, apologies if this is a simple question and I'm just too
daft to see the answer, but I was wondering if it was possible to
programatically access the comments within an OCL file during parsing?
My use-case is that I've got a number of validation profiles created
for a single metamodel defined in Ecore (the same model is used for
different exchange profiles so I need to have the constraints separate
from the model itself). I've got the OCL created and working
successfully against the instance data, but I hoping to be able to add
some documentation to the OCL itself with some annotated comments that
could then feed into the user-readable validation results.
For example:
context TransformerWinding
--@Doc: Magnetizing branch susceptance (B mag) must be set
inv: (self.b <>null)
--@Doc: Magnetizing branch conductance (G mag) must be set
inv: (self.g <>null)
--@Doc: Each TransformerWinding can have at most one TapChanger so
either RatioTapChanger is unset or if it is set then PhaseTapChanger
must not be set
inv: (self.RatioTapChanger =null) or ((self.RatioTapChanger <>null) and
(self.PhaseTapChanger = null))
In my code at the moment to get the constraints for a profile that I
later validate against I do:
OCL<?, EClassifier, ?, ?, ?, ?, ?, ?, ?, Constraint, EClass, EObject>
ocl = OCL.newInstance(factory);
for (Constraint constraint : ocl.parse(oclInput)) {
if (isInvariant(constraint)) {
constraints.add(constraint);
}
}
(Where Constraint is org.eclipse.ocl.ecore.Constraint and the factory
is an EcoreEnvironmentFactory)
I like to be able to find what the comment that preceded that
constraint was in the original OCL so it could be marked against that
constraint as the user-readable documentation. Then if a constraint
failed, I can say to the user something like:
Object <ID> of type TransformerWinding failed because the following
rules failed:
Rule: "Each TransformerWinding can have at most one TapChanger so
either RatioTapChanger is unset or if it is set then PhaseTapChanger
must not be set"
rather than
Object <ID> of type TransformerWinding failed because the following
rules failed:
"inv: (self.RatioTapChanger =null) or ((self.RatioTapChanger <>null)
and (self.PhaseTapChanger = null))"
I've had a dig through the source, but I thought I would check whether
this is something that is already supported that I've just missed, or
if anyone knew how to do it already!
Thanks in advance for any help.
Alan
|
|
| |
Re: Programatically Accessing OCL Comments [message #515836 is a reply to message #515832] |
Sun, 21 February 2010 16:19 |
Ed Willink Messages: 7655 Registered: July 2009 |
Senior Member |
|
|
Hi Alan, Lothar
The Lexer was changed in August (post Galileo, 1.3.0) in
https://bugs.eclipse.org/bugs/show_bug.cgi?id=286724 so that makeComment
is invoked for each comment. This allows LPG's adjunct capabilities to
be used to get the preceding adjuncts of a useful Token.
This was motivated by making comments available for editor colouring.
The change is trivial. You could easily retrofit it to 1.3.0 if you're
comfortable with running LPG.
In order to properly support
https://bugs.eclipse.org/bugs/show_bug.cgi?id=191689 a technique for
persisting comments for OCL embedded in Ecore will be necessary. The
same technique
should allow support for comments in ASTs too. Expect an Ecore
EAnnotation/EMOF Comment to identify token location and adjuncts.
Raised as https://bugs.eclipse.org/bugs/show_bug.cgi?id=303442
Regards
Ed Willink
On 21/02/2010 15:41, Lothar Werzinger wrote:
> Alan McMorran wrote:
>
>> Hi,
>>
>> First of all, apologies if this is a simple question and I'm just too
>> daft to see the answer, but I was wondering if it was possible to
>> programatically access the comments within an OCL file during parsing?
>>
>> My use-case is that I've got a number of validation profiles created
>> for a single metamodel defined in Ecore (the same model is used for
>> different exchange profiles so I need to have the constraints separate
>> from the model itself). I've got the OCL created and working
>> successfully against the instance data, but I hoping to be able to add
>> some documentation to the OCL itself with some annotated comments that
>> could then feed into the user-readable validation results.
>
> That might be interesting even if the OCL constraints are stored as ECore
> annotations, as the usecase to present the user with a human readable
> validation result is the same.
>
> If you find out how to do it with your separated OCL file, can you put your
> findings somewhere on the wiki, so that others can copy your approach?
>
> Thanks,
> Lothar
>
|
|
|
Re: Programatically Accessing OCL Comments [message #515873 is a reply to message #515836] |
Sun, 21 February 2010 23:52 |
Alan McMorran Messages: 55 Registered: July 2009 |
Member |
|
|
> Hi Alan, Lothar
>
> The Lexer was changed in August (post Galileo, 1.3.0) in
> https://bugs.eclipse.org/bugs/show_bug.cgi?id=286724 so that
> makeComment is invoked for each comment. This allows LPG's adjunct
> capabilities to be used to get the preceding adjuncts of a useful Token.
> This was motivated by making comments available for editor colouring.
I noticed that but wasn't entirely sure how to make use of it, but did
some more digging through the source and documentation.
> The change is trivial. You could easily retrofit it to 1.3.0 if you're
> comfortable with running LPG.
Well after over-complicating the whole thing for a few hours I realised
that the Constraint class retains the offset information from the
parsing and so the change to add comment support is really quite
trivial! I created a subclass of OCL and overrode the parse(OCL input)
method and also added an additional Map to OCL to hold a list of
comments for a Constraint (and methods to then access this) as follows:
protected Map<CT, List<String>> comments = new HashMap<CT, List<String>>();
/**
* Returns an array of comments for a particular constraint
*
* @param constraint
* the constraint
* @return the array of comments (empty array returned for constraints
with no comments)
*/
public String[] getComments(CT constraint){
if (comments.containsKey(constraint))
return comments.get(constraint).toArray(new
String[comments.get(constraint).size()]);
else
return new String[0];
}
public List<CT> parse(OCLInput input)
throws ParserException {
String inputString = input.getContentAsString();
OCLAnalyzer<PK, C, O, P, EL, PM, S, COA, SSA, CT, CLS, E> analyzer =
createAnalyzer(inputString);
// clear out old diagnostics
ProblemHandler ph = OCLUtil.getAdapter(getEnvironment(),
ProblemHandler.class);
if (ph != null) {
ph.beginParse();
}
List<CT> result = new java.util.ArrayList<CT>();
analyzer.parseOCLDocument(result);
// Cycle through all created constraints and determine if there are
preceding adjuncts
for (CT c: result){
// Only works for Constraints at the moment
if (c instanceof Constraint){
// The constraint marks its offset as the body, so need to find the
// invariant token that preceded it
IToken token = getInvariantToken((Constraint)c, analyzer);
for (IToken adj : token.getPrecedingAdjuncts()){
// Check it is a single or multi-line comment (should be, but just incase!)
if (adj.getKind() == OCLParsersym.TK_SINGLE_LINE_COMMENT ||
adj.getKind() == OCLParsersym.TK_MULTI_LINE_COMMENT){
String comment = new String(
adj.getIPrsStream().getInputChars(),
adj.getStartOffset(), (adj.getEndOffset()-adj.getStartOffset()+1));
// Add the comment to the comments map
if (!comments.containsKey(c)) comments.put(c, new Vector<String>());
comments.get(c).add(comment);
}
}
}
}
getConstraints().addAll(result);
List<EObject> resContents = getEnvironment().getTypeResolver()
.getResource().getContents();
for (CT ct : result) {
EObject constraintEObject = (EObject) ct;
if (constraintEObject.eResource() == null) {
resContents.add(constraintEObject);
}
}
if (ph != null) {
ph.endParse();
try {
problems = OCLUtil.checkForErrors(ph);
} catch (ParserException e) {
problems = e.getDiagnostic();
throw e;
}
}
return result;
}
protected IToken getInvariantToken(Constraint c, OCLAnalyzer<PK, C, O,
P, EL, PM, S, COA, SSA, CT, CLS, E> analyzer){
IToken token =
analyzer.getAbstractParser().getIPrsStream().getTokenAtChara cter(
((Constraint)c).getSpecification().getBodyExpression().getSt artPosition());
while (token.getKind()!=OCLParsersym.TK_inv &&
token.getKind()!=OCLParsersym.TK_SINGLE_LINE_COMMENT &&
token.getKind()!=OCLParsersym.TK_SINGLE_LINE_COMMENT){
token =
analyzer.getAbstractParser().getIPrsStream().getIToken(token .getTokenIndex()-1);
}
if
(token.getKind()==OCLParsersym.TK_inv)
return token;
else
return null;
}
This seems to work for me, and I can now parse the comments
appropriately to get documentation etc.
If anyone can see any massive, glaring errors, let me know!
Alan
|
|
|
Goto Forum:
Current Time: Thu Apr 25 11:55:36 GMT 2024
Powered by FUDForum. Page generated in 0.03304 seconds
|