~repos /plum

#treesitter#compiler#wasm

git clone https://pyrossh.dev/repos/plum.git

A statically typed, imperative programming language inspired by rust, python


66f4a645 pyrossh

1 year ago
improve
Files changed (10) hide show
  1. readme.md +81 -15
  2. std/bool.mi +39 -9
  3. std/coding/base64.mi +170 -0
  4. std/http.mi +5 -5
  5. std/map.mi +12 -0
  6. std/math.mi +39 -27
  7. std/option.mi +43 -0
  8. std/ranges.mi +65 -8
  9. std/result.mi +123 -0
  10. std/str.mi +60 -62
readme.md CHANGED
@@ -1,34 +1,42 @@
1
1
  # 👾 Pacos Programming Language
2
2
 
3
- A simple, statically typed, imperative, minimalistic programming language. Its main aim to be simple and easy to code correct programs. It takes inspiration for golang, ponylang, and dart. It comes packed with linting, formatting, test runner, language server, and package management in-built.
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
- ```rb
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) -> 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) -> 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,when,match,type
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 := [1, 2, 3] // list[int]
210
+ a := list.of(1, 2, 3) # list[int]
203
- b := [[1, 2], [3, 4], [5, 6]] // list[list[int]]
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 := ["Krabs", "Squidward"]
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
- type bool = true | false
3
+ enum bool =
4
+ | true
4
- fn op_eq(x: bool, y: bool) = x == y
5
+ | false
6
+
5
- fn op_ne(x: bool, y: bool) = x != y
7
+ fn (x: bool) op_ne(y: bool) = x != y
6
- fn op_and(x: bool, y: bool) = x == false || y == false ? false : true
8
+ fn (x: bool) op_and(y: bool) = x == false || y == false ? false : true
7
- fn op_or(x: bool, y: bool) = x == true || y == true ? true : false
9
+ fn (x: bool) op_or(y: bool) = x == true || y == true ? true : false
8
- fn op_not(x: bool): bool = x == true ? false : true
10
+ fn (x: bool) op_not(): bool = x == true ? false : true
9
-
10
- #[ToStr]
11
- fn to_str(x: bool) = x ? "true" : "false"
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 = 200,
10
+ status: 200,
11
- headers = [
11
+ headers: map.of(
12
12
  "Content-Type" => content,
13
13
  "Content-Length" => "2"
14
- ],
14
+ ),
15
- body = data
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
- E = 2.718f // Represents Euler's number, the base of natural logarithms, e
3
+ `Euler's number, the base of natural logarithms, e
4
+ const E = 2.718f
5
+
4
- LN10 = 2.302f // Represents the natural logarithm of 10
6
+ `The natural logarithm of 10
7
+ const LN10 = 2.302f
8
+
5
- LN2 = 0.693f // Represents the natural logarithm of 2
9
+ `The natural logarithm of 2
10
+ const LN2 = 0.693f
11
+
6
- LOG10E = 0.434f // Represents the base 10 logarithm of e
12
+ `The base 10 logarithm of e
13
+ const LOG10E = 0.434f
14
+
7
- LOG2E = 1.442f // Represents the base 2 logarithm of e
15
+ `The base 2 logarithm of e
16
+ const LOG2E = 1.442f
17
+
8
- PI = 3.14159f // Represents the ratio of the circumference of a circle to its diameter
18
+ `The ratio of the circumference of a circle to its diameter
19
+ const PI = 3.14159f
20
+
9
- SQRT1_2 = 0.707f // Represents the square root of 1/2
21
+ `The square root of 1/2
22
+ const SQRT1_2 = 0.707f
23
+
10
- SQRT2 = 1.414f // Represents the square root of 2
24
+ `The square root of 2
25
+ const SQRT2 = 1.414f
26
+
11
- EPSILON = 2.220446049250313e-16f // Represents the difference between 1 and the smallest floating point number greater than 1
27
+ `The difference between 1 and the smallest floating point number greater than 1
12
- MAX_SAFE_INTEGER
28
+ const EPSILON = 2.220446049250313e-16f
13
- MAX_VALUE
29
+
14
- MIN_SAFE_INTEGER
15
- MIN_VALUE
16
- NEGATIVE_INFINITY
30
+ `Lowest valur of i64
31
+ const MIN_INT_VALUE = -0x8000_0000_0000_0000
32
+
17
- POSITIVE_INFINITY
33
+ `Highest valur of i64
18
-
34
+ const MAX_INT_VALUE = 0x7FFF_FFFF_FFFF_FFFF
35
+
36
+ fn abs(v: float): float =
19
- // Returns the absolute value of a number
37
+ `returns the absolute value of a number v
20
- fn abs(v: float): float = a < 0 ? -a : a
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
- // True if exponent is not all 1s
70
+ ` True if exponent is not all 1s
54
- // (bits() and 0x7FF0_0000_0000_0000) != 0x7FF0_0000_0000_0000
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
- if (start < end):
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
- if n != 0:
7
+ match n != 0
11
- cb(n)
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
- // Trait ToStr defines any data that can be converted to a str
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
- // A str is an array of contiguous data stored in memory with a null termination using hex 0x00 or ASCII 0x00.
8
+ `A str is an array of contiguous data stored in memory with a null termination using hex 0x00 or ASCII 0x00.
8
- // It is immutable and cannot be modified. It is copied for any changes and saved to a new memory location.
9
+ `It is immutable and cannot be modified. It is copied for any changes and saved to a new memory location.
9
- // The previous str is freed if its reference count is 0 within the block.
10
+ `The previous str is freed if its reference count is 0 within the block.
10
- struct str(_ptr: *u8) : Comparable, ToStr
11
+ record str(data: list[byte]): Comparable, ToStr
11
12
 
12
- new (s str) create(ptr: *u8) =
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
- _ptr = ptr
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) Comparable::starts_with(search: str): bool =
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
- fn pad_end(sub: str, count: int): str =
84
+ fn (s str) pad_end(sub: str, count: int): str =
87
- pass
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
- fn search(pattern: Regex): str =
87
+ fn (s str) repeat(count: int): str =
99
- pass
88
+ pass
100
89
 
101
- fn slice(start: int, end: int): str =
90
+ fn (s str) replace(pattern: Regex, sub: str): str =
102
- pass
91
+ pass
103
92
 
104
- fn split(separator: str, limit: int): []str =
93
+ fn (s str) replace_all(pattern: Regex, sub: str): str =
105
- pass
94
+ pass
106
95
 
107
- fn sub(start: int, end: int): str =
96
+ fn (s str) search(pattern: Regex): str =
108
- pass
97
+ pass
109
98
 
110
- fn to_lower(): str =
99
+ fn slice(start: int, end: int): str =
111
- pass
100
+ pass
112
101
 
113
- fn to_upper(): str =
102
+ fn split(separator: str, limit: int): []str =
114
- pass
103
+ pass
115
104
 
116
- fn trim(): str =
105
+ fn sub(start: int, end: int): str =
117
- pass
106
+ pass
118
107
 
119
- fn trim_start(): str =
108
+ fn to_lower(): str =
120
- pass
109
+ pass
121
110
 
122
- fn trim_end(): str =
111
+ fn to_upper(): str =
123
- pass
112
+ pass
124
113
 
125
- fn reverse(): str
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
- result
115
+ pass
137
116
 
138
- fn parse_int(): int! =
117
+ fn trim_start(): str =
139
- 0
118
+ pass
140
119
 
141
- fn parse_float(): float! =
120
+ fn trim_end(): str =
142
- 0.0
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
- fn parse_bool(): bool! =
142
+ fn parse_bool(): bool! =
145
- match to_lower()
143
+ match to_lower()
146
- "true" -> bool::true
144
+ "true" -> bool::true
147
- "false" -> bool::false
145
+ "false" -> bool::false
148
- _ -> error("could not parse bool '${this}'")
146
+ _ -> error("could not parse bool '${this}'")
149
147
 
150
148
 
151
149
  _.camelCase