~repos /plum
git clone https://pyrossh.dev/repos/plum.git
A statically typed, imperative programming language inspired by rust, python
c725b923
—
pyrossh 1 year ago
update
- readme.md +119 -55
- std/list.mi +29 -0
- std/map.mi +3 -1
- std/option.mi +7 -31
- 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
|
-
|
|
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
|
-
|
|
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
|
|
11
|
+
fn (o option[T]) get(): T =
|
|
8
12
|
match o
|
|
9
13
|
some(val) -> val
|
|
10
|
-
none -> fail("called
|
|
14
|
+
none -> fail("called 'option.get()' on a 'none' value")
|
|
11
15
|
|
|
12
|
-
fn (o option[T: ToStr])
|
|
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
|
|
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 `
|
|
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
|