~repos /plum
git clone https://pyrossh.dev/repos/plum.git
A statically typed, imperative programming language inspired by rust, python
e502e58c
—
pyrossh 1 year ago
add more code
- readme.md +31 -10
- scratch.pc +67 -1
- std/bool.mi +1 -3
- std/http.mi +9 -9
- std/json.mi +339 -0
- std/list.mi +9 -0
- std/map.mi +19 -10
- std/math.mi +47 -3
- std/result.mi +10 -10
readme.md
CHANGED
|
@@ -81,6 +81,17 @@ fn (c: Cat) talk() =
|
|
|
81
81
|
fn (c: Cat) toStr(): str =
|
|
82
82
|
"Cat<{c.fullname()}, ${c.age}>"
|
|
83
83
|
|
|
84
|
+
enum Temperature =
|
|
85
|
+
| celsius(float)
|
|
86
|
+
| fahrenheit(float)
|
|
87
|
+
|
|
88
|
+
fn (s: Temperature) to_str(): str =
|
|
89
|
+
match s
|
|
90
|
+
celsius(t) && t > 30 -> "${t}C is above 30 celsius"
|
|
91
|
+
celsius(t) -> "${t}C is below 30 celsius"
|
|
92
|
+
fahrenheit(t) && t > 86 -> "${t}F is above 86 fahrenheit"
|
|
93
|
+
fahrenheit(t) -> "${t}F is below 86 fahrenheit"
|
|
94
|
+
|
|
84
95
|
type MapCallback = fn(v: a): v
|
|
85
96
|
|
|
86
97
|
trait Comparable(
|
|
@@ -91,17 +102,27 @@ trait ToStr(
|
|
|
91
102
|
fn to_str(): str
|
|
92
103
|
)
|
|
93
104
|
|
|
94
|
-
|
|
105
|
+
fn connect_db(conn_url: str): DB! =
|
|
95
|
-
| celsius(float)
|
|
96
|
-
|
|
106
|
+
db := postgres_connect(conn_url)?
|
|
107
|
+
db.exec("select 1")?
|
|
97
108
|
|
|
98
|
-
fn (
|
|
109
|
+
fn db_select(conn_url: str): void! =
|
|
99
|
-
match s
|
|
100
|
-
|
|
110
|
+
db := new_db(conn_url)?
|
|
101
|
-
|
|
111
|
+
db.exec("select 1")?
|
|
102
|
-
|
|
112
|
+
|
|
103
|
-
|
|
113
|
+
record DB(conn_url: str)
|
|
104
114
|
|
|
115
|
+
error DatabaseError
|
|
116
|
+
DatabaseNotOnline(conn_url: str)
|
|
117
|
+
RowReadFailure(query: str)
|
|
118
|
+
|
|
119
|
+
fn new_db(conn_url: str) DB! =
|
|
120
|
+
db := DB(conn_url: str)
|
|
121
|
+
online := db.check()?
|
|
122
|
+
if !online
|
|
123
|
+
Err(errors.DatabaseNotOnline(conn_url))
|
|
124
|
+
else
|
|
125
|
+
db
|
|
105
126
|
|
|
106
127
|
test("talks") |t|
|
|
107
128
|
c := Cat(name: "123", age: 1)
|
|
@@ -343,7 +364,7 @@ for v := range list
|
|
|
343
364
|
sum += k + v
|
|
344
365
|
```
|
|
345
366
|
|
|
346
|
-
**
|
|
367
|
+
**Range Over Function**
|
|
347
368
|
|
|
348
369
|
```rb
|
|
349
370
|
type Seq0 = fn(yield: fn(): bool): bool
|
scratch.pc
CHANGED
|
@@ -215,4 +215,70 @@ repeat(|_| i < 9) |i|
|
|
|
215
215
|
pass
|
|
216
216
|
|
|
217
217
|
repeat(|_| a > b && c < d) |i|
|
|
218
|
-
pass
|
|
218
|
+
pass
|
|
219
|
+
|
|
220
|
+
let v = list.of(1, 2, 3)
|
|
221
|
+
|> list.add(1, 2)
|
|
222
|
+
|> list.get(0)
|
|
223
|
+
|
|
224
|
+
let v = list.of(1, 2, 3)
|
|
225
|
+
..add(1, 2)
|
|
226
|
+
..get(0)
|
|
227
|
+
|
|
228
|
+
if v == nil
|
|
229
|
+
error.Error
|
|
230
|
+
else
|
|
231
|
+
c * 20
|
|
232
|
+
|
|
233
|
+
if v == None
|
|
234
|
+
error.Error
|
|
235
|
+
else
|
|
236
|
+
Some(c) := v
|
|
237
|
+
c * 20
|
|
238
|
+
|
|
239
|
+
match v
|
|
240
|
+
None -> return error.Error
|
|
241
|
+
Some(c) ->
|
|
242
|
+
return c * 20
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
#[json]
|
|
246
|
+
record UserData(
|
|
247
|
+
id: int,
|
|
248
|
+
name: str,
|
|
249
|
+
roles: List[str]
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
`This is to follow the http standards
|
|
253
|
+
trait Error(
|
|
254
|
+
fn code(): int
|
|
255
|
+
fn msg(): str
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
`derive implements this func
|
|
259
|
+
`Derive is a compiler plugin/generator similar to dart
|
|
260
|
+
`which runs automatically. Its not a macro more like a decorator.
|
|
261
|
+
fn UserData.fromJsonStr(data: str): UserData | JsonParseError =
|
|
262
|
+
// JsonParseError(line: line, pos: post, object: "UserData")
|
|
263
|
+
pass
|
|
264
|
+
|
|
265
|
+
type FetchDataError = FetchError | IOError | JsonParseError
|
|
266
|
+
|
|
267
|
+
fn fetch_data(route: str): map[str, any] | UserData | FetchError | IOError | JsonParseError =
|
|
268
|
+
res := fetch(route)?
|
|
269
|
+
data := res.body.read_all()?
|
|
270
|
+
parse_json(data)?
|
|
271
|
+
|
|
272
|
+
fn main() =
|
|
273
|
+
res := fetch_data()
|
|
274
|
+
if res is UserData
|
|
275
|
+
printLn("Success ${res.id}")
|
|
276
|
+
else if res is IOError
|
|
277
|
+
printLn("IO failed")
|
|
278
|
+
else if res is Error
|
|
279
|
+
printLn("generic error ${res.msg()}")
|
|
280
|
+
|
|
281
|
+
when res
|
|
282
|
+
UserData -> printLn("Success ${res.id}")
|
|
283
|
+
IOError -> printLn("IO failed")
|
|
284
|
+
_ -> printLn("generic error ${res.msg()}")
|
std/bool.mi
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
module std
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
type bool = true | false
|
|
4
|
-
| true
|
|
5
|
-
| false
|
|
6
4
|
|
|
7
5
|
fn (x: bool) op_eq(y: bool) = x == y
|
|
8
6
|
fn (x: bool) op_ne(y: bool) = x != y
|
std/http.mi
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
+
module std/http
|
|
2
|
+
|
|
1
3
|
import std/path
|
|
2
4
|
import std/os
|
|
3
5
|
import std/http/content_type
|
|
4
6
|
|
|
5
7
|
#[builder]
|
|
6
8
|
record Response(
|
|
7
|
-
headers:
|
|
9
|
+
headers: Map[str, str]
|
|
8
|
-
body: Buffer
|
|
10
|
+
body: str | Buffer | IO
|
|
9
11
|
status: int
|
|
10
12
|
)
|
|
11
13
|
|
|
12
|
-
fn file_response(
|
|
14
|
+
fn file_response(path: str): Response | IOError =
|
|
13
|
-
ext := path::ext(file)
|
|
14
|
-
content := contentTypeFromExt(ext)
|
|
15
|
+
content := contentTypeFromExt(path.ext())
|
|
15
|
-
data :=
|
|
16
|
+
data := os.readFile(file)?
|
|
16
17
|
Response()
|
|
17
18
|
.header("Content-Type", content)
|
|
18
|
-
.header("Content-Length", "2")
|
|
19
19
|
.body(data)
|
|
20
20
|
.status(200)
|
|
21
21
|
|
|
@@ -24,10 +24,10 @@ fn index(): Response! =
|
|
|
24
24
|
file_response("index.html")
|
|
25
25
|
|
|
26
26
|
#[get("/public/<...>")]
|
|
27
|
-
fn public(file: str): Response
|
|
27
|
+
fn public(file: str): Response | IOError =
|
|
28
28
|
ext := path::ext(file)
|
|
29
29
|
content := contentTypeFromExt(ext)
|
|
30
|
-
data := os.readFile
|
|
30
|
+
data := os.readFile(file)?
|
|
31
31
|
Response()
|
|
32
32
|
.header("Content-Type", content)
|
|
33
33
|
.body(data)
|
std/json.mi
ADDED
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
module std/json
|
|
2
|
+
|
|
3
|
+
type Json = Map[str, Json] | List[Json] | int | float | str | bool | nil
|
|
4
|
+
|
|
5
|
+
fn Json.parse(src: str | Buffer | IO): Json | ParseError =
|
|
6
|
+
JsonParser.withSrc(src).parse()
|
|
7
|
+
|
|
8
|
+
#[error(400, "Failed to parse json ${object} at: ${line} ${pos}")]
|
|
9
|
+
record ParseError(
|
|
10
|
+
line: str
|
|
11
|
+
pos: str
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
record JsonParser(
|
|
15
|
+
cur: int = ' '
|
|
16
|
+
_pos: int = 0
|
|
17
|
+
_next: int = ' '
|
|
18
|
+
_buf: str | Buffer | IO
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
fn JsonParser.withSrc(src: str | Buffer | IO): JsonParser =
|
|
22
|
+
JsonParser(_buf = src)
|
|
23
|
+
|
|
24
|
+
fn _is_space(c: U32): Bool => (c == ' ') or ((c >= '\t') and (c <= '\r'))
|
|
25
|
+
|
|
26
|
+
fn _is_delim(c: U32): Bool =>
|
|
27
|
+
(c == ',') or (c == '}') or (c == ':') or (c == ']') or (_is_space(c)) or (c == 0)
|
|
28
|
+
|
|
29
|
+
fn _is_digit(c: U32): Bool => (c >= '0') and (c <= '9')
|
|
30
|
+
|
|
31
|
+
fn (p: Parser) _err(msg: str) => printLn(msg)
|
|
32
|
+
|
|
33
|
+
fn _get_next_raw(): U32 =>
|
|
34
|
+
try
|
|
35
|
+
_inc_pos()
|
|
36
|
+
let chr: (U32, U8) = _buf.utf32(_pos-1)?
|
|
37
|
+
cur = _next = chr._1
|
|
38
|
+
else
|
|
39
|
+
cur = _next = 0
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
fn _get_next(): U32 =>
|
|
43
|
+
try
|
|
44
|
+
repeat
|
|
45
|
+
_inc_pos()
|
|
46
|
+
let chr: (U32, U8) = _buf.utf32(_pos-1)?
|
|
47
|
+
cur = _next = chr._1
|
|
48
|
+
until not _is_space(cur) end
|
|
49
|
+
cur
|
|
50
|
+
else
|
|
51
|
+
cur = _next = 0
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
fn _expect(chr: U32, msg: String): Bool =>
|
|
56
|
+
if cur == chr then
|
|
57
|
+
_get_next()
|
|
58
|
+
true
|
|
59
|
+
else
|
|
60
|
+
_err(msg)
|
|
61
|
+
false
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
fn _inc_pos(i: ISize = 1) => _pos = _pos.add(i)
|
|
66
|
+
|
|
67
|
+
fn (p JsonParser) parse(): Json =
|
|
68
|
+
match parser.get_next()
|
|
69
|
+
'{' -> p.parseObject()
|
|
70
|
+
'[' -> p.parseList()
|
|
71
|
+
_ -> nil
|
|
72
|
+
|
|
73
|
+
fn (p JsonParser) parseObject(): Map[str, Json] =
|
|
74
|
+
object := Map[str, Json]()
|
|
75
|
+
p._get_next() // '{'
|
|
76
|
+
while true
|
|
77
|
+
if p.cur != '"'
|
|
78
|
+
p._err("JSON: Object: expected '\"'\n")
|
|
79
|
+
break
|
|
80
|
+
|
|
81
|
+
val_key := p.parse_string()
|
|
82
|
+
if !p._expect(':', "JSON: Object: expected ':'\n")
|
|
83
|
+
break
|
|
84
|
+
|
|
85
|
+
val_val := Json(nil)
|
|
86
|
+
when p.cur
|
|
87
|
+
'{' ->
|
|
88
|
+
val_val = parse_object(p)
|
|
89
|
+
p._expect('}', "JSON: Object: expected '}'\n")
|
|
90
|
+
'[' ->
|
|
91
|
+
val_val = parse_array(p)
|
|
92
|
+
p._expect(']', "JSON: Object: expected ']'\n")
|
|
93
|
+
'"' ->
|
|
94
|
+
val_val = p.parseString()
|
|
95
|
+
'n' ->
|
|
96
|
+
val_val = try p._get_n()? end // null?
|
|
97
|
+
't' ->
|
|
98
|
+
val_val = try p._get_t()? end // true?
|
|
99
|
+
'f' ->
|
|
100
|
+
val_val = try p._get_f()? end // false?
|
|
101
|
+
ch ->
|
|
102
|
+
if p._is_digit(ch) || ch == '.'
|
|
103
|
+
val_val = p.parseNum()
|
|
104
|
+
else
|
|
105
|
+
p._err("invalid value\n")
|
|
106
|
+
break
|
|
107
|
+
|
|
108
|
+
object.set(val_key, val_val)
|
|
109
|
+
if p.cur == '}'
|
|
110
|
+
break
|
|
111
|
+
if !p._expect(',', "JSON: Object: expected ','\n")
|
|
112
|
+
printLn("failed at: %s\n".cstring(), val_key.cstring())
|
|
113
|
+
object
|
|
114
|
+
|
|
115
|
+
fn (p: JsonParser) parseList(): List[Json] =
|
|
116
|
+
p._get_next() // '['
|
|
117
|
+
while true
|
|
118
|
+
when p.cur
|
|
119
|
+
'{' -> _values.push(JSONObject.create_with_parser(p)); p._expect('}', "JSON: Array: expected object delimiter\n")
|
|
120
|
+
'[' -> _values.push(JSONArray.create_with_parser(p)); p._expect(']', "JSON: Array: expected array delimiter\n")
|
|
121
|
+
'"' -> _values.push(p.parseString())
|
|
122
|
+
't' ->
|
|
123
|
+
t: Bool := p._get_t()?
|
|
124
|
+
_values.push(t)
|
|
125
|
+
'f' ->
|
|
126
|
+
f: Bool := p._get_f()?
|
|
127
|
+
_values.push(f)
|
|
128
|
+
'n' ->
|
|
129
|
+
n: None := p._get_n()?
|
|
130
|
+
_values.push(n)
|
|
131
|
+
_ ->
|
|
132
|
+
if p._is_digit(p.cur)
|
|
133
|
+
let n = p.parseNum()
|
|
134
|
+
_values.push(n)
|
|
135
|
+
|
|
136
|
+
if p.cur == ']'
|
|
137
|
+
break
|
|
138
|
+
if !p._expect(',', "JSON: Array: expected ','\n")
|
|
139
|
+
break
|
|
140
|
+
|
|
141
|
+
fn (p: Parser) parseUtf16(): int =
|
|
142
|
+
result := 0
|
|
143
|
+
count := 0
|
|
144
|
+
while count <= 4
|
|
145
|
+
p._get_next_raw()
|
|
146
|
+
if _is_digit(cur)
|
|
147
|
+
result = ((result << 4) or (cur - '0').i32())
|
|
148
|
+
else if (cur >= 'a') and (cur <= 'f')
|
|
149
|
+
result = ((result << 4) or ((cur - 'a').i32() + 10))
|
|
150
|
+
else if (cur >= 'A') and (cur <= 'F')
|
|
151
|
+
result = ((result << 4) or ((cur - 'A').i32() + 10))
|
|
152
|
+
count = count+1
|
|
153
|
+
result
|
|
154
|
+
|
|
155
|
+
fn (p: JsonParser) parseStr(): str =
|
|
156
|
+
result := ""
|
|
157
|
+
while true
|
|
158
|
+
p._get_next_raw()
|
|
159
|
+
match cur
|
|
160
|
+
0 -> _err("JSON: parseString: expected '\"'\n"); return ""
|
|
161
|
+
'"' -> _get_next(); break
|
|
162
|
+
'\\' ->
|
|
163
|
+
match _next
|
|
164
|
+
'\\' -> result.push('\\'); p._get_next_raw()
|
|
165
|
+
'"' -> result.push('"'); p._get_next_raw()
|
|
166
|
+
'\'' -> result.push('\''); p._get_next_raw()
|
|
167
|
+
'/' -> result.push('/'); p._get_next_raw()
|
|
168
|
+
'b' -> result.push('\b'); p._get_next_raw()
|
|
169
|
+
'f' -> result.push('\f'); p._get_next_raw()
|
|
170
|
+
'n' -> result.push('\n'); p._get_next_raw()
|
|
171
|
+
'r' -> result.push('\r'); p._get_next_raw()
|
|
172
|
+
't' -> result.push('\t'); p._get_next_raw()
|
|
173
|
+
'u' ->
|
|
174
|
+
_get_next_raw()
|
|
175
|
+
ures := p.parseUtf16()
|
|
176
|
+
if ures < 0
|
|
177
|
+
_err("invalid utf escape\n")
|
|
178
|
+
break
|
|
179
|
+
result.push_utf32(ures.u32())
|
|
180
|
+
_ ->
|
|
181
|
+
result.push_utf32(cur.u32())
|
|
182
|
+
result
|
|
183
|
+
|
|
184
|
+
fn (p: JsonParser) parseNum(): int | float =
|
|
185
|
+
result := ""
|
|
186
|
+
is_float := false
|
|
187
|
+
|
|
188
|
+
if cur == '-'
|
|
189
|
+
result.push('-')
|
|
190
|
+
_get_next_raw()
|
|
191
|
+
|
|
192
|
+
if cur == '.'
|
|
193
|
+
result.push('0')
|
|
194
|
+
result.push('.')
|
|
195
|
+
is_float = true
|
|
196
|
+
_get_next_raw()
|
|
197
|
+
else
|
|
198
|
+
while _is_digit(cur)
|
|
199
|
+
result.push(cur.u8())
|
|
200
|
+
_get_next_raw()
|
|
201
|
+
if cur == '.'
|
|
202
|
+
result.push('.')
|
|
203
|
+
_get_next_raw()
|
|
204
|
+
|
|
205
|
+
while _is_digit(cur)
|
|
206
|
+
result.push(cur.u8())
|
|
207
|
+
_get_next_raw()
|
|
208
|
+
|
|
209
|
+
is_exp := when cur
|
|
210
|
+
'e' ->
|
|
211
|
+
result.push('e'); _get_next_raw()
|
|
212
|
+
true
|
|
213
|
+
'E' ->
|
|
214
|
+
result.push('E'); _get_next_raw()
|
|
215
|
+
true
|
|
216
|
+
_ -> false
|
|
217
|
+
|
|
218
|
+
if is_exp
|
|
219
|
+
sign := when cur
|
|
220
|
+
'+' ->
|
|
221
|
+
result.push('+'); _get_next_raw()
|
|
222
|
+
true
|
|
223
|
+
'-' ->
|
|
224
|
+
result.push('-'); _get_next_raw()
|
|
225
|
+
true
|
|
226
|
+
_ -> false
|
|
227
|
+
if sign
|
|
228
|
+
while _is_digit(cur)
|
|
229
|
+
result.push(cur.u8())
|
|
230
|
+
_get_next_raw()
|
|
231
|
+
|
|
232
|
+
res := is_float ? result.f64() : result.i64()
|
|
233
|
+
if _is_space(cur)
|
|
234
|
+
_get_next() // skip to the next non-whitespace character
|
|
235
|
+
res
|
|
236
|
+
|
|
237
|
+
fn _get_n(): None? =>
|
|
238
|
+
_get_next_raw()
|
|
239
|
+
if cur == 'u' then
|
|
240
|
+
_get_nu()?
|
|
241
|
+
else
|
|
242
|
+
error
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
fn _get_nu(): None? =>
|
|
246
|
+
_get_next_raw()
|
|
247
|
+
if cur == 'l' then
|
|
248
|
+
_get_nul()?
|
|
249
|
+
else
|
|
250
|
+
error
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
fn _get_nul(): None? =>
|
|
254
|
+
_get_next_raw()
|
|
255
|
+
if cur == 'l' then
|
|
256
|
+
_get_next()
|
|
257
|
+
None
|
|
258
|
+
else
|
|
259
|
+
error
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
fn _get_t(): bool? =
|
|
263
|
+
_get_next_raw()
|
|
264
|
+
if cur == 'r' then
|
|
265
|
+
_get_tr()?
|
|
266
|
+
else
|
|
267
|
+
error
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
fn _get_tr(): bool? =
|
|
271
|
+
_get_next_raw()
|
|
272
|
+
if cur == 'u' then
|
|
273
|
+
_get_tru()?
|
|
274
|
+
else
|
|
275
|
+
error
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
fn _get_tru(): bool? =
|
|
279
|
+
_get_next_raw()
|
|
280
|
+
if cur == 'e' then
|
|
281
|
+
_get_next()
|
|
282
|
+
true
|
|
283
|
+
else
|
|
284
|
+
error
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
fn _get_f(): bool? =
|
|
288
|
+
_get_next_raw()
|
|
289
|
+
if cur == 'a' then
|
|
290
|
+
_get_fa()?
|
|
291
|
+
else
|
|
292
|
+
error
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
fn _get_fa(): bool? =
|
|
296
|
+
_get_next_raw()
|
|
297
|
+
if cur == 'l' then
|
|
298
|
+
_get_fal()?
|
|
299
|
+
else
|
|
300
|
+
error
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
fn _get_fal(): bool? =
|
|
304
|
+
_get_next_raw()
|
|
305
|
+
if cur == 's' then
|
|
306
|
+
_get_fals()?
|
|
307
|
+
else
|
|
308
|
+
error
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
fn _get_fals(): bool? =
|
|
312
|
+
_get_next_raw()
|
|
313
|
+
if cur == 'e' then
|
|
314
|
+
_get_next()
|
|
315
|
+
false
|
|
316
|
+
else
|
|
317
|
+
error
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
test("parse int") |t|
|
|
321
|
+
assert Json.parse("123") == 123
|
|
322
|
+
|
|
323
|
+
test("parse str") |t|
|
|
324
|
+
assert Json.parse(`"hello"`) == "hello"
|
|
325
|
+
|
|
326
|
+
test("parse bool") |t|
|
|
327
|
+
assert Json.parse("true") == true
|
|
328
|
+
assert Json.parse("false") == false
|
|
329
|
+
|
|
330
|
+
test("parse null") |t|
|
|
331
|
+
assert Json.parse("null") == nil
|
|
332
|
+
|
|
333
|
+
test("parse array") |t|
|
|
334
|
+
assert Json.parse(`[]`) == List[Json]()
|
|
335
|
+
assert Json.parse(`[1, 2]`) == List.of[Json](1, 2)
|
|
336
|
+
|
|
337
|
+
test("parse object") |t|
|
|
338
|
+
assert Json.parse(`{}`) == Map[str, Json]()
|
|
339
|
+
assert Json.parse(`{"a": 1, "b": 2}`) == Map.of[str, Json]("a" => 1, "b" => 2)p-
|
std/list.mi
CHANGED
|
@@ -82,6 +82,15 @@ fn (l: list) contains(v: V): bool =
|
|
|
82
82
|
`returns the index of an item in the list if present and comparable otherwise nil
|
|
83
83
|
pass
|
|
84
84
|
|
|
85
|
+
fn (l: list[T]) op_range(yld: fn(v: T): bool): bool =
|
|
86
|
+
`range over func for a list
|
|
87
|
+
current := l.head
|
|
88
|
+
while current != nil
|
|
89
|
+
if !yld(current.value)
|
|
90
|
+
return false
|
|
91
|
+
current = current.next
|
|
92
|
+
true
|
|
93
|
+
|
|
85
94
|
fn (l: list) op_spread(other: list): list[A] =
|
|
86
95
|
`combines this list with other list and returns a new list
|
|
87
96
|
pass
|
std/map.mi
CHANGED
|
@@ -4,25 +4,34 @@ record Pair[K: Comparable, V](k: K, v: V)
|
|
|
4
4
|
|
|
5
5
|
`A slice is a data structure describing a contiguous section of an array stored separately from the slice variable itself.
|
|
6
6
|
`A slice is not an array. A slice describes a piece of an array.
|
|
7
|
-
record
|
|
7
|
+
record Map[K, V](
|
|
8
8
|
items: list[Pair[K, V]]
|
|
9
9
|
)
|
|
10
10
|
|
|
11
|
-
fn
|
|
11
|
+
fn Map.of[K, V](kvs: ...Pair[K, V]): map[K, V] =
|
|
12
12
|
map[K, V]().add(kvs)
|
|
13
13
|
|
|
14
|
-
fn (m:
|
|
14
|
+
fn (m: Map) add(kvs: ...Pair[K, V]) =
|
|
15
15
|
`adds the specified elements to the start of the list
|
|
16
|
-
items.add(
|
|
16
|
+
items.add(kvs)
|
|
17
17
|
|
|
18
|
+
fn (m: Map[K, V]) op_range(yld: fn(k: K, v: V): bool): bool =
|
|
18
|
-
|
|
19
|
+
for item := range items
|
|
19
|
-
|
|
20
|
+
if !yld(item.k, item.v)
|
|
21
|
+
false
|
|
22
|
+
true
|
|
20
23
|
|
|
21
|
-
fn (m: Map)
|
|
24
|
+
fn (m: Map[K, V]) get(k K): V? =
|
|
25
|
+
for k, v := range m
|
|
26
|
+
if k == k
|
|
27
|
+
return v
|
|
22
|
-
|
|
28
|
+
nil
|
|
23
29
|
|
|
30
|
+
fn (m: Map) put(k K, v V) =
|
|
31
|
+
list.add(Pair(k, v))
|
|
32
|
+
|
|
24
|
-
fn (m: Map) put_if() =
|
|
33
|
+
fn (m: Map) put_if(k K, v V) =
|
|
25
|
-
|
|
34
|
+
if
|
|
26
35
|
|
|
27
36
|
fn (m: Map) update() =
|
|
28
37
|
pass
|
std/math.mi
CHANGED
|
@@ -1,38 +1,64 @@
|
|
|
1
1
|
module math
|
|
2
2
|
|
|
3
3
|
`Euler's number, the base of natural logarithms, e
|
|
4
|
+
`https://oeis.org/A001113
|
|
4
5
|
const E = 2.718f
|
|
5
6
|
|
|
6
7
|
`The natural logarithm of 10
|
|
8
|
+
`https://oeis.org/A002392
|
|
7
9
|
const LN10 = 2.302f
|
|
8
10
|
|
|
9
11
|
`The natural logarithm of 2
|
|
12
|
+
`https://oeis.org/A002162
|
|
10
13
|
const LN2 = 0.693f
|
|
11
14
|
|
|
12
15
|
`The base 10 logarithm of e
|
|
16
|
+
`formula: 1 / LN10
|
|
13
17
|
const LOG10E = 0.434f
|
|
14
18
|
|
|
15
19
|
`The base 2 logarithm of e
|
|
20
|
+
`formula: 1 / LN2
|
|
16
21
|
const LOG2E = 1.442f
|
|
17
22
|
|
|
18
23
|
`The ratio of the circumference of a circle to its diameter
|
|
24
|
+
`https://oeis.org/A000796
|
|
19
25
|
const PI = 3.14159f
|
|
20
26
|
|
|
27
|
+
`https://oeis.org/A001622
|
|
28
|
+
const PHI = 1.6180f
|
|
29
|
+
|
|
21
30
|
`The square root of 1/2
|
|
22
31
|
const SQRT1_2 = 0.707f
|
|
23
32
|
|
|
24
33
|
`The square root of 2
|
|
34
|
+
`https://oeis.org/A002193
|
|
25
35
|
const SQRT2 = 1.414f
|
|
26
36
|
|
|
37
|
+
`https://oeis.org/A019774
|
|
38
|
+
const SQRT_E = 1.64872f
|
|
39
|
+
|
|
40
|
+
`https://oeis.org/A002161
|
|
41
|
+
const SQRT_PI = 1.77245f
|
|
42
|
+
|
|
43
|
+
`https://oeis.org/A139339
|
|
44
|
+
const SQRT_PHI = 1.27201f
|
|
45
|
+
|
|
27
46
|
`The difference between 1 and the smallest floating point number greater than 1
|
|
47
|
+
`formula: 7/3 - 4/3 - 1
|
|
28
48
|
const EPSILON = 2.220446049250313e-16f
|
|
29
49
|
|
|
30
|
-
`Lowest
|
|
50
|
+
`Lowest value of int
|
|
31
51
|
const MIN_INT_VALUE = -0x8000_0000_0000_0000
|
|
32
52
|
|
|
33
|
-
`Highest
|
|
53
|
+
`Highest value of int
|
|
34
54
|
const MAX_INT_VALUE = 0x7FFF_FFFF_FFFF_FFFF
|
|
35
55
|
|
|
56
|
+
`Lowest valur of float
|
|
57
|
+
const MIN_FLOAT_VALUE = 4.9406564584124654417656879286822137236505980e-324
|
|
58
|
+
|
|
59
|
+
`Highest valur of float
|
|
60
|
+
const MAX_FLOAT_VALUE = 1.79769313486231570814527423731704356798070e+308
|
|
61
|
+
|
|
36
62
|
fn abs(v: float): float =
|
|
37
63
|
`returns the absolute value of a number v
|
|
38
64
|
a < 0 ? -a : a
|
|
@@ -44,7 +70,25 @@ fn acos(v: float) =
|
|
|
44
70
|
asin(-1v)
|
|
45
71
|
|
|
46
72
|
|
|
73
|
+
`2**28
|
|
74
|
+
const LARGE = 1 << 28
|
|
47
|
-
fn acosh(v: float)
|
|
75
|
+
fn acosh(v: float): float =
|
|
76
|
+
when
|
|
77
|
+
x < 1 | IsNaN(x) -> // first case is special case
|
|
78
|
+
NaN()
|
|
79
|
+
x == 1 ->
|
|
80
|
+
0
|
|
81
|
+
x >= Large ->
|
|
82
|
+
Log(x) + Ln2 // x > 2**28
|
|
83
|
+
x > 2 ->
|
|
84
|
+
Log(2*x - 1/(x+Sqrt(x*x-1))) // 2**28 > x > 2
|
|
85
|
+
_ ->
|
|
86
|
+
t := x - 1
|
|
87
|
+
// ((2*t+t*t).sqrt() + t).log1p()
|
|
88
|
+
Log1p(t + Sqrt(2*t+t*t)) // 2 >= x > 1
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
48
92
|
fn asin(v: float) = 0f
|
|
49
93
|
fn asinh(v: float) = 0f
|
|
50
94
|
fn atan(v: float) = 0f
|
std/result.mi
CHANGED
|
@@ -2,44 +2,44 @@ module std
|
|
|
2
2
|
|
|
3
3
|
`result is a type that represents either success ok or failure err.
|
|
4
4
|
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
|
5
|
-
enum result[T
|
|
5
|
+
enum result[T]
|
|
6
6
|
| ok(T)
|
|
7
|
-
| err(
|
|
7
|
+
| err(error)
|
|
8
8
|
|
|
9
|
-
fn (
|
|
9
|
+
fn (r result) is_ok(): bool =
|
|
10
10
|
match o
|
|
11
11
|
ok(v) -> return true
|
|
12
12
|
err(e) -> return false
|
|
13
13
|
|
|
14
|
-
fn (
|
|
14
|
+
fn (r result) is_err(): bool =
|
|
15
15
|
!o.is_ok()
|
|
16
16
|
|
|
17
|
-
fn (
|
|
17
|
+
fn (r result[T, E]) ok(): option[T] =
|
|
18
18
|
match o
|
|
19
19
|
ok(v) -> some(v)
|
|
20
20
|
err(e) -> none
|
|
21
21
|
|
|
22
|
-
fn (
|
|
22
|
+
fn (r result[T, E]) err(): option[E] =
|
|
23
23
|
match o
|
|
24
24
|
ok(v) -> none
|
|
25
25
|
err(e) -> some(v)
|
|
26
26
|
|
|
27
|
-
fn (
|
|
27
|
+
fn (r result) get(): T =
|
|
28
28
|
match o
|
|
29
29
|
ok(v) -> v
|
|
30
30
|
err(e) -> panic("called `result.get()` on a `none` value")
|
|
31
31
|
|
|
32
|
-
fn (
|
|
32
|
+
fn (r result) default(d: T): T =
|
|
33
33
|
match o
|
|
34
34
|
ok(v) -> v
|
|
35
35
|
err(e) -> d
|
|
36
36
|
|
|
37
|
-
fn (
|
|
37
|
+
fn (r result) map(cb: fn(v: T)): result =
|
|
38
38
|
match o
|
|
39
39
|
ok(v) -> cb(v)
|
|
40
40
|
err(e) -> unreachable
|
|
41
41
|
|
|
42
|
-
fn (
|
|
42
|
+
fn (r result) map_err(cb: fn(e: E)): result =
|
|
43
43
|
match o
|
|
44
44
|
ok(v) -> unreachable
|
|
45
45
|
err(e) -> cb(v)
|