The SADL Grammar file (SADL.xtext)

/************************************************************************

* Copyright 2007-2020 - General Electric Company, All Rights Reserved

*

* Project: SADL

*

* Description: The Semantic Application Design Language (SADL) is a

* language for building semantic models and expressing rules that

* capture additional domain knowledge. The SADL-IDE (integrated

* development environment) is a set of Eclipse plug-ins that

* support the editing and testing of semantic models using the

* SADL language.

*

* This software is distributed "AS-IS" without ANY WARRANTIES

* and licensed under the Eclipse Public License - v 1.0

* which is available at http://www.eclipse.org/org/documents/epl-v10.php

*

***********************************************************************/

grammar com.ge.research.sadl.SADL hidden(WS, ML_COMMENT, SL_COMMENT) //with with org.eclipse.xtext.common.Terminals


import "http://www.eclipse.org/emf/2002/Ecore" as ecore

generate sADL "http://www.ge.com/research/sadl/SADL"


SadlModel :

'uri' baseUri=STRING ('alias' alias=ID)? ('version' version=STRING)?

annotations+=SadlAnnotation* EOS

imports+=SadlImport*

elements+=SadlModelElement*;

SadlAnnotation :

','? '(' type=('alias'|'note'|'see') contents+=STRING (',' contents+=STRING)* ')'

;


SadlImport :

'import' importedResource=[SadlModel|STRING] ('as' alias=ID)? EOS;


// The various kinds of elements that make up the body of a model.

SadlModelElement :

SadlStatement EOS

| ExpressionStatement => EOS

| RuleStatement => EOS

| QueryStatement => EOS

| UpdateStatement => EOS

| TestStatement => EOS

| PrintStatement => EOS

| ReadStatement => EOS

| ExplainStatement => EOS

| StartWriteStatement

| EndWriteStatement => EOS

| EquationStatement => EOS

| ExternalEquationStatement => EOS

;


EquationStatement:

'Equation' EquationSignature

(body = Expression)?

('return' retval = Expression)?

('where' where=Expression)?

;


ExternalEquationStatement:

'External' EquationSignature

uri = STRING

('located' 'at' location=STRING)?

('where' where=Expression)?

;


fragment EquationSignature returns AbstractSadlEquation:

name=SadlResource (annotations+=NamedStructureAnnotation)* '(' (parameter+=SadlParameterDeclaration (',' parameter+=SadlParameterDeclaration)* )? ')'

('returns' (returnType+=SadlReturnDeclaration (',' returnType+=SadlReturnDeclaration)*))? ':'

;


SadlParameterDeclaration:

type=SadlPrimaryTypeReference name=SadlResource ('(' augtype=ExpressionParameterized<false,false> ('{' units+=UNIT (',' units+=UNIT)* '}')? ')')?

| unknown='--'

| ellipsis='...'

;


SadlReturnDeclaration:

type=SadlPrimaryTypeReference ('(' augtype=ExpressionParameterized<false,false> ('{' units+=UNIT (',' units+=UNIT)* '}')? ')')?

| none ='None'

| unknown='--'

;


// These are the things that translate directly to OWL.

SadlStatement returns SadlStatement:

SadlResource

({SadlClassOrPropertyDeclaration.classOrProperty+=current} 'is' 'a'

('top-level'? 'class'

| 'type' 'of' superElement=SadlPrimaryTypeReference facet=SadlDataTypeFacet?)

(describedBy+=SadlPropertyDeclarationInClass+ | (','? restrictions+=SadlPropertyRestriction)+)?

|{SadlProperty.nameOrRef=current} primaryDeclaration?='is' 'a' 'property' (','? restrictions+=SadlPropertyRestriction)*

|{SadlProperty.nameOrRef=current} (','? restrictions+=SadlPropertyRestriction)+

|{SadlSameAs.nameOrRef=current} 'is' 'the' 'same' 'as' (complement?='not')? sameAs=SadlTypeReference

|{SadlDifferentFrom.nameOrRef=current} 'is' 'not' 'the' 'same' 'as' notTheSameAs=SadlTypeReference

|{SadlInstance.nameOrRef=current} ('is' AnArticle type=SadlTypeReference)? (listInitializer=SadlValueList | propertyInitializers+=SadlPropertyInitializer+)?

|{SadlDisjointClasses.classes+=current} ('and' classes+=SadlResource)+ 'are' 'disjoint'

)

