~repos /plum

#treesitter#compiler#wasm

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

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


1f7d137f pyrossh

1 year ago
lang changes
Files changed (4) hide show
  1. readme.md +108 -61
  2. std/http.mi +7 -7
  3. std/list.mi +47 -135
  4. std/map.mi +17 -7
readme.md CHANGED
@@ -1,14 +1,15 @@
1
1
  # 👾 Pacos Programming Language
2
2
 
3
- A simple statically typed imperative 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 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.
4
4
 
5
5
  The compiler users the tree-sitter parser so has out of the box syntax highlighting support for helix and zed editor.
6
6
 
7
7
  Here is some sample code, please enjoy.
8
+
8
9
  ```rb
9
10
  module lambda
10
11
 
11
- import ca/list
12
+ import pacos/list
12
13
  import pacos/math
13
14
  import pacos/http
14
15
 
@@ -22,12 +23,12 @@ fn sum(a: int, b: int): int = a + b
22
23
  fn sum_all(series: list[int]): int =
23
24
  series.reduce(0, |v| v + 1)
24
25
 
25
- fn fib(n: int): int =
26
+ fn fib(n: int) -> int
26
27
  match n
27
28
  0 | 1 -> n
28
29
  _ -> fib(n - 1) + fib(n - 2)
29
30
 
30
- fn fib(n: int): int =
31
+ fn fib(n: int) -> int
31
32
  if n == 0 || n == 1
32
33
  n
33
34
  else
@@ -86,7 +87,7 @@ enum Temperature =
86
87
  | celsius(float)
87
88
  | fahrenheit(float)
88
89
 
89
- fn (s Temperature) to_str(): str =
90
+ fn (s: Temperature) to_str(): str =
90
91
  match s
91
92
  celsius(t) && t > 30 -> "${t}C is above 30 celsius"
92
93
  celsius(t) -> "${t}C is below 30 celsius"
@@ -94,29 +95,23 @@ fn (s Temperature) to_str(): str =
94
95
  fahrenheit(t) -> "${t}F is below 86 fahrenheit"
95
96
 
96
97
 
97
- group("Cat Record") |g|
98
- test("talks") |t|
98
+ test("talks") |t|
99
- c := Cat(name = "123", age = 1)
99
+ c := Cat(name: "123", age: 1)
100
- c.talk()
100
+ c.talk()
101
-
102
- test("fullname") |t|
103
- Cat("rabby", 21).fullname() == "rabby21"
104
- c2 := Cat(...c, age: c.age + 1)
105
101
 
106
- test("to_str") |t|
102
+ test("fullname") |t|
107
- items := [Cat("Molly", 9), Cat("Fenton", 6)]
103
+ Cat("rabby", 21).fullname() == "rabby21"
108
- .retain(|p| p.name.size > 5)
104
+ c2 := Cat(...c, age: c.age + 1)
109
- .map(|p| describe(p))
110
- .each(|d| println(d))
111
- assert items[0].to_str() == "Cat<Fenton, 6>"
112
105
 
113
- test("enum ordinal value") |t|
106
+ test("to_str") |t|
114
- expect(Value.zero).to_equal(0)
107
+ items := [Cat("Molly", 9), Cat("Fenton", 6)]
115
- expect(Value.one).to_equal(1)
108
+ .retain(|p| p.name.size > 5)
109
+ .map(|p| describe(p))
116
- expect(Value.two).to_equal(2)
110
+ .each(|d| println(d))
111
+ assert items[0].to_str() == "Cat<Fenton, 6>"
117
112
 
118
- bench("1231") |t, n|
113
+ bench("1231") |n|
119
- for 0..n |i|
114
+ for i := range n
120
115
  println(i)
121
116
  ```
122
117
 
@@ -129,6 +124,7 @@ for,while,if,else,record,enum,fn,assert,when,match,type
129
124
  ```
130
125
 
131
126
  ### Types
127
+
132
128
  ```
133
129
  nil, any, bool, byte, int, float, dec, str, time, duration, regex, uuid
