X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.graph.compiler%2Fsrc%2Forg%2Fsimantics%2Fgraph%2Fcompiler%2Finternal%2Fparsing%2FGraph.g;fp=bundles%2Forg.simantics.graph.compiler%2Fsrc%2Forg%2Fsimantics%2Fgraph%2Fcompiler%2Finternal%2Fparsing%2FGraph.g;h=67b11fbaa7a1abc257a4c7117387036f4ae89758;hp=0000000000000000000000000000000000000000;hb=969bd23cab98a79ca9101af33334000879fb60c5;hpb=866dba5cd5a3929bbeae85991796acb212338a08 diff --git a/bundles/org.simantics.graph.compiler/src/org/simantics/graph/compiler/internal/parsing/Graph.g b/bundles/org.simantics.graph.compiler/src/org/simantics/graph/compiler/internal/parsing/Graph.g new file mode 100644 index 000000000..67b11fbaa --- /dev/null +++ b/bundles/org.simantics.graph.compiler/src/org/simantics/graph/compiler/internal/parsing/Graph.g @@ -0,0 +1,453 @@ +grammar Graph; + +options { + language = Java; + output = AST; + ASTLabelType=CommonTree; +} + +tokens { + // lexer + INDENT; + DEDENT; + + // graph + FILE; + RESOURCE; + PROPERTY; + VARIABLE; + EMBEDDED_VALUE; + EMBEDDED_TYPE; + TEMPLATE_INSTANCE; + TEMPLATE_DEFINITION; + + BLANK; + REF; + + EQUALS; + INSTANCE_OF; + INHERITS; + SUBRELATION_OF; + HAS_DOMAIN; + HAS_RANGE; + DOMAIN_OF; + REQUIRES_VALUE_TYPE; + + // data + TYPE_DEFINITIONS; + TYPE_DEFINITION; + + UNION_TYPE; + RECORD_TYPE; + TUPLE_TYPE; + ARRAY_TYPE; + TYPE_REFERENCE; + TYPE_ANNOTATION; + TYPE_COMPONENT; + + VALUE_DEFINITIONS; + VALUE_DEFINITION; + + NO_VALUE; + VARIANT; + ARRAY; + TUPLE; + TAGGED_VALUE; + RECORD; + MAP; + ASSIGNMENT; + TRUE; + FALSE; +} + +@parser::header { package org.simantics.graph.compiler.internal.parsing; } +@lexer::header { package org.simantics.graph.compiler.internal.parsing; + +import gnu.trove.list.array.*; +} + +@lexer::members { +int inParen = 0; + +TIntArrayList iStack = new TIntArrayList(); +{ iStack.add(0); } + +List tokens = new ArrayList(); +public void emit(Token token) { + state.token = token; + tokens.add(token); +} +public Token nextToken() { + if(tokens.isEmpty()) { + super.nextToken(); + if ( tokens.isEmpty() ) { + /* When end-of-file is encountered, we + emit balancing number of DEDENT tokens. + */ + if(iStack.size() <= 1) + return Token.EOF_TOKEN; + else { + while(iStack.size() > 1) { + iStack.removeAt(iStack.size()-1); + state.type = DEDENT; + emit(); + } + iStack.clear(); + } + } + } + return (Token)tokens.remove(0); +} + +} + +// ------------------------------------------------------------------ +// LEXER +// ------------------------------------------------------------------ + +ID : ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'0'..'9'|'_')* + ; + +COMMENT + : '//' ~('\n')* {$channel=HIDDEN;} + | '/*' ( options {greedy=false;} : . )* '*/' {$channel=HIDDEN;} + ; + +WS : ( ' ' + | '\t' + | '\r' + ) {$channel=HIDDEN;} + ; + +LPAREN : '(' { ++ inParen; } ; +RPAREN : ')' { -- inParen; } ; +LBRACKET : '[' { ++ inParen; } ; +RBRACKET : ']' { -- inParen; } ; +LCURLY : '{' { ++ inParen; } ; +RCURLY : '}' { -- inParen; } ; + +INT_RANGE : INT '..' INT? + | '..' INT + ; +RANGE : FLOAT '..' (FLOAT | INT)? + | '..' FLOAT + | INT '..' FLOAT + ; + +NEWLINE +@init { int spaces = 0; } + : '\n' + ( ' ' { ++spaces; } + | '//' ~('\n')* '\n' { spaces = 0; } + | '/*' ( options {greedy=false;} : . )* '*/' + | '\r' + | '\n' { spaces = 0; } + )* + { + int c = input.LA(1); + + if(inParen > 0) { + $channel = HIDDEN; + } + else if(c == EOF) { + while(iStack.size() > 1) { + iStack.removeAt(iStack.size()-1); + state.type = DEDENT; + emit(); + } + $channel = HIDDEN; + iStack.clear(); + } + else { + int stackTop = iStack.get(iStack.size()-1); + if(spaces > stackTop) { + iStack.add(spaces); + $type = INDENT; + } + else if(spaces < stackTop) { + while(spaces < iStack.get(iStack.size()-1)) { + iStack.removeAt(iStack.size()-1); + state.type = DEDENT; + emit(); + } + state.type = NEWLINE; + emit(); + // TODO check that spaces == iStack.get(iStack.size()-1) + } + } + } + ; + +INDENT: { false }?=> 'INDENT' ; +DEDENT: { false }?=> 'DEDENT' ; + +INT : '-'? '0'..'9'+ + ; + +FLOAT + : '-'? + ( ('0'..'9')+ '.' ('0'..'9')* EXPONENT? + | ('0'..'9')+ EXPONENT + ) + ; + +STRING + : '"' ( ESC_SEQ | ~('\\'|'"') )* '"' + | '"""' ( ~('"') | '"' ~('"') | '""' ~('"') )* '"""' + ; + +URI + : '') )* '>' + ; + +fragment +EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ; + +fragment +HEX_DIGIT : ('0'..'9'|'a'..'f'|'A'..'F') ; + +fragment +ESC_SEQ + : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\') + | UNICODE_ESC + ; + +fragment +UNICODE_ESC + : '\\' 'u' HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT + ; + +// ------------------------------------------------------------------ +// STATEMENTS +// ------------------------------------------------------------------ + +file : NEWLINE? resourceDefinitions? EOF -> ^(FILE resourceDefinitions?) ; + +resourceDefinitions + : resourceDefinition (NEWLINE! resourceDefinition)* + ; + +resourceDefinition + : resource + localProperty* + (INDENT property (NEWLINE property)* DEDENT)? + -> ^(RESOURCE resource localProperty* property*) + | template -> ^(RESOURCE ^(BLANK template) template) + ; + +localProperty + : relation resource + -> ^(PROPERTY relation ^(RESOURCE resource)) + ; + +property + : relation + ( resourceDefinition -> ^(PROPERTY relation resourceDefinition) + | INDENT resourceDefinitions DEDENT -> ^(PROPERTY relation resourceDefinitions) + ) + | template + ; + +template + : '@' + ( {input.LT(1).getText().equals("template")}?=> + ID resource+ + INDENT resourceDefinitions DEDENT + -> ^(TEMPLATE_DEFINITION resource+ resourceDefinitions) + | resource+ + (INDENT resourceDefinitions DEDENT)? + -> ^(TEMPLATE_INSTANCE resource+ resourceDefinitions?) + ) + ; + +// ------------------------------------------------------------------ +// RESOURCES +// ------------------------------------------------------------------ + +relation + : ( ID -> ID) + ('.' ID -> ^(REF $relation ID))* + | URI + | ' INHERITS + | ' SUBRELATION_OF + | '<--' -> HAS_DOMAIN + | '-->' -> HAS_RANGE + | '==>' -> REQUIRES_VALUE_TYPE + | '>--' -> DOMAIN_OF + | ':' -> INSTANCE_OF + | '=' -> EQUALS + | '%' ID -> ^(VARIABLE ID) + ; + +resource + : ( {input.LT(1).getText().equals("_")}?=> ID -> ^(BLANK ID) + | ID -> ID) + ('.' (ID -> ^(REF $resource ID) + |STRING -> ^(REF $resource STRING) + ) + )* + | URI + | simpleValue -> ^(EMBEDDED_VALUE simpleValue) + | '$' basicType -> ^(EMBEDDED_TYPE basicType) + | '%' ID -> ^(VARIABLE ID) + ; + +// ------------------------------------------------------------------ +// TYPE DEFINITIONS +// ------------------------------------------------------------------ + +/*typeDefinitions : typeDefinition* -> ^(TYPE_DEFINITIONS typeDefinition*); + +typeDefinition + : 'type' ID '=' type -> ^(TYPE_DEFINITION ID type) + ; +*/ + +type + : arrayType + | unionType + ; + +unionType + : + ('|' unionComponent)+ + -> ^(UNION_TYPE unionComponent+) + ; + +unionComponent : ID ((arrayType) => arrayType)? -> ^(TYPE_COMPONENT ID arrayType?) ; + +arrayType + : (basicType -> basicType) + (LBRACKET arrayLength? RBRACKET -> ^(ARRAY_TYPE $arrayType arrayLength?))* ; + +arrayLength + : INT + | INT_RANGE + ; + +basicType + : tupleType + | recordType + | typeReference + ; + +tupleType + : LPAREN (type (',' type)*)? RPAREN + -> ^(TUPLE_TYPE type*) + ; + +recordType + : LCURLY (component (',' component)*)? RCURLY + -> ^(RECORD_TYPE component*) + ; + +component + : ID ':' type + -> ^(TYPE_COMPONENT ID type) + ; + +typeReference + : ID ((LPAREN)=> LPAREN parameter (',' parameter)* RPAREN)? + -> ^(TYPE_REFERENCE ID parameter*) + ; + +parameter + : ID '=' parameterValue -> ^(TYPE_ANNOTATION ID parameterValue) + | type + ; + +parameterValue + : string + | boolean_ + | number + | rangePar -> ^(RANGE rangePar) + ; + +rangePar : (LBRACKET | LPAREN) range (RBRACKET | RPAREN) ; + +range + : number + | RANGE + | INT_RANGE + ; + +number + : INT + | FLOAT + ; + +string + : STRING + ; + +boolean_ + : 'true' -> TRUE + | 'false' -> FALSE + ; + +// ------------------------------------------------------------------ +// VALUE DEFINITIONS +// ------------------------------------------------------------------ + +valueDefinitions : valueDefinition* -> ^(VALUE_DEFINITIONS valueDefinition*); + +valueDefinition + : ID ':' type '=' value + -> ^(VALUE_DEFINITION ID type value) + ; + +value + : (basicValue -> basicValue) + (':' type -> ^(VARIANT type $value))* + ; + +basicValue + : simpleValue + | map + | {input.LT(1).getText().equals("null")}? ID -> NO_VALUE + | taggedValue + ; + +simpleValue + : string + | number + | boolean_ + | array + | tuple + | record + ; + +array + : LBRACKET (value (',' value)*)? RBRACKET + -> ^(ARRAY value*) + ; + +tuple + : LPAREN (value (',' value)*)? RPAREN + -> ^(TUPLE value*) + ; + +taggedValue + : ID simpleValue? + -> ^(TAGGED_VALUE ID simpleValue?) + ; + +record + : LCURLY (recordAssignment (',' recordAssignment)*)? RCURLY + -> ^(RECORD recordAssignment*) + ; + +recordAssignment + : ID '=' value + -> ^(ASSIGNMENT ID value) + ; + +map : {input.LT(1).getText().equals("map")}?=> ID LCURLY (mapAssignment (',' mapAssignment)*)? RCURLY + -> ^(MAP mapAssignment*) + ; + +mapAssignment + : value '=' value + -> ^(ASSIGNMENT value*) + ; + \ No newline at end of file