| {SadlClassOrPropertyDeclaration} '{' classOrProperty+=SadlResource (',' classOrProperty+=SadlResource)* '}' 'are'

(('top-level'? 'classes' | (oftype='types' | oftype='instances') 'of' superElement=SadlPrimaryTypeReference) describedBy+=SadlPropertyDeclarationInClass*

| {SadlDisjointClasses.types+=current} 'disjoint'

| {SadlDifferentFrom.types+=current} (complement?='not')? 'the' 'same')

| {SadlProperty} AnArticle? ('relationship'|'Relationship') 'of' from=SadlTypeReference 'to' to=SadlTypeReference 'is' property=SadlResource

| AnArticle SadlTypeReference (

{SadlInstance.type=current} instance=SadlResource? propertyInitializers+=SadlPropertyInitializer*

| {SadlNecessaryAndSufficient.subject=current} 'is' AnArticle object=SadlResource 'only' 'if' propConditions+=SadlPropertyCondition ('and' propConditions+=SadlPropertyCondition)*)

;




SadlPropertyCondition :

property=[SadlResource|QNAME] cond+=SadlCondition

;


SadlPropertyInitializer:

','? firstConnective=('with'|'has')? property=[SadlResource|QNAME] (value=SadlExplicitValue | '(' value=SadlNestedInstance')')

|','? firstConnective='is' property=[SadlResource|QNAME] 'of' type=[SadlResource|QNAME]

|','? firstConnective='of' property=[SadlResource|QNAME] 'is' (value=SadlExplicitValue | '(' value=SadlNestedInstance')')

;


SadlNestedInstance returns SadlInstance:

{SadlNestedInstance} (

instance=SadlResource 'is' article=AnArticle type=SadlTypeReference propertyInitializers+=SadlPropertyInitializer*

| article=AnArticle type=SadlTypeReference instance=SadlResource? propertyInitializers+=SadlPropertyInitializer*)

;


SadlResource:

name=[SadlResource|QNAME] annotations+=SadlAnnotation*

;


SadlDataTypeFacet :

{SadlDataTypeFacet} ('(' | minInclusive?='[') min=FacetNumber? ',' max=FacetNumber? (maxInclusive?=']' | ')')

| regex=STRING

| 'length' (len=FacetNumber | minlen=FacetNumber '-' maxlen=(FacetNumber|'*'))

| '{' values+=FacetValue (','? values+=FacetValue)* '}'

;


FacetNumber :

'-'? AnyNumber

;


FacetValue :

STRING | FacetNumber

;


// TypeReferences

SadlTypeReference returns SadlTypeReference:

SadlUnionType

;


SadlUnionType returns SadlTypeReference:

SadlIntersectionType ({SadlUnionType.left=current} ('or') right=SadlIntersectionType)*

;


SadlIntersectionType returns SadlTypeReference:

SadlPrimaryTypeReference ({SadlIntersectionType.left=current} ('and') right=SadlPrimaryTypeReference)*

;


SadlPrimaryTypeReference returns SadlTypeReference:

{SadlSimpleTypeReference} type=[SadlResource|QNAME] list?='List'?

| {SadlPrimitiveDataType} primitiveType=SadlDataType list?='List'?

| {SadlTableDeclaration} 'table' '[' (parameter+=SadlParameterDeclaration (',' parameter+=SadlParameterDeclaration)* )?']'

('with' 'data' (valueTable=ValueTable | 'located' 'at' location=STRING))?

| '(' SadlPropertyCondition ')'

| '{' SadlTypeReference '}'

;


// Built-in primitive data types

enum SadlDataType :

string | boolean | decimal | int | long | float | double | duration | dateTime | time | date |

gYearMonth | gYear | gMonthDay | gDay | gMonth | hexBinary | base64Binary | anyURI |

integer | negativeInteger | nonNegativeInteger | positiveInteger | nonPositiveInteger |

byte | unsignedByte | unsignedInt | anySimpleType;


// Class declarations may also describe the class's properties.

SadlPropertyDeclarationInClass returns SadlProperty:

','? 'described' 'by' nameDeclarations+=SadlResource restrictions+=SadlPropertyRestriction*;


SadlPropertyRestriction :

SadlCondition

| {SadlTypeAssociation} ('describes'|'of') domain=SadlTypeReference

