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

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • 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