# Copyright 2005-2007 Kevin Reid, under the terms of the MIT X license # found at http://www.opensource.org/licenses/mit-license.html ................ ? pragma.enable("accumulator") ? def testGuardMany(things, Thing) :any { > return accum [] for thing :Thing in things { _.with(thing) } > } # value: ? /** Verify that a guard does not print its specimen. */ > def testSpecimenNotPrinted(guard) :void { > escape printed { > escape fail { > guard.coerce(def notPrintSpecimen { to __printOn(_) :void { printed() }}, fail) > throw(`testSpecimenNotPrinted: $guard accepted`) > } > } catch _ { > throw(`testSpecimenNotPrinted: $guard printed`) > } > } # value: any ? any # value: any ? any[int, float64] :DeepFrozen # value: any[int, float64] ? any.__respondsTo("get", 1) # value: true ? any.__respondsTo("get", 10) # value: true ? any.__respondsTo("of", 1) # value: true void ? void # value: void ? void :DeepFrozen # value: void XXX void-coerces-anything property near XXX test with far refs (eventual resolved) ? near # value: near ? {def t :near := 1; t} # value: 1 ? {def t :near := def x {}; t} # value: ? {def t :near := Ref.promise()[0]; t} # problem: must be near vow ? vow :DeepFrozen # value: vow XXX more tests (we're using existing vow.emaker, so we assume for now it's correct) nullOk base ? nullOk # value: nullOk ? {def t :nullOk := 1; t} # problem: must be null ? [{def t :nullOk := null; t}] # value: [null] nullOk will not transform ? {def t :nullOk := def _ { to __conformTo(_) :any {} }; t} # problem: must be null ? [nullOk.getTheTrivialValue()] # value: [null] ? nullOk :DeepFrozen # value: nullOk ? testSpecimenNotPrinted(nullOk) nullOk parameterized ? nullOk[float64] # value: nullOk[float64] ? {def t :nullOk[float64] := 3254.5; t} # value: 3254.5 ? [{def t :nullOk[float64] := null; t}] # value: [null] nullOk[...] will not transform null (is this correct behavior?)-- ? {def t :nullOk[float64] := def _ { to __conformTo(_) :any {} }; t} # problem: the "__main$_" <__main$_> doesn't coerce to a float64 --but its subguard may coerce ? {def t :nullOk[float64] := 144; t} # value: 144.0 ? nullOk[float64] :DeepFrozen # value: nullOk[float64] ? testSpecimenNotPrinted(nullOk[float64]) boolean ? boolean # value: boolean ? testGuardMany([false, true, 1, 0, 42, def _ { to __conformTo(_) :any {return true} }], boolean) # value: [false, true, true] ? boolean.getTheTrivialValue() # value: false XXX more tests XXX should this be a space? ? testSpecimenNotPrinted(boolean) char ? char # value: char ? char + 3 # value: (char + 3) ? testSpecimenNotPrinted(char) XXX more tests int ? int # value: int ? int :DeepFrozen # value: int (indirectly) check that int is a space ? int + 3 # value: (int + 3) ? int.getTheTrivialValue() # value: 0 ? testSpecimenNotPrinted(int) float64 ? float64 # value: float64 ? float64.getTheTrivialValue() # value: 0.0 ? float64 + 3 # value: (float64 + 3) ? testSpecimenNotPrinted(float64) XXX more tests String ? String # value: String ? testSpecimenNotPrinted(String) XXX more tests Guard ? Guard # value: Guard XXX more tests Twine ? Twine # value: Twine ? testSpecimenNotPrinted(Twine) XXX more tests notNull ? notNull # value: notNull notNull comes from a standard .emaker so we need not test it here XXX make sure it has its own tests Tuple ? Tuple :DeepFrozen # value: Tuple ? Tuple[any] :DeepFrozen # value: Tuple[any] ? testGuardMany([["one", 1], ["two", 2.2], ["three"], ["four", 4.0, 4], [5.0, 6.3]], Tuple[String, float64]) # value: [["one", 1.0], ["two", 2.2]] ? [] :Tuple[any] # problem: Need 1 element list: [] ? [1, 2] :Tuple[any] # problem: Need 1 element list: [1, 2] ? 44 :Tuple[any] # problem: the int 44 doesn't coerce to a List ? "44" :Tuple[any] # problem: Need 1 element list: "44" ? testSpecimenNotPrinted(Tuple[any]) __Portrayal ? __Portrayal # value: Tuple[any, String, List[any]] List ? List :DeepFrozen # value: List ? List[float64] :DeepFrozen # value: List[float64] ? {def t :List[float64] := [1, 2.0, 3.4]; t} # value: [1.0, 2.0, 3.4] XXX This is Java-E behavior - is it appropriate? If it were coerced to true list instead, we would have the invariant that anything which passes the List guard is == iff its elements are. As it is, "a" != ['a'] ? "abc" :List # value: "abc" ? "a" != ['a'] # value: true ? testSpecimenNotPrinted(List) ? testSpecimenNotPrinted(List[float64]) Map ? Map # value: Map ? [Map.getKeyGuard(), Map.getValueGuard()] # value: [any, any] ? testGuardMany([[], [].asMap(), [].asMap().diverge(), [1=>2]], Map) # value: [[].asMap(), [1 => 2]] ? Map[float64, int] # value: Map[float64, int] ? [Map[float64, int].getKeyGuard(), Map[float64, int].getValueGuard()] # value: [float64, int] ? testGuardMany([[], [].asMap(), [].asMap().diverge(), [1=>2], [3 => "four"]], Map[float64, int]) # value: [[].asMap(), [1.0 => 2]] XXX conformTo for specimens XXX conformTo primitive guard ValueGuard ? [ValueGuard, ValueGuard == Guard] # value: [Guard, true] Same ? def Same :DeepFrozen := # value: Same ? Same.__respondsTo("coerce", 2) # value: false ? def S1 :DeepFrozen := Same[1.0] # value: Same[1.0] ? S1 == Same[1.0] # value: true ? S1.__optUncall()[0] == Same # value: true ? E.call(E, "call", S1.__optUncall()) == S1 # value: true ? testGuardMany([0, 1, 1.0, Ref.broken(""), Ref.promise()[0], > def _ { to __conformTo(_) :any { return 1 } } > ], S1) # value: [1.0] quoting check ? Same["a"] # value: Same["a"] ? S1.getAllowed() # value: 1.0 ? pragma.enable("call-pattern") ? def Same[v] := S1; v # value: 1.0 ? def Same[v] := any[1.0]; v # problem: the "org.erights.e.elib.slot.makeUnionGuard$makeUnionGuard$unionGuard" any[1.0] doesn't coerce to a Same1 ? def Same[v] := def _ { to __conformTo(_) :any { return S1 } }; v # value: 1.0 Union guards ? any[int, float64] # value: any[int, float64] ? testGuardMany(["a", 'b', 3, 4.0], any[float64, char]) # value: ['b', 3.0, 4.0] ? any[float64, char] :DeepFrozen # value: any[float64, char] ? testSpecimenNotPrinted(any[float64, char]) Intersection guards ? def Point := all[Tuple[any, any], List[float64]] # value: all[Tuple[any, any], List[float64]] ? testGuardMany(["ab", [1, 2], [3.0, 4.0], 5, "six", [7.7, 8]], Point) # value: [[1.0, 2.0], [3.0, 4.0], [7.7, 8.0]] ? testSpecimenNotPrinted(Point) An intersection guard is also a (loose) intersection auditor. ? { interface Foo {} > def both := all[Foo, DeepFrozen] > def bar implements both {} > bar :both } # value: ? pragma.enable("trinary-define") ? escape e { > interface Foo {} > def both := all[Foo, def failer { to audit(_,_) :any {return false} to coerce(_,pe) :any {throw.eject(pe, "no")} }] > def bar implements both { } > def baz :both exit e := bar > } # value: problem: no Negated guards ? Not[int] # value: Not[int] ? testSpecimenNotPrinted(Not[any]) getTheTrivialValue available-but-failing case: ? .getTheTrivialValue() # problem: No trivial value available Native guard behaviors Should not throw on nonnear specimen ? testGuardMany([Ref.promise()[0]], boolean) # value: [] Check no-such-method, etc., as there is a matcher ? boolean.aardvarks() # problem: no such method: org.cubik.cle.native.e.elib.cl-type-guard#aardvarks/0 ? boolean.__respondsTo("aardvarks", 0) # value: false ? boolean.__respondsTo("get", 1) # value: false ? boolean.__respondsTo("of", 1) # value: false XXX should use a native guard which definitely isn't becoming a ordered space in the future ' XXX trivial values for all Java unboxable types