https://github.com/akkartik/mu/blob/main/515parse-float.mu
  1 # no support for scientific notation yet
  2 fn parse-float-decimal in: (addr stream byte) -> _/xmm1: float {
  3   var zero: float
  4   var result/xmm1: float <- copy zero
  5   var first-iter?/ecx: int <- copy 1/true
  6   rewind-stream in
  7   var negative?/edx: int <- copy 0/false
  8   # first loop: integer part
  9   var ten/eax: int <- copy 0xa
 10   var ten-f/xmm2: float <- convert ten
 11   {
 12     var done?/eax: boolean <- stream-empty? in
 13     compare done?, 0/false
 14     break-if-!=
 15     var key/eax: byte <- read-byte in
 16     compare key, 0x2e/decimal-point
 17     break-if-=
 18     $parse-float-decimal:body: {
 19       compare key, 0x2d/-
 20       {
 21         break-if-!=
 22         compare first-iter?, 0/false
 23         {
 24           break-if-!=
 25           abort "parse-float-decimal: '-' only allowed in first position"
 26         }
 27         negative? <- copy 1/true
 28         break $parse-float-decimal:body
 29       }
 30       compare key, 0x30/0
 31       {
 32         break-if->=
 33         abort "parse-float-decimal: invalid character < '0'"
 34       }
 35       compare key, 0x39/9
 36       {
 37         break-if-<=
 38         abort "parse-float-decimal: invalid character > '9'"
 39       }
 40       # key is now a digit
 41       var digit-value/eax: int <- copy key
 42       digit-value <- subtract 0x30
 43       var digit-value-f/xmm3: float <- convert digit-value
 44       result <- multiply ten-f
 45       result <- add digit-value-f
 46     }
 47     first-iter? <- copy 0/false
 48     loop
 49   }
 50   # second loop: fraction
 51   var current-position/xmm0: float <- rational 1, 0xa
 52   {
 53     var done?/eax: boolean <- stream-empty? in
 54     compare done?, 0/false
 55     break-if-!=
 56     var key/eax: byte <- read-byte in
 57     compare key, 0x30/0
 58     {
 59       break-if->=
 60       abort "parse-float-decimal: invalid fraction character < '0'"
 61     }
 62     compare key, 0x39/9
 63     {
 64       break-if-<=
 65       abort "parse-float-decimal: invalid fraction character > '9'"
 66     }
 67     # key is now a digit
 68     var digit-value/eax: int <- copy key
 69     digit-value <- subtract 0x30
 70     var digit-value-f/xmm3: float <- convert digit-value
 71     digit-value-f <- multiply current-position
 72     result <- add digit-value-f
 73     current-position <- divide ten-f
 74     #
 75     first-iter? <- copy 0/false
 76     loop
 77   }
 78   # finally, the sign
 79   compare negative?, 0/false
 80   {
 81     break-if-=
 82     var minus-one/eax: int <- copy -1
 83     var minus-one-f/xmm2: float <- convert minus-one
 84     result <- multiply minus-one-f
 85   }
 86   return result
 87 }
 88 
 89 fn test-parse-float-decimal-zero {
 90   var s-storage: (stream byte 0x10)
 91   var s/esi: (addr stream byte) <- address s-storage
 92   write s, "00"
 93   var x/xmm1: float <- parse-float-decimal s
 94   var expected/eax: int <- copy 0
 95   var expected-f/xmm0: float <- convert expected
 96   compare x, expected-f
 97   {
 98     break-if-=
 99     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "F - test-parse-float-decimal-zero", 3/fg 0/bg
100     move-cursor-to-left-margin-of-next-line 0/screen
101     count-test-failure
102   }
103   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg=cyan, 0/bg
104 }
105 
106 fn test-parse-float-decimal-integer {
107   var s-storage: (stream byte 0x10)
108   var s/esi: (addr stream byte) <- address s-storage
109   write s, "34"
110   var x/xmm1: float <- parse-float-decimal s
111   var expected/eax: int <- copy 0x22/34
112   var expected-f/xmm0: float <- convert expected
113   compare x, expected-f
114   {
115     break-if-=
116     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "F - test-parse-float-decimal-integer", 3/fg 0/bg
117     move-cursor-to-left-margin-of-next-line 0/screen
118     count-test-failure
119   }
120   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg=cyan, 0/bg
121 }
122 
123 fn test-parse-float-decimal-negative-integer {
124   var s-storage: (stream byte 0x10)
125   var s/esi: (addr stream byte) <- address s-storage
126   write s, "-34"
127   var x/xmm1: float <- parse-float-decimal s
128   var expected/eax: int <- copy -0x22/-34
129   var expected-f/xmm0: float <- convert expected
130   compare x, expected-f
131   {
132     break-if-=
133     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "F - test-parse-float-decimal-negative-integer", 3/fg 0/bg
134     move-cursor-to-left-margin-of-next-line 0/screen
135     count-test-failure
136   }
137   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg=cyan, 0/bg
138 }
139 
140 fn test-parse-float-decimal-fraction {
141   var s-storage: (stream byte 0x10)
142   var s/esi: (addr stream byte) <- address s-storage
143   write s, "3.4"
144   var x/xmm1: float <- parse-float-decimal s
145   var expected-f/xmm0: float <- rational 0x22/34, 0xa/10
146   compare x, expected-f
147   {
148     break-if-=
149     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "F - test-parse-float-decimal-fraction", 3/fg 0/bg
150     move-cursor-to-left-margin-of-next-line 0/screen
151     count-test-failure
152   }
153   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg=cyan, 0/bg
154 }
155 
156 fn test-parse-float-decimal-negative-fraction {
157   var s-storage: (stream byte 0x10)
158   var s/esi: (addr stream byte) <- address s-storage
159   write s, "-3.4"
160   var x/xmm1: float <- parse-float-decimal s
161   var expected-f/xmm0: float <- rational -0x22/-34, 0xa/10
162   compare x, expected-f
163   {
164     break-if-=
165     draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, "F - test-parse-float-decimal-negative-fraction", 3/fg 0/bg
166     move-cursor-to-left-margin-of-next-line 0/screen
167     count-test-failure
168   }
169   draw-text-wrapping-right-then-down-from-cursor-over-full-screen 0/screen, ".", 3/fg=cyan, 0/bg
170 }