~repos /plum

#treesitter#compiler#wasm

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

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


19b8452f pyrossh

1 year ago
improve syn
Files changed (14) hide show
  1. .gitignore +1 -0
  2. readme.md +126 -236
  3. scratch.pc +218 -0
  4. std/bool.mi +1 -30
  5. std/coding/base64.mi +0 -170
  6. std/html.mi +43 -0
  7. std/http.mi +15 -53
  8. std/list.mi +4 -33
  9. std/map.mi +0 -2
  10. std/os.mi +5 -0
  11. std/ranges.mi +0 -75
  12. std/regex.mi +1 -0
  13. std/time.mi +3 -0
  14. std/uuid.mi +1 -0
.gitignore CHANGED
@@ -9,3 +9,4 @@ static/bundle/
9
9
  static/monaco-editor-workers/
10
10
  static/worker/
11
11
  syntaxes/
12
+ website
readme.md CHANGED
@@ -1,17 +1,17 @@
1
1
  # 👾 Pacos Programming Language
2
2
 
3
- * A statically typed, functional programming language inspired by rust, koka.
3
+ - A statically typed, imperative 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.
4
+ - The compiler users the tree-sitter parser so has out of the box syntax highlighting support for helix and zed editor.
5
5
 
6
6
  **Rules**
7
+
7
- * Function parameters are passed by value only. You cannot modify a parameter. The compiler will throw an error if you try to.
8
+ - 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
+ - Strict naming convention
9
- * Only one way of doing things ex: loops, condition
10
+ - Only one way of doing things ex: loops, condition
10
11
 
11
12
  **Todo**
12
13
  linter, formatter, test runner, language server, package manager
13
14
 
14
-
15
15
  Here is some sample code, please enjoy.
16
16
 
17
17
  ```go
@@ -47,21 +47,21 @@ fn factorial(n: int): int =
47
47
  a -> 1
48
48
  _ -> n * factorial(n - 1)
49
49
 
50
- fn first_item(l: list[int]): int? =
50
+ fn firstItem(l: list[int]): int? =
51
51
  l[0]
52
52
 
53
- fn first_item(l: list[int]): int? =
53
+ fn firstItem(l: list[int]): int? =
54
54
  match l
55
55
  [] -> nil
56
56
  [head, ...rest] -> head
57
57
 
58
- fn first_item(l: list[int]): int? =
58
+ fn firstItem(l: list[int]): int? =
59
59
  if l.size > 0
60
60
  l[0]
61
61
  else
62
62
  nil
63
63
 
64
- fn to-celsius(f: float): float =
64
+ fn toCelsius(f: float): float =
65
65
  (f - 32) * (5 / 9)
66
66
 
67
67
  record Cat[A: Comparable & Stringable](
@@ -69,16 +69,16 @@ record Cat[A: Comparable & Stringable](
69
69
  age: int
70
70
  )
71
71
 
72
- fn Cat.with_name(name: str): Cat =
72
+ fn Cat.withName(name: str): Cat =
73
73
  Cat(name: name, age: 0)
74
74
 
75
75
  fn (c: Cat) fullname(): str =
76
76
  c.name + c.age.to_str()
77
77
 
78
78
  fn (c: Cat) talk() =
79
- println("cat ${c.name} says meow")
79
+ printLn("cat ${c.name} says meow")
80
80
 
81
- fn (c: Cat) to_str(): str =
81
+ fn (c: Cat) toStr(): str =
82
82
  "Cat<{c.fullname()}, ${c.age}>"
83
83
 
84
84
  type MapCallback = fn(v: a): v
@@ -115,12 +115,12 @@ test("to_str") |t|
115
115
  items := [Cat("Molly", 9), Cat("Fenton", 6)]
116
116
  .retain(|p| p.name.size > 5)
117
117
  .map(|p| describe(p))
118
- .each(|d| println(d))
118
+ .each(|d| printLn(d))
119
119
  assert items[0].to_str() == "Cat<Fenton, 6>"
120
120
 
121
121
  bench("1231") |n|
122
122
  for i := range n
123
- println(i)
123
+ printLn(i)
124
124
  ```
125
125
 
126
126
  ## Language Reference
@@ -128,7 +128,7 @@ bench("1231") |n|
128
128
  **Keywords**
129
129
 
130
130
  ```rs
131
- for,while,if,else,record,enum,fn,assert,match,type
131
+ for,while,if,else if,else,record,enum,fn,assert,match,type
132
132
  ```
