~repos /plum

#treesitter#compiler#wasm

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

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


c725b923 pyrossh

1 year ago
update
Files changed (5) hide show
  1. readme.md +119 -55
  2. std/list.mi +29 -0
  3. std/map.mi +3 -1
  4. std/option.mi +7 -31
  5. std/result.mi +3 -81
readme.md CHANGED
@@ -133,14 +133,6 @@ for,while,if,else,record,enum,fn,assert,match,type
133
133
 
134
134
  ### Types
135
135
 
136
- ```
137
- nil, any, err, bool, byte, int, float, dec, str, time, duration, regex, uuid
138
- [1, 2, 3] for lists list[int], list[list[int]]
139
- [:a => 1, :b => 2] for maps map[int], map[map[int]]
140
- ? for optional int? str?
141
- ! for return error types int!, str!
142
- ```
143
-
144
136
  **nil**
145
137
 
146
138
  The nil type is used to represent types that are nilable
@@ -149,6 +141,10 @@ The nil type is used to represent types that are nilable
149
141
 
150
142
  The any type is an empty trait and is used to represent all types
151
143
 
144
+ **err**
145
+
146
+ The err type is an enum of all errors
147
+
152
148
  **bool**
153
149
 
154
150
  A bool can be either `true` or `false`. It is used in logical operations and conditional statements.
@@ -190,6 +186,10 @@ An int is a signed 64 bit number. It can be represented in various ways,
190
186
 
191
187
  A float represents a 64-bit floating point (52-bit mantissa) IEEE-754-2008 binary64
192
188
 
189
+ **dec**
190
+
191
+ A decimal type represents BCD number. It has a mantissa and exponent.
192
+
193
193
  **str**
194
194
 
195
195
  A str represents an array of runes or unicode code points. It is encoded to UTF-8 by default.
@@ -255,6 +255,22 @@ friends_tree
255
255
  .reduce(0, |k, v| v + 1)
256
256
  ```
257
257
 
258
+ **time**
259
+
260
+ TBD
261
+
262
+ **duration**
263
+
264
+ TBD
265
+
266
+ **regex**
267
+
268
+ TBD
269
+
270
+ **uuid**
271
+
272
+ TBD
273
+
258
274
  **Constants**
259
275
 
260
276
  Constants can be declared at the top level of a program. They cannot be reassigned.
@@ -263,11 +279,11 @@ Constants can be declared at the top level of a program. They cannot be reassign
263
279
  - Reference values like `list, map, records` are initialized at program start and passed by reference when used. Their data can be modified.
264
280
 
265
281
  ```rb
266
- PI = 3.14159f
282
+ const PI = 3.14159f
267
- ERR_MESSAGE = "An unknown error occured"
283
+ const ERR_MESSAGE = "An unknown error occured"
268
- COUNT = count(10)
284
+ const COUNT = count(10)
269
- COUNTRIES_LIST = ["US", "INDIA", "CANADA"]
285
+ const COUNTRIES_LIST = ["US", "INDIA", "CANADA"]
270
- COUNTRY_CODES = [
286
+ const COUNTRY_CODES = [
271
287
  :in => "INDIA",
272
288
  :us => "United States",
273
289
  :ca => "Canada"
@@ -383,44 +399,6 @@ match xs
383
399
  [a] -> "This list has 1 element"
384
400
  [a, b] -> "This list has 2 elements"
385
401
  _ -> "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"
424
402
  ```
425
403
 
426
404
  Arithmetic (+, -, /, \*, @divFloor, @sqrt, @ceil, @log, etc.)
@@ -532,13 +510,99 @@ fn divide(dividend: u32, divisor: u32) !u32 =
532
510
  )
533
511
  BrokenPipe, ConnectionResetByPeer -> return false
534
512
  _ -> error_handler(req, res, err)
535
- ```
536
513
 
514
+ error FileOpenError
515
+ | AccessDenied(str)
516
+ | OutOfMemory(str)
537
- ### Error handling
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")
538
555
 
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
556
 
557
+ use std::num::ParseIntError;
558
+
541
- We have mutiple return values to solve this similar to golang. And failures/panic need to exit/restart the app.
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
+ ```
542
606
 
543
607
  ### General naming convention
544
608
 
std/list.mi CHANGED
@@ -177,3 +177,32 @@ 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
@@ -28,4 +28,6 @@ fn (m: Map) update() =
28
28
  pass
29
29
 
30
30
  fn (m: Map) update_if() =
31
- pass
31
+ pass
32
+
33
+ data.price?.take_if(|a| a != "")
std/option.mi CHANGED
@@ -4,40 +4,16 @@ enum option[T] =
4
4
  | none
5
5
  | some(T)
6
6
 
7
+ enum Option<T> =
8
+ | None
9
+ | Some(T)
10
+
7
- fn (o Option[T]) unwrap(): T =
11
+ fn (o option[T]) get(): T =
8
12
  match o
9
13
  some(val) -> val
10
- none -> fail("called `option.unwrap()` on a `none` value")
14
+ none -> fail("called 'option.get()' on a 'none' value")
11
15
 
12
- fn (o option[T: ToStr]) display(): T =
16
+ fn (o option[T: ToStr]) to_str(): str =
13
17
  match o
14
18
  some(v) -> v.to_str()
15
19
  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/result.mi CHANGED
@@ -1,6 +1,6 @@
1
1
  module std
2
2
 
3
- `result` is a type that represents either success ([`ok`]) or failure ([`err`]).
3
+ `result is a type that represents either success ok or failure err.
4
4
  #[derive(Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
5
5
  enum result[T, E]
6
6
  | ok(T)
@@ -27,7 +27,7 @@ fn (o result[T, E]) err(): option[E] =
27
27
  fn (o result) get(): T =
28
28
  match o
29
29
  ok(v) -> v
30
- err(e) -> panic("called `option.unwrap()` on a `none` value")
30
+ err(e) -> panic("called `result.get()` on a `none` value")
31
31
 
32
32
  fn (o result) default(d: T): T =
33
33
  match o
@@ -42,82 +42,4 @@ fn (o result) map(cb: fn(v: T)): result =
42
42
  fn (o result) map_err(cb: fn(e: E)): result =
43
43
  match o
44
44
  ok(v) -> unreachable
45
- err(e) -> cb(v)
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