# Copyright 2006-2008 Kevin Reid, under the terms of the MIT X license # found at http://www.opensource.org/licenses/mit-license.html ................ These are tests specifically of the text->Kernel-E stages, skipping evaluation and the intermediate unexpanded form; however, the intent is primarily to test expansion, not the parser. ? def pp := > def t(s) :any { return pp.run(s).asKernelE() } > def tp(pat) :any { return pp.pattern(pat, null, null).asKernelE() } > def te(s) :any { return t(s).eval(safeScope.with("println", println)) } # XXX should be interp.getTopScope() > null Where headings are in quotes, it indicates that the names are those I invented for the nodes representing the unexpanded syntax, which are not reified in E-on-Java and have no names. 'AccumExpr' ? t("pragma.enable(\"accumulator\"); accum a if (b) { _.c(d) }") # value: e`def var accum__1 := a # if (b) { # accum__1 := accum__1.c(d) # } else { # null # } # accum__1` ? t("pragma.enable(\"accumulator\"); accum a if (b) { _ + c }") # value: e`def var accum__1 := a # if (b) { # accum__1 := accum__1.add(c) # } else { # null # } # accum__1` ? t("pragma.enable(\"accumulator\"); accum a while (b) { _.c(d) }") # value: e`def var accum__1 := a # escape __break { # __loop.run(def _ { # # method run() :boolean { # if (b) { # escape __continue { # accum__1 := accum__1.c(d) # } # true # } else { # false # } # } # }) # } # accum__1` ? t("pragma.enable(\"accumulator\"); accum a for b => c in d { _.e(f) }") # value: e`def var accum__1 := a # escape __break { # def var valid__2 := true # try { # d.iterate(def _ { # # method run(key__3, value__4) { # __validateFor.run(valid__2) # escape __continue { # escape skip__5 { # def b exit skip__5 := key__3 # def c exit skip__5 := value__4 # accum__1 := accum__1.e(f) # } # null # } # } # }) # } finally { # valid__2 := false # } # null # } # accum__1` 'AndExpr': see ConditionalExpr 'BinaryExpr' ? t("a + b") # value: e`a.add(b)` ? t("a - b") # value: e`a.subtract(b)` ? t("a * b") # value: e`a.multiply(b)` ? t("a / b") # value: e`a.approxDivide(b)` ? t("a // b") # value: e`a.floorDivide(b)` ? t("a % b") # value: e`a.remainder(b)` ? t("a %% b") # value: e`a.mod(b)` ? t("a ** b") # value: e`a.pow(b)` XXX test modPow behaviors ? t("a & b") # value: e`a.and(b)` ? t("a | b") # value: e`a.or(b)` ? t("a &! b") # value: e`a.butNot(b)` ? t("a ^ b") # value: e`a.xor(b)` ? t("a >> b") # value: e`a.shiftRight(b)` ? t("a << b") # value: e`a.shiftLeft(b)` Disabled for now till the final fate of +(,) is decided x ? t("a + (b, c)") x # value: e`a.add(b, c)` ? t("a..b") # value: e`__makeOrderedSpace.op__thru(a, b)` ? t("a..!b") # value: e`__makeOrderedSpace.op__till(a, b)` XXX check that we've tested and implemented all non-simple binary verbs ' 'CoerceExpr' ? t("a :b") # value: e`ValueGuard.coerce(b, throw).coerce(a, throw)` XXX order of evaluation reversal means we need usage rejection 'CompareExpr' ? t("a < b") # value: e`__comparer.lessThan(a, b)` 'ConditionalExpr' (aka 'AndExpr' and 'OrExpr') ? t("(def a := b) || (def c := d)") # value: e`def [ok__1, &&c, &&a] := if (def a := b) { # def &&c := __booleanFlow.broken() # __makeList.run(true, &&c, &&a) # } else { # if (def c := d) { # def &&a := __booleanFlow.broken() # __makeList.run(true, &&c, &&a) # } else { # __booleanFlow.failureList(2) # } # } # ok__1` ? t("(def a := b) && (def c := d)") # value: e`def [ok__1, &&c, &&a] := if (def a := b) { # if (def c := d) { # __makeList.run(true, &&c, &&a) # } else { # __booleanFlow.failureList(2) # } # } else { # __booleanFlow.failureList(2) # } # ok__1` Bug test: temporary names inside a ConditionalExpr would fail NOTE: the exporting of ares__2 here is useless; however, our current expansion system doesn't attempt to determine that. ' ? t("(a[] := true) && true") # value: e`def [ok__1, &&ares__2] := if (a.put(def ares__2 := true) # ares__2) { # if (true) { # __makeList.run(true, &&ares__2) # } else { # __booleanFlow.failureList(1) # } # } else { # __booleanFlow.failureList(1) # } # ok__1` Bug test: reusing names would cause them to be failure-bound on both sides ? t("(def x := 1; true) || (def x := 2; true)") # value: e`def [ok__1, &&x] := if (def x := 1 # true) { # __makeList.run(true, &&x) # } else { # if (def x := 2 # true) { # __makeList.run(true, &&x) # } else { # __booleanFlow.failureList(1) # } # } # ok__1` ? te("[false && false, true && false, false && true, true && true]") # value: [false, false, false, true] ? te("[false || false, true || false, false || true, true || true]") # value: [false, true, true, true] ? def testConditionalResult := te("def testConditionalResult(a, b) :any { > {println([(def r := def ra := a) && \ > (def rba := ra > def r := def rb := b), > &r, &ra, &rb, &rba])} > {println([(def r := def ra := a) || \ > (def r := def rb := b), > &r, &ra, &rb])} > }") # value: ? testConditionalResult(false, false) # stdout: [false, , , , ] # [false, , , ] # ? testConditionalResult(false, true) # stdout: [false, , , , ] # [true, <& true>, , <& true>] # ? testConditionalResult(true, false) # stdout: [false, , , , ] # [true, <& true>, <& true>, ] # ? testConditionalResult(true, true) # stdout: [true, <& true>, <& true>, <& true>, <& true>] # [true, <& true>, <& true>, ] # 'CurryExpr' ? t("pragma.enable(\"verb-curry\"); a.b") # value: e`__makeVerbFacet.curryCall(a, "b")` ? t("pragma.enable(\"verb-curry\"); a <- b") # value: e`__makeVerbFacet.currySend(a, "b")` 'DefrecExpr' ? t("def a := b") # value: e`def a := b` ? t("def [a, b] := [b, c]") # value: e`def [b__1, bR__2] := Ref.promise() # def value__3 := def [a, b] := __makeList.run(b__1, c) # bR__2.resolve(b) # value__3` 'ExitExpr' ? t("return") # value: e`__return.run()` ? t("return a") # value: e`__return.run(a)` ? t("break a") # value: e`__break.run(a)` ? t("continue a") # value: e`__continue.run(a)` 'ForExpr' ? t("for a => b in c { d }") # value: e`escape __break { # def var valid__1 := true # try { # c.iterate(def _ { # # method run(key__2, value__3) { # __validateFor.run(valid__1) # escape __continue { # escape skip__4 { # def a exit skip__4 := key__2 # def b exit skip__4 := value__3 # d # } # null # } # } # }) # } finally { # valid__1 := false # } # null # }` ? t("for a in b { c } catch d { e }") # value: e`escape __break { # def var valid__1 := true # try { # b.iterate(def _ { # # method run(key__2, value__3) { # __validateFor.run(valid__1) # escape __continue { # escape skip__4 { # def _ exit skip__4 := key__2 # def a exit skip__4 := value__3 # c # } # null # } # } # }) # } finally { # valid__1 := false # } # null # } catch d { # e # }` ? t("for a => b in a { c }") # problem: ? t("for a => b in b { c }") # problem: ? t("for via (c) a => b in (def c := d) { e }") # problem: ? t("for a => via (c) b in (def c := d) { e }") # problem: XXX prettier errors XXX look into extracting more of the for-loop expansion into a function 'ForwardExpr' ? t("def a") # value: e`def [a, a__Resolver] := Ref.promise() # a__Resolver` Anything that expands to a noun is allowed. ? t("def ") # value: e`def [a__uriGetter, a__uriGetter__Resolver] := Ref.promise() # a__uriGetter__Resolver` 'FunctionExpr' ? t("pragma.enable(\"anon-lambda\"); fn a { a }") # value: e`def _ { # # method run(a) { # a # } # }` 'InterfaceExpr' ? t("interface a {}") # value: e`def a := { # __makeProtocolDesc.run(null, meta.context().getFQNPrefix().add("a__T"), __makeList.run(), __makeList.run(), __makeList.run()) # }` ? t("interface \"a\" {}") # value: e`{ # __makeProtocolDesc.run(null, "a", __makeList.run(), __makeList.run(), __makeList.run()) # }` ? t("interface \"$a\" {}") # value: e`{ # __makeProtocolDesc.run(null, meta.context().getFQNPrefix().add("a"), __makeList.run(), __makeList.run(), __makeList.run()) # }` ? t("/**hi*/ interface \"a\" {}") # value: e`{ # __makeProtocolDesc.run("hi", "a", __makeList.run(), __makeList.run(), __makeList.run()) # }` ? t("/***/ interface \"a\" {}") # value: e`{ # __makeProtocolDesc.run("", "a", __makeList.run(), __makeList.run(), __makeList.run()) # }` ? t("interface a { to b(c :d) :e > to f() }") # value: e`def a := { # __makeProtocolDesc.run(null, meta.context().getFQNPrefix().add("a__T"), __makeList.run(), __makeList.run(), __makeList.run({ # __makeMessageDesc.run(null, "b", __makeList.run(__makeParamDesc.run("c", d)), e) # }, { # __makeMessageDesc.run(null, "f", __makeList.run(), null) # })) # }` ? t("interface a guards b { to c(d :e) :f > to g() }") # value: e`(def [a, b] := { # __makeProtocolDesc.makePair(null, meta.context().getFQNPrefix().add("a__T"), __makeList.run(), __makeList.run(), __makeList.run({ # __makeMessageDesc.run(null, "c", __makeList.run(__makeParamDesc.run("d", e)), f) # }, { # __makeMessageDesc.run(null, "g", __makeList.run(), null) # })) # }).get(0)` ? t("interface \"a\" guards b {}") # value: e`(def [_, b] := { # __makeProtocolDesc.makePair(null, "a", __makeList.run(), __makeList.run(), __makeList.run()) # }).get(0)` ? t("interface \"a\" { to b(c, d :e, _ :f, _) }") # value: e`{ # __makeProtocolDesc.run(null, "a", __makeList.run(), __makeList.run(), __makeList.run({ # __makeMessageDesc.run(null, "b", __makeList.run(__makeParamDesc.run("c", null), __makeParamDesc.run("d", e), __makeParamDesc.run(null, f), __makeParamDesc.run(null, null)), null) # })) # }` 'ListExpr' ? t("[]") # value: e`__makeList.run()` ? t("[a, b]") # value: e`__makeList.run(a, b)` 'MapExpr' ? t("[a => b]") # value: e`__makeMap.fromPairs(__makeList.run(__makeList.run(a, b)))` ? t("[=> a]") # value: e`__makeMap.fromPairs(__makeList.run(__makeList.run("a", a)))` ? t("[=> &a]") # value: e`__makeMap.fromPairs(__makeList.run(__makeList.run("&a", (&&a).get())))` ? t("[=> &&a]") # value: e`__makeMap.fromPairs(__makeList.run(__makeList.run("&&a", &&a)))` MatchBindExpr ? t("left =~ [rA, &&rB, [rC]]") # value: e`def sp__1 := left # def [ok__2, &&rB, &&rC, &&rA] := escape fail__3 { # def [rA, &&rB, [rC]] exit fail__3 := sp__1 # __makeList.run(true, &&rB, &&rC, &&rA) # } catch problem__4 { # def via (__slotToBinding) &&b__5 := Ref.broken(problem__4) # __makeList.run(false, &&b__5, &&b__5, &&b__5) # } # ok__2` XXX the failure case is similar to __booleanFlow.failureList XXX rewrite the following to use ; they were just copied in from vm.updoc from when MatchBindExpr was kernel ? def tfloat64 := ; null ? def tint := ; null ? {[92 =~ x, x]} # value: [true, 92] ? {[93 =~ x :tint, x]} # value: [true, 93] ? {[94 =~ x :tfloat64, x]} # value: [true, 94.0] ? {[95.0 =~ x :tint, &x]} # value: [false, ] Form of smashed remnants from binding patterns ? def q := def shortProblemGuard { to coerce(_, e) :void { throw.eject(e, "Q") } } # value: ? [1 =~ matchBindNoun :q, &matchBindNoun] # value: [false, ] Given a SlotPattern, we don't know what behavior might be expected of the slot, so the slot itself is broken. ' ? [&any =~ &matchBindNoun :q, &matchBindNoun] # value: [false, ] ? matchBindNoun := "hi" # problem: Q ? matchBindNoun # problem: Q VarPattern slots act like SlotPattern slots. XXX is this most correct? ? [1 =~ var matchBindNoun :q, &matchBindNoun] # value: [false, ] ? matchBindNoun := "hi" # problem: Q ? matchBindNoun # problem: Q MatchBindExpr containing guardless VarPattern (bug test: wouldn't compile because the nonexistent guard variable (nil) was being passed through the match-bind boundary ') ? {[null =~ var x, x, x := 1, x]} # value: [true, null, 1, 1] MatchBindExpr's expansion uses DefineExpr ? te("a =~ a") # problem: XXX error should explain this is due to the expansion 'MismatchExpr' ? t("a !~ b") # value: e`(def sp__1 := a # def [ok__2, &&b] := escape fail__3 { # def b exit fail__3 := sp__1 # __makeList.run(true, &&b) # } catch problem__4 { # def via (__slotToBinding) &&b__5 := Ref.broken(problem__4) # __makeList.run(false, &&b__5) # } # ok__2).not()` 'ModPowExpr' ? t("a ** b %% c") # value: e`a.modPow(b, c)` 'NKAssignExpr' ? t("a := b") # value: e`a := b` ? t("a(b, c) := d") # value: e`a.setRun(b, c, def ares__1 := d) # ares__1` ? t("a[b, c] := d") # value: e`a.put(b, c, def ares__1 := d) # ares__1` ? t("a.getFoo(b, c) := d") # value: e`a.setFoo(b, c, def ares__1 := d) # ares__1` ? t("a.e(b, c) := d") # problem: assignment can only be done to nouns and collection elements (not "e" call) ? t(" := c") # value: e`a__uriGetter.put("b", def ares__1 := c) # ares__1` XXX unary-star assignments? 'NKObjectExpr' base case ? t("def a {}") # value: e`def a { # }` named by bind-pattern ? t("bind a {}") # value: e`def via (__bind.run(a__Resolver)) a__1 := { # def a { # } # }` XXX named by var-pattern parent ? t("def a extends b {}") # value: e`def a := { # def &&super := &&b # def a { # match message__1 { # E.callWithPair(super, message__1) # } # } # }` parent with bind name ? t("def bind a extends b {}") # value: e`def via (__bind.run(a__Resolver)) a__1 := { # def a := { # def &&super := &&b # def a { # match message__2 { # E.callWithPair(super, message__2) # } # } # } # }` XXX The following expansion would be better. Right now, the code doesn't know that if we're inside a bind-expansion then reintroducing the name outside the super-expansion is unnecessary. value: e`def via (__bind.run(a__Resolver)) a__1 := { def &&super := &&b def a { match message__2 { E.callWithPair(super, message__2) } } }` non-NounExpr parent ? t("def a extends b() {}") # value: e`def a := { # def super := b.run() # def a { # match message__1 { # E.callWithPair(super, message__1) # } # } # }` parent with reference to name ? t("def a extends b(a) {}") # value: e`def [a__1, aR__2] := Ref.promise() # def value__3 := def a := { # def super := b.run(a__1) # def a__1 { # match message__4 { # E.callWithPair(super, message__4) # } # } # } # aR__2.resolve(a) # value__3` XXX the above expansion is flawed: the object's pattern should use the original name. Hypothesis: DefrecExpr is overeager. XXX parent with var name 'NullExpr' ? t("{}") # value: e`{ # null # }` 'OrExpr': see ConditionalExpr 'PrefixExpr' ? t("!a") # value: e`a.not()` 'PropertyExpr' ? t("pragma.enable(\"dot-props\"); a::b") # value: e`__getPropertySlot.run(a, "b").get()` ? t("pragma.enable(\"dot-props\"); a::&b") # value: e`__getPropertySlot.run(a, "b")` ? t("pragma.enable(\"dot-props\"); a::\"b\"") # value: e`__getPropertySlot.run(a, "b").get()` ? t("pragma.enable(\"dot-props\"); a::&\"b\"") # value: e`__getPropertySlot.run(a, "b")` 'QuasiExpr' ? t("` a $b ${\"c\"} $\\n $$ `` @@ `") # value: e`simple__quasiParser.valueMaker(" a ${0} ${1} # $$ ` @@ ").substitute(__makeList.run(b, "c"))` ? t("a`b`") # value: e`a__quasiParser.valueMaker("b").substitute(__makeList.run())` ? t("a`@b`") # problem: the (E.ELANG::MEMBER-OF :|parts|) of a E.NONKERNEL:|QuasiExpr| must be a (AND # E.NONKERNEL.IMPL::|QuasiPart| # (NOT # E.NONKERNEL:|QuasiPatternHole|)) (The value # # # NIL)>)> # is not of type # (AND # E.NONKERNEL.IMPL::|QuasiPart| # (NOT # E.NONKERNEL:|QuasiPatternHole|)).) XXX prettier error xxx preserve enough source location info to point to the origin of the problem 'RangeExpr': see 'BinaryExpr' for now 'SameExpr' ? t("a == b") # value: e`__equalizer.sameEver(a, b)` ? t("a != b") # value: e`__equalizer.sameEver(a, b).not()` 'SendExpr' ? t("a <- b(c)") # value: e`E.send(a, "b", __makeList.run(c))` ? t("a <- \"b\"(c)") # value: e`E.send(a, "b", __makeList.run(c))` ? t("a <- (b)") # value: e`E.send(a, "run", __makeList.run(b))` SlotExpr ? t("&a") # value: e`(&&a).get()` ? t("&(&a)") # problem: & of SlotExpr is currently undefined ? t("&(a.b())") # problem: & of CallExpr is currently undefined 'SwitchExpr' ? t("switch (x) { match [a] { b } match c { d } }") # value: e`{ # def specimen__1 := x # escape next__2 { # def [a] exit next__2 := specimen__1 # b # } catch failure__3 { # escape next__2 { # def c exit next__2 := specimen__1 # d # } catch failure__4 { # __switchFailed.run(specimen__1, failure__3, failure__4) # } # } # }` ? te("switch (1) {match ==2 {} match ==3 {}}") # problem: 1 did not match any option: # problem: 1 is not 2 # problem: 1 is not 3 'ThunkExpr' ? t("pragma.enable(\"thunk\"); thunk {}") # value: e`def _ { # # method run() { # null # } # }` ? t("pragma.enable(\"thunk\"); thunk { a }") # value: e`def _ { # # method run() { # a # } # }` x ? t("pragma.enable(\"thunk\"); thunk implements a { b }") x # syntax error: ? t("pragma.enable(\"thunk\"); /** a */ thunk { b }") # value: e`def _ { # # /** a */ # method run() { # b # } # }` 'UpdateExpr' ? t("a += b") # value: e`a := a.add(b)` See above about the related BinaryExpr x ? t("a += (b, c)") x # value: e`a := a.add(b, c)` ? t("a b= c") # value: e`a := a.b(c)` ? t("a b= (c)") # value: e`a := a.b(c)` ? t("a b= (c, d)") # value: e`a := a.b(c, d)` ? t("a b= a") # value: e`a := a.b(a)` ? t("a[b, c] += d") # value: e`def recip__1 := a # def arg__2 := b # def arg__3 := c # recip__1.put(arg__2, arg__3, def ares__4 := recip__1.get(arg__2, arg__3).add(d)) # ares__4` XXX these syntax-level tests don't test the result of arbitrary children to UpdateExpr ' 'URIExpr' ? t("") # value: e`a__uriGetter.get("b")` ? t("") # value: e`a__uriGetter.get("B")` ? t("") # value: e`ab__uriGetter.get("c")` ? t("") # value: e`ab__uriGetter.get("c:d")` 'URISchemeExpr' ? t("") # value: e`a__uriGetter` ? t("") # value: e`a__uriGetter` ? t("") # value: e`::"svn+ssh__uriGetter"` ? try { t("<0>") } catch _ {true} # value: true ? t("") # value: e`::"a+90-.__uriGetter"` ? pp.pattern("", null, null).getOptPrincipalNoun() # value: "a__uriGetter" 'WhenExpr' ? t("pragma.syntax(\"0.8\"); when (a) -> b(c) :d { e }") # problem: (line 1)@47: The optional "easy-when" syntax is currently off. ? t("pragma.syntax(\"0.9\"); pragma.enable(\"hard-when\"); when (a) -> b(c) :d { e } catch f { g }") # value: e`{ # Ref.whenResolved(a, def b { # # method run(resolution__1) :d { # escape __return { # try { # def c := Ref.fulfillment(resolution__1) # e # } catch f { # g # } # null # } # } # }) # }` ? t("pragma.syntax(\"0.9\"); pragma.enable(\"hard-when\"); when (a) -> b(c) :d { e } catch f { g } catch h { i } finally { j }") # value: e`{ # Ref.whenResolved(a, def b { # # method run(resolution__1) :d { # escape __return { # try { # try { # try { # def c := Ref.fulfillment(resolution__1) # e # } catch f { # g # } # } catch h { # i # } # } finally { # j # } # null # } # } # }) # }` ? t("pragma.syntax(\"0.9\"); pragma.enable(\"hard-when\"); when (a) -> b(c) :d { e }") # value: e`{ # Ref.whenResolved(a, def b { # # method run(resolution__1) :d { # escape __return { # def c := Ref.fulfillment(resolution__1) # e # null # } # } # }) # }` ? t("pragma.syntax(\"0.9\"); pragma.enable(\"hard-when\"); when (a, b) -> c(d) :e { f }") # problem: must have same number of expressions and patterns XXX should be syntax error ? t("pragma.syntax(\"0.9\"); pragma.enable(\"hard-when\"); when (a, b) -> c(d, e) :e { f }") # value: e`{ # Ref.whenResolved(promiseAllFulfilled.run(__makeList.run(a, b)), def c { # # method run(resolution__1) :e { # escape __return { # def [d, e] := Ref.fulfillment(resolution__1) # f # null # } # } # }) # }` Implementation test for N-ary when ? def p1; def p2 > def r := te("fn a, b { when (a, b) -> { a + b } }")(p1, p2) # value: ? bind p1 := 1; null ? r # value: ? bind p2 := 2; null ? ? r # value: 3 ? t("pragma.syntax(\"0.9\"); pragma.enable(\"hard-when\"); pragma.disable(\"easy-return\"); when (a) -> b(c) :d { e } catch f { g }") # value: e`{ # Ref.whenResolved(a, def b { # # method run(resolution__1) :d { # escape __return { # try { # def c := Ref.fulfillment(resolution__1) # e # } catch f { # g # } # } # } # }) # }` XXX is there a nicer way to write the below expansion? ? t("pragma.syntax(\"0.9\"); when (a) -> { b }") # value: e`{ # Ref.whenResolved(a, def _ { # # method run(ref__1) { # if (Ref.isBroken(ref__1)) { # Ref.broken(Ref.optProblem(ref__1)) # } else { # b # } # } # }) # }` 'WhileExpr' ? t("while (a) { b }") # value: e`escape __break { # __loop.run(def _ { # # method run() :boolean { # if (a) { # escape __continue { # b # } # true # } else { # false # } # } # }) # }` ? t("while (a) { b } catch c { d }") # value: e`escape __break { # __loop.run(def _ { # # method run() :boolean { # if (a) { # escape __continue { # b # } # true # } else { # false # } # } # }) # } catch c { # d # }` 'BindPattern' ? tp("bind a") # value: epatt`via (__bind.run(a__Resolver)) a__1` ? tp("bind a :b") # value: epatt`via (__bind.run(a__Resolver, b)) a__1` Anything that expands to a noun is allowed. ? tp("bind :b") # value: epatt`via (__bind.run(a__uriGetter__Resolver, b)) a__uriGetter__1` ? t("def bind {}") # value: e`def via (__bind.run(a__uriGetter__Resolver)) a__uriGetter__1 := { # def a__uriGetter { # } # }` ? te("def [a, a__Resolver] := Ref.promise(); def bind a := 1; a") # value: 1 ? te("pragma.enable(\"trinary-define\"); def [a, a__Resolver] := Ref.promise(); a__Resolver.resolve(0); [escape e { def bind a exit e := 1 }, a]") # problem: this resolver's ref has already been resolved, therefore cannot be resolved to 1 XXX should this eject instead? ? te("pragma.enable(\"trinary-define\"); def [a, a__Resolver] := Ref.promise(); [escape e { def bind a :char exit e := 1 }, a]") # value: [problem: the int 1 doesn't coerce to a char, ] 'CallPattern' and 'FunCallPattern' Call patterns are a form of extensible pattern which is more suitable than quasi-patterns for objects which do not naturally have a (semi-)textual syntax. ... ? t("pragma.enable(\"call-pattern\"); def a.b(c) := d") # value: e`def via (__makeVerbFacet.curryCall(a, "match__b/1")) [c] := d` ? t("pragma.enable(\"call-pattern\"); def a(b) := c") # value: e`def via (__makeVerbFacet.curryCall(a, "match__run/1")) [b] := c` XXX the use of expr rather than pattern parsing here is a workaround because pragmas can't be specified in patterns. ' The generated verb includes the arity since there are always exactly two arguments (the specimen and ejector), the arity being otherwise explicit only in the list pattern, which is too late for the matcher to see it. CdrPattern ? tp("[] + a") # value: epatt`via (__splitList.run(0)) [a]` ? tp("[a] + b") # value: epatt`via (__splitList.run(1)) [a, b]` ? tp("[a, b] + c") # value: epatt`via (__splitList.run(2)) [a, b, c]` ? te("[[1, 2, 3] =~ [cp_a] + cp_b, cp_a, cp_b]") # value: [true, 1, [2, 3]] ? te("def [_] + _ := []") # problem: a 0 size list doesn't match a >= 1 size list pattern ? te("[def listoid { > to __conformTo(_) :any { return [3,3,3,3] } > } =~ [cp_a, cp_b] + cp_c, cp_a, cp_b, cp_c]") # value: [true, 3, 3, [3, 3]] XXX now that CdrPattern is nonkernel, merge with TailPattern? 'GuardTestPattern' ? tp("_ :a") # value: epatt`__1 :a` ? te("pragma.enable(\"trinary-define\") > def _ :(println(\"eg\"); float64) exit fn x{println(\"ok\");throw(x)} := 'a'") # stdout: eg # ok # # problem: the char 'a' doesn't coerce to a float64 ? te("pragma.enable(\"trinary-define\") > def _ :(println(\"eg\"); float64) exit fn x{println(\"nok\");throw(x)} := 1") # stdout: eg # # value: 1 'MapPattern' ? tp("[\"a\" => b]") # value: epatt`via (__mapExtract.run("a")) [b, via (__mapEmpty) _]` ? tp("[(a) => b]") # value: epatt`via (__mapExtract.run(a)) [b, via (__mapEmpty) _]` ? tp("[=> a]") # value: epatt`via (__mapExtract.run("a")) [a, via (__mapEmpty) _]` ? tp("[\"a\" => b := c]") # value: epatt`via (__mapExtract."default"("a", c)) [b, via (__mapEmpty) _]` ? te("def [\"a\" => b] := [\"a\" => 1]; b") # value: 1 ? te("pragma.enable(\"trinary-define\"); escape e { def [\"a\" => b] exit e := [].asMap(); b}") # value: problem: "a" not in matched map: [].asMap() ? te("pragma.enable(\"trinary-define\"); escape e { def [\"a\" => b] exit e := [\"a\" => 1, \"b\" => 2]; b}") # value: problem: unused elements in matched map: ["b" => 2] 'QuasiPattern' ? tp("` a $b ${\"c\"} @d @{[e]} $\\n $$ `` @@ `") # value: epatt`via (__quasiMatcher.run(simple__quasiParser.matchMaker(" a ${0} ${1} @{0} @{1} # $$ ` @@ "), __makeList.run(b, "c"))) [d, [e]]` XXX test __quasiMatcher ? tp("`@a $a`") # problem: ? tp("`@{via (a) c} ${def a := b}`") # problem: XXX this print with e`[]` is a bit confusing, though explicable 'SamePattern' ? tp("==x") # value: epatt`via (__matchSame.run(x)) _` ? tp("!=x") # value: epatt`via (__matchSame.different(x)) _` ? te("pragma.enable(\"trinary-define\"); escape e { def ==1 exit e := 1 }") # value: 1 ? te("pragma.enable(\"trinary-define\"); escape e { def ==1 exit e := 2 }") # value: problem: 2 is not 1 ? te("pragma.enable(\"trinary-define\"); escape e { def ==1 exit e := Ref.promise()[0] }") # value: problem: is not yet 1 ? te("pragma.enable(\"trinary-define\"); escape e { def !=1 exit e := 2 }") # value: 2 ? te("pragma.enable(\"trinary-define\"); escape e { def !=1 exit e := 1 }") # value: problem: must not be 1 ? te("pragma.enable(\"trinary-define\"); escape e { def !=1 exit e := Ref.promise()[0] }") # value: problem: is not yet different from 1 SlotExpr ? tp("&a") # value: epatt`via (__slotToBinding) &&a` ? tp("&a :b") # value: epatt`via (__slotToBinding.run(b)) &&a` ? te("def &a := __makeFinalSlot(1); a") # value: 1 ? te("def &a :(__makeFinalSlot.asType()[float64]) := __makeFinalSlot(1); a") # value: 1.0 'SuchThatPattern' ? t("def x ? true := 1") # value: e`def via (__suchThat) [x, via (__suchThat.handle("true", true)) _] := 1` ? te("def x ? true := 1") # value: 1 ? te("def x ? false := 1") # problem: 'TailPattern' list-pattern variety XXX this testing doesn't distinguish between TailPattern and CdrPattern ' ? tp("[] + a") # value: epatt`via (__splitList.run(0)) [a]` ? tp("[a] + b") # value: epatt`via (__splitList.run(1)) [a, b]` map-pattern variety ? tp("[\"a\" => b] | c") # value: epatt`via (__mapExtract.run("a")) [b, c]` x ? tp("[] | a") x # syntax error: ? te("pragma.enable(\"trinary-define\"); escape e { def [\"a\" => b] | c exit e := [\"a\" => 1, \"b\" => 2]; [b, c]}") # value: [1, ["b" => 2]] 'FunctionObject' ? t("pragma.disable(\"easy-return\"); /** a */ def b() :c { d }") # value: e`def b { # # /** a */ # method run() :c { # escape __return { # d # } # } # }` ? t("pragma.enable(\"easy-return\"); /** a */ def b() :c { d }") # value: e`def b { # # /** a */ # method run() :c { # escape __return { # d # null # } # } # }` ? t("pragma.syntax(\"0.9\"); /** a */ def b() :c implements d { e }") # value: e`def b implements d { # # /** a */ # method run() :c { # escape __return { # e # null # } # } # }` ? t("/** a */ def b(c) :d implements c { d }") # problem: ? t("/** a */ def b(c) :(def d := e) implements d { e }") # problem: XXX prettier error 'OneMethodObject' This currently shares most of the implementation of FunctionExpr, so I'm not testing it much. ' ? t("pragma.syntax(\"0.9\"); pragma.enable(\"one-method-object\"); /** a */ def b.c() :d { e }") # value: e`def b { # # /** a */ # method c() :d { # escape __return { # e # null # } # } # }` ? t("pragma.syntax(\"0.9\"); pragma.enable(\"one-method-object\"); def b.c() :d { e }") # value: e`def b { # # method c() :d { # escape __return { # e # null # } # } # }` 'ETo' ? t("pragma.syntax(\"0.8\"); def a { to b() :c { d } }") # value: e`def a { # # method b() :c { # escape __return { # d # } # } # }` ? t("pragma.syntax(\"0.8\"); pragma.disable(\"explicit-result-guard\"); def a { to b() { d } }") # value: e`def a { # # method b() :void { # escape __return { # d # } # } # }` ? t("pragma.syntax(\"0.8\"); pragma.enable(\"easy-return\"); def a { to b() :c { d } }") # value: e`def a { # # method b() :c { # escape __return { # d # null # } # } # }` XXX add behavior tests for all expansions (right now they're only present for the new 'via' expansions) ' XXX test temporary name rules XXX do node-based tests for FunctionObject, TailPattern, UpdateExpr since those aren't quite fully tested just from syntax '