134
130
  [1, 2, 3] for lists list[int], list[list[int]]
@@ -159,6 +155,7 @@ if true || false
159
155
  **byte**
160
156
 
161
157
  A byte represents an unsigned 8 bit number. It is mainly used to represent strings and binary data.
158
+
162
159
  ```rb
163
160
  let data: []byte?
164
161
  data = [104, 101, 197, 130, 197, 130, 111, 0]
@@ -169,7 +166,7 @@ data = [104, 101, 197, 130, 197, 130, 111, 0]
169
166
  An int is a signed 64 bit number. It can be represented in various ways,
170
167
  0b - Binary (Base 2)
171
168
  0x - Hexadecimal (Base 16)
172
- 13 - Standard (Base 10)
169
+ 27 - Standard (Base 10)
173
170
 
174
171
  ```rb
175
172
  0b00101010
@@ -187,7 +184,7 @@ A float represents a 64-bit floating point (52-bit mantissa) IEEE-754-2008 binar
187
184
 
188
185
  **str**
189
186
 
190
- A str represents a slice of runes or unicode code points. It is encoded to UTF-8 by default.
187
+ A str represents an array of runes or unicode code points. It is encoded to UTF-8 by default.
191
188
  It supports interpolation of variables/values that implement the ToStr interface.
192
189
 
193
190
  ```go
@@ -197,7 +194,6 @@ age := 1
197
194
  println("Name ${name} age ${age}")
198
195
  ```
199
196
 
200
-
201
197
  **list**
202
198
 
203
199
  ```py
@@ -206,12 +202,17 @@ import pacos/list
206
202
  a := [1, 2, 3] // list[int]
207
203
  b := [[1, 2], [3, 4], [5, 6]] // list[list[int]]
208
204
 
209
- actors := List.new("Krabs", "Squidward")
205
+ actors := ["Krabs", "Squidward"]
210
206
  actors.add("Spongebob")
211
207
  actors.length() // ==> 3
212
208
  actors.contains("Krabs") // ==> true
213
209
  actors.get(0) // => "Krabs"
214
210
  actors.get(5) // => nil
211
+
212
+ items
213
+ .map(|v| v + 1)
214
+ .each(|v| println("v", v))
215
+ .reduce(0, |v| v + 1)
215
216
  ```
216
217
 
217
218
  **map**
@@ -238,13 +239,19 @@ friends_tree := [
238
239
  ],
239
240
  ],
240
241
  ]
242
+
243
+ friends_tree
244
+ .map(|k, v| v)
245
+ .each(|k, v| println("v", v))
246
+ .reduce(0, |k, v| v + 1)
241
247
  ```
242
248
 
243
249
  **Constants**
244
250
 
245
251
  Constants can be declared at the top level of a program. They cannot be reassigned.
252
+
246
- * Primitive values like`int, float, str` are directly replaced in code.
253
+ - Primitive values like`int, float, str` are directly replaced in code.
247
- * Reference values like `list, map, records` are initialized at program start and passed by reference when used. Their data can be modified.
254
+ - Reference values like `list, map, records` are initialized at program start and passed by reference when used. Their data can be modified.
248
255
 
249
256
  ```rb
250
257
  PI = 3.14159f
