~repos /plum

#treesitter#compiler#wasm

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

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


22a1eb06 pyrossh

1 year ago
update readme
Files changed (1) hide show
  1. readme.md +246 -168
readme.md CHANGED
@@ -42,6 +42,10 @@ fn firstItem(items: list[int]): option[int] =
42
42
  fn toCelsius(f: float): float =
43
43
  (f - 32) * (5 / 9)
44
44
 
45
+ // Variadic function
46
+ fn addItems(items ...str) =
47
+ list.add(items)
48
+
45
49
  record Cat(
46
50
  name: str
47
51
  age: int
@@ -52,39 +56,74 @@ fn Cat.withName(name: str): Cat =
52
56
  Cat(name: name, age: 0)
53
57
 
54
58
  // A simple method
55
- fn (c: Cat) fullname(): str =
59
+ fn fullname(c: Cat): str =
56
60
  c.name + c.age.toStr()
57
61
 
58
- fn (c: Cat) talk() =
62
+ fn talk(c: Cat) =
59
63
  printLn("cat ${c.name} says meow")
60
64
 
61
- fn (c: Cat) toStr(): str =
65
+ fn toStr(c: Cat): str =
62
66
  "Cat<{c.fullname()}, ${c.age}>"
63
67
 
68
+ trait Stringable where
69
+ fn toStr(): str
70
+
71
+ // `Cat is a speciecs of felidae
72
+ struct Cat is Stringable, Equal, Comparable =
73
+ | name: str
74
+ | age: int
75
+
76
+ fn Cat(name: str, age: int) =
77
+ self.name = name
78
+ self.age = age
79
+
80
+ fn Cat.withName(name: str): Cat =
81
+ `Create a cat with only name
82
+ Cat(name: name, age: 0)
83
+
84
+ fn fullname(): str =
85
+ name + age.toStr()
86
+
87
+ fn talk() =
88
+ printLn("cat ${name} says meow")
89
+
90
+ fn toStr(): str =
91
+ "Cat<${fullname()}, ${age}>"
92
+
64
- enum Temperature =
93
+ enum Temperature where
65
94
  | celsius(float)
66
95
  | fahrenheit(float)
67
96
 
68
- fn (s: Temperature) toStr(): str =
97
+ fn toStr(): str =
69
- match s
98
+ match self
70
- celsius(t) && t > 30 -> "${t}C is above 30 celsius"
99
+ celsius(t) && t > 30 -> "${t}C is above 30 celsius"
71
- celsius(t) -> "${t}C is below 30 celsius"
100
+ celsius(t) -> "${t}C is below 30 celsius"
72
- fahrenheit(t) && t > 86 -> "${t}F is above 86 fahrenheit"
101
+ fahrenheit(t) && t > 86 -> "${t}F is above 86 fahrenheit"
73
- fahrenheit(t) -> "${t}F is below 86 fahrenheit"
102
+ fahrenheit(t) -> "${t}F is below 86 fahrenheit"
74
103
 
75
104
  type MapCallback = fn(v: a): v
76
105
 
77
- trait Comparable[A: Compare](
106
+ struct DB(conn_url: str) where
78
- fn compare(left: A, right: A): bool
79
- )
80
107
 
108
+ fn connect(): Result[unit, DatabaseError] =
109
+ `connect to the database
81
- trait Stringable(
110
+ online := status()
82
- fn toStr(): str
111
+ if !online
112
+ Err(NotOnline(conn_url))
113
+ else
83
- )
114
+ Ok(unit)
84
115
 
116
+ fn status(): bool =
117
+ `check if the database is running
118
+ res := exec("select 1")
85
- record DB(
119
+ if res == None
120
+ false
121
+ else
122
+ true
123
+
124
+ fn exec(q: str): Result[unit] =
86
- conn_url: str
125
+ `exec some stuff
87
- )
126
+ printLn("Going to exec q")
88
127
 
89
128
  #[error]
90
129
  enum DatabaseError =
