Syntax definition

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
                            &amp;quot;(&amp;quot; scriptExpression &amp;quot;)&amp;quot;

  identifier_arrowLedTerm = identifier_arrow
                            . (actualParameterList + simpleActualParameters)

  simpleValueLedTerm      = identifier_arrowLedTerm
                          + simpleValueExpression;
                              &amp;quot;match&amp;quot; &amp;quot;(&amp;quot; scriptCaseClauses &amp;quot;)&amp;quot;
                            + ( &amp;quot;.&amp;quot; identifier_arrowLedTerm
                              + (.. parameterSeparator simpleActualParameter)
                              + actualParameterList
                              )

Indexed Script Expressions

Another preparation for an implementation in Scala would be to replace scriptExpression_0..scriptExpression_8 by a script scriptExpression(i:Int) that has an index as a parameter:

  scriptExpression        = operatorModifiers scriptExpression_8

scriptExpression(i:Int) = if (i&amp;gt;=0) (scriptExpression(i-1) .. operator(i))
                            else scriptTerm

  operator(i:Int)         = i matches (
                             case 8 ==&amp;gt;   if newLineSignificant newLine else δ
                             case 7 ==&amp;gt;   &amp;quot;;&amp;quot;   &amp;quot;-;&amp;quot;
                             case 6 ==&amp;gt; + &amp;quot;||&amp;quot;  &amp;quot;|&amp;quot;   &amp;quot;||:&amp;quot;  &amp;quot;|:&amp;quot;
                                          &amp;quot;|+&amp;quot;  &amp;quot;|;&amp;quot;  &amp;quot;|/&amp;quot;
                                          &amp;quot;||+&amp;quot; &amp;quot;||;&amp;quot; &amp;quot;||/&amp;quot;
                                          &amp;quot;|+|&amp;quot; &amp;quot;|;|&amp;quot; &amp;quot;|/|&amp;quot;
                             case 5 ==&amp;gt; + &amp;quot;&amp;amp;&amp;amp;&amp;quot;  &amp;quot;&amp;amp;&amp;quot;  &amp;quot;&amp;amp;&amp;amp;:&amp;quot;  &amp;quot;&amp;amp;:&amp;quot;
                             case 4 ==&amp;gt; + &amp;quot;==&amp;quot;  &amp;quot;==:&amp;quot; networkingArrow
                             case 3 ==&amp;gt;   &amp;quot;+&amp;quot;
                             case 2 ==&amp;gt; + &amp;quot;/&amp;quot;  &amp;quot;%&amp;quot;  &amp;quot;%/&amp;quot;  &amp;quot;%/%/&amp;quot;  &amp;quot;%&amp;amp;&amp;quot;  &amp;quot;%;&amp;quot;
                             case 1 ==&amp;gt; + &amp;quot;·&amp;quot;
                             case 0 ==&amp;gt; if commasOmittable (-) else (+)
                          )

Leave a Reply