SubScript is able to describe its own syntax concisely:
script.. subScriptCode = . "override" & . "implicit"; "script"; scriptDefinition + ".." (scriptDefinition..) scriptDefinition = scriptHeader . ("+=" + "=") scriptExpression scriptHeader = scriptName_dots (.formalParameterList) (.":" typer) .. "," |+| channelName_dots (.formalParameterList) (.":" typer) scriptName_dots = scriptName . ".." + ("."+"..") scriptName channelName_dots = (.identifier) doubleArrow_dots scriptName = identifier %; simpleArrow formalParameterList = "(" (.formalParameters) ")" actualParameterList = "(" (.actualParameters) ")" identifiers = identifier .. "," formalParameters = formalParameter .. "," actualParameters = actualParameter .. parameterSeparator simpleActualParameters = simpleActualParameter .. parameterSeparator formalParameter = . formalOutputMarker; identifier ":" typer actualParameter = valueExpression + actualOutputMarker valueExpression (.postCondition) (. ":" type) simpleActualParameter = simpleValueExpression + actualOutputMarker simpleValueExpression (.postCondition) (. ":" type) formalOutputMarker = "?" + "??" actualOutputMarker = "?" + "??" postCondition = "?if" valueExpression scriptExpression = operatorModifiers dataflowExpression_HP dataflowExpression_HP = scriptExpression_9 . ( "~~~>" scriptLambdaTerm_HP . "+~/~~>" scriptLambdaTerm_HP ) + ( "~/~~>" scriptLambdaTerm_HP ) + ( "~~~" "(" dataflowParameter ")" "~~>" scriptLambdaTerm_HP .. "+~~~" "(" dataflowParameter ")" "~~>" scriptLambdaTerm_HP .. "+~/~~" "(" dataflowParameter ")" "~~>" scriptLambdaTerm_HP ) + ( "~/~~" "(" dataflowParameter ")" "~~>" scriptLambdaTerm_HP .. "+~/~~" "(" dataflowParameter ")" "~~>" scriptLambdaTerm_HP ) dataflowParameter = pattern . "if" valueExpression operatorModifiers = . ("," + naryOperatorDesignator) . naryOperatorDesignator scriptExpression_9 = scriptExpression_8 .. newLine scriptExpression_8 = scriptExpression_7 .. (+ ";" ";-;") scriptExpression_7 = "if" valueExpression "then" scriptExpression_8 . "else" scriptExpression_8 + "do" scriptExpression_7 ( "then" scriptExpression_8 %; "else" scriptExpression_8 ) + scriptExpression_6 scriptExpression_6 = scriptExpression_5 .. (+ "||" "|" orParArrow "|+" "|;" "|/" "||+" "||;" "||/" "|+|" "|;|" "|/|") scriptExpression_5 = scriptExpression_4 .. (+ "&&" "&" andParArrow) scriptExpression_4 = scriptExpression_3 .. "==" scriptExpression_3 = scriptExpression_2 .. "+" scriptExpression_2 = scriptExpression_1 .. (+ "/" "%" "%/" "%/%/" "%&" "%;") scriptExpression_1 = scriptSpaceExpression .. "·" scriptSpaceExpression = scriptDataFlow .. if commasOmittable (-) else (+) scriptDataFlow = scriptTerm (..; "~~>;" scriptLambda %; "~/~>;" scriptLambda) scriptLambda = . parameter "==>;"; simpleScriptTerm scriptTerm = unary + variableDeclaration + valueDeclaration + privateDeclaration unary = ..(unaryPrefixOperator + directive); simpleScriptTerm directive = "@" scalaCode ":" unaryPrefixOperator =+ "!" "-" "~" simpleScriptTerm =; |+| scriptCall codeFragment matchTerm throwTerm whileTerm forTerm tryTerm specialTerm "(" scriptExpression ")" "(*" scriptExpression "*)" "(**" scriptExpression "**)" scriptCall = implicitScriptCall |+| methodOrScriptCall |+| channelScriptCall; . resultHandler implicitScriptCall = simpleActualParameters .postCondition methodOrScriptCall = simpleValueExpression . actualParameterList .postCondition |+| simpleValueExpression "," simpleActualParameters channelScriptCall = .simpleValueExpression; identifier_arrow; (+) + actualParameterList .postCondition + simpleActualParameters resultHandler = "^" + "^^" "{" scalaCode "}" parameterSeparator = "," + if commasOmittable (+) specialTerm =+ "(-)" "(+)" "(+-)" "." ".." "..." "break" valueDeclaration = "val" identifier; . ":" typer ; "=" (.directive) simpleValueExpression variableDeclaration = "var" identifier; ":" typer %; "=" (.directive) simpleValueExpression privateDeclaration = "private" identifiers codeFragment =; + "{" scalaCode "}" "{*" scalaCode "*}" "{?" scalaCode "?}" "{!" scalaCode "!}" "{^" scalaCode "^}" "{." scalaCode ".}" "{..." scalaCode "...}" whileTerm = "while" valueExpression throwTerm = "throw" valueExpression forTerm = "for"; "(" enumerators ")" + "{" enumerators "}" tryTerm = "try" unary (scriptCatchClause %; scriptFinallyClause) matchTerm = simpleValueExpression "match" "{" scriptCaseClauses "}" scriptCatchClause = "catch" "(" (scriptCaseClause..) ")" scriptCaseClause = "case" pattern (. "if" valueExpression) ("=>;" + "*=>;") scriptExpression scriptFinallyClause = "finally" "{" scalaCode "}" valueExpression = parenthesizedExpression + simpleValueExpression parenthesizedExpression = "(" scalaExpression ")" naryOperatorDesignator =+ ";" "-;" "||" "|" orParArrow "|+" "|;" "|/" "||+" "||;" "||/" "|+|" "|;|" "|/|" "&&" "&" andParArrow "==" "+" "/" "%" "%/" "%/%/" "%&" "%;" "·" ("?" simpleValueExpression ":") andParArrow = "&~~>;" + "&~~{" scalaCode "}~>;" + "&~~(" scalaTupel ")~~>;" + "&&~~>;" + "&&~~{" scalaCode "}~>;" + "&&~~(" scalaTupel ")~~>;" orParArrow = "|~~>;" + "|~~{" scalaCode "}~>;" + "|~~(" scalaTupel ")~~>;" + "||~~>;" + "||~~{" scalaCode "}~>;" + "||~~(" scalaTupel ")~~>;" channelName_dots =+ "<-->;" "<~~>;" "<-.->;" "<~.~>;" "<-..->;" "<~..~>;" "<-->;.." "<~~>;.." simpleArrow =+ "<-" "<~" "->;" "~>;" arrow =+ simpleArrow "<-*" "<~*" "*->;" "*~>;" "?->;" "?~>;" simpleValueExpression = "_" + literal + "new" (classTemplate + templateBody) + ( "here" + currentInstanceExpression + identifier . "." currentInstanceExpression ) (.. "." identifier) currentInstanceExpression = "this" + "super" "." identifier
Notes
x %; y
means: at least one of x and y, and x comes before y.
commasOmittable
is a stacked variable set at the start of each scriptExpression, based on the parsing of operatorModifiers
:
commasOmittable
= there is at least one operator modifier and the first one is a comma
If there is at least one operator modifier, then the first one sets the meaning of the space (this may even get the meaning of a comma) in scriptSpaceExpression
If there are two operator modifiers, then the second one sets the meaning of the newline operator in scriptExpression9.
newLine
is a pseudo token that denotes a that the next token is on a different line.
Special symbols
References to Scala syntax:
scalaCode classTemplate literal type enumerators
scalaExpression templateBody identifier pattern
identifier_arrow
is a concatenation of: an identifier
or an empty string, and an arrow
, e.g., a*<=
and ?->
.
·
is a math multiplication symbol denoting sequence, with strong binding.
Script Definitions
Script definitions have ambiguous syntax. Spacing determines where script definitions end.
E.g.,
script a = b c d
c belongs to script a, since its starting column is to the right of the starting column of the script definition line.
d is outside the script.
script .. a = b c = d e f = g h = i j
a, c, f and h are script definitions.
e belongs to c since its starting column is at least the column of the equals symbol of script c.
j is outside the script.. section.
Other Ambiguities
As in many programming languages, there is a syntactic ambiguity with nested if-else constructs.
In such cases an ambiguous else belongs to the immediate preceding if.
For implicit script calls, an optional postcondition belongs to the parameter list.
E.g. suppose there is an implicit script key(??c:Char)
and there is a var c:Char in scope.
Then in ?c ?if isDigit
the postcondition refers to the output parameter c.
There would be no alternative here to enforce that the postcondition is related to the implicit script, instead of the parameter.
Script expressions will often have white space as implicit n-ary operator.
Such whitespace may be omitted around (+-) (-) (+) .. ...
and after ) and .
(optional break).
There is still ambiguity with a.b
and a(b)
.
If there is white space before .
it is an optional break; else it is a path separator.
If there is white space before (
it starts a parenthesized expression; else it starts a parameter list
LL(1) grammar
The SubScript syntax contains ambiguous choices between method calls, script calls and match terms.
Note that simpleTerm and methodOrScriptCall use for this purpose the disambiguating choice operator |+|.
This is an experimental SubScript feature under development.
The ambiguous choice keeps the syntax definition well readable for humans, but it is not a good starting point to write a top-down parser in a language such as Scala. Such an LL parser looks only one token ahead; it is specified using an LL(1) grammar.
An LL(1) grammar for SubScript would have a slightly different definition for simpleTerm, and instead of implicitScriptCall, methodOrScriptCall, channelScriptCall and matchTerm there would be two rather complicated scripts:
simpleTerm =; + simpleValueLedTerm codeFragment throwTerm whileTerm forTerm tryTerm specialTerm &quot;(&quot; scriptExpression &quot;)&quot; identifier_arrowLedTerm = identifier_arrow . (actualParameterList + simpleActualParameters) simpleValueLedTerm = identifier_arrowLedTerm + simpleValueExpression; &quot;match&quot; &quot;(&quot; scriptCaseClauses &quot;)&quot; + ( &quot;.&quot; identifier_arrowLedTerm + (.. parameterSeparator simpleActualParameter) + actualParameterList )
Indexed Script Expressions
Another preparation for an implementation in Scala would be to replace scriptExpression_0
by a script ..
scriptExpression_8scriptExpression(i:Int)
that has an index as a parameter:
scriptExpression = operatorModifiers scriptExpression_8 scriptExpression(i:Int) = if (i&gt;=0) (scriptExpression(i-1) .. operator(i)) else scriptTerm operator(i:Int) = i matches ( case 8 ==&gt; if newLineSignificant newLine else δ case 7 ==&gt; &quot;;&quot; &quot;-;&quot; case 6 ==&gt; + &quot;||&quot; &quot;|&quot; &quot;||:&quot; &quot;|:&quot; &quot;|+&quot; &quot;|;&quot; &quot;|/&quot; &quot;||+&quot; &quot;||;&quot; &quot;||/&quot; &quot;|+|&quot; &quot;|;|&quot; &quot;|/|&quot; case 5 ==&gt; + &quot;&amp;&amp;&quot; &quot;&amp;&quot; &quot;&amp;&amp;:&quot; &quot;&amp;:&quot; case 4 ==&gt; + &quot;==&quot; &quot;==:&quot; networkingArrow case 3 ==&gt; &quot;+&quot; case 2 ==&gt; + &quot;/&quot; &quot;%&quot; &quot;%/&quot; &quot;%/%/&quot; &quot;%&amp;&quot; &quot;%;&quot; case 1 ==&gt; + &quot;·&quot; case 0 ==&gt; if commasOmittable (-) else (+) )