Changeset 2739

Show
Ignore:
Timestamp:
08/25/08 07:23:17 (15 months ago)
Author:
black
Message:

Next iteration of CordedStrings?, with substring nodes. Comparison of Strings with substring nodes is a work in progress. This commit fixes bugs in the Range comparison code that were impeding that progress

Location:
trunk
Files:
7 modified

Legend:

Unmodified
Added
Removed
  • trunk/Library/CordedString.fsi

    r2708 r2739  
    2424  end 
    2525   
     26  trait SubString extends String 
     27    comprises {...} 
     28  end  
     29   
    2630  margin(prefix: String, indent: ZZ32) 
    2731 
  • trunk/Library/CordedString.fss

    r2708 r2739  
    1717 
    1818component CordedString 
     19import List.{...} 
    1920export CordedString 
    2021 
    2122(* I believe that these should eventually go with the range code. *) 
    22  
    2323    (*Intersection of two ranges *) 
    24     opr ∩ (r0: Range[\ZZ32\], r1: Range[\ZZ32\]) = (r0.lower MAX r1.lower) : (r0.upper MIN r1.upper)  
     24    opr ∩ (r0: Range⟦ZZ32⟧, r1: Range⟦ZZ32⟧) = (r0.lower MAX r1.lower) : (r0.upper MIN r1.upper)  
     25       
     26  test rangeIntersect() = do 
     27        assert((0:5) ∩ (0:3), 0:3) 
     28        assert((0:5) ∩ (3:7), 3:5) 
     29        assert((0:5) ∩ (7:10), 7:5) 
     30        assert((5:3).size, 0, "The size of 5:3 is not zero!") 
     31        assert((9:8).size, 0, "The size of 9:8 is not zero!") 
     32        assert( (5:3).isEmpty, "5:3 is not empty!") 
     33        assert( (9:8).isEmpty, "9:8 is not empty!") 
     34        assert( ((0:5) ∩ (7:10)).isEmpty, "0:5 has a non-empty intersection with 7:10 !") 
     35        assert( (7:9)≪7, (0#3), "7:9≪7 isn't 0#3" )  
     36  end 
     37   
    2538    (* Shift a range left by the specified amount.  *) 
    26     opr ↙(r: Range[\ZZ32\], leftShift: ZZ32) = (r.lower - leftShift)#r.extent 
    27  
     39    opr ≪(r: Range⟦ZZ32⟧, leftShift: ZZ32) = (r.lower - leftShift)#r.extent 
     40    (* Shift a range right by the specified amount. *) 
     41    opr ≫(r: Range⟦ZZ32⟧, rightShift: ZZ32) = (r.lower + rightShift)#r.extent 
     42     
     43  test testShiftLeft(): () = do 
     44    assert( (10:12) ≪ 9, 1:3) 
     45  end 
     46   
     47  test testShiftRight(): () = do 
     48    assert( (2:3) ≫ 5, 7:8) 
     49  end 
     50   
     51  test testRangeContainment = do 
     52    assert( (2:3) ≤ (2:3), "(2:3) not less than or equal to (2:3)") 
     53    (* println "(2#2) CMP (2:3) = " ((2#2) CMP (2:3))  *) 
     54    assert( (2#2) ≤ (2:3), "(2#2) not less than or equal to (2:3)") 
     55  end 
     56(*  
     57==== Shared Traits ==== 
     58*) 
     59 
     60  trait Concatenable extends String 
     61    opr || (self, other:String): String =  
     62        if |other| = 0 then self else CatString(self, other) end 
     63    opr || (self, _:EmptyString): String = self 
     64    opr || (self, other:Char) = CatString(self, other.toString) 
     65  end 
    2866(* 
    2967==== CatString ==== 
    3068*) 
    3169 
    32   object CatString(left: String, right:String)  extends String 
     70  object CatString(left: String, right:String)  extends {String, Concatenable} 
    3371    size = left.size + right.size 
    3472    depthField = 1 + (left.depth MAX right.depth) 
     
    4987        if i ∈ left.indices then left[i] else right[i - |left|] end 
    5088 
    51     opr[r0:Range[\ZZ32\]] : String =  do 
     89    opr[r0:Range⟦ZZ32⟧] : String =  do 
    5290        r1 = self.bounds[r0]     (* This will complete r0 if it is incomplete, and throw a bounds exception when necessary *) 
    53         self.uncheckedSubstring(r1) 
     91        if r1.isEmpty then  
     92            EmptyString  
     93        else  
     94            self.uncheckedSubstring(r1) 
     95        end 
    5496      end 
    5597       
     
    65107        right.showStructure(indent+8) 
    66108    end 
    67        
    68     uncheckedSubstring(r0: Range⟦ZZ32⟧) = do 
    69         r1 = (r0 ↙ left.size) 
     109 
     110(* without SubString nodes:  
     111       
     112    uncheckedSubstring(r0: Range⟦ZZ32⟧) = do 
     113        r1 = (r0 ≪ left.size) 
    70114        left.uncheckedSubstring(r0 ∩ left.bounds) || right.uncheckedSubstring(r1 ∩ right.bounds)             
    71115      end 
    72        
    73        
    74 (* Here is the three-way version: this framework is better once we have subString nodes 
    75   
    76     uncheckedSubstring(r0: Range[\ZZ32\]) = do 
     116 *) 
     117             
     118    uncheckedSubstring(r0: Range⟦ZZ32⟧) = do 
    77119        leftBounds' = r0 ∩ left.bounds 
    78         r1 = (r0 left.size) 
     120        r1 = (r0 left.size) 
    79121        rightBounds' = r1 ∩ right.bounds 
    80         if leftBounds.isEmpty then right.uncheckedSubstring(rightBounds') 
    81         else if rightBounds.isEmpty then left.uncheckedSubstring(leftBounds') 
    82         else left.uncheckedSubstring(leftBounds') || right.uncheckedSubstring(rightBounds')             
    83       end   
    84  *) 
    85        
    86  
    87     opr || (self, other:String): String =  
    88         if |other| = 0 then self else CatString(self, other) end 
    89     opr || (self, _:EmptyString) = self 
    90     opr || (self, other:Char) = CatString(self, other.toString) 
    91      
     122(*        atomic do  
     123            println "uncheckedSubstring " r0 " of " 
     124            self.showStructure() 
     125            println "===============" 
     126            println "leftBounds' = " leftBounds' ( if leftBounds'.isEmpty then "(empty)" else "(non-empty)" end ) 
     127            println "rightBounds' = " rightBounds'  ( if rightBounds'.isEmpty then "(empty)" else "(non-empty)" end ) 
     128            println "===============" 
     129        end  *) 
     130        if leftBounds'.isEmpty then  
     131            right.uncheckedSubstring(rightBounds') 
     132        elif rightBounds'.isEmpty then 
     133            left.uncheckedSubstring(leftBounds') 
     134        else 
     135            SubString'(self, r0) 
     136        end        
     137    end   
     138 
    92139    println(self): () = do print(left) ; println(right) end   
    93140    print(self): () = do print(left) ; print(right) end 
    94  
    95   end 
    96  
    97   object ConcatGenerator[\T\](first:Generator[\T\], second:Generator[\T\]) 
    98         extends Generator[\T\] 
    99     generate[\R\](r: Reduction[\R\], body:T->R):R = 
    100         r.join(first.generate[\R\](r, body), second.generate[\R\](r, body)) 
     141     
     142    subdivide(): Maybe⟦Generator⟦(ZZ32, String)⟧⟧ = Just ⟨ (0, left), (|left|, right) ⟩ 
     143 
     144  end 
     145 
     146  object ConcatGenerator⟦T⟧(first:Generator⟦T⟧, second:Generator⟦T⟧) 
     147        extends Generator⟦T⟧ 
     148    generate⟦R⟧(r: Reduction⟦R⟧, body:T->R):R = 
     149        r.join(first.generate⟦R⟧(r, body), second.generate⟦R⟧(r, body)) 
    101150  end 
    102151 
     
    105154*) 
    106155 
    107   value object EmptyString extends String 
     156  value object EmptyString extends {String, Concatenable} 
    108157    getter size() = 0 
    109158    getter bounds() = 0#0 
    110159    getter isEmpty() = true 
    111     getter generator() = Nothing[\Char\] 
     160    getter generator() = Nothing⟦Char⟧ 
    112161    opr CMP(self, other: String) = 
    113162        |self| CMP |other| 
     
    116165    get(i): Char = fail("Can't get characters from an empty string") 
    117166 
    118     opr[r: Range[\ZZ32\]] : String = do 
     167    opr[r: Range⟦ZZ32⟧] : String = do 
    119168        rr = self.indices[r]     (* to raise a bounds error *) 
    120169        EmptyString 
     
    137186 
    138187    opr || (self, other:String): String = other 
    139 (*    opr || (other: String, self): String = other   *)    (* this optimizes the case with EmptyString on the right*) 
    140     opr || (self, _: EmptyString): String = self 
    141188    opr || (self, other:Char) = other.toString 
    142189       
     
    145192   
    146193  end 
    147  
    148   run(args: String...): () = do println "Finished" end  
    149    
    150   test rangeIntersect() = do 
    151         assert((0:5) ∩ (0:3), 0:3) 
    152         assert((0:5) ∩ (3:7), 3:5) 
    153         assert((0:5) ∩ (7:10), 7:5) 
    154         deny(5:3, 9:8)                  (* I hoped that that this would be an assert! *) 
    155         assert((5:3).size, 0, "The size of 5:3 is not zero!") 
    156         assert((9:8).size, 0, "The size of 9:8 is not zero!") 
    157         assert( (5:3).isEmpty, "5:3 is not empty!") 
    158         assert( (9:8).isEmpty, "9:8 is not empty!") 
    159         assert( ((0:5) ∩ (7:10)).isEmpty, "0:5 has a non-empty intersection with 7:10 !") 
     194   
     195  subdivide() = Nothing⟦Generator⟦(ZZ32, String)⟧⟧ 
     196 
     197(* 
     198==== SubString ==== 
     199*) 
     200  trait SubString extends {String, Concatenable} 
     201    comprises {SubString'} 
     202  end  
     203   
     204  object SubString'(parent: String, range: Range⟦ZZ32⟧) extends SubString 
     205    getter size() = range.size 
     206    getter depth() = parent.depth       (* Why not one more than the parent?  Would this break the balancing invariant? *) 
     207    getter isEmpty() = false 
     208     
     209    opr CMP(self, other: String) =  do 
     210 (*       if pgen ← parent.subdivide() then 
     211            BIG LEXICO [(start, str) ← pgen] self.uncheckedSubstring((start#|str|) ∩ self.bounds) CMP str 
     212        else 
     213*) 
     214            (BIG LEXICO [i ← 0#(|self| MIN |other|)] self.get(i) CMP other.get(i)) LEXICO (|self| CMP |other|)                
     215(*        end 
     216*) 
     217    end 
     218     
     219     
     220    verify() = do 
     221        parent.verify() 
     222        deny(range.isEmpty, "SubString (" range ") has empty range") 
     223        assert(range < parent.bounds, "SubString (" range ") has range equal to or greater than that of parent (" parent.bounds ")")  
     224    end 
     225    showStructure(indent) = do 
     226        margin(indent) 
     227        println "S" |self| "=[" range "]"  
     228        parent.showStructure(indent + 8) 
     229    end 
     230     
     231    get(i:ZZ32) = do 
     232      assert(i < range.size, "getting char " i " from a substring of size " |range|) 
     233      parent.get(range.lower+i) 
     234    end 
     235     
     236    uncheckedSubstring(r0: Range⟦ZZ32⟧) = do 
     237        assert((r0≫range.lower) ≤ range, "asking for substring ["  r0 "] of S" self.size) 
     238        if r0.isEmpty then EmptyString 
     239        elif r0 = self.bounds then println "trivial substring"; self 
     240        else SubString'(parent, r0≫range.lower) 
     241        end 
     242    end 
     243     
     244    println(self): () = do print(self) ; println() end   
     245    print(self): () = for ch ← seq(self) do print ch end 
     246           
     247    subdivide(): Maybe⟦Generator⟦(ZZ32, String)⟧⟧ = do 
     248    (* The pairs (start, str) that are generated are such that start[0] = 0 and start[i] = | str[0] || ... || str[i-1] | 
     249      and str[0] || str [1] || ... || str[n] = self 
     250    *) 
     251        pieces = parent.subdivide() 
     252        offset = range.lower 
     253        if pgen ← pieces then 
     254            <| if (start#piece.size) ≤ range then 
     255                    (start-offset, piece) 
     256                else  
     257                    range' = range ∩ (start#piece.size) 
     258                    (range'.lower-offset, SubString'(piece, range'≪start)) 
     259                end | (start, piece) ← pgen,   (range ∩ (start#piece.size)).nonEmpty |> 
     260        else 
     261            Nothing⟦Generator⟦(ZZ32,String)⟧⟧ 
     262        end                     
     263    end 
    160264  end 
    161265   
  • trunk/Library/FortressLibrary.fsi

    r2726 r2739  
    9999    isLeftZero(_:Comparison): Boolean 
    100100end 
     101 
     102opr BIG LEXICO(): BigReduction[\TotalComparison, TotalComparison\] 
    101103 
    102104trait Comparison 
     
    701703trait Condition[\E\] extends SequentialGenerator[\E\] 
    702704    getter isEmpty(): Boolean 
     705    getter nonEmpty(): Boolean 
    703706    getter holds(): Boolean 
    704707    getter size(): ZZ32 
     
    973976        defined as %|self| = 0%. *) 
    974977    getter isEmpty(): Boolean 
     978    getter nonEmpty(): Boolean 
    975979    (** %size()% is depracted; use %|self|% instead. *) 
    976980    abstract getter size(): ZZ32 
     
    18021806                RangeWithExtent[\T\], PartialRange[\T\] } 
    18031807    excludes { Number } 
    1804  
    1805     getter isEmpty(): Boolean 
     1808    
    18061809    opr =(self,_:Range[\T\]): Boolean 
    18071810end 
     
    19691972    opr |self| : ZZ32 
    19701973    opr CASE_INSENSITIVE_CMP(self, other:String): TotalComparison 
     1974     
    19711975    opr [i:ZZ32]: Char 
    19721976    (** As a convenience, we permit LowerRange indexing to go 1 past the bounds 
     
    19781982         should be in a "friends" interface *) 
    19791983    uncheckedSubstring(r0: Range[\ZZ32\]) : String 
     1984     
     1985    subdivide(): Maybe[\Generator[\(ZZ32, String)\]\] 
    19801986 
    19811987    (** The operator %||% with at least one String argument converts to string and 
  • trunk/Library/FortressLibrary.fss

    r2715 r2739  
    135135    isLeftZero(_:Comparison): Boolean = true 
    136136end 
     137 
     138opr BIG LEXICO(): BigReduction[\TotalComparison, TotalComparison\] = 
     139  BigReduction[\TotalComparison,TotalComparison\](LexicographicReduction) 
     140   
    137141 
    138142trait Comparison 
     
    11001104trait Condition[\E\] extends { ZeroIndexed[\E\], SequentialGenerator[\E\] } 
    11011105    getter isEmpty(): Boolean = NOT holds() 
     1106    getter nonEmpty(): Boolean = NOT isEmpty() 
    11021107    getter holds(): Boolean = cond[\Boolean\](fn (_:E):Boolean => true, fn () => false) 
    11031108    getter size(): ZZ32 = if holds() then 1 else 0 end 
     
    14531458        defined as size=0 *) 
    14541459    getter isEmpty(): Boolean = |self| = 0 
    1455     (** %size()% is depracated; use %|self|%. *) 
     1460    getter nonEmpty(): Boolean = NOT self.isEmpty 
     1461    (** %self.size% is equivalent to %|self|%. *) 
    14561462    getter size(): ZZ32 
    14571463    (** bounds() yields a range of indices that are valid for the 
     
    30273033                RangeWithExtent[\T\], PartialRange[\T\] } 
    30283034    excludes { Number } 
    3029     getter isEmpty(): Boolean = (|self| ≤ 0) 
     3035     
    30303036    opr[r:Range[\T\]]: Range[\T\] = fail("Unrecognized Range " r) 
    30313037    opr[_:OpenRange[\Any\]] : Range[\T\] = self 
     
    32843290            self.lower#r.extent 
    32853291        else 
    3286             fail(self "[" r "] is not sufficiently large in some dimension") 
     3292            fail(self "[" r "] is too small in some dimension") 
    32873293        end 
    32883294    opr[r:CompleteRange[\T\]]: CompleteRange[\T\] = 
     
    33033309 
    33043310    opr =(self, other:CompleteRange[\T\]): Boolean = 
    3305         self.isBounded=other.isBounded AND self.lower=other.lower AND 
    3306         self.extent = other.extent 
     3311    (*    isBounded()=other.isBounded() AND  
     3312         APB 2008.08.20: this seems bogus: isBounded tells us only whether we were created  
     3313         using an extent or an upper bound, and should not effect the comparison *) 
     3314         lower()=other.lower() AND extent() = other.extent()     
     3315          
    33073316    opr CMP(self, other:Range[\T\]): Comparison = 
    33083317        typecase other of 
     
    33153324                    (LessThan,LessThan) => Unordered 
    33163325                    (GreaterThan,GreaterThan) => Unordered 
    3317                     (EqualTo,EqualTo) => 
     3326    (*  This case seems unncessary; the (EqualTo,Comparison) case will cover us    --- APB  2008.08.20 
     3327                    (EqualTo,EqualTo) => EqualTo 
    33183328                        if self.isBounded = other.isBounded then 
    33193329                            EqualTo 
     
    33213331                            Unordered 
    33223332                        end 
     3333   *) 
    33233334                    (EqualTo,Comparison) => b 
    33243335                    (GreaterThan,Comparison) => LessThan 
     
    36763687      
    36773688    opr |self| : ZZ32 = self.size 
    3678     opr CASE_INSENSITIVE_CMP(self, other:String): TotalComparison 
    3679     (** As a convenience, we permit LowerRange indexing to go 1 past the bounds 
     3689        
     3690    opr CASE_INSENSITIVE_CMP(self, other:String): TotalComparison = 
     3691      ((BIG LEXICO[i <- 0#(|self| MIN |other|) ] self.get(i) CASE_INSENSITIVE_CMP other.get(i)) LEXICO (|self| CMP |other|)) 
     3692     
     3693    opr CMP(self, other:String): TotalComparison = 
     3694      ((BIG LEXICO[i <- 0#(|self| MIN |other|) ] self.get(i) CMP other.get(i)) LEXICO (|self| CMP |other|)) 
     3695       
     3696    opr [i:ZZ32]: Char = 
     3697        (** As a convenience, we permit LowerRange indexing to go 1 past the bounds 
    36803698        of the String, returning the empty String, in order to permit some convenient 
    36813699        String-trimming idioms. **) 
    3682     opr [i:ZZ32]: Char = 
    36833700        if 0 <= i < |self| 
    36843701        then self.get(i) 
     
    37733790 
    37743791 
    3775 print(a:Any):() = print("" a) 
    3776 println(a:Any):() = println("" a) 
     3792print(a:Any):() = print(a.toString) 
     3793println(a:Any):() = println(a.toString) 
    37773794(* 0-argument versions handle passing of () to single-argument versions. *) 
    37783795print():() = print("") 
     
    37823799println(a: JavaString): () =  
    37833800        builtinPrimitive("com.sun.fortress.interpreter.glue.prim.StringPrim$Println") 
    3784  
    37853801 
    37863802forDigit(x:ZZ32, radix:ZZ32): Maybe[\Char\] = 
  • trunk/Library/JavaString.fss

    r2708 r2739  
    3333    opr |self| : ZZ32 = 
    3434        builtinPrimitive("com.sun.fortress.interpreter.glue.prim.JavaString$Size") 
     35         
    3536    uncheckedSubstring(r1: Range[\ZZ32\]) : String = 
     37    (* We could build a subString node here, but not until everything is working, because that will intorduce  
     38       SubString objects into code that may still expect JavaStrings *) 
    3639        if r1.isEmpty then "" 
    3740        else self.javaSubstr(r1.lower, r1.upper + 1)    (* Java substr's endIndex is one past the last character *) 
    3841        end 
     42         
    3943    opr =(self, other:String): Boolean = 
    4044        builtinPrimitive("com.sun.fortress.interpreter.glue.prim.JavaString$Eq") 
     
    6670         
    6771    (* The following are curently dead code; see lines 3765 ish in FortressLibrary.fss *)     
     72(* 
    6873    javaPrint(a: JavaString): () =  
    6974        builtinPrimitive("com.sun.fortress.interpreter.glue.prim.StringPrim$Print") 
    7075    javaPrintln(a: JavaString): () =  
    7176        builtinPrimitive("com.sun.fortress.interpreter.glue.prim.StringPrim$Println") 
     77*) 
    7278 
    7379    indexOf(c:Char): Maybe[\ZZ32\] = do 
     
    101107 
    102108    opr ||(self, b:String):String = 
    103         CatString(self, b) 
    104     (*  This makes the overloading resolution go beserk ... 
    105     opr ||(self, b:EmptyString):String = self 
    106     *) 
     109    (* It would be good to do something more sophisticated when b is short, such as copying 
     110       self and b into a StringBuffer and then turning the whole thing into a JavaString *) 
     111        if self.isEmpty then b else CatString(self, b) end 
     112         
     113   
    107114    opr ||(self, b:Char): String = 
    108115        if |self| ≥ flatStringInfo.maxSize then 
     
    111118            javaAppend(self, b) 
    112119        end 
     120         
     121    subdivide() = Nothing[\Generator[\(ZZ32, String)\]\] 
    113122 
    114123  end 
  • trunk/ProjectFortress/not_passing_yet/CordedStringTests.fss

    r2708 r2739  
    1818component CordedStringTests 
    1919  import CordedString.{...} 
     20  import JavaString.{...} 
    2021  import Set.{...} 
    2122  import List.{...} 
     
    4546    end 
    4647  end 
    47    
     48  
    4849  test subString(): () = do 
    4950    words = ⟨"The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog."⟩ 
     
    5657        assert(testString[i:j], referenceString[i:j])  
    5758    end 
    58  
    5959  end 
    60  
     60   
     61  test subStringSimplification():() = do 
     62    testString = catStringFrom("The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog.") 
     63    testString.verify() 
     64    sub1 = testString[34:36] 
     65    typecase sub1 of 
     66        JavaString => assert(true) 
     67        String => do sub1.showStructure() 
     68                            assert(false, "sub1=" sub1 " is not a JavaString") end 
     69     end 
     70  end 
     71   
     72  (* test *) validateSubdivision(subject: String, division: Maybe⟦Generator⟦(ZZ32, String)⟧⟧): () = do 
     73    var len: ZZ32 = 0 
     74    var accum: String = "" 
     75    if gen ← division then  
     76      for (start, str) ← seq(gen) do 
     77         assert(start, len, str) 
     78         len := len + |str| 
     79         accum := accum || str 
     80      end 
     81      assert(len, |subject|) 
     82      assert(accum, subject) 
     83    end 
     84  end 
     85     
     86  test testSubdivide():() = do 
     87    subject = CatString("abcd", "efgh") 
     88    substr1 = subject[2:6] 
     89    var len: ZZ32 = 0 
     90    var accum: String = "" 
     91    for (start, str) ← seq(substr1.subdivide()) do 
     92         assert(start, len, str) 
     93         len := len + |str| 
     94         accum := accum || str 
     95    end 
     96    assert(len, |substr1|) 
     97    accum.verify() 
     98    accum.showStructure() 
     99    assert(accum, substr1)   
     100     
     101    substr2 = subject[4:6] 
     102    assert(substr2.subdivide(), Nothing⟦Generator⟦(ZZ32,String)⟧⟧) 
     103     
     104    substr3 = subject[0:5] 
     105    for p ← seq(substr1.subdivide()) do 
     106        println ("found tuple" || p)    (* This should (did?) work prefix string too *) 
     107    end 
     108     
     109  end  
     110   
     111(* 
     112  test comparison():() = do 
     113    smaller = catStringFrom("The", "quick", "brown", "fox", "jumped", "over", "the", "lazy", "dog.") 
     114    bigger = catStringFrom("The", "quick", "brown", "jumped", "fox", "over", "the", "lazy", "doggie.") 
     115    smaller.verify 
     116    bigger.verify 
     117    smaller.showStructure 
     118    bigger.showStructure 
     119    assert(smaller < bigger) 
     120    assert(smaller[10:] < bigger[10:]) 
     121    a = smaller[30:36]  
     122    b = bigger[30:36] 
     123    a.verify 
     124    b.verify 
     125    a.showStructure 
     126    b.showStructure 
     127    assert(smaller[30:36] = bigger[30:36], smaller[30:36] " is not = to " bigger[30:36]) 
     128  end 
     129 *) 
     130  object CatStringReduction extends MonoidReduction[\String\] 
     131    getter toString() = "CatStringReduction" 
     132    empty(): String = EmptyString 
     133    join(a:String, b:String):String = CatString(a, b) 
     134  end 
     135   
     136  test catStringFrom(args: String...): String = 
     137    seq(args).generate⟦String⟧(CatStringReduction, fn(x) => x) 
     138   
     139  
    61140  test testNonEmptyConcat(): () =  do 
    62141    stuff = "Hello " 
     
    66145    assert(hw, "Hello World") 
    67146    assert(hw, CatString("Hell", "o World")) 
    68     assert(hw[2:7], "llo Wo") 
    69     assert(hw[0:3], "Hell") 
    70     assert(hw[5:2], "") 
    71147  end 
    72148   
     
    106182    for i ← result.bounds do assert(result[i] , chars[i]) end 
    107183  end   
    108  
     184   
    109185  run(args:String...):() = do 
    110186    println "Tests complete" 
  • trunk/ProjectFortress/tests/RangeTest.fss

    r2196 r2739  
    131131    chkOrder(mm,i,LessThan), i <- <|lm,lh',lh,mh|> 
    132132    chkOrder(mm,hh,Unordered) 
    133     chkOrder(lh,lh',Unordered) 
    134     chkOrder(lh',lh,Unordered) 
     133    chkOrder(lh,lh',EqualTo)        (* APB 2008.08.20 Changed this from Unordered.  Also changed the code *) 
     134    chkOrder(lh',lh,EqualTo)        (* APB 2008.08.20 Changed this from Unordered.  Also changed the code *) 
    135135  end 
    136136