| 1 | (******************************************************************************* |
|---|
| 2 | Copyright 2008 Sun Microsystems, Inc., |
|---|
| 3 | 4150 Network Circle, Santa Clara, California 95054, U.S.A. |
|---|
| 4 | All rights reserved. |
|---|
| 5 | |
|---|
| 6 | U.S. Government Rights - Commercial software. |
|---|
| 7 | Government users are subject to the Sun Microsystems, Inc. standard |
|---|
| 8 | license agreement and applicable provisions of the FAR and its supplements. |
|---|
| 9 | |
|---|
| 10 | Use is subject to license terms. |
|---|
| 11 | |
|---|
| 12 | This distribution may include materials developed by third parties. |
|---|
| 13 | |
|---|
| 14 | Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered |
|---|
| 15 | trademarks of Sun Microsystems, Inc. in the U.S. and other countries. |
|---|
| 16 | ******************************************************************************) |
|---|
| 17 | |
|---|
| 18 | component CordedString |
|---|
| 19 | export CordedString |
|---|
| 20 | |
|---|
| 21 | (* I believe that these should eventually go with the range code. *) |
|---|
| 22 | |
|---|
| 23 | (*Intersection of two ranges *) |
|---|
| 24 | opr ∩ (r0: Range[\ZZ32\], r1: Range[\ZZ32\]) = (r0.lower MAX r1.lower) : (r0.upper MIN r1.upper) |
|---|
| 25 | (* Shift a range left by the specified amount. *) |
|---|
| 26 | opr ↙(r: Range[\ZZ32\], leftShift: ZZ32) = (r.lower - leftShift)#r.extent |
|---|
| 27 | |
|---|
| 28 | (* |
|---|
| 29 | ==== CatString ==== |
|---|
| 30 | *) |
|---|
| 31 | |
|---|
| 32 | object CatString(left: String, right:String) extends String |
|---|
| 33 | size = left.size + right.size |
|---|
| 34 | depthField = 1 + (left.depth MAX right.depth) |
|---|
| 35 | getter depth() = depthField |
|---|
| 36 | getter bounds() = 0#size |
|---|
| 37 | getter generator() = ConcatGenerator(left.generator, right.generator) |
|---|
| 38 | opr CMP(self, other: String) = |
|---|
| 39 | if |left| ≥ |other| |
|---|
| 40 | then |
|---|
| 41 | left CMP other |
|---|
| 42 | else |
|---|
| 43 | (left CMP other[0#|left|]) LEXICO: (right CMP other[(|left|):]) |
|---|
| 44 | end |
|---|
| 45 | opr CASE_INSENSITIVE_CMP(self, other:String): TotalComparison = EqualTo |
|---|
| 46 | |
|---|
| 47 | get(i): Char = |
|---|
| 48 | (* get is, and should be, without bounds checks. [ ] does the bounds checks,a and then delegates to get *) |
|---|
| 49 | if i ∈ left.indices then left[i] else right[i - |left|] end |
|---|
| 50 | |
|---|
| 51 | opr[r0:Range[\ZZ32\]] : String = do |
|---|
| 52 | r1 = self.bounds[r0] (* This will complete r0 if it is incomplete, and throw a bounds exception when necessary *) |
|---|
| 53 | self.uncheckedSubstring(r1) |
|---|
| 54 | end |
|---|
| 55 | |
|---|
| 56 | verify() = do |
|---|
| 57 | assert(self.depth, (left.depth MAX right.depth) + 1, self) |
|---|
| 58 | assert(self.size(), |left| + |right|, self) |
|---|
| 59 | end |
|---|
| 60 | |
|---|
| 61 | showStructure(indent: ZZ32) = do |
|---|
| 62 | margin(indent) |
|---|
| 63 | println ("C" || |self| "/" self.depth || ":" ) |
|---|
| 64 | left.showStructure(indent+8) |
|---|
| 65 | right.showStructure(indent+8) |
|---|
| 66 | end |
|---|
| 67 | |
|---|
| 68 | uncheckedSubstring(r0: Range⟦ZZ32⟧) = do |
|---|
| 69 | r1 = (r0 ↙ left.size) |
|---|
| 70 | left.uncheckedSubstring(r0 ∩ left.bounds) || right.uncheckedSubstring(r1 ∩ right.bounds) |
|---|
| 71 | 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 |
|---|
| 77 | leftBounds' = r0 ∩ left.bounds |
|---|
| 78 | r1 = (r0 ↙ left.size) |
|---|
| 79 | 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 | |
|---|
| 92 | println(self): () = do print(left) ; println(right) end |
|---|
| 93 | 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)) |
|---|
| 101 | end |
|---|
| 102 | |
|---|
| 103 | (* |
|---|
| 104 | ==== EmptyString ==== |
|---|
| 105 | *) |
|---|
| 106 | |
|---|
| 107 | value object EmptyString extends String |
|---|
| 108 | getter size() = 0 |
|---|
| 109 | getter bounds() = 0#0 |
|---|
| 110 | getter isEmpty() = true |
|---|
| 111 | getter generator() = Nothing[\Char\] |
|---|
| 112 | opr CMP(self, other: String) = |
|---|
| 113 | |self| CMP |other| |
|---|
| 114 | opr CASE_INSENSITIVE_CMP(self, other:String): TotalComparison = |self| CMP |other| |
|---|
| 115 | |
|---|
| 116 | get(i): Char = fail("Can't get characters from an empty string") |
|---|
| 117 | |
|---|
| 118 | opr[r: Range[\ZZ32\]] : String = do |
|---|
| 119 | rr = self.indices[r] (* to raise a bounds error *) |
|---|
| 120 | EmptyString |
|---|
| 121 | end |
|---|
| 122 | |
|---|
| 123 | verify() = do |
|---|
| 124 | assert(self.depth, 0, self) |
|---|
| 125 | assert(self.size, 0, self) |
|---|
| 126 | end |
|---|
| 127 | |
|---|
| 128 | showStructure(indent) = do |
|---|
| 129 | margin(indent) |
|---|
| 130 | println "E" |self| "/" self.depth |
|---|
| 131 | end |
|---|
| 132 | |
|---|
| 133 | uncheckedSubstring(r0: Range⟦ZZ32⟧) = do |
|---|
| 134 | assert r0.isEmpty |
|---|
| 135 | self |
|---|
| 136 | end |
|---|
| 137 | |
|---|
| 138 | 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 |
|---|
| 141 | opr || (self, other:Char) = other.toString |
|---|
| 142 | |
|---|
| 143 | print(self): () = do end |
|---|
| 144 | println(self): () = println("") |
|---|
| 145 | |
|---|
| 146 | 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 !") |
|---|
| 160 | end |
|---|
| 161 | |
|---|
| 162 | margin(indent) = do |
|---|
| 163 | for i ← 0#indent do print " " end |
|---|
| 164 | end |
|---|
| 165 | |
|---|
| 166 | end |
|---|