@@ -260,7 +267,6 @@ COUNTRY_CODES = [
260
267
  fn count(n: int): int = n * 1
261
268
  ```
262
269
 
263
-
264
270
  **Assignment statement**
265
271
 
266
272
  ```rb
@@ -277,43 +283,55 @@ assoc_list["b"]
277
283
  **While statement**
278
284
 
279
285
  ```rb
286
+ low, mid, high := 0, 0, n.size
280
287
  while low < high
281
288
  mid = (low + high) / 2
282
- low = cmp > 0 > mid + 1 : low
289
+ low = cmp > 0 ? mid + 1 : low
283
290
  high = cmp < 0 ? mid : high
284
291
  if cmp == 0
285
292
  return mid, true
293
+
294
+ while a > b
295
+ a += 1
286
296
  ```
287
297
 
288
298
  **For statement**
289
299
 
300
+ type Seq0 = fn(yield: fn(): bool): bool
301
+ type Seq1[V] = fn(yield: fn(V): bool): bool
302
+ type Seq2[K, V] = fn(yield: fn(K, V): bool): bool
303
+
290
304
  ```rb
291
- for players_list |value|
292
- if value == 0
305
+ for i := range 10
293
- continue
294
- sum += value
306
+ sum += i
295
307
 
308
+ n := 5
296
- for items[0..1] |v|
309
+ for i := range n
297
- sum += v
310
+ sum += i + 5
298
311
 
299
- for 0..5 |v|
312
+ for k, v := range json_map
300
- sum3 += v
313
+ sum += k + v
301
314
 
302
- let list = for filter(players_list) |v|
315
+ for v := range list
316
+ sum += k + v
303
317
 
304
- items
305
- .map(|v| v + 1)
306
- .each(|v| println("v", v))
307
- .reduce(0, |v| v + 1)
318
+ record Tree[E](
319
+ value E,
320
+ left: Tree[E]?,
321
+ right: Tree[E]?,
322
+ )
308
323
 
309
- fn range(start: int, end: int, cb: fn(v: T): IterateResult) =
324
+ fn (t Tree[E]) op_range(yld: fn(E): bool): bool =
325
+ t ? true : t.left.in_order(yld) && yld(t.val) && t.right.in_order(yld)
310
326
 
311
- range(0, 5, |v| =>
327
+ tt := Tree(
312
- sum3 += v
328
+ value: 10,
329
+ left: Tree(20, Tree(30), Tree(39)),
330
+ right: Tree(40),
313
331
  )
314
332
 
315
- for items, items2 |i, j|
316
- count += i + j
333
+ for t := range tt
334
+ println(v)
317
335
  ```
318
336
 
319
337
  **When expression/statement**
@@ -342,7 +360,7 @@ match xs
342
360
  _ -> "This list has more than 2 elements"
343
361
  ```
344
362
 
345
- Arithmetic (+, -, /, *, @divFloor, @sqrt, @ceil, @log, etc.)
363
+ Arithmetic (+, -, /, \*, @divFloor, @sqrt, @ceil, @log, etc.)
346
364
  Bitwise operators (>>, <<, &, |, ~, etc.)
347
365
  Comparison operators (<, >, ==, etc.)
348
366
 
@@ -350,9 +368,9 @@ Comparison operators (<, >, ==, etc.)
350
368
 
351
369
  ```rb
352
370
  if post.valid()
353
- RenderNewView()
371
+ render_create_view()
354
372
  else
355
- RenderPostView(post: post)
373
+ render_post(post: post)
356
374
  ```
357
375
 
358
376
  ### Conditional operators
@@ -376,9 +394,10 @@ x ? x : y
376
394
  a?.b?.c?.d
377
395
  ```
378
396
 
379
- **Safe index operator**
397
+ **double-bang operator/not-null assertion operator**
398
+
380
399
  ```rb
381
- array?[1]
400
+ a!!.b
382
401
  ```
383
402
 
384
403
  **elvis operator**
@@ -393,13 +412,41 @@ x ?: y
393
412
  atomic_number ?= 2
394
413
  ```
395
414
 
396
- **Range operator**
415
+ **spread operator**
397
- ```rb
416
+
398
- for 5..10 |i|
399
- println(i)
400
417
  ```
418
+ list := [1, 2, 3]
419
+ list2 := [0, ...list]
420
+ assert list2.length == 4
401
421
 
422
+ list = nil
423
+ list3 := [0, ...list?];
424
+ assert list2.length == 1
425
+ ```
426
+
427
+ **cascade operator**
428
+
429
+ ```dart
430
+ paint := Paint()
431
+ ..color = Colors.black
432
+ ..strokeCap = StrokeCap.round
433
+ ..strokeWidth = 5.0
434
+ ```
435
+
436
+ **variadic function**
437
+
402
- ```rb
438
+ ```go
439
+ fn add(items ...str) =
440
+ list.add(items)
441
+ ```
442
+
443
+ **generics**
444
+ ```
445
+ fn add[T: int | float](a: List[T], b: List[T]): List[T] =
446
+ pass
447
+ ```
448
+
449
+ ```
403
450
  fn create_post_action(req: Request): Response =
404
451
  post := Post(title = req.params.title, body = req.params.body)
405
452
  if post.valid()
std/http.mi CHANGED
@@ -9,17 +9,17 @@ fn file_response(file: str) =
9
9
  Response(
10
10
  status = 200,
11
11
  headers = [
12
- :Content-Type => content,
12
+ "Content-Type" => content,
13
- :Content-Length => "2"
13
+ "Content-Length" => "2"
14
14
  ],
15
15
  body = data
16
16
  )
17
17
 
18
- Response::build()
18
+ Response()
19
- .set_header("Content-Type", content)
19
+ .header("Content-Type", content)
20
- .set_header("Content-Length", "2")
20
+ .header("Content-Length", "2")
21
- .set_body(data)
21
+ .body(data)
22
- .set_status(200)
22
+ .status(200)
23
23
 
24
24
  #[get("/")]
25
25
  fn index(): Response! =
std/list.mi CHANGED
@@ -15,7 +15,10 @@ record node[V](
15
15
  next: node[V]?
16
16
  )
17
17
 
18
+ fn List.of[A](values: ...A): list[A] =
19
+ list[A]().add(values)
20
+
18
- fn (l: list) get(i: int): A =
21
+ fn (l: list) get(i: int) -> A =
19
22
  `gets the element at i'th index of the list
20
23
  current := l.head
21
24
  index := 0
@@ -26,27 +29,43 @@ fn (l: list) get(i: int): A =
26
29
  current = current.next
27
30
  index += 1
28
31
 
29
- fn (l: list) set(i: int, v: V): A =
32
+ fn (l: list) set(i: int, v: V) -> A =
30
33
  `sets the element at i'th index of the list
31
34
  pass
32
35
 
33
- fn (l: list) length(): int =
36
+ fn (l: list) length() -> A =
34
37
  `returns the no of elements in the list
35
38
  _size
36
39
 
37
- fn (l: list) add(c: V) =
40
+ fn (l: list) add(values: ...V) =
38
41
  `adds the specified elements to the start of the list
42
+ for v := range values
39
- l.head = node(value: v, prev: nil, next: l.head)
43
+ l.head = node(value: v, prev: nil, next: l.head)
40
- l.head.next.prev = l.head
44
+ l.head.next.prev = l.head
41
- l._size += 1
45
+ l._size += 1
42
46
 
43
- fn (l: list) remove(i int) =
47
+ fn (l: list) remove_at(i int) =
44
48
  `removes the element at i'th index of the list
45
49
  l.tail?.prev?.next = nil
46
50
  `old tail node gets deallocated due to zero reference count
47
51
  l.tail = list.tail?.prev
48
52
  l._size -= 1
49
53
 
54
+ fn (l: list) remove(v V) =
55
+ `removes the element v from list
56
+ l.tail?.prev?.next = nil
57
+ `old tail node gets deallocated due to zero reference count
58
+ l.tail = list.tail?.prev
59
+ l._size -= 1
60
+
61
+ fn (l: list) clear() =
62
+ `removes all objects from this list
63
+ l.tail?.prev?.next = nil
64
+ `old tail node gets deallocated due to zero reference count
65
+ l.tail = list.tail?.prev
66
+ l._size -= 1
67
+
68
+
50
69
  fn (l: list) reverse(v: fn(v: V): true): list[A] =
51
70
  `returns a new list with the elements in reverse order.
52
71
  pass
@@ -55,24 +74,16 @@ fn (l: list) sort(sorter: fn(v: V): true): list[A] =
55
74
  `returns a new list with the elements sorted by sorter
56
75
  pass
57
76
 
58
- fn (l: list) find(search: V): V? =
77
+ fn (l: list) find(search: V): V?, int =
59
- `returns an item in the list if the item is is equal to search item
78
+ `returns an item and index in the list if the item is is equal to search item
60
- pass
61
-
62
- fn (l: list) find_index(search: V): int? =
63
- `returns the index of an item in the list if present and comparable otherwise nil
64
79
  pass
65
80
 
66
- fn (l: list) contains(v: V): int? =
81
+ fn (l: list) contains(v: V): bool =
67
82
  `returns the index of an item in the list if present and comparable otherwise nil
68
83
  pass
69
84
 
70
- fn (l: list) concat(ol: list): list[A] =
85
+ fn (l: list) op_spread(other: list): list[A] =
71
- `returns the index of an item in the list if present and comparable otherwise nil
86
+ `combines this list with other list and returns a new list
72
- pass
73
-
74
- fn (l: list) sub_list(start: int, end: int?): list[A] =
75
- `returns the index of an item in the list if present and comparable otherwise nil
76
87
  pass
77
88
 
78
89
  fn (l: list) each(cb: fn(v: V)): void =
@@ -103,11 +114,11 @@ fn (l: list) reject(predicate: fn(v: V): A): list[A] =
103
114
  `returns a new list with the elements that matched the predicate removed
104
115
  pass
105
116
 
106
- fn (l: list) any(predicate: fn(v: V): bool) =
117
+ fn (l: list) any(predicate: fn(v: V): bool): bool =
107
118
  `returns true if any element in the list satisfies the predicate
108
119
  pass
109
120
 
110
- fn (l: list) all(predicate: fn(v: V): bool) =
121
+ fn (l: list) every(predicate: fn(v: V): bool): bool =
111
122
  `returns true if all of the elements in the list satisfies the predicate
112
123
  pass
113
124
 
@@ -123,15 +134,23 @@ fn (l: list) last(): A? =
123
134
  `returns the last element in the list
124
135
  l.tail?.value
125
136
 
137
+ fn (l: list) sublist(start: int, end: int): list[A] =
138
+ `returns a list containing the first n elements of the given list
139
+ pass
140
+
126
141
  fn (l: list) take(n: int): list[A] =
127
142
  `returns a list containing the first n elements of the given list
128
143
  pass
129
144
 
145
+ fn (l: list) skip(n: int): list[A] =
146
+ `returns a list containing the first n elements of the given list
147
+ pass
148
+
130
149
  fn (l: list) drop(n: int): list[A] =
131
150
  `Returns a list containing the first n elements of the given list
132
151
 
133
152
  fn (l: list) sample() =
134
- `returns a new list with all elements shuffled`
153
+ `returns a new list with some of the elements taken randomly`
135
154
  pass
136
155
 
137
156
  fn (l: list) shuffle() =
@@ -147,121 +166,14 @@ fn (l: list) chunk() =
147
166
  pass
148
167
 
149
168
  fn (l: list) group_by() =
150
- `returns a new list with all elements shuffled`
169
+ `returns a new list with all elements grouped`
151
170
  pass
152
171
 
153
- fn (l: list) to_str(): str =
172
+ fn (l: list) join(sep: str = ","): str =
154
173
  res := Buffer()
155
174
  l.each() |v|
156
175
  if @HasTrait(V, ToStr)
157
- res.write(v.to_str())
176
+ res.write(v.to_str(), sep)
158
177
  else
159
- res.write(@TypeToString(v))
178
+ res.write(@TypeToString(v), sep)
160
179
  res.to_str()
161
-
162
-
163
-
164
- class List[V]:
165
- head: node[V]?
166
- tail: node[V]?
167
- size: int
168
-
169
- fn get(i: int): A =
170
- `gets the element at i'th index of the list
171
- current := l.head
172
- index := 0
173
- while current != nil
174
- if index == i
175
- current.value
176
- else
177
- current = current.next
178
- index += 1
179
-
180
- fn set(i: int, v: V): A =
181
- `sets the element at i'th index of the list
182
- pass
183
-
184
- fn add(c: V) =
185
- `adds the specified elements to the start of the list
186
- l.head = node(value: v, prev: nil, next: l.head)
187
- l.head.next.prev = l.head
188
- l._size += 1
189
-
190
- fn remove(i int) =
191
- `removes the element at i'th index of the list
192
- l.tail?.prev?.next = nil
193
- `old tail node gets deallocated due to zero reference count
194
- l.tail = list.tail?.prev
195
- l._size -= 1
196
-
197
- fn reverse(v: fn(v: V): true): list[A] =
198
- `returns a new list with the elements in reverse order.
199
- pass
200
-
201
- fn sort(sorter: fn(v: V): true): list[A] =
202
- `returns a new list with the elements sorted by sorter
203
- pass
204
-
205
- fn find(search: V): V? =
206
- `returns an item in the list if the item is is equal to search item
207
- pass
208
-
209
- fn find_index(search: V): int? =
210
- `returns the index of an item in the list if present and comparable otherwise nil
211
- pass
212
-
213
- fn contains(s: V): bool =
214
- `returns whether s is present in the list or not
215
- pass
216
-
217
- fn concat(ol: list): list[A] =
218
- `returns the index of an item in the list if present and comparable otherwise nil
219
- pass
220
-
221
- fn sub_list(start: int, end: int?): list[A] =
222
- `returns the index of an item in the list if present and comparable otherwise nil
223
- pass
224
-
225
- fn each(cb: fn(v: V)): void =
226
- `calls f for each elem in the list
227
- current := l.head
228
- while current != nil
229
- cb(current.value)
230
- current = current.next
231
-
232
- fn map[B](cb: fn(v: V): B): list[A] =
233
- `returns a list made up of B elements for each elem in the list
234
- nl := []
235
- current := l.head
236
- while current != nil
237
- item := cb(current.value)
238
- nl.push(item)
239
- nl
240
-
241
- fn flat_map() =
242
- `returns a new list with all elements shuffled`
243
- pass
244
-
245
- fn retain(predicate: fn(v: V): A): list[A] =
246
- `returns a new list with the elements that matched the predicate
247
- pass
248
-
249
- fn reject(predicate: fn(v: V): A): list[A] =
250
- `returns a new list with the elements that matched the predicate removed
251
- pass
252
-
253
- fn any(predicate: fn(v: V): bool) =
254
- `returns true if any element in the list satisfies the predicate
255
- pass
256
-
257
- fn all(predicate: fn(v: V): bool) =
258
- `returns true if all of the elements in the list satisfies the predicate
259
- pass
260
-
261
- fn reduce[B](acc: B, cb: fn(v: V): A): B =
262
- `returns the accumulated value of all the elements in the list
263
- pass
264
-
265
- fn first(): A? =
266
- `returns the first element in the list
267
- l.head?.value
std/map.mi CHANGED
@@ -1,9 +1,19 @@
1
1
  module std
2
2
 
3
- record map<V>(data: Pointer, length: int)
3
+ record Pair[K: Comparable, V](k: K, v: V)
4
- """
4
+
5
- A slice is a data structure describing a contiguous section of an array stored separately from the slice variable itself.
5
+ `A slice is a data structure describing a contiguous section of an array stored separately from the slice variable itself.
6
- A slice is not an array. A slice describes a piece of an array.
6
+ `A slice is not an array. A slice describes a piece of an array.
7
- """
7
+ record map[K, V](
8
+ items: list[Pair[K, V]]
9
+ )
10
+
11
+ fn map.of[K, V](kvs: ...Pair[K, V]): map[K, V] =
12
+ map[K, V]().add(kvs)
13
+
14
+ fn (m: map) add(kvs: ...Pair[K, V]) =
15
+ `adds the specified elements to the start of the list
8
- new init(): Slice
16
+ items.add(pair)
17
+
18
+ fn (m: Map) op_range() =
9
- pass
19
+ yield k, v