blob: 1d992cfdbf53f3a3a75e753352dafcab400869fe [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.examples.build.latex
import org.eclipse.ocl.pivot.Class
import org.eclipse.ocl.pivot.Element
import org.eclipse.ocl.pivot.Namespace
import org.eclipse.ocl.pivot.Package
import org.eclipse.xtext.AbstractElement
import org.eclipse.xtext.AbstractMetamodelDeclaration
import org.eclipse.xtext.Action
import org.eclipse.xtext.Alternatives
import org.eclipse.xtext.Assignment
import org.eclipse.xtext.CharacterRange
import org.eclipse.xtext.CrossReference
import org.eclipse.xtext.Grammar
import org.eclipse.xtext.Group
import org.eclipse.xtext.Keyword
import org.eclipse.xtext.NegatedToken
import org.eclipse.xtext.RuleCall
import org.eclipse.xtext.TypeRef
import org.eclipse.xtext.UntilToken
import org.eclipse.xtext.Wildcard
import org.eclipse.ocl.pivot.utilities.ClassUtil
import org.eclipse.ocl.pivot.utilities.NameUtil
class GenerateLaTeXForCSModelXtend extends GenerateLaTeXForCSModel
{
/*@NonNull*/ protected override String generateLaTeX(/*@NonNull*/ Package asPackage,
/*@NonNull*/ Grammar grammar, /*@Nullable*/ Package cs2asPackage,
/*@Nullable*/ Package cs2csPackage) {
'''
«emitClasses(asPackage, grammar, cs2asPackage, cs2csPackage)»
«emitExternalModels(grammar)»
«emitTerminalRules(grammar)»
'''
}
protected def String emitAbstractElement(/*@NonNull*/ AbstractElement abstractElement, boolean atRoot) {
switch abstractElement {
Action: return emitAction(abstractElement)
Alternatives: return emitAlternatives(abstractElement, atRoot)
Assignment: return emitAssignment(abstractElement)
CharacterRange: return emitCharacterRange(abstractElement)
CrossReference: return emitCrossReference(abstractElement)
Group: return emitGroup(abstractElement, atRoot)
Keyword: return emitKeyword(abstractElement)
NegatedToken: return '!' + emitAbstractElement(abstractElement.terminal, false) + emitCardinality(abstractElement)
RuleCall: return emitRuleRef(abstractElement.rule) + emitCardinality(abstractElement)
UntilToken: return '-> ' + emitAbstractElement(abstractElement.terminal, false)
Wildcard: return '.' + emitCardinality(abstractElement)
default: return "<<<" + abstractElement.eClass.name + ">>>"
}
}
protected def String emitAction(/*@NonNull*/ Action action) {
if (action.feature !== null) {
return "\n{" + emitTypeRef(action.type) + action.feature + action.operator + "current}";
}
else {
return ""; // "\n{" + emitTypeRef(action.type) + "}";
}
}
protected def String emitAlternatives(/*@NonNull*/ Alternatives alternatives, boolean atRoot) {
if (atRoot && (alternatives.cardinality === null)) {
'''«FOR element : alternatives.elements SEPARATOR '\n| '»«emitAbstractElement(element, false)»«ENDFOR»'''
}
else {
'''«FOR element : alternatives.elements BEFORE '(' SEPARATOR '\n| ' AFTER ')'»«emitAbstractElement(element, false)»«ENDFOR»«alternatives.cardinality»'''
}
}
protected def String emitAssignment(/*@NonNull*/ Assignment assignment) {
return assignment.feature + assignment.operator + emitAbstractElement(assignment.terminal, false) + emitCardinality(assignment) + "\n";
}
protected def emitAssociations(/*@NonNull*/ Class asClass) {
var asAssociations = getSortedAssociations(asClass);
if (asAssociations.size() > 0) {
'''
«emitHeading0a("Associations")»
«FOR asAssociation : asAssociations»
«emitHeading0b(prettyPrint(asAssociation, asClass))»
«emitComment(asAssociation, asClass)»
«ENDFOR»
'''
}
}
protected def emitAttributes(/*@NonNull*/ Class asClass) {
var asAttributes = getSortedAttributes(asClass);
if ( asAttributes.size() > 0) {
'''
«emitHeading0a("Attributes")»
«FOR asAttribute : asAttributes»
«emitHeading0b(prettyPrint(asAttribute, asClass))»
«emitComment(asAttribute, asClass)»
«ENDFOR»
'''
}
}
protected def emitCS2AS(/*@NonNull*/ Class asClass, /*@NonNull*/ Package cs2asPackage) {
var cs2asClass = NameUtil.getNameable(cs2asPackage.getOwnedClasses(), asClass.getName());
if (cs2asClass !== null) {
'''
«emitHeading0a("Abstract Syntax Synthesis")»
«FOR asOperation : ClassUtil.nonNullState(cs2asClass).getOwnedOperations()»
«emitHeading0b(prettyPrint(asOperation, cs2asClass))»
«emitComment(asOperation, asClass)»
«IF asOperation.bodyExpression !== null»
«emitAllTT((asOperation.bodyExpression.getBody().trim()).replace("\n", "\n "))»
«ENDIF»
«ENDFOR»
'''
}
}
protected def emitCS2CS(/*@NonNull*/ Class asClass, /*@NonNull*/ Package cs2asPackage) {
var cs2csClass = NameUtil.getNameable(cs2asPackage.getOwnedClasses(), asClass.getName());
if (cs2csClass !== null) {
'''
«emitHeading0a("Concrete Syntax Disambiguation")»
«FOR asOperation : ClassUtil.nonNullState(cs2csClass).getOwnedOperations()»
«emitHeading0b(prettyPrint(asOperation, cs2csClass))»
«emitComment(asOperation, asClass)»
«IF asOperation.bodyExpression !== null»
«emitAllTT((asOperation.bodyExpression.getBody().trim()).replace("\n", "\n "))»
«ENDIF»
«ENDFOR»
'''
}
}
protected def String emitCardinality(/*@NonNull*/ AbstractElement abstractElement) {
if (abstractElement.cardinality !== null) {
return abstractElement.cardinality;
}
else {
return "";
}
}
protected def String emitCharacterRange(/*@NonNull*/ CharacterRange characterRange) {
if (characterRange.cardinality === null) {
return emitKeyword(characterRange.left) + '..' + emitKeyword(characterRange.right)
}
else {
return "(" + emitKeyword(characterRange.left) + '..' + emitKeyword(characterRange.right) + ")" + characterRange.cardinality
}
}
protected def emitClasses(/*@NonNull*/ Package asPackage,
/*@NonNull*/ Grammar grammar, /*@Nullable*/ Package cs2asPackage,
/*@Nullable*/ Package cs2csPackage) {
var asClasses = getSortedClasses(asPackage);
'''
«FOR asClass : asClasses»
«emitHeading3(prettyPrint(asClass, asClass), null) + emitClassDef(asClass)»
«emitComment(asClass, asClass)»
«emitSuperclasses(asClass)»
«emitAttributes(asClass)»
«emitAssociations(asClass)»
«emitOperations(asClass)»
«emitParserRules(asClass, grammar)»
«IF cs2csPackage !== null»
«emitCS2CS(asClass, ClassUtil.nonNullState(cs2csPackage))»
«ENDIF»
«IF cs2asPackage !== null»
«emitCS2AS(asClass, ClassUtil.nonNullState(cs2asPackage))»
«ENDIF»
«ENDFOR»
'''
}
protected def emitComment(/*@NonNull*/ Element asElement, /*@NonNull*/ Namespace asNamespace) {
if (asElement.getOwnedComments().size() > 0) {
'''
«FOR asComment : asElement.getOwnedComments()»
«prettyPrint(asComment, asNamespace)»
«ENDFOR»
'''
}
}
protected def String emitCrossReference(/*@NonNull*/ CrossReference crossReference) {
return "[" + emitTypeRef(crossReference.type) + '|' + emitAbstractElement(crossReference.terminal, false) + "]" + emitCardinality(crossReference)
}
protected def String emitGroup(/*@NonNull*/ Group group, boolean atRoot) {
if (atRoot && (group.cardinality === null)) {
'''«FOR element : group.elements SEPARATOR ' '»«emitAbstractElement(element, false)»«ENDFOR»'''
}
else {
'''«FOR element : group.elements BEFORE '(' SEPARATOR ' ' AFTER ')'»«emitAbstractElement(element, false)»«ENDFOR»«group.cardinality»'''
}
}
protected def emitExternalModels(/*@NonNull*/ Grammar grammar) {
var metamodelDeclarations = getSortedMetamodelDeclarations(grammar);
'''
«emitHeading3("External Models", labelPrefix + "ExternalModels")»
The following aliases and metamodel URIs are used in the grammar.
«FOR metamodelDeclaration : metamodelDeclarations»
«emitMetamodelDeclaration(metamodelDeclaration)»
«ENDFOR»
'''
}
protected def String emitKeyword(/*@NonNull*/ Keyword keyword) {
return "'" + emitCharacters(keyword.value) + "'" + emitCardinality(keyword)
}
protected def emitMetamodelDeclaration(/*@NonNull*/ AbstractMetamodelDeclaration metamodelDeclaration) {
if (metamodelDeclaration.alias === null) {
return metamodelDeclaration.EPackage.nsURI + " (default)";
}
else {
return metamodelDeclaration.alias + " : " + metamodelDeclaration.EPackage.nsURI;
}
}
protected def emitOperations(/*@NonNull*/ Class asClass) {
var asOperations = getSortedOperations(asClass);
if (asOperations.size() > 0) {
'''
«emitHeading0a("Operations")»
«FOR asOperation : asOperations»
«emitHeading0b(prettyPrint(asOperation, asClass) /*+ (asOperation.isInvalidating ? " invalidating" : "") + (asOperation.isValidating ? " validating" : "")*/)»
«IF asOperation.precedence !== null»
precedence: «emitHeading0b(asOperation.precedence.name)»
«ENDIF»
«emitComment(asOperation, asClass)»
«FOR asConstraint : getSortedPreconditions(asOperation)»
«emitBeginDefinition»
«prettyPrint(asConstraint, asClass)»
«emitEndDefinition»
«ENDFOR»
«IF asOperation.bodyExpression !== null»
«emitBeginDefinition»
body: «asOperation.bodyExpression.getBody()»
«emitEndDefinition»
«ENDIF»
«FOR asConstraint : getSortedPostconditions(asOperation)»
«emitBeginDefinition»
«prettyPrint(asConstraint, asClass)»
«emitEndDefinition»
«ENDFOR»
«ENDFOR»
'''
}
}
/* protected def String emitParserRule(@NonNull org.eclipse.ocl.pivot.Class asClass, @NonNull Collection<ParserRule> parserRules) {
'''
«asClass.name» ::=
«FOR parserRule : parserRules BEFORE " " SEPARATOR "\n|"» «parserRule.name»«ENDFOR»
'''
} */
protected def emitParserRules(/*@NonNull*/ Grammar grammar) {
var parserRules = getSortedParserRules(grammar);
'''
«emitHeading3("Parser Rules", labelPrefix + "ParserRules")»
The parser rules define the parser mapping from parser tokens to generalized concrete syntax elements.
«FOR parserRule : parserRules»
«emitHeading4(parserRule.name, labelPrefix + "ParserRule:" + parserRule.name)»
«emitComment(parserRule)»
Token type: «emitTypeRef(parserRule.type)»
«emitAllTT(emitAbstractElement(parserRule.alternatives, true))»
«ENDFOR»
'''
}
protected def emitParserRules(/*@NonNull*/ Class asClass, /*@NonNull*/ Grammar grammar) {
var parserRules = getSortedParserRules(asClass, grammar);
if (parserRules.size() > 0) {
'''
«IF parserRules.size() > 1»
«emitHeading0a("Parser Rules")»
«ELSE»
«emitHeading0a("Parser Rule")»
«ENDIF»
«FOR parserRule : parserRules»
«IF parserRules.size() > 1»
«emitHeading0b(parserRule.name)»
«ENDIF»
«emitComment(parserRule)»
«emitAllTT((emitRuleDef(parserRule) + " ::=\n" + emitAbstractElement(parserRule.alternatives, true).trim()).replace("\n", "\n "))»
«ENDFOR»
'''
}
}
protected def emitSuperclasses(/*@NonNull*/ Class asClass) {
var asSuperClasses = asClass.getSuperClasses();
if (asSuperClasses.size() > 0) {
'''
«emitHeading0a("Superclasses")»
«FOR asSuperClass : asSuperClasses SEPARATOR ', '»«emitClassRef(asSuperClass)»«ENDFOR»
'''
}
}
protected def emitTerminalRules(/*@NonNull*/ Grammar grammar) {
var terminalRules = getSortedTerminalRules(grammar);
'''
«emitHeading3("Terminal Rules", labelPrefix + "TerminalRules")»
The terminal rules define the lexer mapping from character sequences to parser tokens.
«FOR terminalRule : terminalRules»
«emitHeading4(terminalRule.name, labelPrefix + "TerminalRule:" + terminalRule.name)»
«emitComment(terminalRule)»
Token type: «emitTypeRef(terminalRule.type)»
«emitAllTT(emitAbstractElement(terminalRule.alternatives, true))»
«ENDFOR»
'''
}
protected def emitTypeRef(/*@NonNull*/ TypeRef typeRef) {
if ((typeRef.metamodel.alias == "ecore") && (typeRef.classifier.name == "EString")) {
return "String";
}
else if ((typeRef.metamodel.alias == "ecore") && (typeRef.classifier.name == "EInt")) {
return "Integer";
}
else if (typeRef.metamodel.alias === null) {
return typeRef.classifier.name;
}
else {
return typeRef.metamodel.alias + "::" + typeRef.classifier.name;
}
}
}