# Copyright 2005-2007 Kevin Reid, under the terms of the MIT X license # found at http://www.opensource.org/licenses/mit-license.html ................ XXX todo: move everything else that should be here here This file contains tests for the E parser's grammar; specifically excluding expansion, parser protocol, etc. ' ? def pp := ; null ? def dumpENodes := ; null ? def t(s) :any { return dumpENodes(pp.run(s), stdout) }; null ? def tp(s) :any { return dumpENodes(pp.pattern(s, null, null), stdout) }; null --- Basic source positions --- ? pp.run("ab".asFrom("file:///foo")).getOptSpan() # value: should be 1:0::1:1 but we don't have span information yet --- String syntax --- ? t("'\\u0021'") # stdout: LiteralE. ! ? t("\"\\u0021\"") # stdout: LiteralE. ! ? t("\"\\u00210000\"") # stdout: LiteralE. !0000 ? t("\"\\U00000021\"") # stdout: LiteralE. ! ? t("`$\\u0021`") # stdout: QuasiE. # null # [] QuasiText ! ? t("`$\\u00210000`") # stdout: QuasiE. # null # [] QuasiText !0000 ? t("`$\\U00000021`") # stdout: QuasiE. # null # [] QuasiText ! --- Number commas --- This behavior copied from E-on-Java. ? t("1_234") # stdout: LiteralE. 1234 ? t("12_34") # stdout: LiteralE. 1234 ? t("1_2_3_4") # stdout: LiteralE. 1234 ? t("1234_") # problem: XXX improve this error message ? t("12__34") # problem: ? t("_1234") # stdout: NounE. _1234 --- Float syntax --- A float may be marked by decimal places, ? t("3.2") # stdout: LiteralE. 3.2 an exponent with optional sign, ? t("3e2") # stdout: LiteralE. 300.0 ? t("3E2") # stdout: LiteralE. 300.0 ? t("3e+2") # stdout: LiteralE. 300.0 ? t("3e-2") # stdout: LiteralE. 0.03 or both. ? t("3.2e+2") # stdout: LiteralE. 320.0 ? t("3.2e-2") # stdout: LiteralE. 0.032 A decimal point must have at least one following digit, because otherwise it is ambiguous with call syntax. ? t("3.") # problem: (line 1)@3: unexpected token: <"" @ 1:3> ? t("3.e2") # stdout: CurryE. CallE. # LiteralE. 3 # e2 # [] An additional dot always indicates call syntax. ? t("3.2.a") # stdout: CurryE. CallE. # LiteralE. 3.2 # a # [] ? t("3e2.a") # stdout: CurryE. CallE. # LiteralE. 300.0 # a # [] There must also be at least one preceding digit. ? t(".2") # problem: (line 1)@1: unexpected token: <"." @ 1:1> --- Nouns --- ? t("a") # stdout: NounE. a ? t("pragma.enable(\"noun-string\"); a") # stdout: SeqE. [] NounE. a ? t("pragma.enable(\"noun-string\"); ::\"a\"") # stdout: SeqE. [] NounE. a --- SlotExpr, BindingExpr --- ? t("&a") # stdout: SlotE. NounE. a ? t("&a :b") # stdout: CoerceE. # SlotE. NounE. a # NounE. b ? t("&&a") # stdout: BindingE. NounE. a ? t("&(&a)") # stdout: SlotE. SlotE. NounE. a -- currently meaningless, but it parses. ? t("&&a :b") # stdout: CoerceE. # BindingE. NounE. a # NounE. b -- this does not parse as a guarded BindingExpr. --- Function syntax --- ? t("pragma.enable(\"anon-lambda\"); fn { a }") # stdout: SeqE. [] FunctionE. # [] # NounE. a ? t("pragma.enable(\"anon-lambda\"); fn a { b }") # stdout: SeqE. [] FunctionE. # [] FinalP. # NounE. a # null # NounE. b ? t("pragma.enable(\"anon-lambda\"); fn a, b { c }") # stdout: SeqE. [] FunctionE. # [] # FinalP. # NounE. a # null # FinalP. # NounE. b # null # NounE. c ? t("pragma.enable(\"anon-lambda\"); fn a, b, { c }") # stdout: SeqE. [] FunctionE. # [] # FinalP. # NounE. a # null # FinalP. # NounE. b # null # NounE. c --- Sequence separators --- No SeqExprs around single terminated exprs ? t("a;") # stdout: NounE. a ? t("{a;}") # stdout: HideE. NounE. a Multiple separators of all types are allowed. ? t("a;;") # stdout: NounE. a ? t("a\n;") # stdout: NounE. a ? t("a;\n") # stdout: NounE. a ? t("a\n\n") # stdout: NounE. a ? t("{a;;}") # stdout: HideE. NounE. a ? t("{a\n;}") # stdout: HideE. NounE. a ? t("{a;\n}") # stdout: HideE. NounE. a ? t("{a\n\n}") # stdout: HideE. NounE. a ? t("{a\n\nb;;c;\n}") # stdout: HideE. SeqE. [] # NounE. a # NounE. b # NounE. c ? t("a\n\nb;;c;\n") # stdout: SeqE. [] # NounE. a # NounE. b # NounE. c --- Acceptance of sequences everywhere they should be --- NOTE: these tests were produced by inspection of antlr/e.g. They are not complete. ? t("__makeList(1;2)") # stdout: FunCallE. # NounE. __makeList # [] SeqE. [] # LiteralE. 1 # LiteralE. 2 ? t("[1;2 => 3]") # stdout: MapE. [] MapE.Assoc # SeqE. [] # LiteralE. 1 # LiteralE. 2 # LiteralE. 3 ? t("`${1;2}`") # stdout: QuasiE. # null # [] QuasiE.Hole SeqE. [] # LiteralE. 1 # LiteralE. 2 --- Object expressions in high-precedence positions --- Fails for the sake of sane precedence rules, even though it would be unambiguous, sort of. ? t("1 + def a := 2") # problem: (line 1)@11: unexpected token: <":=" @ 1:11> XXX produce a nice error for this? ? t("a & def _ {}") # stdout: BinaryE. # NounE. a # & # [] ObjectHeadE. # null # IgnoreP. # MethodObject # null # Auditors # null # [] # [] # [] ? t("a & /**b*/def _ {}") # stdout: BinaryE. # NounE. a # & # [] ObjectHeadE. # b # IgnoreP. # MethodObject # null # Auditors # null # [] # [] # [] ? t("a & fn {}") # stdout: BinaryE. # NounE. a # & # [] FunctionE. # [] # NullE. --- Result guards / easy-return --- ? t("pragma.disable(\"easy-return\") > pragma.enable(\"explicit-result-guard\") > def a() {}") # problem: (line 3)@10: You must specify a result guard or disable "explicit-result-guard". XXX source position ? t("pragma.disable(\"easy-return\") > pragma.enable(\"explicit-result-guard\") > def a{ to b() {} }") # problem: (line 3)@16: You must specify a result guard or disable "explicit-result-guard". XXX source position ? t("pragma.disable(\"easy-return\") > pragma.disable(\"explicit-result-guard\") > def a() {}") # stdout: SeqE. [] ObjectHeadE. # null # FinalP. # NounE. a # null # FunctionObject # [] # null # Auditors # null # [] # NullE. # false ? t("pragma.disable(\"easy-return\") > pragma.disable(\"explicit-result-guard\") > def a{ to b() {} }") # stdout: SeqE. [] ObjectHeadE. # null # FinalP. # NounE. a # null # MethodObject # null # Auditors # null # [] # [] ETo # null # b # [] # null # NullE. # false # [] ? t("pragma.enable(\"easy-return\") > pragma.disable(\"explicit-result-guard\") > def a() {}") # stdout: SeqE. [] ObjectHeadE. # null # FinalP. # NounE. a # null # FunctionObject # [] # null # Auditors # null # [] # NullE. # true ? t("pragma.enable(\"easy-return\") > pragma.disable(\"explicit-result-guard\") > def a{ to b() {} }") # stdout: SeqE. [] ObjectHeadE. # null # FinalP. # NounE. a # null # MethodObject # null # Auditors # null # [] # [] ETo # null # b # [] # null # NullE. # true # [] --- pragma.syntax --- ? t("pragma.aardvarks()") # problem: (line 1)@18: Unknown pragma "aardvarks". ? t("pragma.syntax(\"fnorg\")") # problem: (line 1)@22: Unknown syntax version "fnorg". 0.8 has explicit-result-guard on and easy-return off. ? t("pragma.syntax(\"0.8\") > def a() {}") # problem: (line 2)@10: You must specify a result guard or disable "explicit-result-guard". ? t("pragma.syntax(\"0.8\") > def a() :void {}") # stdout: SeqE. [] ObjectHeadE. # null # FinalP. # NounE. a # null # FunctionObject # [] # NounE. void # Auditors # null # [] # NullE. # false 0.9 has explicit-result-guard off and easy-return on. ? t("pragma.syntax(\"0.9\") > def a() {}") # stdout: SeqE. [] ObjectHeadE. # null # FinalP. # NounE. a # null # FunctionObject # [] # null # Auditors # null # [] # NullE. # true Bug test: parsing only a pragma would fail. ? t("pragma.enable(\"accumulator\")") # stdout: NullE. XXX test resulting pragma state directly? --- Function expressions --- ? t("def a() :b {}") # stdout: ObjectHeadE. # null # FinalP. # NounE. a # null # FunctionObject # [] # NounE. b # Auditors # null # [] # NullE. # true ? t("def a() :b implements c {}") # stdout: ObjectHeadE. # null # FinalP. # NounE. a # null # FunctionObject # [] # NounE. b # Auditors # null # [] NounE. c # NullE. # true Testing discrimination between functions and call patterns: ? t("pragma.disable(\"explicit-result-guard\"); def a() {}") # stdout: SeqE. [] ObjectHeadE. # null # FinalP. # NounE. a # null # FunctionObject # [] # null # Auditors # null # [] # NullE. # true ? t("pragma.disable(\"explicit-result-guard\"); def a() implements b {}") # stdout: SeqE. [] ObjectHeadE. # null # FinalP. # NounE. a # null # FunctionObject # [] # null # Auditors # null # [] NounE. b # NullE. # true ? t("def a() :b {}") # stdout: ObjectHeadE. # null # FinalP. # NounE. a # null # FunctionObject # [] # NounE. b # Auditors # null # [] # NullE. # true --- modPow --- ? t("a ** b %% c") # stdout: ModPowE. # NounE. a # NounE. b # NounE. c Parentheses disable modPow form ? t("(a ** b) %% c") # stdout: BinaryE. # BinaryE. # NounE. a # ** # [] NounE. b # %% # [] NounE. c ? t("a %% b ** c") # stdout: BinaryE. # NounE. a # %% # [] BinaryE. # NounE. b # ** # [] NounE. c ? t("a ** b % c") # stdout: BinaryE. # BinaryE. # NounE. a # ** # [] NounE. b # % # [] NounE. c ? t("(a %% b) ** c") # stdout: BinaryE. # BinaryE. # NounE. a # %% # [] NounE. b # ** # [] NounE. c ? t("a %% (b ** c)") # stdout: BinaryE. # NounE. a # %% # [] BinaryE. # NounE. b # ** # [] NounE. c --- CoerceExpr --- ? t("{a} :b") # stdout: CoerceE. # HideE. NounE. a # NounE. b ? t("def _ {} :a") # stdout: CoerceE. # ObjectHeadE. # null # IgnoreP. # MethodObject # null # Auditors # null # [] # [] # [] # NounE. a ? t("a :b :c") # problem: (line 1)@6: unexpected token: <":" @ 1:6> --- ForExpr --- ? t("for a => b in c { d }") # stdout: ForE. # FinalP. # NounE. a # null # FinalP. # NounE. b # null # NounE. c # NounE. d # null ? t("for b in c { d }") # stdout: ForE. # null # FinalP. # NounE. b # null # NounE. c # NounE. d # null ? t("for b in c { d } catch e { f }") # stdout: ForE. # null # FinalP. # NounE. b # null # NounE. c # NounE. d # EMatcher # FinalP. # NounE. e # null # NounE. f --- InterfaceExpr --- XXX more tests (this section was written to test guardless ParamDesc) ? t("interface a { to b(c, d :e, _ :f, _) }") # stdout: InterfaceE. # null # FinalP. # NounE. a # null # null # [] # [] # [] MessageDescE. # null # b # [] # ParamDescE. # c # null # ParamDescE. # d # NounE. e # ParamDescE. # null # NounE. f # ParamDescE. # null # null # null --- MapExpr --- XXX added to test the def case -- write others ? t("[=> def a]") # problem: (line 1)@9: Reserved syntax: forward export See also MapPattern below. --- ObjectExpr --- one-method-object ? t("def a.b() :c {}") # problem: (line 1)@6: The optional "one-method-object" syntax is currently off. ? t("pragma.enable(\"one-method-object\"); def a.b() :c {d}") # stdout: SeqE. [] ObjectHeadE. # null # FinalP. # NounE. a # null # OneMethodObject # b # [] # NounE. c # Auditors # null # [] # NounE. d # true --- Doc-comments --- ? t("def _ {}") # stdout: ObjectHeadE. # null # IgnoreP. # MethodObject # null # Auditors # null # [] # [] # [] ? t("/***/ def _ {}") # stdout: ObjectHeadE. # # IgnoreP. # MethodObject # null # Auditors # null # [] # [] # [] ? t("/**a*/ def _ {}") # stdout: ObjectHeadE. # a # IgnoreP. # MethodObject # null # Auditors # null # [] # [] # [] ? t("/** a */ def _ {}") # stdout: ObjectHeadE. # a # IgnoreP. # MethodObject # null # Auditors # null # [] # [] # [] ? t("def _ { method b() {} }") # stdout: ObjectHeadE. # null # IgnoreP. # MethodObject # null # Auditors # null # [] # [] EMethod # null # b # [] # null # NullE. # [] ? t("def _ { /***/ method b() {} }") # stdout: ObjectHeadE. # null # IgnoreP. # MethodObject # null # Auditors # null # [] # [] EMethod # # b # [] # null # NullE. # [] ? t("def _ { /** a */ method b() {} }") # stdout: ObjectHeadE. # null # IgnoreP. # MethodObject # null # Auditors # null # [] # [] EMethod # a # b # [] # null # NullE. # [] --- Quasis --- Handling of _ and unmeaningful keywords in non-brace quasi-holes. Ignore: ? tp("`@_`") # stdout: QuasiP. # null # [] QuasiP.Hole IgnoreP. ? tp("`$_`") # problem: (line 1)@2: Cannot have ignore as an expression hole. Identifier: ? tp("`@__`") # stdout: QuasiP. # null # [] QuasiP.Hole FinalP. # NounE. __ # null ? tp("`$__`") # stdout: QuasiP. # null # [] QuasiE.Hole NounE. __ Other keyword: ? tp("`@if`") # problem: (line 1)@2: unexpected keyword "if" in quasi hole ? tp("`$if`") # problem: (line 1)@2: unexpected keyword "if" in quasi hole XXX Despite the appearance of the above test, keyword testing is not properly implemented; it is special-cased for "if" in order to test the support code. The following test WILL FAIL once this is fixed, at which point this note should be deleted and the test revised to pass: ? tp("`$while`") # stdout: QuasiP. # null # [] QuasiE.Hole NounE. while --- URISchemeExpr --- ? t("<>") # problem: (line 1)@1: unexpected token: <"<" @ 1:1> ? t("") # stdout: URISchemeE. a case processing ? t("") # stdout: URISchemeE. A would-be-keywords ? t("") # stdout: URISchemeE. to erroneous ? t("") # problem: (line 1)@1: unexpected token: <"<" @ 1:1> ? t("<+a>") # problem: (line 1)@1: unexpected token: <"<" @ 1:1> ? t("") # problem: (line 1)@1: unexpected token: <"<" @ 1:1> --- WhenExpr --- ? t("pragma.syntax(\"0.9\"); when (a) -> { b }") # stdout: SeqE. [] WhenE. # [] NounE. a # WhenBlockE. # NounE. b # [] # null ? t("pragma.syntax(\"0.9\"); when (a) -> { b } catch c { d } finally { e }") # stdout: SeqE. [] WhenE. # [] NounE. a # WhenBlockE. # NounE. b # [] EMatcher # FinalP. # NounE. c # null # NounE. d # NounE. e XXX incomplete tests; borrow when-fn examples from syntax-sugar --- WhileExpr --- ? t("while (a) { b }") # stdout: WhileE. # NounE. a # NounE. b # null ? t("while (a) { b } catch c { d }") # stdout: WhileE. # NounE. a # NounE. b # EMatcher # FinalP. # NounE. c # null # NounE. d --- BindingPattern, SlotPattern --- ? tp("&a") # stdout: SlotP. # NounE. a # null ? tp("&a :b") # stdout: SlotP. # NounE. a # NounE. b ? tp("&&a") # stdout: BindingP. NounE. a ? tp("&(&a)") # problem: (line 1)@2: unexpected token: <"(" @ 1:2> ? tp("&&a :b") # problem: (line 1)@5: unexpected token: <":" @ 1:5> --- CallPattern, FunCallPattern, GetPattern --- ? tp("a.b(c)") # problem: (line 1)@6: The optional "call-pattern" syntax is currently off. ? tp("a(b)") # problem: (line 1)@4: The optional "call-pattern" syntax is currently off. ? t("pragma.enable(\"call-pattern\"); 0 =~ a.b(c)") # stdout: SeqE. [] MatchBindE. # LiteralE. 0 # CallP. # NounE. a # b # [] FinalP. # NounE. c # null ? t("pragma.enable(\"call-pattern\"); 0 =~ a(b)") # stdout: SeqE. [] MatchBindE. # LiteralE. 0 # FunCallP. # NounE. a # [] FinalP. # NounE. b # null ? t("pragma.enable(\"call-pattern\"); 0 =~ a[b]") # stdout: SeqE. [] MatchBindE. # LiteralE. 0 # GetP. # NounE. a # [] FinalP. # NounE. b # null --- IgnorePattern / GuardTestPattern --- ? tp("_") # stdout: IgnoreP. ? tp("_ :int") # stdout: GuardTestP. NounE. int --- MapPattern --- XXX added to test the def and _ cases -- write others ? tp("[=> def a]") # problem: (line 1)@5: Reserved syntax: forward export ? tp("[=> a]") # stdout: MapP. [] MapP.Required MapP.Import FinalP. # NounE. a # null ? tp("[=> _]") # problem: (line 1)@2: unexpected token: <"=>" @ 1:2> NOTE: kpreid doesn't understand why it unexpects the => rather than the _, but considers this good enough behavior See also MapExpr above. --- Via-pattern --- ? tp("via (a) b") # stdout: ViaP. # NounE. a # FinalP. # NounE. b # null --- Miscellaneous --- ? t("a :b[c]") # stdout: CoerceE. # NounE. a # GetE. # NounE. b # [] NounE. c --- Source holes --- ? def tqp(q, s) :any { return dumpENodes(pp.pattern(s, q, null), stdout) }; null ? tqp([[0], []], "$") # stdout: QuasiLiteralPatt 0 ? tqp([[1], []], "[$]") # stdout: ListP. [] QuasiLiteralPatt 0 x ? tqp([[0], []], "$ :any") x # stdout: FinalP. x # QuasiLiteralPatt x # 0 x # NounE. any XXX decide whether this is a good syntax idea: x ? tqp([[2], []], "::$") x # stdout: FinalP. x # QuasiLiteralPatt x # 0 x # null --- Parsing errors --- Printing of tokens in errors, for those tokens which have special treatment: ? t("[") # problem: (line 1)@2: unexpected token: <"" @ 1:2> XXX this is not the best; we shouldn't be quoting the meta NOTE: no handy way to test quasiliteral tokens (DOLLARESC, DOLLAR_IDENT, and AT_IDENT) because they can't occur in the wrong place ? t("0 'a'") # problem: (line 1)@3: unexpected token: <"'a'" @ 1:3> ? t("def a \"b\"") # problem: (line 1)@7: unexpected token: <""b"" @ 1:7> XXX should escape quotes ? t("0 0x10") # problem: (line 1)@3: unexpected token: <"0x10" @ 1:3> ? t("0 010") # problem: (line 1)@3: unexpected token: <"010" @ 1:3> ? t("0 ") # problem: (line 1)@3: unexpected token: <"" @ 1:3> ? t("0 ") # problem: (line 1)@3: unexpected token: <"" @ 1:3> XXX test acceptance of line breaks everywhere XXX general parser tests for everything