@@ -99,53 +138,47 @@ fn newDB(conn_url: str) result[DB, DatabaseError] =
99
138
  else
100
139
  db
101
140
 
102
- fn (d: DB) status(conn_url: str): bool =
141
+ fn (d: DB) status(): bool =
103
142
  res := d.exec("select 1")
104
143
  if res == None
105
144
  false
106
145
  else
107
146
  true
108
147
 
109
- // Testing
148
+ suite "Cat" do
110
- test("talks") |t|
149
+ test "talks" do
111
- c := Cat(name: "123", age: 1)
150
+ c := Cat(name: "123", age: 1)
151
+ c2 := Cat(...c, age: c.age + 1)
112
- c.talk()
152
+ c.talk()
113
-
114
- test("fullname") |t|
115
- Cat("rabby", 21).fullname() == "rabby21"
116
- c2 := Cat(...c, age: c.age + 1)
117
-
118
- test("ToStr") |t|
119
- items := [Cat("Molly", 9), Cat("Fenton", 6)]
120
- .retain(|p| p.name.size > 5)
121
- .map(|p| describe(p))
122
- .each(|d| printLn(d))
123
- assert items[0].toStr() == "Cat<Fenton, 6>"
124
-
125
- bench("1231") |n|
126
- for i := range n
127
- printLn(i)
128
- ```
129
153
 
130
- ## Language Reference
154
+ test "fullname" do
155
+ Assert.equal(Cat("rabby", 21).fullname(), "rabby21")
131
156
 
157
+ test "ToStr" do
158
+ items := [Cat("Molly", 9), Cat("Fenton", 6)]
159
+ .retain(|p| p.name.size > 5)
132
- **Keywords**
160
+ .map(|p| describe(p))
161
+ .each(|d| printLn(d))
162
+ Assert.equal(items[0].toStr(), "Cat<Fenton, 6>")
133
163
 
164
+ suite "diagonal" do
134
- ```rs
165
+ test "3 4 5" do
135
- for,while,if,else,record,type,enum,fn,assert,match
166
+ Assert.equal 5.0 (diagonal 3.0 4.0)
167
+ test "5 12 13" do
168
+ Assert.equal 5.0 (diagonal 3.0 4.0)
136
169
  ```
137
170
 
138
- ### Types
171
+ # Types
139
172
 
140
- **any**
173
+ ### any
141
174
 
142
175
  The any type is an empty trait and is used to represent all types
143
176
 
144
- **error**
177
+ ### error
145
178
 
146
179
  The error type is a trait that represents all Error types
147
180
 
148
- **bool**
181
+ ## bool
149
182
 
150
183
  A bool can be either `true` or `false`. It is used in logical operations and conditional statements.
151
184
 
@@ -156,58 +189,47 @@ if true || false
156
189
  print("works")
157
190
  ```
158
191
 
159
- **byte**
192
+ ## byte
160
193
 
161
194
  A byte represents an unsigned 8-bit number. It is mainly used to represent strings and binary data.
162
195
 