133
133
 
134
134
  ### Types
@@ -158,7 +158,7 @@ if true || false
158
158
 
159
159
  **byte**
160
160
 
161
- A byte represents an unsigned 8 bit number. It is mainly used to represent strings and binary data.
161
+ A byte represents an unsigned 8-bit number. It is mainly used to represent strings and binary data.
162
162
 
163
163
  ```rb
164
164
  let data: []byte?
@@ -167,10 +167,13 @@ data = [104, 101, 197, 130, 197, 130, 111, 0]
167
167
 
168
168
  **int**
169
169
 
170
- An int is a signed 64 bit number. It can be represented in various ways,
170
+ An int is a signed 64-bit number. It can be represented in various ways,
171
+
172
+ ```
171
173
  0b - Binary (Base 2)
172
174
  0x - Hexadecimal (Base 16)
173
175
  27 - Standard (Base 10)
176
+ ```
174
177
 
175
178
  ```rb
176
179
  0b00101010
@@ -184,11 +187,25 @@ An int is a signed 64 bit number. It can be represented in various ways,
184
187
 
185
188
  **float**
186
189
 
187
- A float represents a 64-bit floating point (52-bit mantissa) IEEE-754-2008 binary64
190
+ A float represents a 64-bit floating point [IEEE-754-2008](https://en.wikipedia.org/wiki/Double-precision_floating-point_format).
191
+
192
+ ```java
193
+ 1.2
194
+ -0.4
195
+ 12.0f
196
+ 15.03f
197
+ ```
188
198
 
189
199
  **dec**
190
200
 
191
- A decimal type represents BCD number. It has a mantissa and exponent.
201
+ A dec is a decimal floating-point numbering format which is 64-bit data type.
202
+ It is intended for applications where it is necessary to emulate decimal rounding exactly, such as financial and tax computations.
203
+ It supports 16 decimal digits of significand and an exponent range of −383 to +384.
204
+
205
+ ```java
206
+ 2.4d
207
+ -13.3d
208
+ ```
192
209
 
193
210
  **str**
194
211
 
@@ -199,7 +216,7 @@ It supports interpolation of variables/values that implement the ToStr interface
199
216
  "Hello World"
200
217
  name := "Pacos"
201
218
  age := 1
202
- println("Name ${name} age ${age}")
219
+ printLn("Name ${name} age ${age}")
203
220
  ```
204
221
 
205
222
  **list**
@@ -207,11 +224,15 @@ println("Name ${name} age ${age}")
207
224
  ```py
208
225
  import pacos/list
209
226
 
210
- a := list.of(1, 2, 3) # list[int]
227
+ a := List.of(1, 2, 3) # List[int]
211
- b := list.of(list.of(1), list.of(2), list.of(3)) # list[list[int]]
228
+ b := List.of( # List[List[int]]
229
+ List.of(1),
230
+ List.of(2),
231
+ List.of(3),
232
+ )
212
- c := list.of(1, 2, 3 * 4, 8, n)
233
+ c := List.of(1, 2, 3 * 4, 8, n)
213
234
 
214
- actors := list.of("Krabs", "Squidward")
235
+ actors := List.of("Krabs", "Squidward")
215
236
  actors.add("Spongebob")
216
237
  actors.length() // ==> 3
217
238
  actors.contains("Krabs") // ==> true
@@ -220,58 +241,41 @@ actors.get(5) // => nil
220
241
 
221
242
  items
222
243
  .map(|v| v + 1)
223
- .each(|v| println("v", v))
244
+ .each(|v| printLn("v", v))
224
245
  .reduce(0, |v| v + 1)
225
246
  ```
226
247
 
227
248
  **map**
228
249
 
229
- ```rb
250
+ ```rs
230
251
  import pacos/map
231
252
 
232
- nums := Map.new(:one => 1, :two => 2)
253
+ nums := Map.of(:one => 1, :two => 2)
233
- map.get(:one) // =>`
254
+ map.get(:one) // => 1
234
255
  map.get(:unknown) // => nil
235
-
236
- friends_tree := [
256
+ friends_tree := Map.of(
237
257
  :value => "Fred",
238
- :left => [
258
+ :left => Map.of(
239
259
  :value => "Jim",
240
- ],
260
+ ),
241
- :right => [
261
+ :right => Map.of(
242
262
  :value => "Shiela",
243
- :left => [
263
+ :left => Map.of(
244
264
  :value => "Alice",
245
- },
265
+ ),
246
- :right => [
266
+ :right => Map.of(
247
267
  :value => "Bob"
248
- ],
268
+ ),
249
- ],
269
+ ),
250
- ]
270
+ )
251
271
 
252
272
  friends_tree
253
273
  .map(|k, v| v)
254
- .each(|k, v| println("v", v))
274
+ .each(|k, v| printLn("v", v))
255
275
  .reduce(0, |k, v| v + 1)
256
276
  ```
257
277
 
258
- **time**
259
-
260
- TBD
261
-
262
- **duration**
263
-
264
- TBD
265
-
266
- **regex**
267
-
268
- TBD
269
-
270
- **uuid**
271
-
272
- TBD
273
-
274
- **Constants**
278
+ **constants**
275
279
 
276
280
  Constants can be declared at the top level of a program. They cannot be reassigned.
277
281
 
@@ -279,15 +283,17 @@ Constants can be declared at the top level of a program. They cannot be reassign
279
283
  - Reference values like `list, map, records` are initialized at program start and passed by reference when used. Their data can be modified.
280
284
 
281
285
  ```rb
286
+ const START_YEAR = 2101
282
- const PI = 3.14159f
287
+ const PI = 3.14159
283
- const ERR_MESSAGE = "An unknown error occured"
288
+ const NAME = "pacos"
289
+ const DEBUG_ENABLED = true
284
290
  const COUNT = count(10)
285
- const COUNTRIES_LIST = ["US", "INDIA", "CANADA"]
291
+ const COUNTRIES_LIST = ist.of("US", "INDIA", "CANADA")
286
- const COUNTRY_CODES = [
292
+ const COUNTRY_CODES = map.of(
287
- :in => "INDIA",
293
+ "in" => "INDIA",
288
- :us => "United States",
294
+ "us" => "United States",
289
- :ca => "Canada"
295
+ "ca" => "Canada"
290
- ]
296
+ )
291
297
 
292
298
  fn count(n: int): int = n * 1
293
299
  ```
@@ -305,22 +311,6 @@ assoc_list[:a]
305
311
  assoc_list["b"]
306
312
  ```
307
313
 
308
- **Assignment Operators**
309
-
310
- ```go
311
- x := 5
312
- y := 3
313
- x += y // 8
314
- x -= y // 5
315
- x *= y // 15
316
- x /= y // 5
317
- x %= y // 2
318
- x &= y // 2
319
- x |= y // 3
320
- x <<= y // 24
321
- x >>= y // 3
322
- ```
323
-
324
314
  **While statement**
325
315
 
326
316
  ```rb
@@ -338,10 +328,6 @@ while a > b
338
328
 
339
329
  **For statement**
340
330
 
341
- type Seq0 = fn(yield: fn(): bool): bool
342
- type Seq1[V] = fn(yield: fn(V): bool): bool
343
- type Seq2[K, V] = fn(yield: fn(K, V): bool): bool
344
-
345
331
  ```rb
346
332
  for i := range 10
347
333
  sum += i
@@ -355,24 +341,45 @@ for k, v := range json_map
355
341
 
356
342
  for v := range list
357
343
  sum += k + v
344
+ ```
345
+
346
+ **For Custom Iterator**
347
+
348
+ ```rb
349
+ type Seq0 = fn(yield: fn(): bool): bool
350
+ type Seq1[V] = fn(yield: fn(V): bool): bool
351
+ type Seq2[K, V] = fn(yield: fn(K, V): bool): bool
358
352
 
359
353
  record Tree[E](
360
354
  value E,
361
- left: Tree[E]?,
355
+ left: optional[Tree[E]],
362
- right: Tree[E]?,
356
+ right: optional[Tree[E]],
363
357
  )
364
358
 
365
359
  fn (t Tree[E]) op_range(yld: fn(E): bool): bool =
366
- t ? true : t.left.in_order(yld) && yld(t.val) && t.right.in_order(yld)
360
+ t ? true : t.left?.in_order(yld) && yld(t.val) && t.right?.in_order(yld)
367
361
 
368
- tt := Tree(
362
+ tree := Tree(
369
363
  value: 10,
370
364
  left: Tree(20, Tree(30), Tree(39)),
371
365
  right: Tree(40),
372
366
  )
373
367
 
374
- for t := range tt
368
+ for t := range tree
375
- println(v)
369
+ printLn(v)
370
+ ```
371
+
372
+ **if expression/statement**
373
+
374
+ ```py
375
+ if name == "Andreas"
376
+ printLn("What a nice name!")
377
+ else if name == "Pacman"
378
+ printLn("Game from the 80s")
379
+ else if name == ""
380
+ printLn("Don't you have a name?")
381
+ else
382
+ printLn("Boring name...")
376
383
  ```
377
384
 
378
385
  **When expression/statement**
@@ -394,26 +401,13 @@ when number
394
401
  1 | 3 | 5 | 7 -> "This is an odd number"
395
402
  _ -> "I'm not sure"
396
403
 
397
- match xs
404
+ when xs
398
405
  [] -> "This list is empty"
399
406
  [a] -> "This list has 1 element"
400
407
  [a, b] -> "This list has 2 elements"
401
408
  _ -> "This list has more than 2 elements"
402
409
  ```
403
410
 
404
- Arithmetic (+, -, /, \*, @divFloor, @sqrt, @ceil, @log, etc.)
405
- Bitwise operators (>>, <<, &, |, ~, etc.)
406
- Comparison operators (<, >, ==, etc.)
407
-
408
- **if expression/statement**
409
-
410
- ```rb
411
- if post.valid()
412
- render_create_view()
413
- else
414
- render_post(post: post)
415
- ```
416
-
417
411
  ### Conditional operators
418
412
 
419
413
  **not operator**
@@ -474,13 +468,29 @@ paint := Paint()
474
468
  ..strokeWidth = 5.0
475
469
  ```
476
470
 
477
- **variadic function**
471
+ **variadic operator**
478
472
 
479
473
  ```go
480
474
  fn add(items ...str) =
481
475
  list.add(items)
482
476
  ```
483
477
 
478
+ **assignment operator**
479
+
480
+ ```go
481
+ x := 5
482
+ y := 3
483
+ x += y // 8
484
+ x -= y // 5
485
+ x *= y // 15
486
+ x /= y // 5
487
+ x %= y // 2
488
+ x &= y // 2
489
+ x |= y // 3
490
+ x <<= y // 24
491
+ x >>= y // 3
492
+ ```
493
+
484
494
  **generics**
485
495
 
486
496
  ```
@@ -488,134 +498,14 @@ fn add[T: int | float](a: List[T], b: List[T]): List[T] =
488
498
  pass
489
499
  ```
490
500
 
491
- ```
492
- fn create_post_action(req: Request): Result[Response] =
493
- post := Post(title = req.params.title, body = req.params.body)
494
- if post.valid()
495
- RenderNewView()
496
- else
497
- post := createRecord(post)
498
- setSuccessMessage("Post created")
499
- redirectTo("/posts")
500
-
501
- fn divide(dividend: u32, divisor: u32) !u32 =
502
- if divisor == 0
503
- error.DivideByZero
504
- else
505
- dividend / divisor
506
- dispatch(action, req, res) catch |err|
507
- BodyTooBig -> Response(
508
- status: 431,
509
- body: "Request body is too big",
510
- )
511
- BrokenPipe, ConnectionResetByPeer -> return false
512
- _ -> error_handler(req, res, err)
513
-
514
- error FileOpenError
515
- | AccessDenied(str)
516
- | OutOfMemory(str)
517
- | FileNotFound(str)
518
-
519
- fn parse_version(header: List[int]): result[Version, error] =
520
- header.get(0) != nil ? v : error.InvalidHeaderLength(header.get(0))
521
-
522
- fn main(): result[unit, unit] =
523
- version := parse_version(list.of(1, 2))
524
- match pg.connect()
525
- ok(c) -> return 0
526
- err(e) -> return e
527
-
528
- greeting_file := file.open("hello.txt").unwrap_or_else() |error|
529
- match error
530
- ErrorKind::NotFound ->
531
- File::create("hello.txt").unwrap_or_else() |error|
532
- panic!("Problem creating the file: {:?}", error)
533
- _ ->
534
- panic!("Problem opening the file: {:?}", error)
535
-
536
- conn := match pg.connect()?
537
- create_post_action(req)
538
- .map(|v| 0)
539
- .map_err(|err| 1)
540
-
541
- create_post_action(req)?
542
- ok()
543
-
544
- greeting_file := file.open("hello.txt")?
545
- ok()
546
-
547
- import std/str
548
- import std/result
549
-
550
- fn double_number(s: str): result[i32, unit] =
551
- number_str.parse_int().map(|n| 2 * n)
552
-
553
- fn main(): result<i32, unit> =
554
- double_number("10")
555
-
556
-
557
- use std::num::ParseIntError;
558
-
559
- fn double_number(number_str: &str) -> Result<i32, ParseIntError> {
560
- number_str.parse::<i32>().map(|n| 2 * n)
561
- }
562
-
563
- fn main() {
564
- match double_number("10") {
565
- Ok(n) => assert_eq!(n, 20),
566
- Err(err) => println!("Error: {:?}", err),
567
- }
568
- }
569
-
570
- trait error: debug + display (
571
- fn description(): str
572
- fn cause(): option<error>
573
- )
574
-
575
- trait From<T>(
576
- fn from(v: T) -> Self;
577
- )
578
-
579
- trait Debug(
580
- fn fmt(f: Formateer): result[unit, unit]
581
- )
582
-
583
- trait Display(
584
- fn fmt(f: Formateer): result[unit, unit]
585
- )
586
-
587
- record Car(wheels: int)
588
-
589
- fn getWheels() =
590
- returns 4
591
-
592
- fn main() =
593
- let c1 = some(Car(wheels: 2))
594
- let c2: option<Car> = none
595
-
596
- let c1 = Some(Car(wheels: 2))
597
- let c2: Option<Car> = None
598
-
599
- match c
600
- none -> print("no car")
601
- some(car) -> car.getWheels()
602
-
603
- Car c2 = null
604
- c2.getWheels() // Null pointer
605
- ```
606
-
607
501
  ### General naming convention
608
502
 
609
- | Item | Convention |
503
+ | Item | Convention |
610
- | ----------------------- | ------------------------ |
504
+ | ------------------------ | ----------------------- |
611
- | Modules | snake_case |
505
+ | Modules | snake_case |
612
- | Types | UpperCamelCase |
613
- | Traits | UpperCamelCase |
506
+ | Types/Traits/Enum | UpperCamelCase |
614
- | Enum variants | UpperCamelCase |
507
+ | Fields/Functions/Methods | lowerCamelCase |
615
- | Functions | snake_case |
616
- | Methods | snake_case |
617
- | General constructors | new or with_more_details |
618
- | Conversion constructors | from_some_other_type |
508
+ | Conversion constructors | from_some_other_type |
619
- | Local variables | snake_case |
509
+ | Local variables | snake_case |
620
- | Constants | SCREAMING_SNAKE_CASE |
510
+ | Constants | SCREAMING_SNAKE_CASE |
621
- | Generics | single uppercase letter |
511
+ | Generics | single uppercase letter |
scratch.pc ADDED
@@ -0,0 +1,218 @@
1
+ data.price?.take_if(|a| a != "")
2
+ trait Iterator(
3
+ fun has_next(): Bool
4
+ fun next(): T?
5
+ )
6
+
7
+ trait HasEq[A](
8
+ fn eq(that: a): bool
9
+ )
10
+
11
+ trait Equatable[A]
12
+ `A trait that defines equal and not equal operations
13
+
14
+ fn eq(b: Equatable[A]): bool
15
+ fn ne(b: Equatable[A]): bool
16
+ end
17
+
18
+ enum Compare
19
+ | Less
20
+ | Equal
21
+ | Greater
22
+ end
23
+
24
+ trait Comparable[A] is Equatable[A]
25
+ fn lt(that: A): bool
26
+ fn le(that: A): bool
27
+ fn ge(that: A): bool
28
+ fn gt(that: A): bool
29
+ fn compare(that: a): Compare
30
+ end
31
+
32
+ enum list<T> =
33
+ | empty
34
+ | link(v: T, rest: list<T>)
35
+
36
+ fn list.of[A](values: ...A): list[A] =
37
+ list[A]().add(values)
38
+
39
+ fn (o list<T>) each(cb: fn(v: T)) =
40
+ match o
41
+ empty -> return
42
+ link(a, rest) ->
43
+ cb(a)
44
+ rest.each(cb)
45
+
46
+ fn (l: list) append(values: ...V) =
47
+ `adds the specified elements to the start of the list
48
+ range(values) |v|
49
+ l.add(v)
50
+
51
+ fn (l: list) append(v: V) =
52
+ `adds the specified elements to the start of the list
53
+ l.last().rest = link(v, empty)
54
+
55
+ fn (l: list) prepend(v: V) =
56
+ `adds the specified elements to the start of the list
57
+ l.first() = link(v, l.first())
58
+
59
+
60
+ fn range(start: int, e: int, cb: fn(int)) =
61
+ match start < end ->
62
+ cb(start)
63
+ range(start + 1, end, cb)
64
+
65
+ fn repeat(n: int, cb: fn(int): void) =
66
+ match n != 0
67
+ cb()
68
+ repeat(n - 1, cb)
69
+
70
+ fn repeat(cb: fn(int): void) =
71
+ cb()
72
+ repeat(cb)
73
+
74
+ fn iterate[T](l: list[T], cb: fn(t: T)) =
75
+ pass
76
+
77
+ fn main() =
78
+ repeat(10) |i|
79
+ println(i)
80
+ range(10, 20) |i|
81
+ println(i)
82
+
83
+ ```
84
+ fn create_post_action(req: Request): Result[Response] =
85
+ post := Post(title = req.params.title, body = req.params.body)
86
+ if post.valid()
87
+ RenderNewView()
88
+ else
89
+ post := createRecord(post)
90
+ setSuccessMessage("Post created")
91
+ redirectTo("/posts")
92
+
93
+ fn divide(dividend: u32, divisor: u32) !u32 =
94
+ if divisor == 0
95
+ error.DivideByZero
96
+ else
97
+ dividend / divisor
98
+
99
+ error FileOpenError
100
+ | AccessDenied(str)
101
+ | OutOfMemory(str)
102
+ | FileNotFound(str)
103
+
104
+ fn parse_version(header: List[int]): result[Version, error] =
105
+ header.get(0) != nil ? v : error.InvalidHeaderLength(header.get(0))
106
+
107
+ fn main(): result[unit, unit] =
108
+ version := parse_version(list.of(1, 2))
109
+ match pg.connect()
110
+ ok(c) -> return 0
111
+ err(e) -> return e
112
+
113
+ greeting_file := file.open("hello.txt").unwrap_or_else() |error|
114
+ match error
115
+ ErrorKind::NotFound ->
116
+ File::create("hello.txt").unwrap_or_else() |error|
117
+ panic!("Problem creating the file: {:?}", error)
118
+ _ ->
119
+ panic!("Problem opening the file: {:?}", error)
120
+
121
+ conn := match pg.connect()?
122
+ create_post_action(req)
123
+ .map(|v| 0)
124
+ .map_err(|err| 1)
125
+
126
+ create_post_action(req)?
127
+ ok()
128
+
129
+ greeting_file := file.open("hello.txt")?
130
+ ok()
131
+
132
+ import std/str
133
+ import std/result
134
+
135
+ fn double_number(s: str): result[i32, unit] =
136
+ number_str.parse_int().map(|n| 2 * n)
137
+
138
+ fn main(): result<i32, unit> =
139
+ double_number("10")
140
+
141
+
142
+ use std::num::ParseIntError;
143
+
144
+ fn double_number(number_str: &str) -> Result<i32, ParseIntError> {
145
+ number_str.parse::<i32>().map(|n| 2 * n)
146
+ }
147
+
148
+ fn main() {
149
+ match double_number("10") {
150
+ Ok(n) => assert_eq!(n, 20),
151
+ Err(err) => printLn!("Error: {:?}", err),
152
+ }
153
+ }
154
+
155
+ trait error: debug + display (
156
+ fn description(): str
157
+ fn cause(): option<error>
158
+ )
159
+
160
+ trait From<T>(
161
+ fn from(v: T) -> Self;
162
+ )
163
+
164
+ trait Debug(
165
+ fn fmt(f: Formateer): result[unit, unit]
166
+ )
167
+
168
+ trait Display(
169
+ fn fmt(f: Formateer): result[unit, unit]
170
+ )
171
+
172
+ record Car(wheels: int)
173
+
174
+ fn getWheels() =
175
+ returns 4
176
+
177
+ fn main() =
178
+ let c1 = some(Car(wheels: 2))
179
+ let c2: option<Car> = none
180
+
181
+ let c1 = Some(Car(wheels: 2))
182
+ let c2: Option<Car> = None
183
+
184
+ match c
185
+ none -> print("no car")
186
+ some(car) -> car.getWheels()
187
+
188
+ Car c2 = null
189
+ c2.getWheels() // Null pointer
190
+ ```
191
+
192
+ (1 + 2).mod(3).pow(2).sqrt()
193
+
194
+ math.sqrt(math.pow(math.mod(1 + 2, 3)))
195
+
196
+ repeat(10) |i|
197
+ pass
198
+
199
+ repeat(n) |i|
200
+ pass
201
+
202
+ data.each() |k, v|
203
+ pass
204
+
205
+ list.of(1, 2, 3).each() |v, i|
206
+ pass
207
+
208
+ map.of("a" => 1, "b" => 2).each() |k, v|
209
+ pass
210
+
211
+ repeat() |_|
212
+ pass
213
+
214
+ repeat(|_| i < 9) |i|
215
+ pass
216
+
217
+ repeat(|_| a > b && c < d) |i|
218
+ pass
std/bool.mi CHANGED
@@ -4,38 +4,9 @@ enum bool =
4
4
  | true
5
5
  | false
6
6
 
7
+ fn (x: bool) op_eq(y: bool) = x == y
7
8
  fn (x: bool) op_ne(y: bool) = x != y
8
9
  fn (x: bool) op_and(y: bool) = x == false || y == false ? false : true
9
10
  fn (x: bool) op_or(y: bool) = x == true || y == true ? true : false
10
11
  fn (x: bool) op_not(): bool = x == true ? false : true
11
12
  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 DELETED
@@ -1,170 +0,0 @@
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/html.mi ADDED
@@ -0,0 +1,43 @@
1
+ module std
2
+
3
+ test("HTML DSL") |_|
4
+ tree := html(class: "123")
5
+ head() |_|
6
+ title("Pacos")
7
+ link(href: "https://pacos.dev")
8
+ body(class: "bg-white") |_|
9
+ div(class: "box") |_|
10
+ text("Hello")
11
+ div() |_|
12
+ text("World")
13
+ assert tree.to_str() == ```
14
+ <html>
15
+ <head>
16
+ <title>Pacos</title>
17
+ <link href="https://pacos.dev" />
18
+ </head>
19
+ <body>
20
+ <div class="box">
21
+ Hello
22
+ </div>
23
+ <div>
24
+ World
25
+ </div>
26
+ </body>
27
+ </html>
28
+ ```
29
+
30
+ html(class: "123") {
31
+ head() {
32
+ title("name")
33
+ link(href: "123")
34
+ }
35
+ body(class: "class") {
36
+ div(class: "132") {
37
+ text("Hello")
38
+ }
39
+ div() {
40
+ text("World")
41
+ }
42
+ }
43
+ }
std/http.mi CHANGED
@@ -1,20 +1,18 @@
1
1
  import std/path
2
2
  import std/os
3
- import http/content_type
3
+ import std/http/content_type
4
+
5
+ #[builder]
6
+ record Response(
7
+ headers: map[str, str]
8
+ body: Buffer
9
+ status: int
10
+ )
4
11
 
5
12
  fn file_response(file: str): Response! =
6
13
  ext := path::ext(file)
7
- content := content_type::from_ext(ext)
14
+ content := contentTypeFromExt(ext)
8
15
  data := try os.read_file(file)
9
- Response(
10
- status: 200,
11
- headers: map.of(
12
- "Content-Type" => content,
13
- "Content-Length" => "2"
14
- ),
15
- body: data
16
- )
17
-
18
16
  Response()
19
17
  .header("Content-Type", content)
20
18
  .header("Content-Length", "2")
@@ -28,45 +26,9 @@ fn index(): Response! =
28
26
  #[get("/public/<...>")]
29
27
  fn public(file: str): Response! =
30
28
  ext := path::ext(file)
31
- content := content_type::from_ext(ext)
29
+ content := contentTypeFromExt(ext)
32
- data := try os.read_file(file)
30
+ data := os.readFile?(file)
33
- Response(
31
+ Response()
32
+ .header("Content-Type", content)
33
+ .body(data)
34
- status: 200,
34
+ .status(200)
35
- headers: [
36
- :ContentType => content,
37
- ],
38
- body: data,
39
- )
40
-
41
-
42
- /// Http similar to rocket
43
- /// GET,DELETE Request -> fn params are got from query
44
- /// POST,PUT,PATCH Request -> fn params got from multi part form body
45
- /// DI at compiler level
46
- /// Controller similar to IHP
47
-
48
- #[path("/counters")]
49
- record CounterController(db: DB)
50
- static path = "/counters"
51
-
52
- fn all(): HttpResponse =
53
- counters := db.query(Counter).fetchAll()
54
- render(CounterList(counters))
55
-
56
- fn view() =
57
- counter := fetchOne(Counter) ?? createOne(Counter)
58
- if counter := fetchOne(Counter)
59
- render CounterView(counter)
60
- else
61
- counter <- newRecord @Counter |> set #count 0 |> createRecord
62
- render CounterView(counter)
63
-
64
- fn increment(id: str) =
65
- counter <- fetch counterId
66
- updatedCounter <- counter |> incrementField #count |> updateRecord
67
- respondHtml $ counterView updatedCounter
68
-
69
- fn decrement(id: str) =
70
- counter <- fetch counterId
71
- updatedCounter <- counter |> decrementField #count |> updateRecord
72
- respondHtml $ counterView updatedCounter
std/list.mi CHANGED
@@ -15,7 +15,7 @@ record node[V](
15
15
  next: node[V]?
16
16
  )
17
17
 
18
- fn List.of[A](values: ...A): list[A] =
18
+ fn listOf[A](values: ...A): list[A] =
19
19
  list[A]().add(values)
20
20
 
21
21
  fn (l: list) get(i: int) -> A =
@@ -44,7 +44,7 @@ fn (l: list) add(values: ...V) =
44
44
  l.head.next.prev = l.head
45
45
  l._size += 1
46
46
 
47
- fn (l: list) remove_at(i int) =
47
+ fn (l: list) removeAt(i int) =
48
48
  `removes the element at i'th index of the list
49
49
  l.tail?.prev?.next = nil
50
50
  `old tail node gets deallocated due to zero reference count
@@ -102,7 +102,7 @@ fn (l: list) map[B](cb: fn(v: V): B): list[A] =
102
102
  nl.push(item)
103
103
  nl
104
104
 
105
- fn (l: list) flat_map() =
105
+ fn (l: list) flatMap() =
106
106
  `returns a new list with all elements shuffled`
107
107
  pass
108
108
 
@@ -165,7 +165,7 @@ fn (l: list) chunk() =
165
165
  `returns a new list with all elements shuffled`
166
166
  pass
167
167
 
168
- fn (l: list) group_by() =
168
+ fn (l: list) groupBy() =
169
169
  `returns a new list with all elements grouped`
170
170
  pass
171
171
 
@@ -177,32 +177,3 @@ fn (l: list) join(sep: str = ","): str =
177
177
  else
178
178
  res.write(@TypeToString(v), sep)
179
179
  res.to_str()
180
-
181
-
182
-
183
- enum list<T> =
184
- | empty
185
- | link(v: T, rest: list<T>)
186
-
187
- fn list.of[A](values: ...A): list[A] =
188
- list[A]().add(values)
189
-
190
- fn (o list<T>) each(cb: fn(v: T)) =
191
- match o
192
- empty -> return
193
- link(a, rest) ->
194
- cb(a)
195
- rest.each(cb)
196
-
197
- fn (l: list) append(values: ...V) =
198
- `adds the specified elements to the start of the list
199
- range(values) |v|
200
- l.add(v)
201
-
202
- fn (l: list) append(v: V) =
203
- `adds the specified elements to the start of the list
204
- l.last().rest = link(v, empty)
205
-
206
- fn (l: list) prepend(v: V) =
207
- `adds the specified elements to the start of the list
208
- l.first() = link(v, l.first())
std/map.mi CHANGED
@@ -29,5 +29,3 @@ fn (m: Map) update() =
29
29
 
30
30
  fn (m: Map) update_if() =
31
31
  pass
32
-
33
- data.price?.take_if(|a| a != "")
std/os.mi ADDED
@@ -0,0 +1,5 @@
1
+ module std
2
+
3
+ fn printLn(): result[unit, unit] =
4
+ `Writes the specified data, followed by the current line terminator, to the standard output stream.
5
+ pass
std/ranges.mi DELETED
@@ -1,75 +0,0 @@
1
- fn range(start: int, e: int, cb: fn(int)) =
2
- match start < end ->
3
- cb(start)
4
- range(start + 1, end, cb)
5
-
6
- fn repeat(n: int, cb: fn(int): void) =
7
- match n != 0
8
- 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
17
-
18
- fn main() =
19
- repeat(10) |i|
20
- println(i)
21
- range(10, 20) |i|
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/regex.mi ADDED
@@ -0,0 +1 @@
1
+ TBD
std/time.mi ADDED
@@ -0,0 +1,3 @@
1
+ record time()
2
+
3
+ record duration()
std/uuid.mi ADDED
@@ -0,0 +1 @@
1
+ type uuid = string