~repos /plum
git clone https://pyrossh.dev/repos/plum.git
A statically typed, imperative programming language inspired by rust, python
66f4a645
—
pyrossh 1 year ago
improve
- readme.md +81 -15
- std/bool.mi +39 -9
- std/coding/base64.mi +170 -0
- std/http.mi +5 -5
- std/map.mi +12 -0
- std/math.mi +39 -27
- std/option.mi +43 -0
- std/ranges.mi +65 -8
- std/result.mi +123 -0
- std/str.mi +60 -62
readme.md
CHANGED
|
@@ -1,34 +1,42 @@
|
|
|
1
1
|
# 👾 Pacos Programming Language
|
|
2
2
|
|
|
3
|
-
A
|
|
3
|
+
* A statically typed, functional programming language inspired by rust, koka.
|
|
4
|
+
* The compiler users the tree-sitter parser so has out of the box syntax highlighting support for helix and zed editor.
|
|
5
|
+
|
|
6
|
+
**Rules**
|
|
7
|
+
* Function parameters are passed by value only. You cannot modify a parameter. The compiler will throw an error if you try to.
|
|
8
|
+
* Strict naming convention
|
|
9
|
+
* Only one way of doing things ex: loops, condition
|
|
10
|
+
|
|
11
|
+
**Todo**
|
|
12
|
+
linter, formatter, test runner, language server, package manager
|
|
4
13
|
|
|
5
|
-
The compiler users the tree-sitter parser so has out of the box syntax highlighting support for helix and zed editor.
|
|
6
14
|
|
|
7
15
|
Here is some sample code, please enjoy.
|
|
8
16
|
|
|
9
|
-
```
|
|
17
|
+
```go
|
|
10
18
|
module lambda
|
|
11
19
|
|
|
12
20
|
import pacos/list
|
|
13
21
|
import pacos/math
|
|
14
22
|
import pacos/http
|
|
15
23
|
|
|
16
|
-
START_YEAR = 2101
|
|
24
|
+
const START_YEAR = 2101
|
|
17
|
-
END_YEAR = 2111
|
|
25
|
+
const END_YEAR = 2111
|
|
18
|
-
NAME = "Gleam"
|
|
26
|
+
const NAME = "Gleam"
|
|
19
|
-
SIZE = 100
|
|
27
|
+
const SIZE = 100
|
|
20
28
|
|
|
21
29
|
fn sum(a: int, b: int): int = a + b
|
|
22
30
|
|
|
23
31
|
fn sum_all(series: list[int]): int =
|
|
24
32
|
series.reduce(0, |v| v + 1)
|
|
25
33
|
|
|
26
|
-
fn fib(n: int)
|
|
34
|
+
fn fib(n: int): int =
|
|
27
35
|
match n
|
|
28
36
|
0 | 1 -> n
|
|
29
37
|
_ -> fib(n - 1) + fib(n - 2)
|
|
30
38
|
|
|
31
|
-
fn fib(n: int)
|
|
39
|
+
fn fib(n: int): int =
|
|
32
40
|
if n == 0 || n == 1
|
|
33
41
|
n
|
|
34
42
|
else
|
|
@@ -120,13 +128,13 @@ bench("1231") |n|
|
|
|
120
128
|
**Keywords**
|
|
121
129
|
|
|
122
130
|
```rs
|
|
123
|
-
for,while,if,else,record,enum,fn,assert,
|
|
131
|
+
for,while,if,else,record,enum,fn,assert,match,type
|
|
124
132
|
```
|
|
125
133
|
|
|
126
134
|
### Types
|
|
127
135
|
|
|
128
136
|
```
|
|
129
|
-
nil, any, bool, byte, int, float, dec, str, time, duration, regex, uuid
|
|
137
|
+
nil, any, err, bool, byte, int, float, dec, str, time, duration, regex, uuid
|
|
130
138
|
[1, 2, 3] for lists list[int], list[list[int]]
|
|
131
139
|
[:a => 1, :b => 2] for maps map[int], map[map[int]]
|
|
132
140
|
? for optional int? str?
|
|
@@ -199,10 +207,11 @@ println("Name ${name} age ${age}")
|
|
|
199
207
|
```py
|
|
200
208
|
import pacos/list
|
|
201
209
|
|
|
202
|
-
a :=
|
|
210
|
+
a := list.of(1, 2, 3) # list[int]
|
|
203
|
-
b :=
|
|
211
|
+
b := list.of(list.of(1), list.of(2), list.of(3)) # list[list[int]]
|
|
212
|
+
c := list.of(1, 2, 3 * 4, 8, n)
|
|
204
213
|
|
|
205
|
-
actors :=
|
|
214
|
+
actors := list.of("Krabs", "Squidward")
|
|
206
215
|
actors.add("Spongebob")
|
|
207
216
|
actors.length() // ==> 3
|
|
208
217
|
actors.contains("Krabs") // ==> true
|
|
@@ -374,6 +383,44 @@ match xs
|
|
|
374
383
|
[a] -> "This list has 1 element"
|
|
375
384
|
[a, b] -> "This list has 2 elements"
|
|
376
385
|
_ -> "This list has more than 2 elements"
|
|
386
|
+
|
|
387
|
+
enum Option<T> =
|
|
388
|
+
| None
|
|
389
|
+
| Some(T)
|
|
390
|
+
|
|
391
|
+
record Car(wheels: int)
|
|
392
|
+
|
|
393
|
+
fn getWheels() =
|
|
394
|
+
returns 4
|
|
395
|
+
|
|
396
|
+
fn main() =
|
|
397
|
+
let c1 = some(Car(wheels: 2))
|
|
398
|
+
let c2: option<Car> = none
|
|
399
|
+
|
|
400
|
+
let c1 = Some(Car(wheels: 2))
|
|
401
|
+
let c2: Option<Car> = None
|
|
402
|
+
|
|
403
|
+
match c
|
|
404
|
+
none -> print("no car")
|
|
405
|
+
some(car) -> car.getWheels()
|
|
406
|
+
|
|
407
|
+
Car c2 = null
|
|
408
|
+
c2.getWheels() // Null pointer
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
match c
|
|
412
|
+
none -> print("no car")
|
|
413
|
+
some(car) -> car.getWheels()
|
|
414
|
+
|
|
415
|
+
fn (o option[T]) unwrap(): T =
|
|
416
|
+
match o
|
|
417
|
+
some(val) -> val
|
|
418
|
+
none -> fail("called `option.unwrap()` on a `none` value")
|
|
419
|
+
|
|
420
|
+
fn (o option[T: ToStr]) display(): T =
|
|
421
|
+
match o
|
|
422
|
+
some(v) -> v.to_str()
|
|
423
|
+
none -> "none"
|
|
377
424
|
```
|
|
378
425
|
|
|
379
426
|
Arithmetic (+, -, /, \*, @divFloor, @sqrt, @ceil, @log, etc.)
|
|
@@ -464,7 +511,7 @@ fn add[T: int | float](a: List[T], b: List[T]): List[T] =
|
|
|
464
511
|
```
|
|
465
512
|
|
|
466
513
|
```
|
|
467
|
-
fn create_post_action(req: Request): Response =
|
|
514
|
+
fn create_post_action(req: Request): Result[Response] =
|
|
468
515
|
post := Post(title = req.params.title, body = req.params.body)
|
|
469
516
|
if post.valid()
|
|
470
517
|
RenderNewView()
|
|
@@ -472,8 +519,27 @@ fn create_post_action(req: Request): Response =
|
|
|
472
519
|
post := createRecord(post)
|
|
473
520
|
setSuccessMessage("Post created")
|
|
474
521
|
redirectTo("/posts")
|
|
522
|
+
|
|
523
|
+
fn divide(dividend: u32, divisor: u32) !u32 =
|
|
524
|
+
if divisor == 0
|
|
525
|
+
error.DivideByZero
|
|
526
|
+
else
|
|
527
|
+
dividend / divisor
|
|
528
|
+
dispatch(action, req, res) catch |err|
|
|
529
|
+
BodyTooBig -> Response(
|
|
530
|
+
status: 431,
|
|
531
|
+
body: "Request body is too big",
|
|
532
|
+
)
|
|
533
|
+
BrokenPipe, ConnectionResetByPeer -> return false
|
|
534
|
+
_ -> error_handler(req, res, err)
|
|
475
535
|
```
|
|
476
536
|
|
|
537
|
+
### Error handling
|
|
538
|
+
|
|
539
|
+
> Exceptions are used as both a way to model extra “return values” of functions and as a failure handling mechanism, leading them to be lousy at both. Exceptions suck. Thats why we don't have exceptions. - Sir Whinesalot
|
|
540
|
+
|
|
541
|
+
We have mutiple return values to solve this similar to golang. And failures/panic need to exit/restart the app.
|
|
542
|
+
|
|
477
543
|
### General naming convention
|
|
478
544
|
|
|
479
545
|
| Item | Convention |
|
std/bool.mi
CHANGED
|
@@ -1,11 +1,41 @@
|
|
|
1
1
|
module std
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
enum bool =
|
|
4
|
+
| true
|
|
4
|
-
|
|
5
|
+
| false
|
|
6
|
+
|
|
5
|
-
|
|
7
|
+
fn (x: bool) op_ne(y: bool) = x != y
|
|
6
|
-
|
|
8
|
+
fn (x: bool) op_and(y: bool) = x == false || y == false ? false : true
|
|
7
|
-
|
|
9
|
+
fn (x: bool) op_or(y: bool) = x == true || y == true ? true : false
|
|
8
|
-
|
|
10
|
+
fn (x: bool) op_not(): bool = x == true ? false : true
|
|
9
|
-
|
|
10
|
-
#[ToStr]
|
|
11
|
-
|
|
11
|
+
fn (x: bool) to_str() = x ? "true" : "false"
|
|
12
|
+
|
|
13
|
+
trait Iterator(
|
|
14
|
+
fun has_next(): Bool
|
|
15
|
+
fun next(): T?
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
trait HasEq[A](
|
|
19
|
+
fn eq(that: a): bool
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
trait Equatable[A]
|
|
23
|
+
`A trait that defines equal and not equal operations
|
|
24
|
+
|
|
25
|
+
fn eq(b: Equatable[A]): bool
|
|
26
|
+
fn ne(b: Equatable[A]): bool
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
enum Compare
|
|
30
|
+
| Less
|
|
31
|
+
| Equal
|
|
32
|
+
| Greater
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
trait Comparable[A] is Equatable[A]
|
|
36
|
+
fn lt(that: A): bool
|
|
37
|
+
fn le(that: A): bool
|
|
38
|
+
fn ge(that: A): bool
|
|
39
|
+
fn gt(that: A): bool
|
|
40
|
+
fn compare(that: a): Compare
|
|
41
|
+
end
|
std/coding/base64.mi
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
module base64
|
|
2
|
+
|
|
3
|
+
import std/collections
|
|
4
|
+
import std/testing/assert
|
|
5
|
+
|
|
6
|
+
fun encode_pem(data: ReadSeq[U8]): str =
|
|
7
|
+
`Encode for PEM (RFC 1421)
|
|
8
|
+
encode(data, '+', '/', '=', 64)
|
|
9
|
+
|
|
10
|
+
fun encode_mime(data: ReadSeq[U8]): str =
|
|
11
|
+
`Encode for MIME (RFC 2045)
|
|
12
|
+
encode(data, '+', '/', '=', 76)
|
|
13
|
+
|
|
14
|
+
fun encode_url[A: Seq[U8]](data: ReadSeq[U8], pad: Bool = false): A =
|
|
15
|
+
`Encode for URLs (RFC 4648). Padding characters are stripped by default
|
|
16
|
+
c := pad ? '=' else 0
|
|
17
|
+
encode[A](data, '-', '_', c)
|
|
18
|
+
|
|
19
|
+
fun encode[A: Seq[U8]](data: ReadSeq[U8], at62: U8 = '+', at63: U8 = '/', pad: U8 = '=', linelen: USize = 0, linesep: str = "\r\n"): A =
|
|
20
|
+
`Configurable encoding. The defaults are for RFC 4648.
|
|
21
|
+
len := ((data.size() + 2) / 3) * 4
|
|
22
|
+
out := recover A(len) end
|
|
23
|
+
lineblocks := linelen / 4
|
|
24
|
+
|
|
25
|
+
srclen := data.size()
|
|
26
|
+
blocks := USize(0)
|
|
27
|
+
i := USize(0)
|
|
28
|
+
|
|
29
|
+
try
|
|
30
|
+
while srclen >= 3 do
|
|
31
|
+
let in1 = data(i)?
|
|
32
|
+
let in2 = data(i + 1)?
|
|
33
|
+
let in3 = data(i + 2)?
|
|
34
|
+
|
|
35
|
+
let out1 = in1 >> 2
|
|
36
|
+
let out2 = ((in1 and 0x03) << 4) + (in2 >> 4)
|
|
37
|
+
let out3 = ((in2 and 0x0f) << 2) + (in3 >> 6)
|
|
38
|
+
let out4 = in3 and 0x3f
|
|
39
|
+
|
|
40
|
+
out.push(_enc_byte(out1, at62, at63)?)
|
|
41
|
+
out.push(_enc_byte(out2, at62, at63)?)
|
|
42
|
+
out.push(_enc_byte(out3, at62, at63)?)
|
|
43
|
+
out.push(_enc_byte(out4, at62, at63)?)
|
|
44
|
+
|
|
45
|
+
i = i + 3
|
|
46
|
+
blocks = blocks + 1
|
|
47
|
+
srclen = srclen - 3
|
|
48
|
+
|
|
49
|
+
if (lineblocks > 0) and (blocks == lineblocks) then
|
|
50
|
+
out.append(linesep)
|
|
51
|
+
blocks = 0
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
if srclen >= 1 then
|
|
56
|
+
let in1 = data(i)?
|
|
57
|
+
let in2 = if srclen == 2 then data(i + 1)? else 0 end
|
|
58
|
+
|
|
59
|
+
let out1 = in1 >> 2
|
|
60
|
+
let out2 = ((in1 and 0x03) << 4) + (in2 >> 4)
|
|
61
|
+
let out3 = (in2 and 0x0f) << 2
|
|
62
|
+
|
|
63
|
+
out.push(_enc_byte(out1, at62, at63)?)
|
|
64
|
+
out.push(_enc_byte(out2, at62, at63)?)
|
|
65
|
+
|
|
66
|
+
if srclen == 2 then
|
|
67
|
+
out.push(_enc_byte(out3, at62, at63)?)
|
|
68
|
+
else
|
|
69
|
+
out.push(pad)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
out.push(pad)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
if lineblocks > 0 then
|
|
76
|
+
out.append(linesep)
|
|
77
|
+
end
|
|
78
|
+
else
|
|
79
|
+
out.clear()
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
out
|
|
83
|
+
|
|
84
|
+
fun decode_url[A: Seq[U8] iso = Array[U8] iso](data: ReadSeq[U8]): A^ ? =>
|
|
85
|
+
"""
|
|
86
|
+
Decode for URLs (RFC 4648).
|
|
87
|
+
"""
|
|
88
|
+
decode[A](data, '-', '_')?
|
|
89
|
+
|
|
90
|
+
fun decode[A: Seq[U8] iso = Array[U8] iso](
|
|
91
|
+
data: ReadSeq[U8],
|
|
92
|
+
at62: U8 = '+',
|
|
93
|
+
at63: U8 = '/',
|
|
94
|
+
pad: U8 = '=')
|
|
95
|
+
: A^ ?
|
|
96
|
+
=>
|
|
97
|
+
"""
|
|
98
|
+
Configurable decoding. The defaults are for RFC 4648. Missing padding is
|
|
99
|
+
not an error. Non-base64 data, other than whitespace (which can appear at
|
|
100
|
+
any time), is an error.
|
|
101
|
+
"""
|
|
102
|
+
let len = (data.size() * 4) / 3
|
|
103
|
+
let out = recover A(len) end
|
|
104
|
+
|
|
105
|
+
var state = U8(0)
|
|
106
|
+
var input = U8(0)
|
|
107
|
+
var output = U8(0)
|
|
108
|
+
|
|
109
|
+
for i in Range(0, data.size()) do
|
|
110
|
+
input = data(i)?
|
|
111
|
+
|
|
112
|
+
let value =
|
|
113
|
+
match input
|
|
114
|
+
| ' ' | '\t' | '\r' | '\n' => continue
|
|
115
|
+
| pad => break
|
|
116
|
+
| at62 => 62
|
|
117
|
+
| at63 => 63
|
|
118
|
+
| if (input >= 'A') and (input <= 'Z') =>
|
|
119
|
+
(input - 'A')
|
|
120
|
+
| if (input >= 'a') and (input <= 'z') =>
|
|
121
|
+
((input - 'a') + 26)
|
|
122
|
+
| if (input >= '0') and (input <= '9') =>
|
|
123
|
+
((input - '0') + 52)
|
|
124
|
+
else
|
|
125
|
+
error
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
match state
|
|
129
|
+
| 0 =>
|
|
130
|
+
output = value << 2
|
|
131
|
+
state = 1
|
|
132
|
+
| 1 =>
|
|
133
|
+
out.push(output or (value >> 4))
|
|
134
|
+
output = (value and 0x0f) << 4
|
|
135
|
+
state = 2
|
|
136
|
+
| 2 =>
|
|
137
|
+
out.push(output or (value >> 2))
|
|
138
|
+
output = (value and 0x03) << 6
|
|
139
|
+
state = 3
|
|
140
|
+
| 3 =>
|
|
141
|
+
out.push(output or value)
|
|
142
|
+
state = 0
|
|
143
|
+
else
|
|
144
|
+
error
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
if output != 0 then
|
|
149
|
+
Fact(input != pad)?
|
|
150
|
+
|
|
151
|
+
match state
|
|
152
|
+
| 1 | 2 => out.push(output)
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
out
|
|
157
|
+
|
|
158
|
+
fun _enc_byte(i: U8, at62: U8, at63: U8): U8 ? =>
|
|
159
|
+
"""
|
|
160
|
+
Encode a single byte.
|
|
161
|
+
"""
|
|
162
|
+
match i
|
|
163
|
+
| 62 => at62
|
|
164
|
+
| 63 => at63
|
|
165
|
+
| if i < 26 => 'A' + i
|
|
166
|
+
| if i < 52 => ('a' - 26) + i
|
|
167
|
+
| if i < 62 => ('0' - 52) + i
|
|
168
|
+
else
|
|
169
|
+
error
|
|
170
|
+
end
|
std/http.mi
CHANGED
|
@@ -2,17 +2,17 @@ import std/path
|
|
|
2
2
|
import std/os
|
|
3
3
|
import http/content_type
|
|
4
4
|
|
|
5
|
-
fn file_response(file: str) =
|
|
5
|
+
fn file_response(file: str): Response! =
|
|
6
6
|
ext := path::ext(file)
|
|
7
7
|
content := content_type::from_ext(ext)
|
|
8
8
|
data := try os.read_file(file)
|
|
9
9
|
Response(
|
|
10
|
-
status
|
|
10
|
+
status: 200,
|
|
11
|
-
headers
|
|
11
|
+
headers: map.of(
|
|
12
12
|
"Content-Type" => content,
|
|
13
13
|
"Content-Length" => "2"
|
|
14
|
-
|
|
14
|
+
),
|
|
15
|
-
body
|
|
15
|
+
body: data
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
Response()
|
std/map.mi
CHANGED
|
@@ -17,3 +17,15 @@ fn (m: map) add(kvs: ...Pair[K, V]) =
|
|
|
17
17
|
|
|
18
18
|
fn (m: Map) op_range() =
|
|
19
19
|
yield k, v
|
|
20
|
+
|
|
21
|
+
fn (m: Map) put() =
|
|
22
|
+
pass
|
|
23
|
+
|
|
24
|
+
fn (m: Map) put_if() =
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
fn (m: Map) update() =
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
fn (m: Map) update_if() =
|
|
31
|
+
pass
|
std/math.mi
CHANGED
|
@@ -1,23 +1,41 @@
|
|
|
1
1
|
module math
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`Euler's number, the base of natural logarithms, e
|
|
4
|
+
const E = 2.718f
|
|
5
|
+
|
|
4
|
-
|
|
6
|
+
`The natural logarithm of 10
|
|
7
|
+
const LN10 = 2.302f
|
|
8
|
+
|
|
5
|
-
|
|
9
|
+
`The natural logarithm of 2
|
|
10
|
+
const LN2 = 0.693f
|
|
11
|
+
|
|
6
|
-
|
|
12
|
+
`The base 10 logarithm of e
|
|
13
|
+
const LOG10E = 0.434f
|
|
14
|
+
|
|
7
|
-
|
|
15
|
+
`The base 2 logarithm of e
|
|
16
|
+
const LOG2E = 1.442f
|
|
17
|
+
|
|
8
|
-
|
|
18
|
+
`The ratio of the circumference of a circle to its diameter
|
|
19
|
+
const PI = 3.14159f
|
|
20
|
+
|
|
9
|
-
|
|
21
|
+
`The square root of 1/2
|
|
22
|
+
const SQRT1_2 = 0.707f
|
|
23
|
+
|
|
10
|
-
|
|
24
|
+
`The square root of 2
|
|
25
|
+
const SQRT2 = 1.414f
|
|
26
|
+
|
|
11
|
-
|
|
27
|
+
`The difference between 1 and the smallest floating point number greater than 1
|
|
12
|
-
|
|
28
|
+
const EPSILON = 2.220446049250313e-16f
|
|
13
|
-
|
|
29
|
+
|
|
14
|
-
MIN_SAFE_INTEGER
|
|
15
|
-
MIN_VALUE
|
|
16
|
-
|
|
30
|
+
`Lowest valur of i64
|
|
31
|
+
const MIN_INT_VALUE = -0x8000_0000_0000_0000
|
|
32
|
+
|
|
17
|
-
|
|
33
|
+
`Highest valur of i64
|
|
18
|
-
|
|
34
|
+
const MAX_INT_VALUE = 0x7FFF_FFFF_FFFF_FFFF
|
|
35
|
+
|
|
36
|
+
fn abs(v: float): float =
|
|
19
|
-
|
|
37
|
+
`returns the absolute value of a number v
|
|
20
|
-
|
|
38
|
+
a < 0 ? -a : a
|
|
21
39
|
|
|
22
40
|
fn acos(v: float) =
|
|
23
41
|
if v < 0.1
|
|
@@ -47,11 +65,10 @@ fn random(): float =
|
|
|
47
65
|
fn is_int(): bool =
|
|
48
66
|
pass
|
|
49
67
|
|
|
50
|
-
|
|
51
|
-
// Check whether this number is finite, ie not +/-infinity and not NaN.
|
|
52
68
|
fn is_finite(): bool = true
|
|
69
|
+
` Check whether this number is finite, ie not +/-infinity and not NaN.
|
|
53
|
-
|
|
70
|
+
` True if exponent is not all 1s
|
|
54
|
-
|
|
71
|
+
(bits() and 0x7FF0_0000_0000_0000) != 0x7FF0_0000_0000_0000
|
|
55
72
|
|
|
56
73
|
// Check whether this number is +/-infinity
|
|
57
74
|
is_infinite: Bool =>
|
|
@@ -98,11 +115,6 @@ fun sqrt(): F64 =>
|
|
|
98
115
|
@"llvm.sqrt.f64"(this)
|
|
99
116
|
end
|
|
100
117
|
|
|
101
|
-
MIN_INT_VALUE = 0
|
|
102
|
-
MAX_INT_VALUE = 0xFFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF_FFFF
|
|
103
|
-
|
|
104
|
-
fn min_value() => -0x8000_0000_0000_0000
|
|
105
|
-
fn max_value() => 0x7FFF_FFFF_FFFF_FFFF
|
|
106
118
|
fn abs(a: int): int => a < 0 ? -a : a
|
|
107
119
|
fn to_str(v: int): str = ""
|
|
108
120
|
|
std/option.mi
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
module std
|
|
2
|
+
|
|
3
|
+
enum option[T] =
|
|
4
|
+
| none
|
|
5
|
+
| some(T)
|
|
6
|
+
|
|
7
|
+
fn (o Option[T]) unwrap(): T =
|
|
8
|
+
match o
|
|
9
|
+
some(val) -> val
|
|
10
|
+
none -> fail("called `option.unwrap()` on a `none` value")
|
|
11
|
+
|
|
12
|
+
fn (o option[T: ToStr]) display(): T =
|
|
13
|
+
match o
|
|
14
|
+
some(v) -> v.to_str()
|
|
15
|
+
none -> "none"
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
enum list<T> =
|
|
19
|
+
| empty
|
|
20
|
+
| link(v: T, rest: list<T>)
|
|
21
|
+
|
|
22
|
+
fn list.of[A](values: ...A): list[A] =
|
|
23
|
+
list[A]().add(values)
|
|
24
|
+
|
|
25
|
+
fn (o list<T>) each(cb: fn(v: T)) =
|
|
26
|
+
match o
|
|
27
|
+
empty -> return
|
|
28
|
+
link(a, rest) ->
|
|
29
|
+
cb(a)
|
|
30
|
+
rest.each(cb)
|
|
31
|
+
|
|
32
|
+
fn (l: list) append(values: ...V) =
|
|
33
|
+
`adds the specified elements to the start of the list
|
|
34
|
+
range(values) |v|
|
|
35
|
+
l.add(v)
|
|
36
|
+
|
|
37
|
+
fn (l: list) append(v: V) =
|
|
38
|
+
`adds the specified elements to the start of the list
|
|
39
|
+
l.last().rest = link(v, empty)
|
|
40
|
+
|
|
41
|
+
fn (l: list) prepend(v: V) =
|
|
42
|
+
`adds the specified elements to the start of the list
|
|
43
|
+
l.first() = link(v, l.first())
|
std/ranges.mi
CHANGED
|
@@ -1,18 +1,75 @@
|
|
|
1
1
|
fn range(start: int, e: int, cb: fn(int)) =
|
|
2
|
-
|
|
2
|
+
match start < end ->
|
|
3
3
|
cb(start)
|
|
4
4
|
range(start + 1, end, cb)
|
|
5
|
-
elif (start > end):
|
|
6
|
-
cb(start)
|
|
7
|
-
range(start - 1, end, cb)
|
|
8
5
|
|
|
9
|
-
fn repeat(n: int, cb: fn(int)) =
|
|
6
|
+
fn repeat(n: int, cb: fn(int): void) =
|
|
10
|
-
|
|
7
|
+
match n != 0
|
|
11
|
-
cb(
|
|
8
|
+
cb()
|
|
12
|
-
repeat(n-1, cb)
|
|
9
|
+
repeat(n - 1, cb)
|
|
10
|
+
|
|
11
|
+
fn repeat(cb: fn(int): void) =
|
|
12
|
+
cb()
|
|
13
|
+
repeat(cb)
|
|
14
|
+
|
|
15
|
+
fn iterate[T](l: list[T], cb: fn(t: T)) =
|
|
16
|
+
pass
|
|
13
17
|
|
|
14
18
|
fn main() =
|
|
15
19
|
repeat(10) |i|
|
|
16
20
|
println(i)
|
|
17
21
|
range(10, 20) |i|
|
|
18
22
|
println(i)
|
|
23
|
+
|
|
24
|
+
//support unocss
|
|
25
|
+
|
|
26
|
+
html(class: "123") |_|
|
|
27
|
+
head() |_|
|
|
28
|
+
title("name")
|
|
29
|
+
link(href: "123")
|
|
30
|
+
body(class: "bg-white") |_|
|
|
31
|
+
div(class: "132") |_|
|
|
32
|
+
text("Hello")
|
|
33
|
+
div()
|
|
34
|
+
|
|
35
|
+
html(class: "123") {
|
|
36
|
+
head() {
|
|
37
|
+
title("name")
|
|
38
|
+
link(href: "123")
|
|
39
|
+
}
|
|
40
|
+
body(class: "class") {
|
|
41
|
+
div(class: "132") {
|
|
42
|
+
text("Hello")
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
`kotlin
|
|
48
|
+
html("lang": "en") {
|
|
49
|
+
head {
|
|
50
|
+
meta("charset": "UTF-8")
|
|
51
|
+
title {
|
|
52
|
+
text("Kotlin HTML DSL")
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
body {
|
|
56
|
+
h1 {
|
|
57
|
+
text("Hello, World!")
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
`dart
|
|
63
|
+
Html(
|
|
64
|
+
class: "123",
|
|
65
|
+
head: list.of(
|
|
66
|
+
titl("name")
|
|
67
|
+
link(href: "123")
|
|
68
|
+
),
|
|
69
|
+
body: list.of(
|
|
70
|
+
div(class: "class", list.of(
|
|
71
|
+
text("Hello")
|
|
72
|
+
),
|
|
73
|
+
)
|
|
74
|
+
)
|
|
75
|
+
)
|
std/result.mi
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
module std
|
|
2
|
+
|
|
3
|
+
`result` is a type that represents either success ([`ok`]) or failure ([`err`]).
|
|
4
|
+
#[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
|
|
5
|
+
enum result[T, E]
|
|
6
|
+
| ok(T)
|
|
7
|
+
| err(E)
|
|
8
|
+
|
|
9
|
+
fn (o result) is_ok(): bool =
|
|
10
|
+
match o
|
|
11
|
+
ok(v) -> return true
|
|
12
|
+
err(e) -> return false
|
|
13
|
+
|
|
14
|
+
fn (o result) is_err(): bool =
|
|
15
|
+
!o.is_ok()
|
|
16
|
+
|
|
17
|
+
fn (o result[T, E]) ok(): option[T] =
|
|
18
|
+
match o
|
|
19
|
+
ok(v) -> some(v)
|
|
20
|
+
err(e) -> none
|
|
21
|
+
|
|
22
|
+
fn (o result[T, E]) err(): option[E] =
|
|
23
|
+
match o
|
|
24
|
+
ok(v) -> none
|
|
25
|
+
err(e) -> some(v)
|
|
26
|
+
|
|
27
|
+
fn (o result) get(): T =
|
|
28
|
+
match o
|
|
29
|
+
ok(v) -> v
|
|
30
|
+
err(e) -> panic("called `option.unwrap()` on a `none` value")
|
|
31
|
+
|
|
32
|
+
fn (o result) default(d: T): T =
|
|
33
|
+
match o
|
|
34
|
+
ok(v) -> v
|
|
35
|
+
err(e) -> d
|
|
36
|
+
|
|
37
|
+
fn (o result) map(cb: fn(v: T)): result =
|
|
38
|
+
match o
|
|
39
|
+
ok(v) -> cb(v)
|
|
40
|
+
err(e) -> unreachable
|
|
41
|
+
|
|
42
|
+
fn (o result) map_err(cb: fn(e: E)): result =
|
|
43
|
+
match o
|
|
44
|
+
ok(v) -> unreachable
|
|
45
|
+
err(e) -> cb(v)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
error FileOpenError
|
|
49
|
+
| AccessDenied(str)
|
|
50
|
+
| OutOfMemory(str)
|
|
51
|
+
| FileNotFound(str)
|
|
52
|
+
|
|
53
|
+
fn parse_version(header: List[int]): result[Version, error] =
|
|
54
|
+
header.get(0) != nil ? v : error.InvalidHeaderLength(header.get(0))
|
|
55
|
+
|
|
56
|
+
fn main(): result[unit, unit] =
|
|
57
|
+
version := parse_version(list.of(1, 2))
|
|
58
|
+
match pg.connect()
|
|
59
|
+
ok(c) -> return 0
|
|
60
|
+
err(e) -> return e
|
|
61
|
+
|
|
62
|
+
greeting_file := file.open("hello.txt").unwrap_or_else() |error|
|
|
63
|
+
match error
|
|
64
|
+
ErrorKind::NotFound ->
|
|
65
|
+
File::create("hello.txt").unwrap_or_else() |error|
|
|
66
|
+
panic!("Problem creating the file: {:?}", error)
|
|
67
|
+
_ ->
|
|
68
|
+
panic!("Problem opening the file: {:?}", error)
|
|
69
|
+
|
|
70
|
+
conn := match pg.connect()?
|
|
71
|
+
create_post_action(req)
|
|
72
|
+
.map(|v| 0)
|
|
73
|
+
.map_err(|err| 1)
|
|
74
|
+
|
|
75
|
+
create_post_action(req)?
|
|
76
|
+
ok()
|
|
77
|
+
|
|
78
|
+
greeting_file := file.open("hello.txt")?
|
|
79
|
+
ok()
|
|
80
|
+
|
|
81
|
+
import std/str
|
|
82
|
+
import std/result
|
|
83
|
+
|
|
84
|
+
fn double_number(s: str): result[i32, unit] =
|
|
85
|
+
number_str.parse_int().map(|n| 2 * n)
|
|
86
|
+
|
|
87
|
+
fn main(): result<i32, unit> =
|
|
88
|
+
double_number("10")?
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
use std::num::ParseIntError;
|
|
92
|
+
|
|
93
|
+
fn double_number(number_str: &str) -> Result<i32, ParseIntError> {
|
|
94
|
+
number_str.parse::<i32>().map(|n| 2 * n)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
fn main() {
|
|
98
|
+
match double_number("10") {
|
|
99
|
+
Ok(n) => assert_eq!(n, 20),
|
|
100
|
+
Err(err) => println!("Error: {:?}", err),
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
trait error: debug + display (
|
|
105
|
+
fn description(): str
|
|
106
|
+
fn cause(): option<error>
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
trait From<T>(
|
|
110
|
+
fn from(v: T) -> Self;
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
trait Debug(
|
|
114
|
+
fn fmt(f: Formateer): result[unit, unit]
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
trait Display(
|
|
118
|
+
fn fmt(f: Formateer): result[unit, unit]
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
data.price?.take_if(|a| a != "")
|
|
122
|
+
|
|
123
|
+
put_if
|
std/str.mi
CHANGED
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
module std
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
`ToStr defines any data that can be converted to a str
|
|
4
|
-
trait ToStr
|
|
4
|
+
trait ToStr(
|
|
5
5
|
fn to_str(): str
|
|
6
|
+
)
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
`A str is an array of contiguous data stored in memory with a null termination using hex 0x00 or ASCII 0x00.
|
|
8
|
-
|
|
9
|
+
`It is immutable and cannot be modified. It is copied for any changes and saved to a new memory location.
|
|
9
|
-
|
|
10
|
+
`The previous str is freed if its reference count is 0 within the block.
|
|
10
|
-
|
|
11
|
+
record str(data: list[byte]): Comparable, ToStr
|
|
11
12
|
|
|
12
|
-
|
|
13
|
+
fn str.of(bs ...byte): str =
|
|
13
|
-
// TODO: have a check in dev builds to throw an error if not null terminated
|
|
14
|
-
// to prevent undefined behavior
|
|
15
|
-
|
|
14
|
+
data.add(bs)
|
|
16
15
|
|
|
17
16
|
fn (s str) get(i: int) =
|
|
18
17
|
data[i]
|
|
@@ -50,10 +49,9 @@ fn (t BTree) delete(key str): bool =
|
|
|
50
49
|
return true
|
|
51
50
|
return false
|
|
52
51
|
|
|
53
|
-
fn (s str)
|
|
52
|
+
fn (s str) starts_with(search: str): bool =
|
|
54
53
|
pass
|
|
55
54
|
|
|
56
|
-
|
|
57
55
|
fn (s str) concat(other: str): str =
|
|
58
56
|
s + other
|
|
59
57
|
|
|
@@ -83,69 +81,69 @@ fn (s str) match_all(pattern: Regex): []str =
|
|
|
83
81
|
fn (s str) pad_start(sub: str, count: int): str =
|
|
84
82
|
pass
|
|
85
83
|
|
|
86
|
-
|
|
84
|
+
fn (s str) pad_end(sub: str, count: int): str =
|
|
87
|
-
|
|
85
|
+
pass
|
|
88
|
-
|
|
89
|
-
fn repeat(count: int): str =
|
|
90
|
-
pass
|
|
91
|
-
|
|
92
|
-
fn replace(pattern: Regex, sub: str): str =
|
|
93
|
-
pass
|
|
94
|
-
|
|
95
|
-
fn replace_all(pattern: Regex, sub: str): str =
|
|
96
|
-
pass
|
|
97
86
|
|
|
98
|
-
|
|
87
|
+
fn (s str) repeat(count: int): str =
|
|
99
|
-
|
|
88
|
+
pass
|
|
100
89
|
|
|
101
|
-
|
|
90
|
+
fn (s str) replace(pattern: Regex, sub: str): str =
|
|
102
|
-
|
|
91
|
+
pass
|
|
103
92
|
|
|
104
|
-
|
|
93
|
+
fn (s str) replace_all(pattern: Regex, sub: str): str =
|
|
105
|
-
|
|
94
|
+
pass
|
|
106
95
|
|
|
107
|
-
|
|
96
|
+
fn (s str) search(pattern: Regex): str =
|
|
108
|
-
|
|
97
|
+
pass
|
|
109
98
|
|
|
110
|
-
|
|
99
|
+
fn slice(start: int, end: int): str =
|
|
111
|
-
|
|
100
|
+
pass
|
|
112
101
|
|
|
113
|
-
|
|
102
|
+
fn split(separator: str, limit: int): []str =
|
|
114
|
-
|
|
103
|
+
pass
|
|
115
104
|
|
|
116
|
-
|
|
105
|
+
fn sub(start: int, end: int): str =
|
|
117
|
-
|
|
106
|
+
pass
|
|
118
107
|
|
|
119
|
-
|
|
108
|
+
fn to_lower(): str =
|
|
120
|
-
|
|
109
|
+
pass
|
|
121
110
|
|
|
122
|
-
|
|
111
|
+
fn to_upper(): str =
|
|
123
|
-
|
|
112
|
+
pass
|
|
124
113
|
|
|
125
|
-
|
|
114
|
+
fn trim(): str =
|
|
126
|
-
"""reverses a str
|
|
127
|
-
start := 0
|
|
128
|
-
end := length - 1
|
|
129
|
-
result := []
|
|
130
|
-
while start < end
|
|
131
|
-
const temp = data[start]
|
|
132
|
-
result[start] = data[end]
|
|
133
|
-
result[end] = temp
|
|
134
|
-
end = end - 1
|
|
135
|
-
start = start + 1
|
|
136
|
-
|
|
115
|
+
pass
|
|
137
116
|
|
|
138
|
-
|
|
117
|
+
fn trim_start(): str =
|
|
139
|
-
|
|
118
|
+
pass
|
|
140
119
|
|
|
141
|
-
|
|
120
|
+
fn trim_end(): str =
|
|
142
|
-
|
|
121
|
+
pass
|
|
143
122
|
|
|
123
|
+
fn reverse(): str
|
|
124
|
+
"""reverses a str
|
|
125
|
+
start := 0
|
|
126
|
+
end := length - 1
|
|
127
|
+
result := []
|
|
128
|
+
while start < end
|
|
129
|
+
const temp = data[start]
|
|
130
|
+
result[start] = data[end]
|
|
131
|
+
result[end] = temp
|
|
132
|
+
end = end - 1
|
|
133
|
+
start = start + 1
|
|
134
|
+
result
|
|
135
|
+
|
|
136
|
+
fn parse_int(): int! =
|
|
137
|
+
0
|
|
138
|
+
|
|
139
|
+
fn parse_float(): float! =
|
|
140
|
+
0.0
|
|
141
|
+
|
|
144
|
-
|
|
142
|
+
fn parse_bool(): bool! =
|
|
145
|
-
|
|
143
|
+
match to_lower()
|
|
146
|
-
|
|
144
|
+
"true" -> bool::true
|
|
147
|
-
|
|
145
|
+
"false" -> bool::false
|
|
148
|
-
|
|
146
|
+
_ -> error("could not parse bool '${this}'")
|
|
149
147
|
|
|
150
148
|
|
|
151
149
|
_.camelCase
|