~repos /plum
git clone https://pyrossh.dev/repos/plum.git
A statically typed, imperative programming language inspired by rust, python
c772e73b
—
pyrossh 1 year ago
improve syn
- example/aa.kk +84 -0
- example/fn.palm +83 -0
- example/sample.palm +261 -26
- src/language/palm.langium +3 -3
example/aa.kk
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
fun print10()
|
|
2
|
+
for(1,10) fn(i)
|
|
3
|
+
println(i)
|
|
4
|
+
|
|
5
|
+
fun encode2( s : string, shift : int )
|
|
6
|
+
s.map( fn(c)
|
|
7
|
+
if c < 'a' || c > 'z' then return c
|
|
8
|
+
val base = (c - 'a').int
|
|
9
|
+
val rot = (base + shift) % 26
|
|
10
|
+
(rot.char + 'a')
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
fun printhi10()
|
|
14
|
+
repeat(10)
|
|
15
|
+
println("hi")
|
|
16
|
+
|
|
17
|
+
fun sublist( xs : list<a>, start : int, len : int = xs.length ) : list<a>
|
|
18
|
+
if start <= 0 return xs.take(len)
|
|
19
|
+
match xs
|
|
20
|
+
Nil -> Nil
|
|
21
|
+
Cons(_,xx) -> xx.sublist(start - 1, len)
|
|
22
|
+
|
|
23
|
+
fun chisqr( xs : list<float64>, ys : list<float64> ) : float64
|
|
24
|
+
zipwith(xs,ys, fn(x,y) ((x - y)^2.0)/y ).foldr(0.0,(+))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
fun fib(n : int) : div int
|
|
28
|
+
if n <= 0 then 0
|
|
29
|
+
elif n == 1 then 1
|
|
30
|
+
else fib(n - 1) + fib(n - 2)
|
|
31
|
+
|
|
32
|
+
fun fib2(n)
|
|
33
|
+
var x := 0
|
|
34
|
+
var y := 1
|
|
35
|
+
repeat(n)
|
|
36
|
+
val y0 = y
|
|
37
|
+
y := x+y
|
|
38
|
+
x := y0
|
|
39
|
+
x
|
|
40
|
+
|
|
41
|
+
fun wrong() : (() -> console ())
|
|
42
|
+
var x := 1
|
|
43
|
+
(fn(){ x := x + 1; println(x) })
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
struct person
|
|
47
|
+
age : int
|
|
48
|
+
name : string
|
|
49
|
+
realname : string = name
|
|
50
|
+
|
|
51
|
+
type person
|
|
52
|
+
Person
|
|
53
|
+
age : int
|
|
54
|
+
name : string
|
|
55
|
+
realname : string = name
|
|
56
|
+
|
|
57
|
+
val brian = Person( 29, "Brian" )
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
type color
|
|
61
|
+
Red
|
|
62
|
+
Green
|
|
63
|
+
Blue
|
|
64
|
+
|
|
65
|
+
type number
|
|
66
|
+
Infinity
|
|
67
|
+
Integer( i : int )
|
|
68
|
+
|
|
69
|
+
type bool
|
|
70
|
+
False
|
|
71
|
+
True
|
|
72
|
+
|
|
73
|
+
type list<a>
|
|
74
|
+
Nil
|
|
75
|
+
Cons{ head : a; tail : list<a> }
|
|
76
|
+
|
|
77
|
+
type tree
|
|
78
|
+
Tip
|
|
79
|
+
Bin( left: tree, value : int, right: tree )
|
|
80
|
+
|
|
81
|
+
fun tmap-inorder( t : tree, f : int -> int ) : tree
|
|
82
|
+
match t
|
|
83
|
+
Bin(l,x,r) -> Bin( l.tmap-inorder(f), f(x), r.tmap-inorder(f) )
|
|
84
|
+
Tip -> Tip
|
example/fn.palm
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
bool = (true | false)
|
|
2
|
+
op_eq(x: bool, y: bool) = x == y
|
|
3
|
+
op_ne(x: bool, y: bool) = x != y
|
|
4
|
+
op_and(x: bool, y: bool) = x && y
|
|
5
|
+
op_or(x: bool, y: bool) = x || y
|
|
6
|
+
op_xor(x: bool, y: bool) = x <> y
|
|
7
|
+
op_not(x: bool,): bool = !x
|
|
8
|
+
str(x: bool) = x.str()
|
|
9
|
+
|
|
10
|
+
list = (first | link(v: a, rest: list))
|
|
11
|
+
each(l: list, cb: (v: a)) =
|
|
12
|
+
match l
|
|
13
|
+
first => first
|
|
14
|
+
link(v, rest) =>
|
|
15
|
+
cb(v)
|
|
16
|
+
each(rest, cb)
|
|
17
|
+
|
|
18
|
+
map(l: list, cb: (v: a): v) =
|
|
19
|
+
match l
|
|
20
|
+
first => first
|
|
21
|
+
link(v, rest) => link(cb(v), map(rest, cb))
|
|
22
|
+
|
|
23
|
+
enum List<a>
|
|
24
|
+
first
|
|
25
|
+
link(v: a, rest: List)
|
|
26
|
+
|
|
27
|
+
fn each(l: list, cb: fn(v: a)) =
|
|
28
|
+
match l
|
|
29
|
+
first => first
|
|
30
|
+
link(v, rest) =>
|
|
31
|
+
cb(v)
|
|
32
|
+
each(rest, cb)
|
|
33
|
+
|
|
34
|
+
fn map(l: list, cb: fn(v: a): v) =
|
|
35
|
+
match l
|
|
36
|
+
first => first
|
|
37
|
+
link(v, rest) => link(cb(v), map(rest, cb))
|
|
38
|
+
|
|
39
|
+
Cat = (name: str, age: int)
|
|
40
|
+
fullname(c: Cat) =
|
|
41
|
+
c.name + c.age.str()
|
|
42
|
+
talk(c: Cat) =
|
|
43
|
+
println("cat ${c.name} says meow")
|
|
44
|
+
|
|
45
|
+
struct Cat(a, b)
|
|
46
|
+
name: str
|
|
47
|
+
age: int
|
|
48
|
+
fullname(c: Cat) =
|
|
49
|
+
c.name + c.age.str()
|
|
50
|
+
talk(c: Cat) =
|
|
51
|
+
println("cat ${c.name} says meow")
|
|
52
|
+
|
|
53
|
+
c = Cat(name = "123", age = 1)
|
|
54
|
+
c |> Cat.talk()
|
|
55
|
+
[1, 2, 3] |> list.each(println)
|
|
56
|
+
|
|
57
|
+
fib(n: int = 0) = 0
|
|
58
|
+
fib(n: int = 1) = 1
|
|
59
|
+
fib(n: int) = fib(n - 1) + fib(n - 2)
|
|
60
|
+
|
|
61
|
+
factorial(n: int) = 1
|
|
62
|
+
factorial(n: int) = n * factorial(n - 1)
|
|
63
|
+
|
|
64
|
+
to-celsius(f: float) = (f - 32) * (5 / 9)
|
|
65
|
+
|
|
66
|
+
repeat(n: int, cb: fn(int)) =
|
|
67
|
+
if n != 0:
|
|
68
|
+
cb(n)
|
|
69
|
+
repeat(n-1, cb)
|
|
70
|
+
|
|
71
|
+
range(start: int, e: int, cb: fn(int)) =
|
|
72
|
+
if (start < end):
|
|
73
|
+
cb(start)
|
|
74
|
+
range(start + 1, end, cb)
|
|
75
|
+
elif (start > end):
|
|
76
|
+
cb(start)
|
|
77
|
+
range(start - 1, end, cb)
|
|
78
|
+
|
|
79
|
+
main() =
|
|
80
|
+
repeat(10) |i|:
|
|
81
|
+
println(i)
|
|
82
|
+
range(10, 20) |i|:
|
|
83
|
+
println(i)
|
example/sample.palm
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
module palm
|
|
2
2
|
|
|
3
|
+
// byte, *byte, bool, int, float, str, decimal, time
|
|
3
|
-
// [] for
|
|
4
|
+
// [] for slices []int []str
|
|
4
|
-
// {} for maps
|
|
5
|
+
// {} for maps [int]int [str]str
|
|
5
|
-
// ? for optional int?
|
|
6
|
+
// ? for optional int? str?
|
|
6
|
-
// ! for error types int!,
|
|
7
|
+
// ! for error types int!, str!
|
|
7
8
|
// nil
|
|
8
9
|
|
|
9
10
|
// match a {
|
|
@@ -13,25 +14,151 @@ module palm
|
|
|
13
14
|
// _ => 10
|
|
14
15
|
// }
|
|
15
16
|
|
|
17
|
+
trait Comparable<a>:
|
|
18
|
+
fn compare(left: a, right: a): bool
|
|
19
|
+
|
|
20
|
+
trait Stringable:
|
|
16
|
-
|
|
21
|
+
fn str() str
|
|
22
|
+
|
|
23
|
+
entity arr<A>:
|
|
24
|
+
val data: *A
|
|
25
|
+
val length: int
|
|
26
|
+
|
|
27
|
+
fn map(cb: fn(v: A) A):
|
|
28
|
+
return cb(a)
|
|
29
|
+
|
|
30
|
+
fn each():
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
entity number is Comparable, Stringable {
|
|
34
|
+
fn sqrt() {
|
|
35
|
+
}
|
|
36
|
+
fn abs() {
|
|
37
|
+
}
|
|
38
|
+
fn acos() {
|
|
39
|
+
}
|
|
40
|
+
fn acosh() {
|
|
41
|
+
}
|
|
42
|
+
fn asin() {
|
|
43
|
+
}
|
|
44
|
+
fn asinh() {
|
|
45
|
+
}
|
|
17
46
|
}
|
|
18
47
|
|
|
48
|
+
alias list<a, n : int> = {
|
|
49
|
+
data : a[n],
|
|
50
|
+
length : uint32
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
19
|
-
primitive
|
|
54
|
+
primitive math {
|
|
55
|
+
fn sqrt() {
|
|
56
|
+
}
|
|
57
|
+
|
|
20
|
-
fn
|
|
58
|
+
fn log() {
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fn round() {
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
2.0
|
|
66
|
+
|> math.sqrt()
|
|
67
|
+
|> math.log()
|
|
68
|
+
|> math.round()
|
|
69
|
+
|
|
70
|
+
var nn = 2.0
|
|
71
|
+
|
|
72
|
+
entity str is Comparable, Stringable {
|
|
73
|
+
val data: *u16
|
|
74
|
+
val length: int
|
|
75
|
+
|
|
76
|
+
// fn reverse() {
|
|
77
|
+
// let start = 0
|
|
78
|
+
// let end = this.length - 1
|
|
79
|
+
// let result = []
|
|
80
|
+
// while (start < end) {
|
|
81
|
+
// const temp = this[start]
|
|
82
|
+
// this[start] = this[end]
|
|
83
|
+
// this[end] = temp
|
|
84
|
+
// end = end - 1
|
|
85
|
+
// start = start + 1
|
|
86
|
+
// }
|
|
87
|
+
// }
|
|
88
|
+
|
|
89
|
+
fn to_int() int! {
|
|
90
|
+
if (fail) {
|
|
91
|
+
throw errors.int_parse;
|
|
92
|
+
}
|
|
93
|
+
return 0
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
fn to_float() float! {
|
|
97
|
+
if (fail) {
|
|
98
|
+
throw errors.float_parse;
|
|
99
|
+
}
|
|
100
|
+
return 0.0
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
primitive int is Stringable {
|
|
105
|
+
fn add(y: int) {
|
|
106
|
+
@"llvm.uadd.with.overflow.i32"(this, y)
|
|
21
107
|
}
|
|
22
108
|
fn sub() {
|
|
23
109
|
}
|
|
110
|
+
|
|
24
111
|
fn minus() {
|
|
25
112
|
}
|
|
113
|
+
|
|
114
|
+
fn str() {
|
|
115
|
+
if (this == 0) {
|
|
116
|
+
return "0";
|
|
117
|
+
}
|
|
118
|
+
let result = str(31)
|
|
119
|
+
let i = 0
|
|
120
|
+
let num = this
|
|
121
|
+
while (num != 0) {
|
|
122
|
+
const rem = num % 10
|
|
123
|
+
result.push((rem > 9) ? (rem - 10) + 'a' : rem + '0')
|
|
124
|
+
num = num / 10
|
|
125
|
+
}
|
|
126
|
+
if (this < 0) {
|
|
127
|
+
result.push("-")
|
|
128
|
+
}
|
|
129
|
+
return result.reverse()
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
fn str() {
|
|
133
|
+
}
|
|
26
134
|
}
|
|
27
135
|
|
|
28
|
-
primitive float {
|
|
136
|
+
primitive float is Stringable {
|
|
29
137
|
fn add() {
|
|
30
138
|
}
|
|
31
139
|
fn sub() {
|
|
32
140
|
}
|
|
33
141
|
fn minus() {
|
|
34
142
|
}
|
|
143
|
+
|
|
144
|
+
// fn str() {
|
|
145
|
+
// ipart = (int)n
|
|
146
|
+
// fpart = n - (float)ipart
|
|
147
|
+
// // convert integer part to string
|
|
148
|
+
// int i = intToStr(ipart, res, 0)
|
|
149
|
+
|
|
150
|
+
// // check for display option after point
|
|
151
|
+
// if (afterpoint != 0) {
|
|
152
|
+
// res[i] = '.'; // add dot
|
|
153
|
+
|
|
154
|
+
// // Get the value of fraction part upto given no.
|
|
155
|
+
// // of points after dot. The third parameter
|
|
156
|
+
// // is needed to handle cases like 233.007
|
|
157
|
+
// fpart = fpart * pow(10, afterpoint);
|
|
158
|
+
|
|
159
|
+
// intToStr((int)fpart, res + i + 1, afterpoint);
|
|
160
|
+
// }
|
|
161
|
+
// }
|
|
35
162
|
}
|
|
36
163
|
|
|
37
164
|
entity decimal {
|
|
@@ -39,7 +166,7 @@ entity decimal {
|
|
|
39
166
|
exponent: float
|
|
40
167
|
}
|
|
41
168
|
|
|
42
|
-
fn println()
|
|
169
|
+
fn println() bool? {
|
|
43
170
|
}
|
|
44
171
|
|
|
45
172
|
// value Email(str) {
|
|
@@ -80,20 +207,35 @@ trait IO {
|
|
|
80
207
|
|
|
81
208
|
// // static fn only(top: double = 0, left: double = 0, bottom: double = 0, right: double = 0) {
|
|
82
209
|
// // return EdgeInsets(top, left, bottom, right)
|
|
83
|
-
// // }
|
|
210
|
+
// // }
|
|
84
211
|
// }
|
|
85
212
|
|
|
86
213
|
enum bool {
|
|
87
214
|
false
|
|
88
215
|
true
|
|
89
|
-
|
|
90
|
-
fn is_equal(other: bool) -> bool {
|
|
91
|
-
// return this == other
|
|
92
|
-
}
|
|
93
216
|
|
|
217
|
+
fn op_eq(y: bool) bool {
|
|
218
|
+
this == y;
|
|
219
|
+
}
|
|
220
|
+
fn op_ne(y: bool) bool {
|
|
221
|
+
this != y
|
|
222
|
+
}
|
|
223
|
+
fn op_and(y: bool) bool {
|
|
224
|
+
this and y
|
|
225
|
+
}
|
|
226
|
+
fn op_or(y: bool) bool {
|
|
227
|
+
this or y
|
|
228
|
+
}
|
|
229
|
+
fn op_xor(y: bool) bool {
|
|
230
|
+
this xor y
|
|
231
|
+
}
|
|
232
|
+
fn op_not() bool {
|
|
233
|
+
!this
|
|
234
|
+
}
|
|
235
|
+
|
|
94
|
-
fn
|
|
236
|
+
fn str() str {
|
|
95
237
|
println("123")
|
|
96
|
-
println(1 + 2 + 4 + 5.33 + 7.8km)
|
|
238
|
+
// println(1 + 2 + 4 + 5.33 + 7.8km)
|
|
97
239
|
}
|
|
98
240
|
}
|
|
99
241
|
|
|
@@ -106,11 +248,11 @@ enum Color {
|
|
|
106
248
|
println("log")
|
|
107
249
|
}
|
|
108
250
|
|
|
109
|
-
fn
|
|
251
|
+
fn str() str {
|
|
110
|
-
println("
|
|
252
|
+
println("Str")
|
|
111
253
|
}
|
|
112
254
|
|
|
113
|
-
fn where_is()
|
|
255
|
+
fn where_is() int {
|
|
114
256
|
// match a {
|
|
115
257
|
// 1, 2, 3 => 0,
|
|
116
258
|
// 5...100 => 1,
|
|
@@ -120,14 +262,76 @@ enum Color {
|
|
|
120
262
|
}
|
|
121
263
|
}
|
|
122
264
|
|
|
265
|
+
enum List
|
|
266
|
+
| first
|
|
267
|
+
| link(first: a, rest: List<a>)
|
|
268
|
+
|
|
269
|
+
fn sum():
|
|
270
|
+
case this:
|
|
271
|
+
| first => 0
|
|
272
|
+
| link(a, res) => a + sum(res)
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
enitity List<a> {
|
|
278
|
+
data: Pointer
|
|
279
|
+
length: int
|
|
280
|
+
|
|
281
|
+
fn construct(items ...a) {
|
|
282
|
+
repeat(items) |item| {
|
|
283
|
+
data.alloc(item)
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
enum List<a> {
|
|
289
|
+
first
|
|
290
|
+
link(first: a, rest: List<a>)
|
|
291
|
+
|
|
292
|
+
fn op_brackets(items ...a) {
|
|
293
|
+
l = link(items[0])
|
|
294
|
+
range(items.length-2) |i| {
|
|
295
|
+
l.rest = link(items[i+1])
|
|
296
|
+
}
|
|
297
|
+
return l
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
fn sum() {
|
|
301
|
+
match this {
|
|
302
|
+
first => 0
|
|
303
|
+
link(a, res) => a + sum(res)
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
test("List") |t| {
|
|
309
|
+
fn sum(l: List<int>) int {
|
|
310
|
+
return l.reduce(|it| it.value, 0)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
sum(empty) is 0
|
|
314
|
+
sum(link(1, link(2, link(3, empty)))) is 6
|
|
315
|
+
sum([1, 2, 3]) is 6
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
enum Tree<a> {
|
|
319
|
+
leaf
|
|
320
|
+
node(value: a, left: Tree<a>, right: Tree<a>)
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
fn main() int {
|
|
324
|
+
repeat(10) |i| {
|
|
325
|
+
println(i)
|
|
326
|
+
}
|
|
327
|
+
range(10, 20) |i| {
|
|
328
|
+
println(i)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
|
|
123
333
|
|
|
124
|
-
// repeat(10) |i| {
|
|
125
|
-
// println(i)
|
|
126
|
-
// }
|
|
127
334
|
|
|
128
|
-
// range(10, 20) |i| {
|
|
129
|
-
// println(i)
|
|
130
|
-
// }
|
|
131
335
|
|
|
132
336
|
// fn decrement() {
|
|
133
337
|
// println("decrementing")
|
|
@@ -181,4 +385,35 @@ enum Color {
|
|
|
181
385
|
|
|
182
386
|
// Node "Fred" (Node "Jim" Leaf Leaf)
|
|
183
387
|
// (Node "Sheila" (Node "Alice" Leaf Leaf)
|
|
184
|
-
// (Node "Bob" Leaf Leaf))
|
|
388
|
+
// (Node "Bob" Leaf Leaf))
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
class Cat(let name: String, let lives: Int64)
|
|
395
|
+
class Dog(let name: String, let years: Int64)
|
|
396
|
+
union Pet of Cat, Dog
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
class Person(
|
|
400
|
+
let firstName: String,
|
|
401
|
+
let lastName: String,
|
|
402
|
+
var age: Int64
|
|
403
|
+
) {
|
|
404
|
+
fun fullName(): String = "${self.firstName} ${self.lastName}"
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
fun sum(a: Int64, b: Int64): Int64 = a + b
|
|
408
|
+
|
|
409
|
+
2.0.sqrt()
|
|
410
|
+
|
|
411
|
+
fun describe(pet: Pet): String = if pet
|
|
412
|
+
... is Cat(let name, let lives) { "cat $name has $lives lives" }
|
|
413
|
+
... is Dog(let name, let years) { "dog $name is $years of age" }
|
|
414
|
+
|
|
415
|
+
List(Cat("Molly", 9), Dog("Fenton", 6))
|
|
416
|
+
.retain(|p| p.name.size > 5)
|
|
417
|
+
.map (|p| describe(p))
|
|
418
|
+
.each (|d| println(d))
|
|
419
|
+
// → dog Fenton is 6 years of age
|
src/language/palm.langium
CHANGED
|
@@ -21,7 +21,7 @@ Enum:
|
|
|
21
21
|
'}';
|
|
22
22
|
|
|
23
23
|
EnumField:
|
|
24
|
-
name=ID;
|
|
24
|
+
name=ID ('(' (params+=Param (',' params+=Param)*)? ')')?;
|
|
25
25
|
|
|
26
26
|
Trait:
|
|
27
27
|
'trait' name=ID Generics '{'
|
|
@@ -51,8 +51,8 @@ QualifiedName returns string:
|
|
|
51
51
|
type AbstractDefinition = FunctionDefinition | Param;
|
|
52
52
|
|
|
53
53
|
FunctionDefinition<isMethod, isTrait>:
|
|
54
|
-
(<isMethod> static?='static')?
|
|
54
|
+
(<isMethod> static?='static')?
|
|
55
|
-
'fn' name=ID '(' (params+=Param (',' params+=Param)*)? ')' (
|
|
55
|
+
'fn' name=ID '(' (params+=Param (',' params+=Param)*)? ')' (returns+=ReturnType (',' returns+=ReturnType)*)? (<!isTrait> Block);
|
|
56
56
|
|
|
57
57
|
ParamType:
|
|
58
58
|
type=[Type] (nilable?='?')?;
|