src/providers/swift/parsing/parser.ml (2,882 lines of code) (raw):
(* Copyright (c) 2017 Uber Technologies, Inc. *)
(* *)
(* Permission is hereby granted, free of charge, to any person obtaining a copy *)
(* of this software and associated documentation files (the "Software"), to deal *)
(* in the Software without restriction, including without limitation the rights *)
(* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell *)
(* copies of the Software, and to permit persons to whom the Software is *)
(* furnished to do so, subject to the following conditions: *)
(* *)
(* The above copyright notice and this permission notice shall be included in *)
(* all copies or substantial portions of the Software. *)
(* *)
(* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *)
(* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *)
(* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *)
(* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *)
(* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, *)
(* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN *)
(* THE SOFTWARE. *)
open Angstrom
open Combinators
open Neal.Absyn
let rec grammar = ()
(*|GRAMMAR OF AN IDENTIFIER |*)
(*| implicit-parameter-name -> "$" decimal-digits |*)
and implicitParameterName () =
mkNode "ImplicitParameter"
<* wchar '$'
<:> mkPropE "Offset" decimalDigits
(*| identifier-head -> Upper- or lowercase letter A through Z |*)
(*| identifier-head -> "_" |*)
(*| identifier-head -> U+00A8, U+00AA, U+00AD, U+00AF, U+00B2–U+00B5, or U+00B7–U+00BA |*)
(*| identifier-head -> U+00BC–U+00BE, U+00C0–U+00D6, U+00D8–U+00F6, or U+00F8–U+00FF |*)
(*| identifier-head -> U+0100–U+02FF, U+0370–U+167F, U+1681–U+180D, or U+180F–U+1DBF |*)
(*| identifier-head -> U+1E00–U+1FFF |*)
(*| identifier-head -> U+200B–U+200D, U+202A–U+202E, U+203F–U+2040, U+2054, or U+2060–U+206F |*)
(*| identifier-head -> U+2070–U+20CF, U+2100–U+218F, U+2460–U+24FF, or U+2776–U+2793 |*)
(*| identifier-head -> U+2C00–U+2DFF or U+2E80–U+2FFF |*)
(*| identifier-head -> U+3004–U+3007, U+3021–U+302F, U+3031–U+303F, or U+3040–U+D7FF |*)
(*| identifier-head -> U+F900–U+FD3D, U+FD40–U+FDCF, U+FDF0–U+FE1F, or U+FE30–U+FE44 |*)
(*| identifier-head -> U+FE47–U+FFFD |*)
(*| identifier-head -> U+10000–U+1FFFD, U+20000–U+2FFFD, U+30000–U+3FFFD, or U+40000–U+4FFFD |*)
(*| identifier-head -> U+50000–U+5FFFD, U+60000–U+6FFFD, U+70000–U+7FFFD, or U+80000–U+8FFFD |*)
(*| identifier-head -> U+90000–U+9FFFD, U+A0000–U+AFFFD, U+B0000–U+BFFFD, or U+C0000–U+CFFFD |*)
(*| identifier-head -> U+D0000–U+DFFFD or U+E0000–U+EFFFD |*)
and identifierHead () =
satisfy (function
| 'a'..'z'
| 'A'..'Z'
| '_'
| '\xA8'
| '\xAA'
| '\xAD'
| '\xAF'
| '\xB2'..'\xB5'
| '\xB7'..'\xBA' ->
(*TODO: unicode*)
true
| _ -> false
)
(*| identifier-character -> Digit 0 through 9 |*)
(*| identifier-character -> U+0300–U+036F, U+1DC0–U+1DFF, U+20D0–U+20FF, or U+FE20–U+FE2F |*)
(*| identifier-character -> identifier-head |*)
and identifierCharacter () =
identifierHead ()
<|> satisfy (function
| '0'..'9' ->
(*TODO: unicode*)
true
| _ -> false
)
(*| identifier-characters -> identifier-character identifier-characters ??? |*)
and identifierCharacters () =
many1 identifierCharacter
(*| identifier -> identifier-head identifier-characters ??? |*)
(*| identifier -> backtick-identifier (not a separate production in the original grammar) |*)
(*| identifier -> implicit-parameter-name |*)
and nonReservedIdentifier pos keywords =
(
(List.cons <$> identifierHead () <*> (option [] (identifierCharacters ())))
) >>= fun chars ->
match string_of_chars chars with
| String l when List.mem l keywords ->
fail "Keyword can't be used as identifier"
| str ->
return (NodeHolder (pos, Node ("Identifier", Off pos, [("Value", str)])))
(*| backtick-identifier -> "`" identifier-head identifier-characters ??? "`" |*)
and backtickIdentifier pos =
(char '`' *> (List.cons <$> identifierHead () <*> (option [] (identifierCharacters()))) <* char '`') >>= fun str ->
return (NodeHolder (pos, Node ("Identifier", Off pos, [("Value", string_of_chars str)])))
and identifier' keywords =
pos >>= fun p ->
anyspace *> (
nonReservedIdentifier p keywords
<|> implicitParameterName ()
<|> backtickIdentifier p
)
and paramKeywords = ["inout"; "var"; "let"]
and paramName () = identifier' paramKeywords
and keywords = [
"associatedtype";
"class";
"deinit";
"enum";
"extension";
"fileprivate";
"func";
"import";
"init";
"inout";
"internal";
"let";
"open";
"operator";
"private";
"protocol";
"public";
"static";
"struct";
"subscript";
"typealias";
"var";
" break";
"case";
"continue";
"default";
"defer";
"do";
"else";
"fallthrough";
"for";
"guard";
"if";
"in";
"repeat";
"return";
"switch";
"where";
"while";
"as";
"catch";
"false";
"is";
"nil";
"rethrows";
"super";
"self";
"throw";
"throws";
"true";
"try";
"await";
]
and identifier () = identifier' keywords
(*| identifier-list -> identifier | identifier "," identifier-list |*)
and identifierList () =
commaSep identifier
(*| GRAMMAR OF A LITERAL |*)
(*| literal -> numeric-literal | string-literal | boolean-literal | nil-literal |*)
and literal () =
numericLiteral ()
<!> stringLiteral
<!> booleanLiteral
<!> nilLiteral
(*| numeric-literal -> "- ???" integer-literal | "- ???" floating-point-literal |*)
and numericLiteral () =
mkOptPropEmpty (mkBoolProp "Negative" (wchar '-')) >>= fun p ->
(
floatingPointLiteral ()
<!> integerLiteral
) <:> (return p)
(*| boolean-literal -> "true" | "false" |*)
and booleanLiteral () =
mkNode "BooleanLiteral"
<:> mkProp "Value" (
(wstring "true" *> pos >>| fun pos -> NodeHolder (pos, Bool true))
<|>
(wstring "false" *> pos >>| fun pos -> NodeHolder (pos, Bool false))
)
(*| nil-literal -> "nil" |*)
and nilLiteral () =
mkNode "NilLiteral"
<* wstring "nil"
(*| GRAMMAR OF AN INTEGER LITERAL |*)
(*| integer-literal -> binary-literal |*)
(*| integer-literal -> octal-literal |*)
(*| integer-literal -> decimal-literal |*)
(*| integer-literal -> hexadecimal-literal |*)
and integerLiteral () =
binaryLiteral ()
<!> octalLiteral
<!> hexadecimalLiteral
<!> decimalLiteral
(*| binary-literal -> "0b" binary-digit binary-literal-characters ??? |*)
and binaryLiteral () =
mkNode "NumericLiteral"
<:> mkProp "Type" (mkString "Binary")
<* anyspace
<* string "0b"
<:> mkProp "StringValue" (
pos >>= fun p ->
binaryDigit() >>= fun d ->
option [] (binaryLiteralCharacters ()) >>= fun ds ->
return (NodeHolder (p, string_of_chars ('0'::'b'::d::ds)))
)
(*| binary-digit -> Digit 0 or 1 |*)
and binaryDigit () =
satisfy (function
| '0'..'1' -> true
| _ -> false
)
(*| binary-literal-character -> binary-digit | "_" |*)
and binaryLiteralCharacter () =
binaryDigit ()
<|> char '_'
(*| binary-literal-characters -> binary-literal-character binary-literal-characters ??? |*)
and binaryLiteralCharacters () =
many1 binaryLiteralCharacter
(*| octal-literal -> "0o" octal-digit octal-literal-characters ??? |*)
and octalLiteral () =
mkNode "NumericLiteral"
<:> mkProp "Type" (mkString "Octal")
<* anyspace
<* string "0o"
<:> mkProp "StringValue" (
pos >>= fun p ->
octalDigit() >>= fun d ->
option [] (octalLiteralCharacters ()) >>= fun ds ->
return (NodeHolder (p, string_of_chars ('0'::'o'::d::ds)))
)
(*| octal-digit -> Digit 0 through 7 |*)
and octalDigit () =
satisfy (function
| '0'..'7' -> true
| _ -> false
)
(*| octal-literal-character -> octal-digit | "_" |*)
and octalLiteralCharacter () =
octalDigit ()
<|> char '_'
(*| octal-literal-characters -> octal-literal-character octal-literal-characters ??? |*)
and octalLiteralCharacters () =
many1 octalLiteralCharacter
(*| decimal-literal -> decimal-digit decimal-literal-characters ??? |*)
and decimalLiteral () =
mkNode "NumericLiteral"
<:> mkProp "Type" (mkString "Decimal")
<* anyspace
<:> mkProp "StringValue" (
pos >>= fun p ->
decimalDigit() >>= fun d ->
option [] (decimalLiteralCharacters ()) >>= fun ds ->
return (NodeHolder (p, string_of_chars (d::ds)))
)
(*| decimal-digit -> Digit 0 through 9 |*)
and decimalDigit () =
satisfy(function
| '0'..'9' -> true
| _ -> false)
(*| decimal-digits -> decimal-digit decimal-digits ??? |*)
and decimalDigits () =
many1 decimalDigit >>= fun chars ->
pos >>| fun pos -> NodeHolder (pos, string_of_chars chars)
(*| decimal-literal-character -> decimal-digit | "_" |*)
and decimalLiteralCharacter () =
decimalDigit ()
<|> char '_'
(*| decimal-literal-characters -> decimal-literal-character decimal-literal-characters ??? |*)
and decimalLiteralCharacters () =
many1 decimalLiteralCharacter
(*| hexadecimal-literal -> "0x" hexadecimal-digit hexadecimal-literal-characters ??? |*)
and hexadecimalLiteral () =
mkNode "NumericLiteral"
<:> mkProp "Type" (mkString "Hexadecimal")
<* anyspace
<* string "0x"
<:> mkProp "StringValue" (
pos >>= fun p ->
hexadecimalDigit() >>= fun d ->
option [] (hexadecimalLiteralCharacters ()) >>= fun ds ->
return (NodeHolder (p, string_of_chars ('0'::'x'::d::ds)))
)
(*| hexadecimal-digit -> Digit 0 through 9, a through f, or A through F |*)
and hexadecimalDigit () =
satisfy (function
| '0'..'9'
| 'a'..'f'
| 'A'..'F' -> true
| _ -> false
)
(*| hexadecimal-literal-character -> hexadecimal-digit | "_" |*)
and hexadecimalLiteralCharacter () =
hexadecimalDigit ()
<|> char '_'
(*| hexadecimal-literal-characters -> hexadecimal-literal-character hexadecimal-literal-characters ??? |*)
and hexadecimalLiteralCharacters () =
many1 hexadecimalLiteralCharacter
(*| GRAMMAR OF A FLOATING-POINT LITERAL |*)
(*| floating-point-literal -> decimal-literal decimal-fraction ??? decimal-exponent ??? |*)
(*| floating-point-literal -> hexadecimal-literal hexadecimal-fraction ??? hexadecimal-exponent |*)
and floatingPointLiteral () =
(* NOTE: split each of the cases into two where at least one of the *)
(* properties have to be present, otherwise integer literals will be parsed *)
(* as floating point literals *)
mkNode "FloatingPointLiteral"
<:> (
(
mkPropE "Integer" decimalLiteral
<:> mkPropE "Fraction" decimalFraction
<:> mkOptPropE "Exponent" decimalExponent
) <|> (
mkPropE "Integer" decimalLiteral
<:> mkPropE "Exponent" decimalExponent
) <|> (
mkPropE "Integer" hexadecimalLiteral
<:> mkPropE "Fraction" hexadecimalFraction
<:> mkOptPropE "Exponent" hexadecimalExponent
) <|> (
mkPropE "Integer" hexadecimalLiteral
<:> mkPropE "Exponent" hexadecimalExponent
)
)
(*| decimal-fraction -> "." decimal-literal |*)
and decimalFraction () =
char '.' *> decimalLiteral()
(*| decimal-exponent -> floating-point-e sign ??? decimal-literal |*)
and decimalExponent () =
floatingPointE () *> mkOptE sign >>= fun sign ->
decimalLiteral ()
<:> mkProp "Sign" (return sign)
(*| hexadecimal-fraction -> "." hexadecimal-digit hexadecimal-literal-characters ??? |*)
and hexadecimalFraction () =
char '.' *> pos >>= fun p ->
hexadecimalDigit() >>= fun d ->
option [] (hexadecimalLiteralCharacters ()) >>| fun ds ->
NodeHolder (p, string_of_chars (d::ds))
(*| hexadecimal-exponent -> floating-point-p sign ??? decimal-literal |*)
and hexadecimalExponent () =
floatingPointP () *> mkOptE sign >>= fun sign ->
decimalLiteral()
<:> mkProp "Sign" (return sign)
(*| floating-point-e -> "e" | "E" |*)
and floatingPointE () =
char 'e' <|> char 'E'
(*| floating-point-p -> "p" | "P" |*)
and floatingPointP () =
char 'p' <|> char 'P'
(*| sign -> "+" | "-" |*)
and sign () =
(wfstring "+" <|> wfstring "-") >>= mkString
(*| GRAMMAR OF A STRING LITERAL |*)
(*| string-literal -> static-string-literal | interpolated-string-literal |*)
(*| static-string-literal -> "\"" quoted-text? "\"" |*)
(*| static-string-literal -> "\"\"\"" multiline-quoted-text? "\"\"\"" |*)
(*| interpolated-string-literal -> "\"" interpolated-text? "\"" |*)
(*| interpolated-string-literal -> "\"\"\"" multiline-interpolated-text ? "\"\"\"" |*)
(* NOTE: this diverges from the original grammar as the static-string-literal
* and interpolated-string-literal productions had to be inline so that we are
* able to mix static and interpolated strings to always check for multiline
* strings first
*)
and stringLiteral () =
multilineStaticStringLiteral ()
<!> multilineInterpolatedStringLiteral
<!> singleLineStaticStringLiteral
<!> singleLineInterpolatedStringLiteral
and staticStringLiteral () =
multilineStaticStringLiteral ()
<!> singleLineStaticStringLiteral
and multilineStaticStringLiteral () =
mkNode "StaticStringLiteral"
<* anyspace
<* string "\"\"\""
<:> mkOptPropE "Value" multilineQuotedText
<* string "\"\"\""
(*| multiline-quoted-text -> multiline-quoted-text-item multiline-quoted-text? |*)
and multilineQuotedText () =
pos >>= fun pos ->
many1 multilineQuotedTextItem >>| fun strs ->
NodeHolder (pos, String (String.concat "" strs))
(*| multiline-quoted-text-item -> escaped-character |*)
(*| multiline-quoted-text-item -> Any Unicode scalar value except \ |*)
(*| multiline-quoted-text-item -> escaped-newline|*)
and multilineQuotedTextItem () =
(
(string "\"\"\"")
<|> escapedCharacter ()
<|> (
satisfy (function
| '\\' -> false
| _ -> true
) >>| String.make 1
)
<|> escapedNewline ()
) >>= function
| "\"\"\"" -> fail "end of multiline string"
| str -> return str
and escapedNewline () =
char '\\' *> anyspace *> char 'n' *> return "\n"
and singleLineStaticStringLiteral () =
mkNode "StaticStringLiteral"
<* anyspace
<* char '"'
<:> mkOptPropE "Value" quotedText
<* char '"'
(*| quoted-text -> quoted-text-item quoted-text ??? |*)
and quotedText () =
pos >>= fun pos ->
many1 quotedTextItem >>| fun strs ->
NodeHolder (pos, String (String.concat "" strs))
(*| quoted-text-item -> escaped-character |*)
(*| quoted-text-item -> Any Unicode scalar value except "\"", "\\", U+000A, or U+000D |*)
and quotedTextItem () =
escapedCharacter ()
<|>
(satisfy(function
| '"'
| '\\'
| '\x0a'
| '\x0d'
-> false
| _ -> true) >>| String.make 1)
and multilineInterpolatedStringLiteral () =
mkNode "InterpolatedStringLiteral"
<* anyspace
<* string "\"\"\""
<:> mkOptPropE "Fragments" multilineInterpolatedText
<* string "\"\"\""
(*| multiline-interpolated-text -> multiline-interpolated-text-item multiline-interpolated-text? |*)
and multilineInterpolatedText () = interpolatedText' multilineQuotedTextItem
and singleLineInterpolatedStringLiteral () =
mkNode "InterpolatedStringLiteral"
<* anyspace
<* char '"'
<:> mkOptPropE "Fragments" interpolatedText
<* char '"'
(*| interpolated-text -> interpolated-text-item interpolated-text ??? |*)
(*| interpolated-text-item -> "\(" expression ")" | quoted-text-item |*)
and interpolatedText () = interpolatedText' quotedTextItem
and interpolatedText' textItem =
many1 (fun () -> interpolatedTextItem' textItem) >>= fun l ->
List.fold_left (fun acc i ->
match acc,i with
| (InterpolatedCodePoints cs)::rest, (InterpolatedCodePoints [c]) ->
InterpolatedCodePoints (c::cs) :: rest
| (InterpolatedCodePoints cs)::rest, (InterpolatedExp e) ->
(InterpolatedExp e)::(InterpolatedCodePoints cs)::rest
| l,e ->
e::l
) [] l
|> List.rev
|> List.map (function
| InterpolatedCodePoints cs -> NodeHolder (0, String (String.concat "" (List.rev cs)))
| InterpolatedExp e -> e)
|> toList
and interpolatedTextItem' textItem =
(
string "\\("
*> anyspace
*> (expressionList () >>| fun e -> InterpolatedExp e)
<* wchar ')'
) <|> (
(textItem () >>| fun c -> InterpolatedCodePoints [c])
)
(*| escaped-character -> "\0" | "\\" | "\t" | "\n" | "\r" | "\"" | "\'" |*)
(*| escaped-character -> "\u" "{" unicode-scalar-digits "}" |*)
and escapedCharacter () =
(string "\\0" *> return (String.make 1 (Char.chr 0)))
<|>
(string "\\\\" *> return "\\")
<|>
(string "\\t" *> return "\t")
<|>
(string "\\n" *> return "\n")
<|>
(string "\\r" *> return "\r")
<|>
(string "\\\""*> return "\"")
<|>
(string "\\\'" *> return "'")
<|>
(string "\\u{" *> unicodeScalarDigits () <* wchar '}')
(*| unicode-scalar-digits -> Between one and eight hexadecimal digits |*)
and unicodeScalarDigits () =
many1 hexadecimalDigit >>= fun digits ->
if List.length digits > 8
then fail "Invalid unicode sequence"
else match string_of_chars digits with
| String s -> return ("\\u{" ^ s ^ "}")
| _ -> pos >>= unreachable
(*| GRAMMAR OF OPERATORS |*)
(*| operator-head -> "/" | "=" | "-" | "+" | "!" | "*" | "%" | "<" | ">" | "&" | "|" | "^" | "~" | "?" |*)
(*| operator-head -> U+00A1–U+00A7 |*)
(*| operator-head -> U+00A9 or U+00AB |*)
(*| operator-head -> U+00AC or U+00AE |*)
(*| operator-head -> U+00B0–U+00B1, U+00B6, U+00BB, U+00BF, U+00D7, or U+00F7 |*)
(*| operator-head -> U+2016–U+2017 or U+2020–U+2027 |*)
(*| operator-head -> U+2030–U+203E |*)
(*| operator-head -> U+2041–U+2053 |*)
(*| operator-head -> U+2055–U+205E |*)
(*| operator-head -> U+2190–U+23FF |*)
(*| operator-head -> U+2500–U+2775 |*)
(*| operator-head -> U+2794–U+2BFF |*)
(*| operator-head -> U+2E00–U+2E7F |*)
(*| operator-head -> U+3001–U+3003 |*)
(*| operator-head -> U+3008–U+3030 |*)
(*TODO: unicode*)
and operatorHead () =
satisfy (function
| '/' | '=' | '-' | '+' | '!' | '*' | '%' | '<' | '>' | '&' | '|' | '^' | '~' | '?'
| '\xA1'..'\xA7'
| '\xA9' | '\xAB'
| '\xAC' | '\xAE'
| '\xB0'..'\xB1' | '\xB6' | '\xBB' | '\xBF' | '\xD7' | '\xF7'
-> true
| _ -> false
)
(*| operator-character -> operator-head |*)
(*| operator-character -> U+0300–U+036F |*)
(*| operator-character -> U+1DC0–U+1DFF |*)
(*| operator-character -> U+20D0–U+20FF |*)
(*| operator-character -> U+FE00–U+FE0F |*)
(*| operator-character -> U+FE20–U+FE2F |*)
(*| operator-character -> U+E0100–U+E01EF |*)
(*TODO: unicode*)
and operatorCharacter () = operatorHead ()
(*| operator-characters -> operator-character operator-characters ??? |*)
and operatorCharacters () =
many1 operatorCharacter
(*| dot-operator-head -> "." |*)
and dotOperatorHead () =
char '.'
(*| dot-operator-character -> "." | operator-character |*)
and dotOperatorCharacter () =
char '.' <|> operatorCharacter ()
(*| dot-operator-characters -> dot-operator-character dot-operator-characters ??? |*)
and dotOperatorCharacters () =
many1 dotOperatorCharacter
and check_operator = function
| [ '/'; '*' ]
| [ '*'; '/' ]
| [ '/'; '/' ]
| [ '?' ]
-> fail "Invalid operator"
| _ -> return ()
(*| operator -> operator-head operator-characters ??? |*)
(*| operator -> dot-operator-head dot-operator-characters |*)
and operator' () =
(*whitespace-less version that allows disambiguating operators*)
(List.cons <$> operatorHead () <*> option [] (operatorCharacters())
<|>
(List.cons <$> dotOperatorHead () <*> dotOperatorCharacters ())
>>= (fun c ->
pos >>= fun pos ->
check_operator c *> return (NodeHolder (pos, string_of_chars c))))
and operator () =
anyspace *> operator' ()
and operatorWithGenerics () =
let aux head tail =
let rec f chars =
(genericParameterClause () >>| fun gpc -> (chars, gpc))
<|> (
(tail >>= fun tl -> f (chars@[tl]))
<|>
(mkOpt (genericParameterClause ()) >>| fun gpc -> (chars, gpc))
)
in anyspace *> head >>= f
in
(
aux (operatorHead () >>| fun c -> [c]) (operatorCharacter ())
<|>
aux (dotOperatorHead() >>= fun h ->
dotOperatorCharacter () >>| fun c -> [h; c])
(dotOperatorCharacter ())
) >>= fun (chars, gpc) ->
check_operator chars
*> mkProp "FunctionName" (return (NodeHolder (0, string_of_chars chars)))
<:> mkProp "GenericParameterClause" (return gpc)
(*| binary-operator -> operator |*)
and binaryOperator () =
(lhsOperatorWhitespace true *> anyspace *> operator' () <* rhsOperatorWhitespace true <* anyspace)
<|>
(lhsOperatorWhitespace false *> operator' () <* rhsOperatorWhitespace false)
(*| prefix-operator -> operator |*)
and prefixOperator () =
(
(lhsOperatorWhitespace true *> anyspace)
<|>
(lhsOperatorWhitespace false)
) *> operator' () <* rhsOperatorWhitespace false
(*| postfix-operator -> operator |*)
and postfixOperator exp =
(lhsOperatorWhitespace false *> operator' ())
>>= fun op ->
(
(match op with
| NodeHolder(_, String(op')) when op' = "!" || op' = "?" ->
fail "missing whitespace on right-hand side of postfix operator"
| _ ->
rhsOperatorWhitespace true
)
) *>
mkNode "PostfixOperation"
<:> mkProp "Operand" (return exp)
<:> mkProp "Operator" (return op)
(*| Types |*)
(*| GRAMMAR OF A TYPE IDENTIFIER |*)
(*| type-name -> identifier |*)
and typeName () = identifier ()
(*| GRAMMAR OF A GENERIC ARGUMENT CLAUSE |*)
(*| generic-argument -> type |*)
and genericArgument () =
fix type'
(*| generic-argument-list -> generic-argument | generic-argument "," generic-argument-list |*)
and genericArgumentList () =
commaSep genericArgument
(*| generic-argument-clause -> "<" generic-argument-list ">" |*)
and genericArgumentClause () =
wchar '<' *> genericArgumentList () <* wchar '>'
(*| type-identifier -> type-name generic-argument-clause ??? | type-name generic-argument-clause ??? "." type-identifier |*)
and typeIdentifier' ~forceMultiple _ =
mkNode "TypeIdentifier"
<:> mkPropE "TypeName" typeName
<:> mkOptPropE "GenericArgumentClause" genericArgumentClause
<:> (
if forceMultiple
then mkProp "TypeIdentifier" (wchar '.' *> typeIdentifier ())
else mkOptProp "TypeIdentifier" (wchar '.' *> typeIdentifier ())
)
and typeIdentifier ?(forceMultiple=false) () =
fix (typeIdentifier' ~forceMultiple)
(*| GRAMMAR OF A TYPE |*)
(*| type -> array-type | dictionary-type | function-type | type-identifier | tuple-type | optional-type | implicitly-unwrapped-optional-type | protocol-composition-type | metatype-type | "Any" | "Self" |*)
and type' _ =
let aux () =
arrayType ()
<!> dictionaryType
<!> functionType
<!> tupleType
<|> (typeIdentifier () >>= fun t -> option t (protocolCompositionType t))
<|> (wstring "Any" *> mkNode "AnyType")
<|> (wstring "Self" *> mkNode "SelfType")
in
let rec aux' t =
option t (
(
metatypeType t
<|> optionalType t
<|> implicitlyUnwrappedOptionalType t
) >>= aux'
)
in
aux () >>= aux'
(*| GRAMMAR OF A TYPE ANNOTATION |*)
(*| type-annotation -> ":" attributes ??? "inout"??? type |*)
and typeAnnotation () =
mkNode "TypeAnnotation"
<* wchar ':'
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmpty (mkBoolProp "Inout" (wstring "inout"))
<:> mkProp "Type" (fix type')
(*| GRAMMAR OF A TUPLE TYPE |*)
(*| tuple-type -> "(" tuple-type-element-list ??? ")" |*)
and tupleType () =
mkNode "TupleType"
<* wchar '('
<:> mkOptPropE "Elements" tupleTypeElementList
<* wchar ')'
(*| tuple-type-element-list -> tuple-type-element | tuple-type-element "," tuple-type-element-list |*)
and tupleTypeElementList () =
commaSep tupleTypeElement
(*| tuple-type-element -> element-name type-annotation | type |*)
and tupleTypeElement () =
(
elementName ()
<:> mkPropE "TypeAnnotation" typeAnnotation
)
<|> fix type'
(*| element-name -> identifier |*)
and elementName () =
identifier ()
(*| function-properties -> async ??? throws ??? |*)
(*| function-properties -> async ??? rethrows ??? |*)
and functionProperties () =
mkPropHolder
<:> mkOptPropEmpty (
mkBoolProp "Async" (wstring "async")
)
<:> mkOptPropEmpty (
mkBoolProp "Throws" (wstring "throws")
<|>
mkBoolProp "Rethrows" (wstring "rethrows")
)
(*| GRAMMAR OF A FUNCTION TYPE |*)
(*| function-type -> attributes ??? function-type-argument-clause function-properties "->" type |*)
and functionType () =
mkNode "FunctionType"
<:> mkOptPropE "Attributes" attributes
<:> mkPropE "FunctionTypeArgumentClause" functionTypeArgumentClause
<:> functionProperties ()
<* wfstring "->"
<:> mkProp "ReturnType" (fix type')
(*| function-type-argument-clause -> "(" ")" |*)
(*| function-type-argument-clause -> "(" function-type-argument-list "... ???" ")" |*)
and functionTypeArgumentClause () =
mkNode "FunctionTypeArgumentClause"
<* wchar '('
<:> mkOptPropEmpty (
mkPropE "ArgumentList" functionTypeArgumentList
<:> mkOptPropEmpty (mkBoolProp "Variadic" (wstring "..."))
)
<* wchar ')'
(*| function-type-argument-list -> function-type-argument | function-type-argument "," function-type-argument-list |*)
and functionTypeArgumentList () =
commaSep functionTypeArgument
(*| function-type-argument -> attributes ??? "inout ???" type | argument-label type-annotation |*)
and functionTypeArgument () =
mkNode "FunctionTypeAgument"
<:> (
(
wstring "_"
*> mkOptPropE "ArgumentLabel" argumentLabel
<:> mkPropE "TypeAnnotation" typeAnnotation
) <|> (
mkOptPropE "Attributes" attributes
<:> mkOptPropEmpty (mkBoolProp "Inout" (wstring "inout"))
<:> mkProp "Type" (fix type')
)
)
(*| argument-label -> identifier |*)
and argumentLabel () =
identifier ()
(*| GRAMMAR OF AN ARRAY TYPE |*)
(*| array-type -> "[" type "]" |*)
and arrayType () =
mkNode "ArrayType"
<* wchar '['
<:> mkProp "Type" (fix type')
<* wchar ']'
(*| GRAMMAR OF A DICTIONARY TYPE |*)
(*| dictionary-type -> "[" type ":" type "]" |*)
and dictionaryType () =
mkNode "DictionaryType"
<* wchar '['
<:> mkProp "KeyType" (fix type')
<* wchar ':'
<:> mkProp "ValueType" (fix type')
<* wchar ']'
(*| GRAMMAR OF AN OPTIONAL TYPE |*)
(*| optional-type -> type "?" |*)
and optionalType t =
return t
<:> mkBoolProp "Optional" (char '?')
(*| GRAMMAR OF AN IMPLICITLY UNWRAPPED OPTIONAL TYPE |*)
(*| implicitly-unwrapped-optional-type -> type "!" |*)
and implicitlyUnwrappedOptionalType t =
return t
<:> mkBoolProp "ImplicitlyUnwrappedOptional" (wchar '!')
(*| GRAMMAR OF A PROTOCOL COMPOSITION TYPE |*)
(*| protocol-composition-type -> protocol-identifier "&" protocol-composition-continuation |*)
(*| protocol-composition-continuation -> protocol-identifier | protocol-composition-type |*)
and protocolCompositionType t =
wchar '&' *>
sepBy1 '&' protocolIdentifier >>= fun pis ->
List.fold_left
(fun p i ->
mkNode "ProtocolCompositionType"
<:> mkProp "Lhs" p
<:> mkProp "Rhs" (return i)
)
(return t)
pis
(*| protocol-identifier -> type-identifier |*)
and protocolIdentifier () =
typeIdentifier ()
(*| GRAMMAR OF A METATYPE TYPE |*)
(*| metatype-type -> type "." "Type" | type "." "Protocol" |*)
and metatypeType t =
return t
<* wchar '.'
<:> mkProp "Metatype" (
(wstring "Type" *> mkString "Type")
<|>
(wstring "Protocol" *> mkString "Protocol")
)
(*| GRAMMAR OF A TYPE INHERITANCE CLAUSE |*)
(*| type-inheritance-list -> type-identifier | type-identifier "," type-inheritance-list |*)
and typeInheritanceList () =
commaSep typeIdentifier
(*| class-requirement -> "class" |*)
and classRequirement () =
wstring "class"
(*| type-inheritance-clause -> ":" class-requirement "," type-inheritance-list |*)
(*| type-inheritance-clause -> ":" class-requirement |*)
(*| type-inheritance-clause -> ":" type-inheritance-list |*)
and typeInheritanceClause () =
wchar ':' *> (
(classRequirement () *> (mkOpt (wchar ',' *> typeInheritanceList ())))
<!> typeInheritanceList
)
(*| Expressions |*)
(*| GRAMMAR OF A TRY EXPRESSION |*)
(*| try-operator -> "try" | "try" "?" | "try" "!" |*)
and tryOperator () =
(
wstring "try?"
<|> wstring "try!"
<|> wstring "try"
) >>= mkString
(*| await-operator -> "await" |*)
and awaitOperator () =
(
wstring "await"
) >>= mkString
(*| GRAMMAR OF AN ASSIGNMENT OPERATOR |*)
(*| assignment-operator -> "=" |*)
and assignmentOperator () =
wchar '='
(*| GRAMMAR OF A CONDITIONAL OPERATOR |*)
(*| conditional-operator -> "?" try-operator ??? expression ":" |*)
and conditionalOperator () =
wchar '?'
*> mkOptPropE "ConsequentTry" tryOperator
<:> mkProp "Consequent" (fix expression)
<* wchar ':'
(*| GRAMMAR OF A TYPE-CASTING OPERATOR |*)
(*| type-casting-operator -> "is" type |*)
(*| type-casting-operator -> "as" type |*)
(*| type-casting-operator -> "as" "?" type |*)
(*| type-casting-operator -> "as" "!" type |*)
and typeCastingOperator () =
mkProp "Operator" (
(
wstring "is"
<|> wstring "as?"
<|> wstring "as!"
<|> wstring "as"
) >>= mkString
)
<:> mkProp "Type" (fix type')
(*| GRAMMAR OF A PRIMARY EXPRESSION |*)
(*| primary-expression -> identifier generic-argument-clause ??? |*)
(*| primary-expression -> literal-expression |*)
(*| primary-expression -> self-expression |*)
(*| primary-expression -> superclass-expression |*)
(*| primary-expression -> closure-expression |*)
(*| primary-expression -> parenthesized-expression |*)
(*| primary-expression -> tuple-expression |*)
(*| primary-expression -> implicit-member-expression |*)
(*| primary-expression -> wildcard-expression |*)
(*| primary-expression -> selector-expression |*)
(*| primary-expression -> key-path-expression |*)
(*| primary-expression -> key-path-string-expression |*)
and primaryExpression () =
literalExpression ()
<!> selfExpression
<!> superclassExpression
<!> closureExpression
<!> parenthesizedExpression
<!> tupleExpression
<!> wildcardExpression
<!> selectorExpression
<!> keyPathStringExpression
<!> keyPathExpression
<|> (identifier () <:> mkOptProp "GenericArgumentClause" (genericArgumentClause ()) >>= fun ident ->
option ident (
mkNode "FunctionReference"
<* wchar '('
<:> mkPropE "Parameters" argumentNames
<* wchar ')'
)
)
<!> implicitMemberExpression
(*| GRAMMAR OF A LITERAL EXPRESSION |*)
(*| literal-expression -> literal |*)
(*| literal-expression -> array-literal | dictionary-literal | playground-literal |*)
(*| literal-expression -> "#file" | "#line" | "#column" | "#function" |*)
and literalExpression () =
literal ()
<!> arrayLiteral
<!> dictionaryLiteral
<!> playgroundLiteral
<|> (wstring "#file" *> mkNode "HashFileLiteral")
<|> (wstring "#line" *> mkNode "HashLineLiteral")
<|> (wstring "#column" *> mkNode "HashColumnLiteral")
<|> (wstring "#function" *> mkNode "HashFunctionLiteral")
(*| array-literal -> "[" array-literal-items ??? "]" |*)
and arrayLiteral () =
mkNode "ArrayLiteral"
<* wchar '['
<:> mkOptPropE "Items" arrayLiteralItems
<* wchar ']'
(*| array-literal-items -> array-literal-item ", ???" | array-literal-item "," array-literal-items |*)
and arrayLiteralItems () =
sepBy1 ',' arrayLiteralItem
<* anyspace
<* option () (skip (function ',' -> true | _ -> false))
>>= toList
(*| array-literal-item -> expression |*)
and arrayLiteralItem () =
fix expression
(*| dictionary-literal -> "[" dictionary-literal-items "]" | "[" ":" "]" |*)
and dictionaryLiteral () =
mkNode "DictionaryLiteral"
<* wchar '['
<:> mkProp "Items" (
dictionaryLiteralItems ()
<|>
(wchar ':' *> pos >>| fun pos -> NodeHolder (pos, List []))
)
<* wchar ']'
(*| dictionary-literal-items -> dictionary-literal-item ", ???" | dictionary-literal-item "," dictionary-literal-items |*)
and dictionaryLiteralItems () =
sepBy1 ',' dictionaryLiteralItem
<* anyspace
<* option () (skip (function ',' -> true | _ -> false))
>>= toList
(*| dictionary-literal-item -> expression ":" expression |*)
and dictionaryLiteralItem () =
mkNode "DictionaryLiteralItem"
<:> mkProp "Key" (fix expression)
<* wchar ':'
<:> mkProp "Value" (fix expression)
(*| playground-literal -> "#colorLiteral" "(" "red" ":" expression "," "green" ":" expression "," "blue" ":" expression "," "alpha" ":" expression ")" |*)
(*| playground-literal -> "#fileLiteral" "(" "resourceName" ":" expression ")" |*)
(*| playground-literal -> "#imageLiteral" "(" "resourceName" ":" expression ")" |*)
and playgroundLiteral () =
(
mkNode "ColorLiteral"
<* wstring "#colorLiteral" <* wchar '('
<:> mkProp "Red" (wstring "red" *> wchar ':' *> fix expression)
<* wchar ','
<:> mkProp "Green" (wstring "green" *> wchar ':' *> fix expression)
<* wchar ','
<:> mkProp "Blue" (wstring "blue" *> wchar ':' *> fix expression)
<* wchar ','
<:> mkProp "Alpha" (wstring "alpha" *> wchar ':' *> fix expression)
<* wchar ')'
) <|> (
mkNode "FileLiteral"
<* wstring "#fileLiteral" <* wchar '('
<:> mkProp "Name" (wstring "resourceName" *> wchar ':' *> fix expression)
<* wchar ')'
) <|> (
mkNode "ImageLiteral"
<* wstring "#imageLiteral" <* wchar '('
<:> mkProp "Name" (wstring "resourceName" *> wchar ':' *> fix expression)
<* wchar ')'
)
(*| GRAMMAR OF A SELF EXPRESSION |*)
(*| self-expression -> "self" | self-method-expression | self-subscript-expression | self-initializer-expression |*)
and selfExpression () =
(wstring "self" *> mkNode "SelfExpression")
<!> selfMethodExpression
<!> selfSubscriptExpression
<!> selfInitializerExpression
(*| self-method-expression -> "self" "." identifier |*)
and selfMethodExpression () =
mkNode "SelfMethodExpression"
<* wstring "self"
<* wchar '.'
<:> mkPropE "MethodName" identifier
(*| self-subscript-expression -> "self" "[" expression-list "]" |*)
and selfSubscriptExpression () =
mkNode "SelfSubscriptExpression"
<* wstring "self"
<* wchar '['
<:> mkPropE "SubscriptExpressionList" expressionList
<* wchar ']'
(*| self-initializer-expression -> "self" "." "init" |*)
and selfInitializerExpression () =
mkNode "SelfInitializerExpression"
<* wstring "self"
<* wchar '.'
<* wstring "init"
(*| GRAMMAR OF A SUPERCLASS EXPRESSION |*)
(*| superclass-expression -> superclass-method-expression | superclass-subscript-expression | superclass-initializer-expression |*)
and superclassExpression () =
superclassMethodExpression ()
<!> superclassSubscriptExpression
<!> superclassInitializerExpression
(*| superclass-method-expression -> "super" "." identifier |*)
and superclassMethodExpression () =
mkNode "SuperclassMethodExpression"
<* wstring "super"
<* wchar '.'
<:> mkPropE "MethodName" identifier
(*| superclass-subscript-expression -> "super" "[" expression-list "]" |*)
and superclassSubscriptExpression () =
mkNode "SuperclassSubscriptExpression"
<* wstring "super"
<* wchar '['
<:> mkPropE "SubscriptExpressionList" expressionList
<* wchar ']'
(*| superclass-initializer-expression -> "super" "." "init" |*)
and superclassInitializerExpression () =
mkNode "SuperclassInitializerExpression"
<* wstring "super"
<* wchar '.'
<* wstring "init"
(*| GRAMMAR OF A CLOSURE EXPRESSION |*)
(*| closure-expression -> "{" closure-signature ??? statements ??? "}" |*)
and closureExpression () =
mkNode "ClosureExpression"
<* wchar '{'
<:> mkOptPropEmptyE closureSignature
<* anyspace
<:> mkOptProp "Statements" (fix statements)
<* wchar '}'
(*| closure-signature -> capture-list ??? closure-parameter-clause "throws ???" function-result ??? "in" |*)
(*| closure-signature -> capture-list "in" |*)
and closureSignature () =
(
mkOptProp "CaptureList" (captureList () <* anyspace)
<:> mkPropE "ClosureParameterClause" closureParameterClause
<:> mkOptPropEmpty (mkBoolProp "Throws" (wstring "throws"))
<:> mkOptPropE "FunctionResult" functionResult
<* wstring "in"
) <|> (
mkPropE "CaptureList" captureList
<* wstring "in"
)
(*| closure-parameter-clause -> "(" ")" | "(" closure-parameter-list ")" | identifier-list |*)
and closureParameterClause () =
(
wchar '('
*> mkOptE closureParameterList
<* wchar ')'
)
<!> identifierList
(*| closure-parameter-list -> closure-parameter | closure-parameter "," closure-parameter-list |*)
and closureParameterList () =
commaSep closureParameter
(*| closure-parameter -> closure-parameter-name type-annotation ??? |*)
(*| closure-parameter -> closure-parameter-name type-annotation "..." |*)
and closureParameter () =
mkNode "ClosureParameter"
<:> (
(wstring "_" *> mkPropE "Name" closureParameterName)
<|> mkPropE "Name" closureParameterName
) <:> (
(
mkPropE "TypeAnnotation" typeAnnotation
<:> mkBoolProp "Variadic" (wstring "...")
)
<|> mkOptPropE "TypeAnnotation" typeAnnotation
)
(*| closure-parameter-name -> identifier |*)
and closureParameterName () =
identifier ()
(*| capture-list -> "[" capture-list-items "]" |*)
and captureList () =
wchar '[' *> captureListItems () <* wchar ']'
(*| capture-list-items -> capture-list-item | capture-list-item "," capture-list-items |*)
and captureListItems () =
commaSep captureListItem
(*| capture-list-item -> capture-specifier ??? expression |*)
and captureListItem () =
mkOptPropEmptyE captureSpecifier >>= fun captureSpecifier ->
mkNode "CaptureItem"
<:> mkProp "Expression" (fix expression)
<:> (return captureSpecifier)
(*| capture-specifier -> "weak" | "unowned" | "unowned(safe)" | "unowned(unsafe)" |*)
and captureSpecifier () =
mkBoolProp "Weak" (wstring "weak")
<|> mkBoolProp "Unowned" (wstring "unowned")
<|> mkBoolProp "UnownedSafe" (wstring "unowned(safe)")
<|> mkBoolProp "UnownedUnsafe" (wstring "unowned(unsafe)")
(*| GRAMMAR OF A IMPLICIT MEMBER EXPRESSION |*)
(*| implicit-member-expression -> "." identifier |*)
and implicitMemberExpression () =
mkNode "ImplicitMemberExpression"
<* wchar '.'
<:> mkPropE "Property" identifier
(*| GRAMMAR OF A PARENTHESIZED EXPRESSION |*)
(*| parenthesized-expression -> "(" expression ")" |*)
and parenthesizedExpression () =
wchar '(' *> fix expression <* wchar ')'
(*| GRAMMAR OF A TUPLE EXPRESSION |*)
(*| tuple-expression -> "(" ")" | "(" tuple-element "," tuple-element-list ")" |*)
and tupleExpression () =
mkNode "TupleExpression"
<* wchar '('
<:> mkOptPropE "Items" tupleElementList
<* wchar ')'
(*| tuple-element-list -> tuple-element | tuple-element "," tuple-element-list |*)
and tupleElementList () =
commaSep tupleElement
(*| tuple-element -> expression | identifier ":" expression |*)
and tupleElement () =
mkNode "TupleElement"
<:> mkOptProp "Label" (identifier () <* wchar ':')
<:> mkProp "Expression" (fix expression)
(*| GRAMMAR OF A WILDCARD EXPRESSION |*)
(*| wildcard-expression -> "_" |*)
and wildcardExpression () =
mkNode "WildcardExpression"
<* wstring "_"
(*| GRAMMAR OF A SELECTOR EXPRESSION |*)
(*| selector-expression -> "#selector" "(" expression ")" |*)
(*| selector-expression -> "#selector" "(" "getter:" expression ")" |*)
(*| selector-expression -> "#selector" "(" "setter:" expression ")" |*)
and selectorExpression () =
mkNode "SelectorExpression"
<* wstring "#selector"
<* wchar '('
<:> (
mkProp "GetterExpression" (wstring "getter:" *> fix expression)
<|> mkProp "SetterExpression" (wstring "setter:" *> fix expression)
<|> mkProp "Expression" (fix expression)
)
<* wchar ')'
(*| GRAMMAR OF A KEY-PATH EXPRESSION |*)
(*| key-path-expression -> "\\" type? "." key-path-components |*)
and keyPathExpression () =
mkNode "KeyPathExpression"
<* wchar '\\'
<:> mkProp "Expression" (fix expression)
<:> mkOptProp "KeyPathComponents" (wchar '.' *> keyPathComponents ())
(*| key-path-components -> key-path-component | key-path-component . key-path-components |*)
and keyPathComponents () =
sepBy1 '.' keyPathComponent >>= toList
(*| key-path-component -> identifier key-path-postfixes? | key-path-postfixes |*)
and keyPathComponent () =
mkNode "KeyPathComponent"
<:> ((
mkPropHolder
<:> mkPropE "Identifier" identifier
<:> mkOptPropE "Postfixes" keyPathPostfixes
) <|> (
mkPropHolder
<:> mkPropE "Postfixes" keyPathPostfixes
))
(*| key-path-postfixes -> key-path-postfix key-path-postfixes? |*)
and keyPathPostfixes () =
many1 keyPathPostfix >>= toList
(*| key-path-postfix -> "?" | "!" | "[" function-call-argument-list "]" |*)
and keyPathPostfix () =
(
wchar '?' *> mkNode "KeyPathOptionalPostfix"
) <|> (
wchar '!' *> mkNode "KeyPathForcedPostfix"
) <|> (
mkNode "KeyPathSubscriptPostfix"
<* wchar '['
<:> mkPropE "Arguments" functionCallArgumentList
<* wchar ']'
)
(*| key-path-string-expression -> "#keyPath" "(" expression ")" |*)
and keyPathStringExpression () =
mkNode "KeyPathStringExpression"
<* wstring "#keyPath"
<* wchar '('
<:> mkProp "Expression" (fix expression)
<* wchar ')'
(*| GRAMMAR OF A FUNCTION CALL EXPRESSION |*)
(*| trailing-closure -> closure-expression |*)
and trailingClosure ~allowTrailingClosure () =
if allowTrailingClosure
then closureExpression ()
else fail "trailing closure requires parentheses for disambiguation in this context"
(*| function-call-argument -> expression | identifier ":" expression |*)
(*| function-call-argument -> operator | identifier ":" operator |*)
and functionCallArgument () =
mkNode "FunctionCallArgument"
<:> mkOptProp "Label" (identifier () <* wchar ':')
<:> (
mkProp "Expression" (fix expression)
<|> mkPropE "Operator" operator
)
(*| function-call-argument-list -> function-call-argument | function-call-argument "," function-call-argument-list |*)
and functionCallArgumentList () =
commaSep functionCallArgument
(*| function-call-argument-clause -> "(" ")" | "(" function-call-argument-list ")" |*)
and functionCallArgumentClause () =
(wchar '(' *> wchar ')' *> toList [])
<|>
(wchar '(' *> functionCallArgumentList () <* wchar ')')
(*| function-call-expression -> postfix-expression function-call-argument-clause |*)
(*| function-call-expression -> postfix-expression function-call-argument-clause ??? trailing-closure |*)
and functionCallExpression ~allowTrailingClosure callee =
(* This functions is absolutely awful. It turns out that you cannot have *)
(* two trailing closures in a row, i.e. `f{}(){}` is ok but `f{}{}` is not. *)
(* even though both expression are equivalent only the first one is *)
(* succesfully parsed by the swift compiler. This is not encoded in the *)
(* official grammar in any way, but it turns out a different version of the *)
(* grammar is available in comments in the swift parser: *)
(*https://github.com/apple/swift/blob/96f2a04f558891bbc48e82ce9373465dd00b9014/lib/Parse/ParseExpr.cpp#L1001*)
pos >>= fun pos ->
(
mkNode ~pos:(Some pos) "CallExpression"
<:> mkProp "Callee" (return callee)
<:> mkOptPropE "Arguments" functionCallArgumentClause
<:> mkPropE "Closure" (trailingClosure ~allowTrailingClosure)
>>= fun exp ->
postfixExpression' ~allowTrailingClosure:false exp
>>= fun exp' ->
if exp <> exp'
then postfixExpression' ~allowTrailingClosure exp'
else return exp'
) <|> (
mkNode ~pos:(Some pos) "CallExpression"
<:> mkProp "Callee" (return callee)
<:> mkPropE "Arguments" functionCallArgumentClause
)
(*| GRAMMAR OF AN INITIALIZER EXPRESSION |*)
(*| initializer-expression -> postfix-expression "." "init" |*)
(*| initializer-expression -> postfix-expression "." "init" "(" argument-names ")" |*)
and initializerExpression exp =
mkNode "InitializerExpression"
<* wchar '.'
<* wstring "init"
<:> mkProp "Expression" (return exp)
<:> mkOptProp "Arguments" (wchar '(' *> argumentNames () <* wchar ')')
(*| GRAMMAR OF A POSTFIX EXPRESSION |*)
(*| postfix-expression -> primary-expression |*)
(*| postfix-expression -> postfix-expression postfix-operator |*)
(*| postfix-expression -> function-call-expression |*)
(*| postfix-expression -> initializer-expression |*)
(*| postfix-expression -> explicit-member-expression |*)
(*| postfix-expression -> postfix-self-expression |*)
(*| postfix-expression -> dynamic-type-expression |*)
(*| postfix-expression -> subscript-expression |*)
(*| postfix-expression -> forced-value-expression |*)
(*| postfix-expression -> optional-chaining-expression |*)
and postfixExpression ~allowTrailingClosure ~allowTypeAnnotation () =
(
(ifParsingPattern *> fix (pattern ~allowExpression:false ~allowIdentiifer:false ~allowTypeAnnotation))
<!> primaryExpression
<!> dynamicTypeExpression
) >>= postfixExpression' ~allowTrailingClosure
and postfixExpression' ~allowTrailingClosure exp =
option exp (
(
explicitMemberExpression exp
<|> optionalChainingExpression exp
<|> postfixOperator exp
<|> postfixSelfExpression exp
<|> initializerExpression exp
<|> subscriptExpression exp
<|> forcedValueExpression exp
<|> functionCallExpression ~allowTrailingClosure exp
) >>= postfixExpression' ~allowTrailingClosure
)
(*| GRAMMAR OF A PREFIX EXPRESSION |*)
(*| in-out-expression -> "&" identifier |*)
and inOutExpression () =
mkNode "InOutExpression"
<:> mkBoolProp "Inout" (wchar '&')
<:> mkPropE "Value" identifier
(*| prefix-expression -> prefix-operator ??? postfix-expression |*)
(*| prefix-expression -> in-out-expression |*)
and prefixExpression ~allowTrailingClosure ~allowTypeAnnotation () =
(
mkNode "PrefixExpression"
<:> mkPropE "Operator" prefixOperator
<:> mkPropE "Operand" (postfixExpression ~allowTrailingClosure ~allowTypeAnnotation)
)
<!> postfixExpression ~allowTrailingClosure ~allowTypeAnnotation
<!> inOutExpression
(*| GRAMMAR OF A BINARY EXPRESSION |*)
(*| binary-expression -> binary-operator prefix-expression |*)
(*| binary-expression -> assignment-operator try-operator ??? prefix-expression |*)
(*| binary-expression -> conditional-operator try-operator ??? prefix-expression |*)
(*| binary-expression -> type-casting-operator |*)
and binaryExpression ~allowAssignment ~allowTrailingClosure ~allowTypeAnnotation exp =
let assignmentExpression () =
mkNode "AssignmentExpression"
<:> mkProp "Assignee" (return exp)
<* assignmentOperator ()
<:> mkOptPropE "Await" awaitOperator
<:> mkOptPropE "Try" tryOperator
<:> mkPropE "Value" (prefixExpression ~allowTrailingClosure ~allowTypeAnnotation)
and conditionalExpression () =
mkNode "ConditionalExpression"
<:> conditionalOperator ()
<:> mkOptPropE "Await" awaitOperator
<:> mkOptPropE "AlternateTry" tryOperator
<:> mkPropE "Alternate" (prefixExpression ~allowTrailingClosure ~allowTypeAnnotation)
and typeCastingExpression () =
mkNode "TypeCastingExpresion"
<:> typeCastingOperator ()
and binaryExpression () =
mkNode "BinaryExpression"
<:> mkProp "Lhs" (return exp)
<:> mkPropE "Operator" binaryOperator
<:> mkPropE "Rhs" (prefixExpression ~allowTrailingClosure ~allowTypeAnnotation)
in
(assignmentExpression () >>| fun assignment ->
if allowAssignment
then assignment
(* we have to return a placeholder here to break the recursion on
* `binary-expressions` since if we just `fail` if will fall through and
* match `binaryExpression`
*)
else invalidNode
)
<!> conditionalExpression
<!> typeCastingExpression
<!> binaryExpression
(*| binary-expressions -> binary-expression binary-expressions ??? |*)
and binaryExpressions ~allowAssignment ~allowTrailingClosure ~allowTypeAnnotation exp =
option exp (
binaryExpression ~allowAssignment ~allowTrailingClosure ~allowTypeAnnotation exp
>>= (function
(* Here we look for the placeholder emitted above and break the
* recursion if we hit an assignment in a context where it's not allowed
*)
| e when e = invalidNode -> fail "Terminate BinaryExpression"
| e -> return e
) >>= binaryExpressions ~allowAssignment ~allowTrailingClosure ~allowTypeAnnotation
)
(*| GRAMMAR OF AN EXPRESSION |*)
(*| expression -> await-operator ??? try-operator ??? prefix-expression binary-expressions ??? |*)
and expression
?allowAssignment:(allowAssignment:bool = true)
?allowTrailingClosure:(allowTrailingClosure:bool = true)
?(allowTypeAnnotation=true)
_
=
mkOptE tryOperator
>>=
fun tryop ->
mkOptE awaitOperator
>>=
fun awaitop ->
prefixExpression ~allowTrailingClosure ~allowTypeAnnotation ()
>>=
fun pre ->
option pre (binaryExpressions ~allowAssignment ~allowTrailingClosure ~allowTypeAnnotation pre)
<:> mkProp "Try" (return tryop)
<:> mkProp "Await" (return awaitop)
(*| expression-list -> expression | expression "," expression-list |*)
and expressionList () =
sepBy1 ',' (fun () ->
(
mkNode "LabeledExpression"
<:> mkPropE "Label" identifier
<* wchar ':'
<:> mkProp "Expression" (fix expression)
) <|> fix expression
) >>= function
| [e] -> return e
| l -> toList l
(*| GRAMMAR OF AN EXPLICIT MEMBER EXPRESSION |*)
(*| explicit-member-expression -> postfix-expression "." decimal-digits |*)
(*| explicit-member-expression -> postfix-expression "." identifier generic-argument-clause ??? |*)
(*| explicit-member-expression -> postfix-expression "." identifier "(" argument-names ")" |*)
and explicitMemberExpression exp =
wchar '.'
*> (
(
mkNode "TupleMemberExpression"
<:> mkProp "Expression" (return exp)
<:> mkPropE "Field" decimalDigits
) <|> (
mkNode "ExplicitMemberExpression"
<:> mkProp "Object" (return exp)
<:> mkPropE "Member" identifier
<* wchar '('
<:> mkPropE "Parameters" argumentNames
<* wchar ')'
) <|> (
mkNode "ExplicitMemberExpression"
<:> mkProp "Object" (return exp)
<:> mkPropE "Member" identifier
<:> mkOptPropE "GenericArgumentClause" genericArgumentClause
)
)
(*| argument-names -> argument-name argument-names ??? |*)
and argumentNames () =
mkList1 argumentName
(*| argument-name -> identifier ":" |*)
and argumentName () =
identifier ()
<* wchar ':'
(*| GRAMMAR OF A SELF EXPRESSION |*)
(*| postfix-self-expression -> postfix-expression "." "self" |*)
and postfixSelfExpression exp =
mkNode "SelfExpression"
<* wchar '.'
<* wstring "self"
<:> mkProp "Expression" (return exp)
(*| GRAMMAR OF A DYNAMIC TYPE EXPRESSION |*)
(*| dynamic-type-expression -> "type" "(" "of" ":" expression ")" |*)
and dynamicTypeExpression () =
mkNode "DynamicTypeExpression"
<* wstring "type"
<* wchar '('
<* wstring "of"
<* wchar ':'
<:> mkProp "Expression" (fix expression)
<* wchar ')'
(*| GRAMMAR OF A SUBSCRIPT EXPRESSION |*)
(*| subscript-expression -> postfix-expression "[" expression-list "]" |*)
and subscriptExpression exp =
mkNode "SubscriptExpression"
<* wchar '['
<:> mkProp "Expression" (return exp)
<:> mkPropE "SubscriptExpressionList" expressionList
<* wchar ']'
(*| GRAMMAR OF A FORCED-VALUE EXPRESSION |*)
(*| forced-value-expression -> postfix-expression "!" |*)
and forcedValueExpression exp =
mkNode "ForcedValueExpression"
<* char '!'
<:> mkProp "Expression" (return exp)
(*| GRAMMAR OF AN OPTIONAL-CHAINING EXPRESSION |*)
(*| optional-chaining-expression -> postfix-expression "?" |*)
and optionalChainingExpression exp =
mkNode "OptionalChainingExpression"
<* char '?'
<:> mkProp "Expression" (return exp)
(*| GRAMMAR OF A LOOP STATEMENT |*)
(*| loop-statement -> for-in-statement |*)
(*| loop-statement -> while-statement |*)
(*| loop-statement -> repeat-while-statement |*)
and loopStatement () =
forInStatement ()
<!> whileStatement
<!> repeatWhileStatement
(*| GRAMMAR OF A FOR-IN STATEMENT |*)
(*| async-sequence-operator -> "try ??? await" |*)
and asyncSequenceOperator () =
(wstring "await") <|> (wstring "try" *> anyspace *> wstring "await")
(*| for-in-statement -> "for" "case ???" pattern "in" expression where-clause ??? code-block |*)
(*| for-in-statement -> "for" async-sequence-operator ??? pattern "in" expression where-clause ??? code-block |*)
and forInStatement () =
mkNode "ForInStatement"
<* wstring "for"
<:> mkOptPropEmpty (mkBoolProp "Case" (wstring "case"))
<:> mkOptPropEmpty (mkBoolProp "AsyncSequence" (asyncSequenceOperator ()))
<:> mkProp "Pattern" (fix (pattern ~allowExpression:false))
<* wstring "in"
<:> mkProp "Condition" (fix (expression ~allowTrailingClosure:false))
<:> mkOptPropE "WhereClause" whereClause
<:> mkPropE "Body" codeBlock
(*| GRAMMAR OF A WHILE STATEMENT |*)
(*| while-statement -> "while" condition-list code-block |*)
and whileStatement () =
mkNode "WhileStatement"
<* wstring "while"
<:> mkPropE "Conditions" conditionList
<:> mkPropE "Body" codeBlock
(*| condition-list -> condition | condition "," condition-list |*)
and conditionList () =
commaSep condition
(*| condition -> expression | availability-condition | case-condition | optional-binding-condition |*)
and condition () =
let allowTrailingClosure = false in
availabilityCondition ()
<!> caseCondition ~allowTrailingClosure
<!> optionalBindingCondition ~allowTrailingClosure
<|> fix (expression ~allowTrailingClosure)
(*| case-condition -> "case" pattern initializer |*)
and caseCondition ~allowTrailingClosure () =
mkNode "CaseCondition"
<* wstring "case"
<:> mkProp "Pattern" (fix (pattern ~allowAssignment:false))
<:> mkProp "Initializer" (initializer' ~allowTrailingClosure ())
(*| optional-binding-condition -> "let" pattern initializer | "var" pattern initializer |*)
and optionalBindingCondition ~allowTrailingClosure () =
mkNode "OptionalBindingInitializer"
<:> (
mkBoolProp "Constant" (wstring "let")
<|> (wstring "var" *> mkPropHolder)
)
<:> mkProp "Pattern" (fix (pattern ~allowAssignment:false ~allowExpression:false))
<:> mkProp "Initializer" (initializer' ~allowTrailingClosure ())
(*| GRAMMAR OF A REPEAT-WHILE STATEMENT |*)
(*| repeat-while-statement -> "repeat" code-block "while" expression |*)
and repeatWhileStatement () =
mkNode "RepeatWhileStatement"
<* wstring "repeat"
<:> mkPropE "Body" codeBlock
<* wstring "while"
<:> mkProp "Condition" (fix expression)
(*| GRAMMAR OF A BRANCH STATEMENT |*)
(*| branch-statement -> if-statement |*)
(*| branch-statement -> guard-statement |*)
(*| branch-statement -> switch-statement |*)
and branchStatement () =
fix ifStatement
<!> guardStatement
<!> switchStatement
(*| GRAMMAR OF AN IF STATEMENT |*)
(*| if-statement -> "if" condition-list code-block else-clause ??? |*)
and ifStatement _ =
mkNode "IfStatement"
<* wstring "if"
<:> mkPropE "Conditions" conditionList
<:> mkPropE "Consequent" codeBlock
<:> mkOptPropE "Alternate" elseClause
(*| else-clause -> "else" code-block | "else" if-statement |*)
and elseClause () =
wstring "else"
*> (
codeBlock ()
<|> fix ifStatement
)
(*| GRAMMAR OF A GUARD STATEMENT |*)
(*| guard-statement -> "guard" condition-list "else" code-block |*)
and guardStatement () =
mkNode "GuardStatement"
<* wstring "guard"
<:> mkPropE "Conditions" conditionList
<* wstring "else"
<:> mkPropE "Alternate" codeBlock
(*| GRAMMAR OF A SWITCH STATEMENT |*)
(*| switch-statement -> "switch" expression "{" switch-cases ??? "}" |*)
and switchStatement () =
mkNode "SwitchStatement"
<* wstring "switch"
<:> mkProp "Value" (fix expression)
<* wchar '{'
<:> mkOptPropE "Cases" switchCases
<* wchar '}'
(*| switch-cases -> switch-case switch-cases ??? |*)
and switchCases () =
mkList1 switchCase
(*| switch-case -> case-label statements | default-label statements |*)
and switchCase () =
mkNode "SwitchCase"
<:> (
mkPropE "CaseLabel" caseLabel
<|> mkPropE "DefaultLabel" defaultLabel
)
<:> mkProp "Body" (fix statements)
(*| case-label -> "case" case-item-list ":" |*)
and caseLabel () =
mkNode "CaseLabel"
<* wstring "case"
<:> mkPropE "Items" caseItemList
<* wchar ':'
(*| case-item-list -> pattern where-clause ??? | pattern where-clause ??? "," case-item-list |*)
and caseItemList () =
commaSep (fun () ->
mkNode "CaseItem"
<:> mkProp "Pattern" (fix (pattern ~allowTypeAnnotation:false))
<:> mkOptPropE "WhereClause" whereClause
)
(*| default-label -> "default" ":" |*)
and defaultLabel () =
mkNode "DefaultLabel"
<* wstring "default"
<* wchar ':'
(*| where-clause -> "where" where-expression |*)
and whereClause () =
wstring "where" *> whereExpression ()
(*| where-expression -> expression |*)
and whereExpression () =
fix (expression ~allowTrailingClosure:false)
(*| GRAMMAR OF A LABELED STATEMENT |*)
(*| labeled-statement -> statement-label loop-statement |*)
(*| labeled-statement -> statement-label if-statement |*)
(*| labeled-statement -> statement-label switch-statement |*)
(*| labeled-statement -> statement-label do-statement |*)
and labeledStatement () =
mkNode "LabeledStatement"
<:> mkPropE "Label" statementLabel
<:> mkProp "Statement" (
loopStatement ()
<|> fix ifStatement
<!> switchStatement
<!> doStatement
)
(*| statement-label -> label-name ":" |*)
and statementLabel () =
labelName ()
<* wchar ':'
(*| label-name -> identifier |*)
and labelName () =
identifier ()
(*This is not part of the grammar, but `default` is not a valid label*)
(*for `break` or `continue` statements.*)
and nonReservedLabelName () =
((wstring "default" <|> wstring "case") *> return invalidNode)
<|> labelName ()
>>= function
| l when l = invalidNode ->
fail "Default is a reserved label name"
| l -> return l
(*| GRAMMAR OF A CONTROL TRANSFER STATEMENT |*)
(*| control-transfer-statement -> break-statement |*)
(*| control-transfer-statement -> continue-statement |*)
(*| control-transfer-statement -> fallthrough-statement |*)
(*| control-transfer-statement -> return-statement |*)
(*| control-transfer-statement -> throw-statement |*)
and controlTransferStatement () =
breakStatement ()
<!> continueStatement
<!> fallthroughStatement
<!> returnStatement
<!> throwStatement
(*| GRAMMAR OF A BREAK STATEMENT |*)
(*| break-statement -> "break" label-name ??? |*)
and breakStatement () =
mkNode "BreakStatement"
<* wstring "break"
<:> mkOptPropE "Label" nonReservedLabelName
(*| GRAMMAR OF A CONTINUE STATEMENT |*)
(*| continue-statement -> "continue" label-name ??? |*)
and continueStatement () =
mkNode "ContinueStatement"
<* wstring "continue"
<:> mkOptPropE "Label" nonReservedLabelName
(*| GRAMMAR OF A FALLTHROUGH STATEMENT |*)
(*| fallthrough-statement -> "fallthrough" |*)
and fallthroughStatement () =
mkNode "FallthroughStatement"
<* wstring "fallthrough"
(*| GRAMMAR OF A RETURN STATEMENT |*)
(*| return-statement -> "return" expression ??? |*)
and returnStatement () =
mkNode "ReturnStatement"
<* wstring "return"
<:> mkOptProp "Expression" (fix expression)
(*| GRAMMAR OF A THROW STATEMENT |*)
(*| throw-statement -> "throw" expression |*)
and throwStatement () =
mkNode "ThrowStatement"
<* wstring "throw"
<:> mkProp "Expression" (fix expression)
(*| GRAMMAR OF A DEFER STATEMENT |*)
(*| defer-statement -> "defer" code-block |*)
and deferStatement () =
mkNode "DeferStatement"
<* wstring "defer"
<:> mkPropE "Body" codeBlock
(*| GRAMMAR OF A DO STATEMENT |*)
(*| do-statement -> "do" code-block catch-clauses ??? |*)
and doStatement () =
mkNode "DoStatement"
<* wstring "do"
<:> mkPropE "Body" codeBlock
<:> mkOptPropE "CatchClauses" catchClauses
(*| catch-clauses -> catch-clause catch-clauses ??? |*)
and catchClauses () =
mkList1 catchClause
(*| catch-clause -> "catch" pattern ??? where-clause ??? code-block |*)
and catchClause () =
mkNode "Catch"
<* wstring "catch"
<:> (
(* We need to try to match the body first, as it has higher precedence *)
(* than a closure expression (arising from pattern) *)
mkPropE "Body" codeBlock
<|> (
mkOptProp "Pattern" (fix (pattern ~allowTrailingClosure:false))
<:> mkOptPropE "Where" whereClause
<:> mkPropE "Body" codeBlock
)
)
(*| GRAMMAR OF A COMPILER CONTROL STATEMENT |*)
(*| compiler-control-statement -> conditional-compilation-block |*)
(*| compiler-control-statement -> line-control-statement |*)
and compilerControlStatement () =
conditionalCompilationBlock ()
<|>
lineControlStatement ()
(*| GRAMMAR OF A CONDITIONAL COMPILATION BLOCK |*)
(*| conditional-compilation-block -> if-directive-clause elseif-directive-clauses ??? else-directive-clause ??? endif-directive |*)
and conditionalCompilationBlock () =
mkNode "ConditionalCompilationBlock"
<:> mkPropE "IfDirectiveClause" ifDirectiveClause
<:> mkOptPropE "ElseifDirectiveClauses" elseifDirectiveClauses
<:> mkOptPropE "ElseDirectiveClause" elseDirectiveClause
<* endifDirective ()
(*| if-directive-clause -> if-directive compilation-condition statements ??? |*)
and ifDirectiveClause () =
ifDirective ()
*> mkNode "IfDirective"
<:> mkProp "CompilationCondition" (fix compilationCondition)
<* anyspace
<:> mkOptProp "Statements" (fix statements)
(*| elseif-directive-clauses -> elseif-directive-clause elseif-directive-clauses ??? |*)
and elseifDirectiveClauses () =
mkList1 elseifDirectiveClause
(*| elseif-directive-clause -> elseif-directive compilation-condition statements ??? |*)
and elseifDirectiveClause () =
elseifDirective ()
*> mkNode "ElseifDirective"
<:> mkProp "CompilationCondition" (fix compilationCondition)
<* anyspace
<:> mkOptProp "Statements" (fix statements)
(*| else-directive-clause -> else-directive statements ??? |*)
and elseDirectiveClause () =
elseDirective ()
*> mkNode "ElseDirectiveClause"
<:> mkOptProp "Statements" (fix statements)
(*| if-directive -> "#if" |*)
and ifDirective () =
wstring "#if"
(*| elseif-directive -> "#elseif" |*)
and elseifDirective () =
wstring "#elseif"
(*| else-directive -> "#else" |*)
and elseDirective () =
wstring "#else"
(*| endif-directive -> "#endif" |*)
and endifDirective () =
wstring "#endif"
(*| compilation-condition -> platform-condition |*)
(*| compilation-condition -> identifier |*)
(*| compilation-condition -> boolean-literal |*)
(*| compilation-condition -> "(" compilation-condition ")" |*)
(*| compilation-condition -> "!" compilation-condition |*)
(*| compilation-condition -> compilation-condition "&&" compilation-condition |*)
(*| compilation-condition -> compilation-condition "||" compilation-condition |*)
and compilationCondition _ =
let aux () =
platformCondition ()
<!> identifier
<!> booleanLiteral
<|> (wchar '(' *> fix compilationCondition <* wchar ')')
<|> (
mkNode "CompilationConditionExpression"
<:> mkProp "Operator" (wchar '!' *> mkString "!")
<* commit
<:> mkProp "Operand" (fix compilationCondition)
)
in
let rec aux' t =
option t (
(
mkNode "CompilationConditionExpression"
<:> mkProp "Lhs" (return t)
<:> mkProp "Operator" ((wfstring "&&" <|> wfstring "||") >>= mkString)
<:> mkProp "Rhs" (fix compilationCondition)
) >>= aux'
)
in
aux () >>= aux'
(*| platform-condition -> "os" "(" operating-system ")" |*)
(*| platform-condition -> "arch" "(" architecture ")" |*)
(*| platform-condition -> "swift" "(" ">=" swift-version ")" |*)
and platformCondition () =
(wstring "os" *> wchar '(' *> operatingSystem () <* wchar ')')
<|>
(wstring "arch" *> wchar '(' *> architecture () <* wchar ')')
<|>
(wstring "swift" *> wchar '(' *> wstring ">=" *> swiftVersion () <* wchar ')')
(*| operating-system -> "macOS" | "iOS" | "watchOS" | "tvOS" |*)
and operatingSystem () =
mkNode "OperatingSystem"
<:> mkProp "Value" (
(wstring "macOS" >>= mkString)
<|>
(wstring "iOS" >>= mkString)
<|>
(wstring "watchOS" >>= mkString)
<|>
(wstring "tvOS" >>= mkString)
)
(*| architecture -> "i386" | "x86_64" | "arm" | "arm64" |*)
and architecture () =
mkNode "Architecture"
<:> mkProp "Value" (
(wstring "i386" >>= mkString)
<|>
(wstring "x86_64" >>= mkString)
<|>
(wstring "arm" >>= mkString)
<|>
(wstring "arm64" >>= mkString)
)
(*| swift-version -> decimal-digits "." decimal-digits |*)
and swiftVersion () =
mkNode "SwiftVersion"
<:> mkPropE "Major" decimalDigits
<* wchar '.'
<:> mkPropE "Minor" decimalDigits
(*| GRAMMAR OF A LINE CONTROL STATEMENT |*)
(*| line-control-statement -> "#sourceLocation" "(" "file:" file-name "," "line:" line-number ")" |*)
(*| line-control-statement -> "#sourceLocation" "(" ")" |*)
and lineControlStatement () =
wstring "#sourceLocation"
*> wchar '('
*> mkNode "LineControlStatement"
<:> (
mkOptPropEmpty (
mkPropHolder
<:> mkProp "FileName" (wstring "file:" *> fileName ())
<:> mkProp "LineNumber" (wstring "file:" *> lineNumber ())
)
) <* wchar ')'
(*| line-number -> A decimal integer greater than zero |*)
and lineNumber () = decimalDigits ()
(*| file-name -> static-string-literal |*)
and fileName () = staticStringLiteral ()
(*| GRAMMAR OF AN AVAILABILITY CONDITION |*)
(*| availability-condition -> "#available" "(" availability-arguments ")" |*)
and availabilityCondition () =
mkNode "AvailabilityCondition"
<* wstring "#available"
<* wchar '('
<:> mkPropE "Arguments" availabilityArguments
<* wchar ')'
(*| availability-arguments -> availability-argument | availability-argument "," availability-arguments |*)
and availabilityArguments () =
commaSep availabilityArgument
(*| availability-argument -> platform-name platform-version |*)
(*| availability-argument -> "*" |*)
and availabilityArgument () =
mkNode "AvailabilityArgument"
<:> (
(
mkPropHolder
<:> platformName ()
<:> mkPropE "Version" platformVersion
) <|> (
mkBoolProp "Wildcard" (wchar '*')
)
)
(*| platform-name -> "iOS" | "iOSApplicationExtension" |*)
(*| platform-name -> "macOS" | "macOSApplicationExtension" |*)
(*| platform-name -> "watchOS" |*)
(*| platform-name -> "tvOS" |*)
and platformName () =
let plat str =
mkBoolProp str (wstring str)
in
plat "iOS"
<|> plat "iOSApplicationExtension"
<|> plat "macOS"
<|> plat "macOSApplicationExtension"
<|> plat "watchOS"
<|> plat "tvOS"
(*| platform-version -> decimal-digits |*)
(*| platform-version -> decimal-digits "." decimal-digits |*)
(*| platform-version -> decimal-digits "." decimal-digits "." decimal-digits |*)
and platformVersion () =
mkNode "PlatformVersion"
<* whitespace
<:> mkPropE "Major" decimalDigits
<:> mkOptProp "Minor" (wchar '.' *> decimalDigits ())
<:> mkOptProp "Patch" (wchar '.' *> decimalDigits ())
(*| GRAMMAR OF AN IMPORT DECLARATION |*)
(*| import-path-identifier -> identifier | operator |*)
and importPathIdentifier () =
identifier ()
<|> operator ()
(*| import-path -> import-path-identifier | import-path-identifier "." import-path |*)
and importPath () =
sepBy1 '.' importPathIdentifier >>= toList
(*| import-kind -> "typealias" | "struct" | "class" | "enum" | "protocol" | "var" | "func" |*)
and importKind () =
wstring "typealias"
<|> wstring "struct"
<|> wstring "class"
<|> wstring "enum"
<|> wstring "protocol"
<|> wstring "var"
<|> wstring "func"
(*| import-declaration -> attributes ??? "import" import-kind ??? import-path |*)
and importDeclaration () =
mkNode "ImportDeclaration"
<:> mkOptProp "Attributes" (attributes ())
<* wstring "import"
<:> mkOptProp "Kind" (importKind () >>= mkString)
<:> mkProp "ImportPath" (importPath ())
(*| GRAMMAR OF A CONSTANT DECLARATION |*)
(*| constant-declaration -> attributes ??? declaration-modifiers ??? "let" pattern-initializer-list |*)
and constantDeclaration () =
mkNode "ConstantDeclaration"
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE declarationModifiers
<* wstring "let"
<:> mkPropE "PatternInitializerList" patternInitializerList
(*| pattern-initializer-list -> pattern-initializer | pattern-initializer "," pattern-initializer-list |*)
and patternInitializerList () =
commaSep patternInitializer
(*| pattern-initializer -> pattern initializer ??? |*)
and patternInitializer () =
mkNode "PatternInitializer"
<:> mkProp "Pattern" (fix (pattern ~allowExpression:false ~allowAssignment:false))
<:> mkOptPropE "Initializer" initializer'
(*| initializer -> "=" expression |*)
and initializer' ?allowTrailingClosure:(allowTrailingClosure:bool = true) () =
wchar '=' *> fix (expression ~allowTrailingClosure)
(*| GRAMMAR OF A VARIABLE DECLARATION |*)
(*| variable-declaration -> variable-declaration-head pattern-initializer-list |*)
(*| variable-declaration -> variable-declaration-head variable-name type-annotation code-block |*)
(*| variable-declaration -> variable-declaration-head variable-name type-annotation getter-setter-block |*)
(*| variable-declaration -> variable-declaration-head variable-name type-annotation getter-setter-keyword-block |*)
(*| variable-declaration -> variable-declaration-head variable-name initializer willSet-didSet-block |*)
(*| variable-declaration -> variable-declaration-head variable-name type-annotation initializer ??? willSet-didSet-block |*)
and variableDeclaration () =
mkNode "VariableDeclaration"
<:> variableDeclarationHead ()
<:> (
(
mkPropHolder
<:> mkPropE "VariableName" variableName
<:> mkPropE "TypeAnnotation" typeAnnotation
<:> mkProp "Initializer" (
getterSetterBlock()
<|> getterSetterKeywordBlock()
<|> codeBlock ()
)
) <|> (
mkPropHolder
<:> mkPropE "VariableName" variableName
<:> mkPropE "Initializer" initializer'
<:> willSetDidSetBlock()
) <|> (
mkPropHolder
<:> mkPropE "VariableName" variableName
<:> mkPropE "TypeAnnotation" typeAnnotation
<:> mkOptPropE "Initializer" initializer'
<:> willSetDidSetBlock()
)
<|> mkPropE "PatternInitializerList" patternInitializerList
)
(*| variable-declaration-head -> attributes ??? declaration-modifiers ??? "var" |*)
and variableDeclarationHead () =
mkPropHolder
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE declarationModifiers
<* wstring "var"
(*| variable-name -> identifier |*)
and variableName () =
identifier ()
(*| getter-setter-block -> code-block |*)
(*| getter-setter-block -> "{" getter-clause setter-clause ??? "}" |*)
(*| getter-setter-block -> "{" setter-clause getter-clause "}" |*)
and getterSetterBlock () =
(
wchar '{'
*> mkNode "GetterSetterBlock"
<:> mkPropE "GetterClause" getterClause
<:> mkOptPropE "SetterClause" setterClause
<* wchar '}'
) <|> (
wchar '{'
*> mkNode "GetterSetterBlock"
<:> mkPropE "SetterClause" setterClause
<:> mkPropE "GetterClause" getterClause
<* wchar '}'
) <|> codeBlock ()
(*| getter-clause -> attributes ??? mutation-modifier ??? "get" code-block |*)
and getterClause () =
mkNode "GetterBlock"
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE mutationModifier
<* wstring "get"
<:> mkPropE "Body" codeBlock
(*| setter-clause -> attributes ??? mutation-modifier ??? "set" setter-name ??? code-block |*)
and setterClause () =
mkNode "SetterBlock"
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE mutationModifier
<* wstring "set"
<:> mkOptPropE "Name" setterName
<:> mkPropE "Body" codeBlock
(*| setter-name -> "(" identifier ")" |*)
and setterName () =
wchar '(' *> identifier () <* wchar ')'
(*| getter-setter-keyword-block -> "{" getter-keyword-clause setter-keyword-clause ??? "}" |*)
(*| getter-setter-keyword-block -> "{" setter-keyword-clause getter-keyword-clause "}" |*)
and getterSetterKeywordBlock () =
(
wchar '{'
*> mkNode "GetterSetterKeywordBlock"
<:> mkPropE "GetterKeywordClause" getterKeywordClause
<:> mkOptPropE "SetterKeywordClause" setterKeywordClause
<* wchar '}'
) <|> (
wchar '{'
*> mkNode "GetterSetterKeywordBlock"
<:> mkPropE "SetterKeywordClause" setterKeywordClause
<:> mkPropE "GetterKeywordClause" getterKeywordClause
<* wchar '}'
)
(*| getter-keyword-clause -> attributes ??? mutation-modifier ??? "get" |*)
and getterKeywordClause () =
mkNode "GetterKeywordBlock"
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE mutationModifier
<* wstring "get"
(*| setter-keyword-clause -> attributes ??? mutation-modifier ??? "set" |*)
and setterKeywordClause () =
mkNode "GetterKeywordBlock"
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE mutationModifier
<* wstring "set"
(*| willSet-didSet-block -> "{" willSet-clause didSet-clause ??? "}" |*)
(*| willSet-didSet-block -> "{" didSet-clause willSet-clause ??? "}" |*)
and willSetDidSetBlock () =
wchar '{' *>
(
(
mkPropHolder
<:> mkPropE "WillSetClause" willSetClause
<:> mkOptPropE "DidSetClause" didSetClause
) <|> (
mkPropHolder
<:> mkPropE "DidSetClause" didSetClause
<:> mkOptPropE "WillSetClause" willSetClause
)
)
<* wchar '}'
(*| willSet-clause -> attributes ??? "willSet" setter-name ??? code-block |*)
and willSetClause () =
mkNode "WillSetClause"
<:> mkOptPropE "Attributes" attributes
<* wstring "willSet"
<:> mkOptPropE "SetterName" setterName
<:> mkPropE "CodeBlock" codeBlock
(*| didSet-clause -> attributes ??? "didSet" setter-name ??? code-block |*)
and didSetClause () =
mkNode "DidSetClause"
<:> mkOptPropE "Attributes" attributes
<* wstring "didSet"
<:> mkOptPropE "SetterName" setterName
<:> mkPropE "CodeBlock" codeBlock
(*| GRAMMAR OF A TYPE ALIAS DECLARATION |*)
(*| typealias-declaration -> attributes ??? access-level-modifier ??? "typealias" typealias-name generic-parameter-clause ??? typealias-assignment |*)
and typealiasDeclaration () =
mkNode "TypealiasDeclaration"
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE accessLevelModifier
<* wstring "typealias"
<:> mkPropE "TypealiasName" typealiasName
<:> mkOptPropE "GenericParameterClause" genericParameterClause
<:> mkPropE "TypealiasAssignment" typealiasAssignment
(*| typealias-name -> identifier |*)
and typealiasName () =
identifier ()
(*| typealias-assignment -> "=" type |*)
and typealiasAssignment () =
wchar '=' *> fix type'
(*| GRAMMAR OF A CODE BLOCK |*)
(*| code-block -> "{" statements ??? "}" |*)
and codeBlock () =
wchar '{' *> mkOpt (fix statements) <* wchar '}'
(*| GRAMMAR OF A FUNCTION DECLARATION |*)
(*| function-head -> attributes ??? declaration-modifiers ??? "func" |*)
and functionHead () =
mkPropHolder
<* anyspace
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE declarationModifiers
<* wstring "func"
(*| function-name -> identifier | operator |*)
and functionName () =
(
mkPropE "FunctionName" identifier
<* anyspace
<:> mkOptPropE "GenericParameterClause" genericParameterClause
) <|> operatorWithGenerics ()
(*| function-result -> "->" attributes ??? type |*)
and functionResult () =
wfstring "->"
*> mkNode "FunctionResult"
<:> mkOptPropE "Attributes" attributes
<:> mkProp "Type" (fix type')
(*| function-body -> code-block |*)
and functionBody () = codeBlock ()
(*| external-parameter-name -> identifier |*)
and externalParameterName () = paramName ()
(*| local-parameter-name -> identifier |*)
and localParameterName () = paramName ()
(*| default-argument-clause -> "=" expression |*)
and defaultArgumentClause () =
mkNode "DefaultArgumentClause"
<* wchar '='
<:> mkProp "Expression" (fix expression)
(*| parameter -> external-parameter-name ??? local-parameter-name type-annotation default-argument-clause ??? |*)
(*| parameter -> external-parameter-name ??? local-parameter-name type-annotation |*)
(*| parameter -> external-parameter-name ??? local-parameter-name type-annotation "..." |*)
and parameter () =
mkNode "Parameter"
<:> (
(
mkPropE "ExternalParameterName" externalParameterName
<:> mkPropE "LocalParameterName" localParameterName
)
<|> mkPropE "LocalParameterName" localParameterName
)
<:> mkPropE "TypeAnnotation" typeAnnotation
<:> mkOptPropEmpty (
mkPropE "DefaultArgumentClause" defaultArgumentClause
<|> mkBoolProp "Variadic" (wstring "...")
)
(*| parameter-list -> parameter | parameter "," parameter-list |*)
and parameterList () =
commaSep parameter
(*| parameter-clause -> "(" ")" | "(" parameter-list ")" |*)
and parameterClause () =
wchar '(' *> mkOptE parameterList <* wchar ')'
(*| function-signature -> parameter-clause function-properties function-result??? |*)
and functionSignature () =
mkPropHolder
<:> mkPropE "ParameterClause" parameterClause
<:> functionProperties ()
<:> mkOptPropE "FunctionResult" functionResult
(*| function-declaration -> function-head function-name generic-parameter-clause ??? function-signature generic-where-clause ??? function-body ??? |*)
and functionDeclaration () =
mkNode "FunctionDeclaration"
<:> functionHead ()
<:> functionName ()
<:> mkOptPropE "genericParameterClause" genericParameterClause
<:> functionSignature ()
<:> mkOptPropE "GenericWhereClause" genericWhereClause
<:> mkOptPropE "FunctionBody" functionBody
(*| GRAMMAR OF AN ENUMERATION DECLARATION |*)
(*| enum-declaration -> attributes ??? access-level-modifier ??? union-style-enum |*)
(*| enum-declaration -> attributes ??? access-level-modifier ??? raw-value-style-enum |*)
and enumDeclaration () =
mkNode "EnumDeclaration"
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE accessLevelModifier
<:> (
unionStyleEnum ()
<|> rawValueStyleEnum ()
)
(*| union-style-enum -> "indirect ???" "enum" enum-name generic-parameter-clause ??? type-inheritance-clause ??? generic-where-clause ??? "{" union-style-enum-members ??? "}" |*)
and unionStyleEnum () =
mkPropHolder
<:> mkOptPropEmpty (mkBoolProp "Indirect" (wstring "indirect"))
<* wstring "enum"
<:> mkPropE "Name" enumName
<:> mkOptPropE "genericParameterClause" genericParameterClause
<:> mkOptPropE "TypeInheritanceClause" typeInheritanceClause
<* wchar '{'
<:> mkOptPropE "Members" unionStyleEnumMembers
<* wchar '}'
(*| union-style-enum-members -> union-style-enum-member union-style-enum-members ??? |*)
and unionStyleEnumMembers () =
mkList1 unionStyleEnumMember
(*| union-style-enum-member -> declaration | union-style-enum-case-clause | compiler-control-statement |*)
and unionStyleEnumMember () =
fix declaration
<|> unionStyleEnumCaseClause ()
<|> compilerControlStatement ()
<* optSemi
(*| union-style-enum-case-clause -> attributes ??? "indirect ???" "case" union-style-enum-case-list |*)
and unionStyleEnumCaseClause () =
mkNode "EnumCaseClause"
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmpty (mkBoolProp "Indirect" (wstring "indirect"))
<* wstring "case"
<:> mkPropE "Cases" unionStyleEnumCaseList
(*| union-style-enum-case-list -> union-style-enum-case | union-style-enum-case "," union-style-enum-case-list |*)
and unionStyleEnumCaseList () =
commaSep unionStyleEnumCase
(*| union-style-enum-case -> enum-case-name tuple-type ??? |*)
and unionStyleEnumCase () =
mkNode "EnumCase"
<:> mkPropE "Name" enumCaseName
<:> mkOptPropE "Type" tupleType
(*| enum-name -> identifier |*)
and enumName () =
identifier ()
(*| enum-case-name -> identifier |*)
and enumCaseName () =
identifier ()
(*| raw-value-style-enum -> "enum" enum-name generic-parameter-clause ??? type-inheritance-clause generic-where-clause ??? "{" raw-value-style-enum-members "}" |*)
and rawValueStyleEnum () =
mkPropHolder
<* wstring "enum"
<:> mkPropE "Name" enumName
<:> mkOptPropE "GenericParameterClause" genericParameterClause
<:> mkPropE "TypeInheritanceClause" typeInheritanceClause
<:> mkOptPropE "GenericWhereClause" genericWhereClause
<* wchar '{'
<:> mkPropE "Members" rawValueStyleEnumMembers
<* wchar '}'
(*| raw-value-style-enum-members -> raw-value-style-enum-member raw-value-style-enum-members ??? |*)
and rawValueStyleEnumMembers () =
mkList1 rawValueStyleEnumMember
(*| raw-value-style-enum-member -> declaration | raw-value-style-enum-case-clause | compiler-control-statement |*)
and rawValueStyleEnumMember () =
fix declaration
<|> rawValueStyleEnumCaseClause ()
<|> compilerControlStatement ()
<* optSemi
(*| raw-value-style-enum-case-clause -> attributes ??? "case" raw-value-style-enum-case-list |*)
and rawValueStyleEnumCaseClause () =
mkNode "EnumCaseClause"
<:> mkOptPropE "Attributes" attributes
<* wstring "case"
<:> mkPropE "Cases" rawValueStyleEnumCaseList
(*| raw-value-style-enum-case-list -> raw-value-style-enum-case | raw-value-style-enum-case "," raw-value-style-enum-case-list |*)
and rawValueStyleEnumCaseList () =
commaSep rawValueStyleEnumCase
(*| raw-value-style-enum-case -> enum-case-name raw-value-assignment ??? |*)
and rawValueStyleEnumCase () =
mkNode "EnumCase"
<:> mkPropE "Name" enumCaseName
<:> mkOptPropE "Value" rawValueAssignment
(*| raw-value-assignment -> "=" raw-value-literal |*)
and rawValueAssignment () =
wchar '=' *> rawValueLiteral ()
(*| raw-value-literal -> numeric-literal | static-string-literal | boolean-literal |*)
and rawValueLiteral () =
numericLiteral ()
<!> staticStringLiteral
<!> booleanLiteral
(*| GRAMMAR OF A STRUCTURE DECLARATION |*)
(*| struct-declaration -> attributes ??? access-level-modifier ??? "struct" struct-name generic-parameter-clause ??? type-inheritance-clause ??? generic-where-clause ??? struct-body |*)
and structDeclaration () =
mkNode "StructDeclaration"
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE accessLevelModifier
<* wstring "struct"
<:> mkPropE "Name" structName
<:> mkOptPropE "GenericParameterClause" genericParameterClause
<:> mkOptPropE "TypeInheritanceClause" typeInheritanceClause
<:> mkOptPropE "GenericWhereClause" genericWhereClause
<:> mkPropE "Body" structBody
(*| struct-name -> identifier |*)
and structName () =
identifier ()
(*| struct-body -> "{" struct-members ??? "}" |*)
and structBody () =
wchar '{' *> mkOpt (commit *> structMembers ()) <* wchar '}'
(*| struct-members -> struct-member struct-members ??? |*)
and structMembers () =
mkList1 structMember
(*| struct-member -> declaration | compiler-control-statement |*)
and structMember () =
fix declaration
<!> compilerControlStatement
<* optSemi
(*| GRAMMAR OF A CLASS DECLARATION |*)
(*| class-name -> identifier |*)
and className () = identifier ()
(*| class-member -> declaration | compiler-control-statement |*)
and classMember () =
fix declaration
<!> compilerControlStatement
<* optSemi
(*| class-members -> class-member class-members ??? |*)
and classMembers () =
mkList1 (fun () -> commit *> classMember ())
(*| class-body -> "{" class-members ??? "}" |*)
and classBody () =
wchar '{' *> mkOptE classMembers <* wchar '}'
(*| reference-type -> class | actor |*)
and referenceType () =
(
mkBoolProp "Actor" (wstring "actor")
<|> (wstring "class" *> mkPropHolder)
)
(*| class-declaration -> attributes??? access-level-modifier??? "final"??? "class" class-name generic-parameter-clause??? type-inheritance-clause??? generic-where-clause??? class-body |*)
(*| class-declaration -> attributes??? "final" access-level-modifier??? "class" class-name generic-parameter-clause??? type-inheritance-clause??? generic-where-clause??? class-body |*)
and classDeclaration () =
mkNode "ClassDeclaration"
<:> mkOptPropE "Attributes" attributes
<:> (
(
mkBoolProp "Final" (wstring "final")
<:> mkOptPropEmptyE accessLevelModifier
) <|> (
mkOptPropEmptyE accessLevelModifier
<:> mkOptPropEmpty (mkBoolProp "Final" (wstring "final"))
)
)
<:> referenceType ()
<:> mkPropE "ClassName" className
<:> mkOptPropE "GenericParameterClause" genericParameterClause
<:> mkOptPropE "TypeInheritanceClause" typeInheritanceClause
<:> mkOptPropE "GenericWhereClause" genericWhereClause
<:> mkPropE "ClassBody" classBody
(*| GRAMMAR OF A PROTOCOL DECLARATION |*)
(*| protocol-declaration -> attributes ??? access-level-modifier ??? "protocol" protocol-name type-inheritance-clause ??? protocol-body |*)
and protocolDeclaration () =
mkNode "ProtocolDeclaration"
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE accessLevelModifier
<* wstring "protocol"
<:> mkPropE "Name" protocolName
<:> mkOptPropE "TypeInheritanceClause" typeInheritanceClause
<:> mkPropE "ProtocolBody" protocolBody
(*| protocol-name -> identifier |*)
and protocolName () = identifier ()
(*| protocol-body -> "{" protocol-members ??? "}" |*)
and protocolBody () =
wchar '{' *> mkOptE protocolMembers <* wchar '}'
(*| protocol-members -> protocol-member protocol-members ??? |*)
and protocolMembers () =
mkList1 protocolMember
(*| protocol-member -> protocol-member-declaration | compiler-control-statement |*)
and protocolMember () =
protocolMemberDeclaration ()
<|>
compilerControlStatement ()
(*| protocol-member-declaration -> protocol-property-declaration |*)
(*| protocol-member-declaration -> protocol-method-declaration |*)
(*| protocol-member-declaration -> protocol-initializer-declaration |*)
(*| protocol-member-declaration -> protocol-subscript-declaration |*)
(*| protocol-member-declaration -> protocol-associated-type-declaration |*)
(*| protocol-member-declaration -> typealias-declaration |*)
and protocolMemberDeclaration () =
protocolPropertyDeclaration ()
<!> protocolMethodDeclaration
<!> protocolInitializerDeclaration
<!> protocolSubscriptDeclaration
<!> protocolAssociatedTypeDeclaration
<!> typealiasDeclaration
(*| GRAMMAR OF A PROTOCOL PROPERTY DECLARATION |*)
(*| protocol-property-declaration -> variable-declaration-head variable-name type-annotation getter-setter-keyword-block |*)
and protocolPropertyDeclaration () =
mkNode "ProtocolPropertyDeclaration"
<:> variableDeclarationHead ()
<:> mkPropE "VariableName" variableName
<:> mkPropE "TypeAnnotation" typeAnnotation
<:> mkPropE "GetterSetterKeywordBlock" getterSetterKeywordBlock
(*| GRAMMAR OF A PROTOCOL METHOD DECLARATION |*)
(*| protocol-method-declaration -> function-head function-name generic-parameter-clause ??? function-signature generic-where-clause ??? |*)
and protocolMethodDeclaration () =
mkNode "ProtocolMethodDeclaration"
<:> functionHead ()
<:> functionName ()
<:> mkOptPropE "GenericParameterClause" genericParameterClause
<:> functionSignature ()
<:> mkOptPropE "GenericWhereClause" genericWhereClause
(*| GRAMMAR OF A PROTOCOL INITIALIZER DECLARATION |*)
(*| protocol-initializer-declaration -> initializer-head generic-parameter-clause ??? parameter-clause function-properties generic-where-clause ??? |*)
and protocolInitializerDeclaration () =
mkNode "ProtocolInitializerDeclaration"
<:> initializerHead ()
<:> mkOptPropE "GenericParameterClause" genericParameterClause
<:> mkPropE "ParameterClause" parameterClause
<:> functionProperties ()
<:> mkOptPropE "GenericWhereClause" genericWhereClause
(*| GRAMMAR OF A PROTOCOL SUBSCRIPT DECLARATION |*)
(*| protocol-subscript-declaration -> subscript-head subscript-result getter-setter-keyword-block |*)
and protocolSubscriptDeclaration () =
mkNode "ProtocolSubscriptDeclaration"
<:> subscriptHead ()
<:> mkPropE "SubscriptResult" subscriptResult
<:> mkPropE "GetterSetterKeywordBlock" getterSetterKeywordBlock
(*| GRAMMAR OF A PROTOCOL ASSOCIATED TYPE DECLARATION |*)
(*| protocol-associated-type-declaration -> attributes ??? access-level-modifier ??? "associatedtype" typealias-name type-inheritance-clause ??? typealias-assignment ??? |*)
and protocolAssociatedTypeDeclaration () =
mkNode "ProtocolAssociatedTypeDeclaration"
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE accessLevelModifier
<* wstring "associatedtype"
<:> mkPropE "TypealiasName" typealiasName
<:> mkOptPropE "TypeInheritanceClause" typeInheritanceClause
<:> mkOptPropE "TypealiasAssignment" typealiasAssignment
(*| GRAMMAR OF AN INITIALIZER DECLARATION |*)
(*| initializer-declaration -> initializer-head generic-parameter-clause ??? parameter-clause function-properties generic-where-clause ??? initializer-body |*)
and initializerDeclaration () =
mkNode "InitializerDeclaration"
<:> initializerHead ()
<:> mkOptPropE "GenericParameterClause" genericParameterClause
<:> mkPropE "ParameterClause" parameterClause
<:> mkOptPropEmpty (
mkBoolProp "Throws" (wstring "throws")
<|>
mkBoolProp "Rethrows" (wstring "rethrows")
)
<:> functionProperties ()
<:> mkOptPropE "GenericWhereClause" genericWhereClause
<:> mkPropE "InitializerBody" initializerBody
(*| initializer-head -> attributes ??? declaration-modifiers ??? "init" |*)
(*| initializer-head -> attributes ??? declaration-modifiers ??? "init" "?" |*)
(*| initializer-head -> attributes ??? declaration-modifiers ??? "init" "!" |*)
and initializerHead () =
(
mkPropHolder
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE declarationModifiers
)
<* wstring "init"
<:> mkOptPropEmpty (
mkBoolProp "Optional" (char '?')
<|>
mkBoolProp "Force" (char '!')
)
(*| initializer-body -> code-block |*)
and initializerBody () = codeBlock ()
(*| GRAMMAR OF A DEINITIALIZER DECLARATION |*)
(*| deinitializer-declaration -> attributes ??? "deinit" code-block |*)
and deinitializerDeclaration () =
mkNode "DeinitializerDeclaration"
<:> mkOptPropE "Attributes" attributes
<* wstring "deinit"
<:> mkPropE "Body" codeBlock
(*| GRAMMAR OF AN EXTENSION DECLARATION |*)
(*| extension-declaration -> attributes ??? access-level-modifier ??? "extension" type-identifier type-inheritance-clause ??? extension-body |*)
(*| extension-declaration -> attributes ??? access-level-modifier ??? "extension" type-identifier generic-where-clause extension-body |*)
and extensionDeclaration () =
mkNode "ExtensionDeclaration"
<:> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE accessLevelModifier
<* wstring "extension"
<:> mkPropE "Name" typeIdentifier
<:> mkOptPropEmpty (
mkPropE "TypeInheritanceClause" typeInheritanceClause
<|>
mkPropE "GenericWhereClause" genericWhereClause
)
<:> mkPropE "Body" extensionBody
(*| extension-body -> "{" extension-members ??? "}" |*)
and extensionBody () =
wchar '{' *> mkOptE extensionMembers <* wchar '}'
(*| extension-members -> extension-member extension-members ??? |*)
and extensionMembers () =
mkList1 (fun () -> commit *> extensionMember ())
(*| extension-member -> declaration | compiler-control-statement |*)
and extensionMember () =
fix declaration
<!> compilerControlStatement
<* optSemi
(*| GRAMMAR OF A SUBSCRIPT DECLARATION |*)
(*| subscript-declaration -> subscript-head subscript-result code-block |*)
(*| subscript-declaration -> subscript-head subscript-result getter-setter-block |*)
(*| subscript-declaration -> subscript-head subscript-result getter-setter-keyword-block |*)
and subscriptDeclaration () =
mkNode "SubscriptDeclaration"
<:> subscriptHead ()
<:> mkPropE "ResultType" subscriptResult
<:> mkProp "Body" (
codeBlock ()
<!> getterSetterBlock
<!> getterSetterKeywordBlock
)
(*| subscript-head -> attributes ??? declaration-modifiers ??? "subscript" parameter-clause |*)
and subscriptHead () =
mkPropHolder
<|> mkOptPropE "Attributes" attributes
<:> mkOptPropEmptyE declarationModifiers
<* wstring "subscript"
<:> mkPropE "ParameterClause" parameterClause
(*| subscript-result -> "->" attributes ??? type |*)
and subscriptResult () =
wfstring "->"
*> mkNode "SubscriptResult"
<:> mkOptPropE "Attributes" attributes
<:> mkProp "Type" (fix type')
(*| GRAMMAR OF AN OPERATOR DECLARATION |*)
(*| operator-declaration -> prefix-operator-declaration | postfix-operator-declaration | infix-operator-declaration |*)
and operatorDeclaration () =
prefixOperatorDeclaration ()
<!> postfixOperatorDeclaration
<!> infixOperatorDeclaration
(*| prefix-operator-declaration -> "prefix" "operator" operator |*)
and prefixOperatorDeclaration () =
mkNode "PrefixOperatorDeclaration"
<* wstring "prefix"
<* wstring "operator"
<:> mkPropE "Operator" operator
(*| postfix-operator-declaration -> "postfix" "operator" operator |*)
and postfixOperatorDeclaration () =
mkNode "PostfixOperatorDeclaration"
<* wstring "postfix"
<* wstring "operator"
<:> mkPropE "Operator" operator
(*| infix-operator-declaration -> "infix" "operator" operator infix-operator-group ??? |*)
and infixOperatorDeclaration () =
mkNode "InfixOperatorDeclaration"
<* wstring "infix"
<* wstring "operator"
<:> mkPropE "Operator" operator
<:> mkOptPropE "Group" infixOperatorGroup
(*| infix-operator-group -> ":" precedence-group-name |*)
and infixOperatorGroup () =
wchar ':' *> precedenceGroupName ()
(*| GRAMMAR OF A PRECEDENCE GROUP DECLARATION |*)
(*| precedence-group-declaration -> "precedencegroup" precedence-group-name "{" precedence-group-attributes ??? "}" |*)
and precedenceGroupDeclaration () =
mkNode "PrecedenceGroupDeclaration"
<* wstring "precedencegroup"
<:> mkPropE "Name" precedenceGroupName
<* wchar '{'
<:> mkOptPropE "Attributes" precedenceGroupAttributes
<* wchar '}'
(*| precedence-group-attributes -> precedence-group-attribute precedence-group-attributes ??? |*)
and precedenceGroupAttributes () =
mkList1 precedenceGroupAttribute
(*| precedence-group-attribute -> precedence-group-relation |*)
(*| precedence-group-attribute -> precedence-group-assignment |*)
(*| precedence-group-attribute -> precedence-group-associativity |*)
and precedenceGroupAttribute () =
precedenceGroupRelation ()
<!> precedenceGroupAssignment
<!> precedenceGroupAssociativity
(*| precedence-group-relation -> "higherThan" ":" precedence-group-names |*)
(*| precedence-group-relation -> "lowerThan" ":" precedence-group-names |*)
and precedenceGroupRelation () =
(
mkNode "HigherThanPrecedenceRelation"
<* wstring "higherThan"
<* wchar ':'
<:> mkPropE "Relatives" precedenceGroupNames
) <|> (
mkNode "LowerThanPrecedenceRelation"
<* wstring "lowerThan"
<* wchar ':'
<:> mkPropE "Relatives" precedenceGroupNames
)
(*| precedence-group-assignment -> "assignment" ":" boolean-literal |*)
and precedenceGroupAssignment () =
mkNode "PrecedenceGroupAssignment"
<* wstring "assignment"
<* wchar ':'
<:> mkPropE "Value" booleanLiteral
(*| precedence-group-associativity -> "associativity" ":" "left" |*)
(*| precedence-group-associativity -> "associativity" ":" "right" |*)
(*| precedence-group-associativity -> "associativity" ":" "none" |*)
and precedenceGroupAssociativity () =
wstring "associativity" *>
wchar ':' *> (
(wstring "left" *> mkNode "LeftAssociative")
<|>
(wstring "right" *> mkNode "RightAssociative")
<|>
(wstring "none" *> mkNode "NonAssociative")
)
(*| precedence-group-names -> precedence-group-name | precedence-group-name "," precedence-group-names |*)
and precedenceGroupNames () =
commaSep precedenceGroupName
(*| precedence-group-name -> identifier |*)
and precedenceGroupName () =
identifier ()
(*| GRAMMAR OF A DECLARATION MODIFIER |*)
(*| declaration-modifier -> "class" | "convenience" | "dynamic" | "final" | "infix" | "lazy" | "optional" | "override" | "postfix" | "prefix" | "required" | "static" | "unowned" | "unowned" "(" "safe" ")" | "unowned" "(" "unsafe" ")" | "weak" |*)
(*| declaration-modifier -> access-level-modifier |*)
(*| declaration-modifier -> mutation-modifier |*)
and declarationModifier () =
mkBoolProp "Class" (wstring "class")
<|>
mkBoolProp "Convenience" (wstring "convenience")
<|>
mkBoolProp "Dynamic" (wstring "dynamic")
<|>
mkBoolProp "Final" (wstring "final")
<|>
mkBoolProp "Infix" (wstring "infix")
<|>
mkBoolProp "Lazy" (wstring "lazy")
<|>
mkBoolProp "Optional" (wstring "optional")
<|>
mkBoolProp "Override" (wstring "override")
<|>
mkBoolProp "Postfix" (wstring "postfix")
<|>
mkBoolProp "Prefix" (wstring "prefix")
<|>
mkBoolProp "Required" (wstring "required")
<|>
mkBoolProp "Static" (wstring "static")
<|>
mkBoolProp "Unowned" (wstring "unowned")
<|>
mkBoolProp "UnownedSafe" (wstring "unowned" *> wchar '(' *> wstring "safe" *> wchar ')')
<|>
mkBoolProp "UnownedUnsafe" (wstring "unowned" *> wchar '(' *> wstring "unsafe" *> wchar ')')
<|>
mkBoolProp "Weak" (wstring "weak")
<|>
mkBoolProp "ParallelAsync" (wstring "async")
<|>
accessLevelModifier ()
<|>
mutationModifier ()
(*| declaration-modifiers -> declaration-modifier declaration-modifiers ??? |*)
and declarationModifiers () =
many1 declarationModifier >>= fun mods ->
List.fold_left (fun p m -> p <:> (return m)) mkPropHolder mods
(*| access-level-modifier -> "private" | "private" "(" "set" ")" |*)
(*| access-level-modifier -> "fileprivate" | "fileprivate" "(" "set" ")" |*)
(*| access-level-modifier -> "internal" | "internal" "(" "set" ")" |*)
(*| access-level-modifier -> "public" | "public" "(" "set" ")" |*)
(*| access-level-modifier -> "open" | "open" "(" "set" ")" |*)
and accessLevelModifier () =
mkPropHolder
<:> (
mkBoolProp "PrivateSet" (wstring "private" *> wchar '(' *> wstring "set" *> wchar ')')
<|> mkBoolProp "Private" (wstring "private")
<|> mkBoolProp "FileprivateSet" (wstring "fileprivate" *> wchar '(' *> wstring "set" *> wchar ')')
<|> mkBoolProp "Fileprivate" (wstring "fileprivate")
<|> mkBoolProp "InternalSet" (wstring "internal" *> wchar '(' *> wstring "set" *> wchar ')')
<|> mkBoolProp "Internal" (wstring "internal")
<|> mkBoolProp "PublicSet" (wstring "public" *> wchar '(' *> wstring "set" *> wchar ')')
<|> mkBoolProp "Public" (wstring "public")
<|> mkBoolProp "OpenSet" (wstring "open" *> wchar '(' *> wstring "set" *> wchar ')')
<|> mkBoolProp "Open" (wstring "open")
)
(*| mutation-modifier -> "mutating" | "nonmutating" |*)
and mutationModifier () =
mkBoolProp "Mutating" (wstring "mutating")
<|>
mkBoolProp "Nonmutating" (wstring "nonmutating")
(*| Declarations |*)
(*| GRAMMAR OF A DECLARATION |*)
(*| declaration -> import-declaration |*)
(*| declaration -> constant-declaration |*)
(*| declaration -> variable-declaration |*)
(*| declaration -> typealias-declaration |*)
(*| declaration -> function-declaration |*)
(*| declaration -> enum-declaration |*)
(*| declaration -> struct-declaration |*)
(*| declaration -> class-declaration |*)
(*| declaration -> protocol-declaration |*)
(*| declaration -> initializer-declaration |*)
(*| declaration -> deinitializer-declaration |*)
(*| declaration -> extension-declaration |*)
(*| declaration -> subscript-declaration |*)
(*| declaration -> operator-declaration |*)
(*| declaration -> precedence-group-declaration |*)
and declaration _ =
importDeclaration ()
<|> constantDeclaration ()
<|> variableDeclaration ()
<|> typealiasDeclaration ()
<|> functionDeclaration ()
<|> enumDeclaration ()
<|> structDeclaration ()
<|> classDeclaration ()
<|> protocolDeclaration ()
<|> initializerDeclaration ()
<|> deinitializerDeclaration ()
<|> extensionDeclaration ()
<|> subscriptDeclaration ()
<|> operatorDeclaration ()
<|> precedenceGroupDeclaration ()
(*| declarations -> declaration declarations ??? |*)
and declarations () = many1 (fun () -> fix declaration <* optSemi)
(*| Statements |*)
(*| GRAMMAR OF A STATEMENT |*)
(*| statement -> expression "; ???" |*)
(*| statement -> declaration "; ???" |*)
(*| statement -> loop-statement "; ???" |*)
(*| statement -> branch-statement "; ???" |*)
(*| statement -> labeled-statement "; ???" |*)
(*| statement -> control-transfer-statement "; ???" |*)
(*| statement -> defer-statement "; ???" |*)
(*| statement -> do-statement ": ???" |*)
(*| statement -> compiler-control-statement |*)
and statement () =
fix declaration
<|> loopStatement ()
<|> branchStatement ()
<|> labeledStatement ()
<|> controlTransferStatement ()
<|> deferStatement ()
<|> doStatement ()
<|> compilerControlStatement ()
(* leave expression last otherwise any keyword will be matched as an identifier *)
<|> fix expression
<* optSemi
(*| statements -> statement statements ??? |*)
and statements _ =
mkList1 statement
(*| Attributes |*)
(*| GRAMMAR OF AN ATTRIBUTE |*)
(*| attribute -> "@" attribute-name attribute-argument-clause ??? |*)
and attribute () =
anyspace
*> wchar '@'
*> mkNode "Attribute"
<:> mkPropE "AttributeName" attributeName
<:> mkOptPropE "AttributeArgumentClause" attributeArgumentClause
(*| attribute-name -> identifier |*)
and attributeName () =
identifier ()
(*| attribute-argument-clause -> "(" balanced-tokens ??? ")" |*)
and attributeArgumentClause () =
char '(' *> mkOpt (fix balancedTokens) <* wchar ')'
(*| attributes -> attribute attributes ??? |*)
and attributes () =
mkList1 attribute <* anyspace
(*| balanced-tokens -> balanced-token balanced-tokens ??? |*)
and balancedTokens _ =
mkList1 (fun () -> fix balancedToken)
(*| balanced-token -> "(" balanced-tokens ??? ")" |*)
(*| balanced-token -> "[" balanced-tokens ??? "]" |*)
(*| balanced-token -> "{" balanced-tokens ??? "}" |*)
(*| balanced-token -> Any identifier, keyword, literal, or operator |*)
(*| balanced-token -> Any punctuation except "(" , ")" , "[" , "]" , "{" , or "}" |*)
and balancedToken _ =
wchar '(' *> fix balancedTokens <* wchar '*'
<|>
wchar '[' *> fix balancedTokens <* wchar ']'
<|>
wchar '{' *> fix balancedTokens <* wchar '}'
<|> (
pos >>= fun pos ->
many1(fun () -> satisfy(function
| '(' | ')'
| '[' | ']'
| '{' | '}'
-> false
| _ -> true
)) >>| fun chars ->
NodeHolder(pos, string_of_chars chars)
)
(*| GRAMMAR OF A PATTERN |*)
(*| pattern -> wildcard-pattern type-annotation ??? |*)
(*| pattern -> identifier-pattern type-annotation ??? |*)
(*| pattern -> value-binding-pattern |*)
(*| pattern -> tuple-pattern type-annotation ??? |*)
(*| pattern -> enum-case-pattern |*)
(*| pattern -> optional-pattern |*)
(*| pattern -> type-casting-pattern |*)
(*| pattern -> expression-pattern |*)
and pattern
?allowExpression:(allowExpression=true)
?allowAssignment:(allowAssignment=true)
?allowTrailingClosure:(allowTrailingClosure=true)
?allowTypeAnnotation:(allowTypeAnnotation=true)
?(allowIdentiifer=true)
_
=
let typeAnnot =
if allowTypeAnnotation then
mkOptProp "TypeAnnotation" (typeAnnotation ())
else
mkPropHolder
in
let rec aux pattern =
option pattern (asPattern pattern >>= aux)
in
(startPattern *> (
(wildcardPattern () <:> typeAnnot)
<|> (tuplePattern () <:> typeAnnot)
<|> fix (valueBindingPattern ~allowTrailingClosure ~allowTypeAnnotation ~allowExpression)
<|> isPattern ()
<|> (
if allowExpression
then expressionPattern ~allowAssignment ~allowTrailingClosure ~allowTypeAnnotation ()
else fail "" (* skip to next case *)
)
<|> enumCasePattern ()
<|> (
if allowIdentiifer
then identifierPattern () <:> typeAnnot
else fail "" (* skip to next case *)
)
>>= aux
) <* stopPattern
(* TODO: This is a terrible hack to ensure we record when we exit a pattern *)
(* I should come up with a better fix at some point *)
) <|> stopPattern *> fail "Not a pattern"
(*| GRAMMAR OF A WILDCARD PATTERN |*)
(*| wildcard-pattern -> "_" |*)
and wildcardPattern () =
wstring "_" *> mkNode "WildcardPattern"
(*| GRAMMAR OF AN IDENTIFIER PATTERN |*)
(*| identifier-pattern -> identifier |*)
and identifierPattern () =
mkNode "IdentifierPattern"
<:> mkPropE "Identifier" identifier
(*| GRAMMAR OF A VALUE-BINDING PATTERN |*)
(*| value-binding-pattern -> "var" pattern | "let" pattern |*)
and valueBindingPattern ~allowTrailingClosure ~allowTypeAnnotation ~allowExpression _ =
(
(wstring "var" *> mkNode "VarBinding")
<|>
(wstring "let" *> mkNode "LetBinding")
)
<:> mkProp "Pattern" (fix (pattern ~allowTrailingClosure ~allowTypeAnnotation ~allowExpression ~allowAssignment:false))
(*| GRAMMAR OF A TUPLE PATTERN |*)
(*| tuple-pattern -> "(" tuple-pattern-element-list ??? ")" |*)
and tuplePattern () =
mkNode "TuplePattern"
<* wchar '('
<:> mkOptPropE "Elements" tuplePatternElementList
<* wchar ')'
(*| tuple-pattern-element-list -> tuple-pattern-element | tuple-pattern-element "," tuple-pattern-element-list |*)
and tuplePatternElementList () =
commaSep tuplePatternElement
(*| tuple-pattern-element -> pattern | identifier ":" pattern |*)
and tuplePatternElement () =
(
mkNode "TuplePatternElement"
<:> mkPropE "Identifier" identifier
<* wchar ':'
<:> mkProp "Pattern" (fix pattern)
) <|> fix pattern
(*| GRAMMAR OF AN ENUMERATION CASE PATTERN |*)
(*| enum-case-pattern -> type-identifier ??? "." enum-case-name tuple-pattern ??? |*)
and enumCasePattern () =
mkNode "EnumCasePattern"
<:> mkProp "EnumCaseName" (
wchar '.' *> enumCaseName ()
<|> typeIdentifier ~forceMultiple:true ()
)
<:> mkOptPropE "TuplePattern" tuplePattern
(*| GRAMMAR OF AN OPTIONAL PATTERN |*)
(*| optional-pattern -> identifier-pattern "?" |*)
(* actually parsed by the Swift compiler as an expression-pattern with
* optional-chaining-expression inside *)
(*| GRAMMAR OF A TYPE CASTING PATTERN |*)
(*| type-casting-pattern -> is-pattern | as-pattern |*)
(* Both cases can't be handled together due to incompatible prefixes. *)
(* `is-pattern` and `as-pattern` will be called directly from `pattern` *)
(*and typeCastingPattern () =*)
(*isPattern () <|> asPattern ()*)
(*| is-pattern -> "is" type |*)
and isPattern () =
mkNode "IsPattern"
<* wstring "is"
<:> mkProp "Type" (fix type')
(*| as-pattern -> pattern "as" type |*)
and asPattern pattern =
mkNode "AsPattern"
<:> mkProp "Pattern" (return pattern)
<* wstring "as"
<:> mkProp "Type" (fix type')
(*| GRAMMAR OF AN EXPRESSION PATTERN |*)
(*| expression-pattern -> expression |*)
and expressionPattern ~allowAssignment ~allowTrailingClosure ~allowTypeAnnotation () =
mkNode "ExpressionPattern"
<:> mkProp "Expression" (fix (expression ~allowAssignment ~allowTrailingClosure ~allowTypeAnnotation))
(*| Generic Parameters and Arguments |*)
(*| GRAMMAR OF A GENERIC PARAMETER CLAUSE |*)
(*| generic-parameter-clause -> "<" generic-parameter-list ">" |*)
and genericParameterClause () =
wchar '<'
*> mkNode "GenericParameterClause"
<:> mkPropE "GenericParameterList" genericParameterList
<* anyspace
<* wchar '>'
<* anyspace
(*| generic-parameter-list -> generic-parameter | generic-parameter "," generic-parameter-list |*)
and genericParameterList () =
commaSep genericParameter
(*| generic-parameter -> type-name |*)
(*| generic-parameter -> type-name ":" type-identifier |*)
(*| generic-parameter -> type-name ":" protocol-composition-type |*)
and genericParameter () =
mkNode "GenericParameter"
<:> mkPropE "TypeName" typeName
<:> mkOptPropEmpty (
wchar ':' *> (
mkProp "TypeIdentifier" (typeIdentifier () >>= fun t -> option t (protocolCompositionType t))
)
)
(*| generic-where-clause -> "where" requirement-list |*)
and genericWhereClause () =
wstring "where"
*> requirementList ()
(*| requirement-list -> requirement | requirement "," requirement-list |*)
and requirementList () =
commaSep requirement
(*| requirement -> conformance-requirement | same-type-requirement |*)
and requirement () =
conformanceRequirement ()
<|>
sameTypeRequirement ()
(*| conformance-requirement -> type-identifier ":" type-identifier |*)
(*| conformance-requirement -> type-identifier ":" protocol-composition-type |*)
and conformanceRequirement () =
mkNode "ConformanceRequirement"
<:> mkPropE "Lhs" typeIdentifier
<* wchar ':'
<:> mkProp "Rhs" (
typeIdentifier () >>= fun t -> option t (protocolCompositionType t)
)
(*| same-type-requirement -> type-identifier "==" type |*)
and sameTypeRequirement () =
mkNode "SameTypeRequirement"
<:> mkPropE "Lhs" typeIdentifier
<* wfstring "=="
<:> mkProp "Rhs" (fix type')
(*| GRAMMAR OF A TOP-LEVEL DECLARATION |*)
(*| top-level-declaration -> statements ??? |*)
let topLevelDeclaration () =
anyspace *> mkOpt (fix statements) >>= fun stm ->
pos >>= fun pos ->
(
anyspace *> end_of_input <?> (" at offset " ^ string_of_int pos ^ ", expected")
) *> return stm
let parse file input =
isParsingPattern := false;
patternDepth := 0;
match parse_only (topLevelDeclaration ()) (`String input) with
| Ok ast ->
let program = extractNode ast in
let comments' = get_comments () in
List (comments' @ [program])
| Error e ->
failwith (Printf.sprintf "%s: SyntaxError%s" file e)