| {SadlRangeRestriction} ('has'|'with') ('a' singleValued?='single' 'value'|'values') 'of' 'type' ((typeonly=('class'|'data')) | range=SadlPrimaryTypeReference facet=SadlDataTypeFacet?)

| {SadlIsInverseOf} 'is' 'the' 'inverse' 'of' otherProperty=[SadlResource|QNAME]

| {SadlIsTransitive} 'is' 'transitive'

| {SadlIsSymmetrical} 'is' 'symmetrical'

| {SadlIsAnnotation} 'is' 'a' 'type' 'of' 'annotation'

| {SadlDefaultValue} 'has' ('level' level=NUMBER)? 'default' defValue=SadlExplicitValue

| {SadlIsFunctional} 'has' 'a' 'single' (inverse?='subject' | 'value')?

| {SadlMustBeOneOf} 'must' 'be' 'one' 'of' '{' values+=SadlExplicitValue (',' values+=SadlExplicitValue)* '}'

| {SadlCanOnlyBeOneOf} 'can' 'only' 'be' 'one' 'of' '{' values+=SadlExplicitValue (',' values+=SadlExplicitValue)* '}'

;


SadlCondition :

SadlAllValuesCondition

| SadlHasValueCondition

| SadlCardinalityCondition

;


SadlAllValuesCondition :

'only' ('has'|'with') 'values' 'of' 'type' type=SadlPrimaryTypeReference facet=SadlDataTypeFacet?;


SadlHasValueCondition :

'always' ('has'|'with') 'value' (restriction=SadlExplicitValue | '(' restriction=SadlNestedInstance ')');


SadlCardinalityCondition :

('has'|'with')

('at' operator=('least'|'most') |'exactly')?

cardinality=CardinalityValue ('value'|'values')

('of' 'type' type=SadlPrimaryTypeReference facet=SadlDataTypeFacet?)?;


CardinalityValue :

NUMBER | 'one'

;


SadlExplicitValue:

SadlExplicitValueLiteral |

=>({SadlUnaryExpression} operator=('-' | 'not') value=SadlExplicitValueLiteral)

;

SadlExplicitValueLiteral:

SadlResource // e.g., George

| {SadlNumberLiteral} literalNumber=AnyNumber (-> unit=UNIT)?

| {SadlStringLiteral} literalString=STRING

| {SadlBooleanLiteral} (truethy?='true'|'false')

| SadlValueList

| {SadlConstantLiteral} term=('PI'|'e'|'known')

;


UNIT: STRING | ID;


SadlValueList:

{SadlValueList} '[' (explicitValues+=SadlExplicitValue (',' explicitValues+=SadlExplicitValue)*)? ']'

;


// These articles can appear before the property name and are indicative of the functionality of the property or

// the cardinality of the property on the class

AnArticle :

IndefiniteArticle | DefiniteArticle;


IndefiniteArticle :

'A'|'a'|'An'|'an'|'any'|'some'|'another';


DefiniteArticle :

'The'|'the';


Ordinal :

'first'

| 'second' | 'other'

| 'third'

| 'fourth'

| 'fifth'

| 'sixth'

| 'seventh'

| 'eighth'

| 'ninth'

| 'tenth'

;


// This is primarily for debugging purposes. Any expression can be given after "Expr:" to see if it is valid.

// Such an expression has no meaning in translation.

ExpressionStatement returns ExpressionScope :

{ExpressionStatement}

'Expr:' expr=Expression ('=>' evaluatesTo=STRING)?;


NamedStructureAnnotation :

','? '(' type=SadlResource contents+=SadlExplicitValue (',' contents+=SadlExplicitValue)* ')'

;


RuleStatement returns ExpressionScope :

{RuleStatement}

('Stage' stage=NUMBER)? 'Rule' name=SadlResource (annotations+=NamedStructureAnnotation)* ':'?

('given' ifs+=Expression)?

('if' ifs+=Expression)?

'then' thens += (Expression | ThereExistsStatement)

;


ThereExistsStatement returns Expression :

{ThereExistsStatement}

('there' 'exists') match=Expression ('plus' plus=Expression)?

;



QueryStatement returns ExpressionScope :

{QueryStatement}

start = ('Ask'|'Graph') ((name=SadlResource (annotations+=NamedStructureAnnotation)* )? ':'

(expr=(ConstructExpression | AskExpression | Expression) (':' '['parameterizedValues = ValueRow']')?)

| srname=SadlResource

)