163
- ```rb
196
+ ```go
197
+ up_event := 'a'
164
- let data: []byte?
198
+ key_code := 102
165
- data = [104, 101, 197, 130, 197, 130, 111, 0]
166
199
  ```
167
200
 
168
- **int**
201
+ ## int
169
202
 
170
203
  An int is a signed 64-bit number. It can be represented in various ways,
171
204
 
172
- ```
205
+ | Notation | Type | Base | Example |
206
+ | -------- | ----------- | ------- | ------------------------- |
173
- 0b - Binary (Base 2)
207
+ | 0b | Binary | Base 2 | `0b00101010`, `0b1_1111` |
174
- 0x - Hexadecimal (Base 16)
208
+ | 0x | Hexadecimal | Base 16 | `0xff00ff`, `0xFF80_0000` |
175
- 27 - Standard (Base 10)
209
+ | number | Standard | Base 10 | `98762`, `98_762` |
176
- ```
177
-
178
- ```rb
179
- 0b00101010
180
- 0b1_1111_1
181
- 0xff00ff
182
- 0xFF00FF
183
- 0xFF80_0000_0000_0000
184
- 98762
185
- 1_000_000
186
- ```
187
210
 
188
- **float**
211
+ ## float
189
212
 
190
213
  A float represents a 64-bit floating point [IEEE-754-2008](https://en.wikipedia.org/wiki/Double-precision_floating-point_format).
191
214
 
215
+ | Type | Example |
216
+ | ----------- | ----------------- |
192
- ```java
217
+ | Normal | `1.2`, `-0.4` |
193
- 1.2
194
- -0.4
195
- 12.0f
196
- 15.03f
218
+ | With suffix | `15.03f`, `12.0f` |
197
- ```
219
+ | E notation | `2.7e-12`, `1e10` |
198
220
 
199
- **dec**
221
+ ## dec
200
222
 
201
223
  A dec is a decimal floating-point numbering format which is 64-bit data type.
202
224
  It is intended for applications where it is necessary to emulate decimal rounding exactly, such as financial and tax computations.
203
225
  It supports 16 decimal digits of significand and an exponent range of −383 to +384.
204
226
 
205
- ```java
227
+ | Type | Example |
206
- 2.4d
228
+ | ---------- | ----------------- |
207
- -13.3d
229
+ | Normal | `2.4d`, `-13.3d` |
208
- ```
230
+ | E notation | `2.7e-12`, `1e10` |
209
231
 
210
- **str**
232
+ ## str
211
233
 
212
234
  A str represents an array of runes or unicode code points. It is encoded to UTF-8 by default.
213
235
  It supports interpolation of variables/values that implement the ToStr interface.
@@ -284,16 +306,14 @@ An option is a type that represents either value present `some` or nothing prese
284
306
  ```go
285
307
  import std/option
286
308
 
287
- record Car(wheels: int)
288
-
289
- c := some(Car(wheels: 2))
309
+ c := some(2)
290
310
 
291
311
  match c
292
312
  none -> print("no car")
293
- some(car) -> car.wheels
313
+ some(c) -> print("${c}")
294
314
 
295
- if Some(car) = c
315
+ if some(count) = c
296
- printLn("Hello ${car.wheels}")
316
+ printLn("Hello ${count}")
297
317
  else
298
318
  printLn("nothing")
299
319
  ```
@@ -347,7 +367,9 @@ fn main(): result[int] =
347
367
  ok(0)
348
368
  ```
349
369
 
370
+ # Declarations
371
+
350
- **constants**
372
+ ## constants
351
373
 
352
374
  Constants can be declared at the top level of a program. They cannot be reassigned.
353
375
 
