Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Modeling » OCL » Programatically Accessing OCL Comments
Programatically Accessing OCL Comments [message #515831] Sun, 21 February 2010 10:28 Go to next message
Alan McMorran is currently offline 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 #515832 is a reply to message #515831] Sun, 21 February 2010 10:41 Go to previous messageGo to next message
Lothar Werzinger is currently offline Lothar Werzinger
Messages: 153
Registered: July 2009
Location: Bay Area
Senior Member
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 #515836 is a reply to message #515832] Sun, 21 February 2010 11:19 Go to previous messageGo to next message
Ed Willink is currently offline Ed Willink
Messages: 4003
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 18:52 Go to previous message
Alan McMorran is currently offline 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
Previous Topic:undefined on expressions
Next Topic:Operation, Instantiation and post clause: Invalid Class?
Goto Forum:
  


Current Time: Fri Jul 25 03:07:39 EDT 2014

Powered by FUDForum. Page generated in 0.04976 seconds