;


UpdateStatement returns ExpressionScope :

{UpdateStatement}

'Update' ((name=SadlResource (annotations+=NamedStructureAnnotation)* )? ':' expr=(UpdateExpression | Expression)

| name=SadlResource

)

;


ConstructExpression returns Expression :

{ConstructExpression}

'construct' subj=SadlResource ','? pred=SadlResource ','? obj=SadlResource 'where' whereExpression=Expression

;


AskExpression returns Expression :

{AskExpression}

'ask' 'where' whereExpression=Expression

;


UpdateExpression returns Expression :

{UpdateExpression}

('delete' dData='data'? deleteExpression=Expression)?

('insert' iData='data'? insertExpression=Expression)?

('where' whereExpression=Expression)?

;


TestStatement returns ExpressionScope :

{TestStatement}

'Test:' tests+=Expression

;


PrintStatement :

'Print:'

(displayString=STRING

| model='Deductions'

| model='Model');


ExplainStatement :

'Explain:'

(expr=Expression

| 'Rule' rulename=SadlResource)

;

StartWriteStatement :

write='Write:' (dataOnly='data')? '{'

;


EndWriteStatement :

'}' 'to' filename=STRING

;

ReadStatement :

'Read:' 'data' 'from' filename=STRING ('using' templateFilename=STRING)?

;



Expression returns Expression: // (1)

SelectExpression<true, true>

;


NestedExpression returns Expression: // (1)

SelectExpression<true, false>

;


SelectExpression<EnabledWith, EnableComma> returns Expression :

->({SelectExpression}

'select' distinct?='distinct'? ('*' | selectFrom+=SadlResource (','? selectFrom+=SadlResource)*) 'where' whereExpression=ExpressionParameterized<EnabledWith, EnableComma> (orderby='order' 'by' orderList+=OrderElement ->(','? (orderList+=OrderElement))*)?)

| ExpressionParameterized<EnabledWith, EnableComma>

;


OrderElement :

('asc' | desc?='desc')? orderBy=SadlResource;


// Real expressions start here

ExpressionParameterized<EnabledWith, EnableComma> returns Expression: // (1)

{Sublist} AnArticle? 'sublist' 'of' list=OrExpression<EnabledWith, EnableComma> 'matching' where=OrExpression<EnabledWith, EnableComma>

| OrExpression<EnabledWith, EnableComma>;


OrExpression<EnabledWith, EnableComma> returns Expression:

AndExpression<EnabledWith, EnableComma> ({BinaryOperation.left=current} op=OpOr right=AndExpression<EnabledWith, EnableComma>)*;


OpOr:

'or' | '||';


AndExpression<EnabledWith, EnableComma> returns Expression:

EqualityExpression<EnabledWith, EnableComma> ({BinaryOperation.left=current} op=OpAnd right=EqualityExpression<EnabledWith, EnableComma>)*;


OpAnd:

'and' | '&&';

EqualityExpression<EnabledWith, EnableComma> returns Expression:

RelationalExpression<EnabledWith, EnableComma> ({BinaryOperation.left=current} op=InfixOperator right=RelationalExpression<EnabledWith, EnableComma>)*;


InfixOperator :

'=='

| '!='

| '='

| 'is' ('not'? 'unique' 'in')?

| 'contains'

| 'does' 'not' 'contain'

;


RelationalExpression<EnabledWith, EnableComma> returns Expression:

Addition<EnabledWith, EnableComma> ->({BinaryOperation.left=current} =>op=OpCompare right=Addition<EnabledWith, EnableComma>)*;


OpCompare:

'>=' | '<=' | '>' | '<';


Addition<EnabledWith, EnableComma> returns Expression:

Multiplication<EnabledWith, EnableComma> ({BinaryOperation.left=current} op=AddOp right=Multiplication<EnabledWith, EnableComma>)*;


AddOp:

'+' | '-'

;


Multiplication<EnabledWith, EnableComma> returns Expression:

Power<EnabledWith, EnableComma> ({BinaryOperation.left=current} op=MultiOp right=Power<EnabledWith, EnableComma>)*;

MultiOp :

'*'|'/'|'%'

;


Power<EnabledWith, EnableComma> returns Expression:

PropOfSubject<EnabledWith, EnableComma> ({BinaryOperation.left=current} op='^' right=PropOfSubject<EnabledWith, EnableComma>)*;


PropOfSubject<EnabledWith, EnableComma> returns Expression:

ElementInList<EnabledWith, EnableComma> ->(

({PropOfSubject.left=current} of=('of'|'for'|'in') right=PropOfSubject<EnabledWith, EnableComma>)

| ->({SubjHasProp.left=current} (<EnableComma> comma?=',')? (<EnabledWith>'with'|'has')? prop=SadlResource ->right=ElementInList<EnabledWith, EnableComma>?)+)?

;


ElementInList<EnabledWith, EnableComma> returns Expression:

UnitExpression<EnabledWith, EnableComma> |

{ElementInList} 'element' (before?='before'|after?='after')? element=UnitExpression<EnabledWith, EnableComma>

;


UnitExpression<EnabledWith, EnableComma> returns Expression:

UnaryExpression<EnabledWith, EnableComma> ({UnitExpression.left=current} unit=STRING)?

;


UnaryExpression<EnabledWith, EnableComma> returns Expression:

PrimaryExpression<EnabledWith, EnableComma> |

{UnaryExpression} op=('not' | '!' | 'only' | '-') expr=PrimaryExpression<EnabledWith, EnableComma>

;


// primary expressions are the atom units of expression in the grammar

PrimaryExpression<EnabledWith, EnableComma> returns Expression:

'(' SelectExpression<EnabledWith, EnableComma> ')'

| Name

| {Declaration} article=AnArticle ordinal=Ordinal? type=SadlPrimaryTypeReference

(

'[' arglist+=NestedExpression? (',' arglist+=NestedExpression)* ']'

|'length' len=FacetNumber ->('-' maxlen=(FacetNumber|'*'))?

)?

| {StringLiteral} value=STRING

| {NumberLiteral} value=AnyNumber

| {BooleanLiteral} value=BooleanValue

| {Constant} constant=Constants

| {ValueTable} valueTable=ValueTable;


Name returns SadlResource:

{Name} name=[SadlResource|QNAME] ->(function?='(' arglist+=NestedExpression? (',' arglist+=NestedExpression)* ')')?

;


// the truth table

ValueTable:

'[' row=ValueRow ']'

// e.g., [George, 23, "Purple", 38.186111]

| '{' '[' rows+=ValueRow ']' (','? '[' rows+=ValueRow ']')* '}'

// e.g., {[George, 23, "Purple", 38.186111], [Martha, 24, "Pink", 45.203]}

;


BooleanValue:

'true' | 'false';


Constants:

'PI' | 'known' | 'e' | '--' | 'None' | 'a'? 'type' | DefiniteArticle? 'length' | 'count' | DefiniteArticle? 'index' | ('first'|'last'|AnArticle Ordinal?) 'element' | 'value';


ValueRow:

explicitValues+=NestedExpression (',' explicitValues+=NestedExpression)*; // e.g., George, 23, "Purple", 38.186111


DNAME:

ID;


AnyNumber returns ecore::EBigDecimal :

DecimalNumber EXPONENT?;


DecimalNumber returns ecore::EBigDecimal :

NUMBER ;


EXPONENT returns ecore::EBigDecimal:

('e' | 'E') ('-' | '+')? DecimalNumber;


EOS:

'.';

QNAME :

QNAME_TERMINAL | ID

;

terminal NUMBER returns ecore::EInt :

'0'..'9'+;


terminal WS:

('\u00A0' | ' ' | '\t' | '\r' | '\n')+;


terminal ID:

'^'? ('a'..'z' | 'A'..'Z' | '_') ('a'..'z' | 'A'..'Z' | '_' | '0'..'9' | '-' | '%' | '~')* ;

terminal QNAME_TERMINAL:

ID ':' ID;

terminal STRING:

'"' ('\\' ('b' | 't' | 'n' | 'f' | 'r' | 'u' | '"' | "'" | '\\') | !('\\' | '"'))* '"' |

"'" ('\\' ('b' | 't' | 'n' | 'f' | 'r' | 'u' | '"' | "'" | '\\') | !('\\' | "'"))* "'";


terminal ML_COMMENT:

'/*'->'*/';


terminal SL_COMMENT:

'//' !('\n' | '\r')* ('\r'? '\n')?;


terminal ANY_OTHER:

.;