@@ -370,20 +392,115 @@ const COUNTRY_CODES = map.of(
370
392
  fn count(n: int): int = n * 1
371
393
  ```
372
394
 
395
+ ## variables
396
+
397
+ Variables can be declared only at the local scope of a function as they are mutable. They are references/pointers to data.
398
+ We use the Short Variable Declaration Operator `:=` to declare a variable
399
+
400
+ ```go
401
+ fn calculate(n: int): int =
402
+ a := 1 + n
403
+ b := 1 * n
404
+ a * b
405
+ ```
406
+
407
+ ## Functions
408
+
409
+ ```rs
410
+ fn fib(n: int): int =
411
+ match n
412
+ 0 | 1 -> n
413
+ _ -> fib(n - 1) + fib(n - 2)
414
+
415
+ fn log(level: str, msg: str) =
416
+ printLn("${level}: ${msg}")
417
+
418
+ fn info(msg: str) =
419
+ printLn("INFO", msg)
420
+
421
+ fn warning(msg: str) =
422
+ printLn("WARN", msg)
423
+
424
+ fn addLists[T](a: List[T], b: List[T]): List[T] =
425
+ a.concat(b)
426
+
427
+ // Variadic function
428
+ fn addItems(items ...str) =
429
+ for i, v := range items
430
+ printLn("${i} ${v}")
431
+ ```
432
+
433
+ ## Records
434
+
435
+ A record is a collect of data indexed by fields. It is a reference type and reference counted.
436
+
437
+ ```rs
438
+ struct Cat is Stringable =
439
+ | name: str
440
+ | age: int
441
+
442
+ fn Cat.withName(name: str): Cat =
443
+ Cat(name: name, age: 0)
444
+
445
+ fn fullname(): str =
446
+ name + age.toStr()
447
+
448
+ fn talk() =
449
+ printLn("cat ${name} says meow")
450
+
451
+ fn toStr(): str =
452
+ "Cat<${fullname()}, ${age}>"
453
+ ```
454
+
455
+ ## Traits
456
+
457
+ ```rs
458
+ trait Equatable[A] where
459
+ fn eq(left: A, right: A): bool
460
+ fn neq(left: A, right: A): bool
461
+
462
+ trait Comparable[A: Ord] where
463
+ fn compare(left: A, right: A): Ordering
464
+ ```
465
+
466
+ ## Enums
467
+
468
+ An Algebraic Data Type
469
+
470
+ ```rs
471
+ enum Ordering is Stringable =
472
+ | LT
473
+ | EQ
474
+ | GT
475
+
476
+ fn toStr(): str =
477
+ match self
478
+ LT -> "LT"
479
+ EQ -> "EQ"
480
+ GT -> "GT"
481
+ ```
482
+
483
+ ## Type
484
+
485
+ ```rs
486
+ type Size = int
487
+ type Metre = float
488
+ type MapString[T] = Map[String, T]
489
+ ```
490
+
491
+ # Statements
492
+
373
- **Assignment statement**
493
+ ## Assignment statement
374
494
 
375
495
  ```rb
376
496
  low, mid, high := 0, 0, n.numItems
377
497
  x := 10
378
498
  y := 20
379
- xy_list := [x, y]
499
+ xy_list := List.of(1, 2, 3)
380
- xy_map := [x: x, y: y]
381
- assoc_list = [:a => 1, :b => 2]
500
+ xy_map := Map.of(1 => "one", 2 => "two")
382
- assoc_list[:a]
383
- assoc_list["b"]
384
501
  ```
385
502
 
386
- **While statement**
503
+ ## while statement
387
504
 
388
505
  ```rb
389
506
  low, mid, high := 0, 0, n.size
@@ -396,9 +513,12 @@ while low < high
396
513
 
397
514
  while a > b
398
515
  a += 1
516
+
517
+ while Some(top) = stack.pop()
518
+ printLn(top)
399
519
  ```
400
520
 
401
- **For statement**
521
+ ## for statement
402
522
 
403
523
  ```rb
404
524
  for i := range 10
@@ -415,7 +535,7 @@ for v := range list
415
535
  sum += k + v
416
536
  ```
417
537
 
418
- **if expression/statement**
538
+ ## if expression/statement
419
539
 
420
540
  ```py
421
541
  if name == "Andreas"
@@ -435,7 +555,7 @@ fn getPerimeter(shape: Shape): Result[float] =
435
555
  match shape
436
556
  Rectangle(r) -> Ok(2 * r.length() + 2 * r.width())
437
557
  Circle(c) -> Ok(2 * c.radius() * PI)
438
- c -> err(RuntimeError("expected shape but found ${@TypeName(c)}"))
558
+ _ -> Err(RuntimeError("expected shape but found ${@TypeName(shape)}"))
439
559
 
440
560
  match x, y
441
561
  1, 1 -> "both are 1"
@@ -456,6 +576,23 @@ match
456
576
 
457
577
  ## Operators
458
578
 
579
+ **assignment operator**
580
+
581
+ ```go
582
+ x := 5
583
+ y := 3
584
+ x += y // 8
585
+ x -= y // 5
586
+ x *= y // 15
587
+ x /= y // 5
588
+ x %= y // 2
589
+ x &= y // 2
590
+ x |= y // 3
591
+ x <<= y // 24
592
+ x >>= y // 3
593
+ a ?= 2 // elvis assignment operator
594
+ ```
595
+
459
596
  **not operator**
460
597
 
461
598
  ```rb
@@ -466,7 +603,7 @@ match
466
603
  **ternary operator**
467
604
 
468
605
  ```rb
469
- x ? x : y
606
+ x ? a : b
470
607
  ```
471
608
 
472
609
  **safe navigation operator**
@@ -475,37 +612,13 @@ x ? x : y
475
612
  a?.b?.c?.d
476
613
  ```
477
614
 
478
- **double-bang operator/not-null assertion operator**
479
-
480
- ```rb
481
- a!!.b
482
- ```
483
-
484
615
  **elvis operator**
485
616
 
486
617
  ```rb
487
618
  x ?: y
488
619
  ```
489
620
 
490
- **elvis assignment operator**
491
-
492
- ```rb
493
- atomic_number ?= 2
494
- ```
495
-
496
- **spread operator**
497
-
498
- ```
499
- list := [1, 2, 3]
500
- list2 := [0, ...list]
501
- assert list2.length == 4
502
-
503
- list = nil
504
- list3 := [0, ...list?];
505
- assert list2.length == 1
506
- ```
507
-
508
- **cascade operator**
621
+ **cascade operator (remove??)**
509
622
 
510
623
  ```dart
511
624
  paint := Paint()
@@ -518,62 +631,31 @@ v := list.of(1, 2, 3)
518
631
  ..get(0)
519
632
  ```
520
633
 
521
- **variadic operator**
522
-
523
- ```go
524
- fn add(items ...str) =
525
- list.add(items)
526
- ```
527
-
528
- **assignment operator**
529
-
530
- ```go
531
- x := 5
532
- y := 3
533
- x += y // 8
534
- x -= y // 5
535
- x *= y // 15
536
- x /= y // 5
537
- x %= y // 2
538
- x &= y // 2
539
- x |= y // 3
540
- x <<= y // 24
541
- x >>= y // 3
542
- ```
543
-
544
634
  **range operator**
545
635
 
546
- ```go
636
+ ```rs
547
637
  type Seq0 = fn(yield: fn(): bool): bool
548
638
  type Seq1[V] = fn(yield: fn(V): bool): bool
549
639
  type Seq2[K, V] = fn(yield: fn(K, V): bool): bool
550
640
 
551
- record Tree[E](
641
+ struct Tree[E] =
552
- value E,
642
+ | value E
553
- left: Option[Tree],
643
+ | left: Option[Tree]
554
- right: Option[Tree],
644
+ | right: Option[Tree]
555
- )
556
645
 
557
- fn (t Tree[E]) op_range(yld: fn(E): bool): bool =
646
+ fn op_range(yld: fn(E): bool): bool =
558
- t ? true : t.left?.in_order(yld) && yld(t.val) && t.right?.in_order(yld)
647
+ t ? true : t.left?.in_order(yld) && yld(t.val) && t.right?.in_order(yld)
559
648
 
560
- tree := Tree(
649
+ let tree = Tree(
561
650
  value: 10,
562
651
  left: Tree(20, Tree(30), Tree(39)),
563
652
  right: Tree(40),
564
653
  )
565
654
 
566
- for t := range tree
655
+ for t := range tree:
567
656
  printLn(v)
568
657
  ```
569
658
 
570
- ## Generics
571
-
572
- ```
573
- fn add[T: int | float](a: List[T], b: List[T]): List[T] =
574
- pass
575
- ```
576
-
577
659
  ## Rules
578
660
 
579
661
  - Function parameters are passed by value only. You cannot modify a parameter. The compiler will throw an error if you try to.
@@ -590,7 +672,3 @@ fn add[T: int | float](a: List[T], b: List[T]): List[T] =
590
672
  | Local variables | snake_case |
591
673
  | Constants | SCREAMING_SNAKE_CASE |
592
674
  | Generics | single uppercase letter |
593
-
594
- ## Todo
595
-
596
- linter, formatter, test runner, language server, package manager