~repos /plum
git clone https://pyrossh.dev/repos/plum.git
A statically typed, imperative programming language inspired by rust, python
5f5d99d4
—
Peter John 1 year ago
new syntax
- .gitignore +0 -1
- .vscode/launch.json +11 -11
- libs/std/bool.ks +0 -53
- libs/std/bool.plum +23 -0
- libs/std/encode/base64.plum +199 -0
- libs/std/err.plum +8 -0
- libs/std/float.ks +0 -0
- libs/std/float.plum +33 -0
- libs/std/html.mi +0 -34
- libs/std/{http.mi → http.plum} +8 -11
- libs/std/int.ks +0 -178
- libs/std/int.plum +140 -0
- libs/std/{json.mi → json.plum} +42 -55
- libs/std/{list.mi → list.plum} +0 -1
- libs/std/map.mi +0 -75
- libs/std/map.plum +39 -0
- libs/std/option.ks +0 -36
- libs/std/result.ks +0 -38
- libs/std/str.mi +0 -182
- libs/std/str.plum +177 -0
- test/add.plum +1 -1
- test/sample.plum +83 -432
- tooling/vscode-plum/language-configuration.json +15 -3
- tooling/vscode-plum/syntaxes/plum.tmLanguage.json +182 -0
.gitignore
CHANGED
|
@@ -8,6 +8,5 @@ src/language/generated/
|
|
|
8
8
|
static/bundle/
|
|
9
9
|
static/monaco-editor-workers/
|
|
10
10
|
static/worker/
|
|
11
|
-
syntaxes/
|
|
12
11
|
node_modules
|
|
13
12
|
*.vsix
|
.vscode/launch.json
CHANGED
|
@@ -3,15 +3,15 @@
|
|
|
3
3
|
// Hover to view descriptions of existing attributes.
|
|
4
4
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
5
|
{
|
|
6
|
-
|
|
6
|
+
"version": "0.2.0",
|
|
7
|
-
|
|
7
|
+
"configurations": [
|
|
8
|
-
|
|
8
|
+
{
|
|
9
|
-
|
|
9
|
+
"name": "Extension",
|
|
10
|
-
|
|
10
|
+
"type": "extensionHost",
|
|
11
|
-
|
|
11
|
+
"request": "launch",
|
|
12
|
-
|
|
12
|
+
"args": [
|
|
13
|
-
|
|
13
|
+
"--extensionDevelopmentPath=${workspaceFolder}/tooling/vscode-plum"
|
|
14
|
-
|
|
14
|
+
]
|
|
15
|
-
|
|
15
|
+
}
|
|
16
|
-
|
|
16
|
+
]
|
|
17
17
|
}
|
libs/std/bool.ks
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
module std
|
|
2
|
-
|
|
3
|
-
trait Bool : ToStr permits True, False {
|
|
4
|
-
operator fn eq(other: Bool) -> Bool
|
|
5
|
-
operator fn neq(other: Bool) -> Bool
|
|
6
|
-
operator fn and(other: Bool) -> Bool
|
|
7
|
-
operator fn or(other: Bool) -> Bool
|
|
8
|
-
operator fn not() -> Bool
|
|
9
|
-
override fn toStr() -> Str
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
tuple True() : Bool {
|
|
13
|
-
operator fn eq(other: Bool) -> Bool {
|
|
14
|
-
return other is True
|
|
15
|
-
}
|
|
16
|
-
operator fn neq(other: Bool) -> Bool {
|
|
17
|
-
return !self.eq()
|
|
18
|
-
}
|
|
19
|
-
operator fn and(other: Bool) -> Bool {
|
|
20
|
-
return other is False ? False : True
|
|
21
|
-
}
|
|
22
|
-
operator fn or(other: Bool) -> Bool {
|
|
23
|
-
return True
|
|
24
|
-
}
|
|
25
|
-
operator fn not() -> Bool {
|
|
26
|
-
return False
|
|
27
|
-
}
|
|
28
|
-
override fn toStr() -> Str {
|
|
29
|
-
return "True"
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
tuple False() : Bool {
|
|
35
|
-
operator fn eq(other: Bool) -> Bool {
|
|
36
|
-
return other is False
|
|
37
|
-
}
|
|
38
|
-
operator fn neq(other: Bool) -> Bool {
|
|
39
|
-
return !self.eq()
|
|
40
|
-
}
|
|
41
|
-
operator fn and(other: Bool) -> Bool {
|
|
42
|
-
return False
|
|
43
|
-
}
|
|
44
|
-
operator fn or(other: Bool) -> Bool {
|
|
45
|
-
return other is True ? True : False
|
|
46
|
-
}
|
|
47
|
-
operator fn not() -> Bool {
|
|
48
|
-
return True
|
|
49
|
-
}
|
|
50
|
-
override fn toStr() -> Str {
|
|
51
|
-
return "False"
|
|
52
|
-
}
|
|
53
|
-
}
|
libs/std/bool.plum
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module std
|
|
2
|
+
|
|
3
|
+
Bool =
|
|
4
|
+
| True
|
|
5
|
+
| False
|
|
6
|
+
|
|
7
|
+
# Might not be needed
|
|
8
|
+
Bool\toStr() -> Str =
|
|
9
|
+
"True"
|
|
10
|
+
|
|
11
|
+
Bool\and(other: Bool) -> Bool =
|
|
12
|
+
match self, other is
|
|
13
|
+
True, True => True
|
|
14
|
+
True, False => False
|
|
15
|
+
False, True => False
|
|
16
|
+
False, False => False
|
|
17
|
+
|
|
18
|
+
Bool\or(other: Bool) -> Bool =
|
|
19
|
+
match self, other is
|
|
20
|
+
True, True => True
|
|
21
|
+
True, False => True
|
|
22
|
+
False, True => True
|
|
23
|
+
False, False => False
|
libs/std/encode/base64.plum
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
```
|
|
2
|
+
# Base64 package
|
|
3
|
+
|
|
4
|
+
The Base64 package contains support for doing Base64 binary-to-text encodings.
|
|
5
|
+
We currently have support 3 encodings: PEM, MIME and URL.
|
|
6
|
+
|
|
7
|
+
To learn more about Base64, we suggest you check out the
|
|
8
|
+
[wikipedia entry](https://en.wikipedia.org/wiki/Base64).
|
|
9
|
+
|
|
10
|
+
## Example code
|
|
11
|
+
|
|
12
|
+
use "encode/base64"
|
|
13
|
+
|
|
14
|
+
actor Main
|
|
15
|
+
new create(env: Env) =>
|
|
16
|
+
env.out.print(Base64.encode("foobar"))
|
|
17
|
+
try
|
|
18
|
+
env.out.print(Base64.decode[String iso]("Zm9vYmFy")?)
|
|
19
|
+
end
|
|
20
|
+
```
|
|
21
|
+
module base64
|
|
22
|
+
|
|
23
|
+
# Encode for PEM (RFC 1421).
|
|
24
|
+
encodePEM(data: ReadSeq[U8]) -> String =
|
|
25
|
+
encode(data, '+', '/', '=', 64)
|
|
26
|
+
|
|
27
|
+
# Encode for MIME (RFC 2045).
|
|
28
|
+
encodeMIME(data: ReadSeq[U8]) -> String =
|
|
29
|
+
encode(data, '+', '/', '=', 76)
|
|
30
|
+
|
|
31
|
+
# Encode for URLs (RFC 4648). Padding characters are stripped by default.
|
|
32
|
+
encodeURL(data: ReadSeq[U8], pad: Bool = False) -> String =
|
|
33
|
+
let c: U8 = if pad then '=' else 0 end
|
|
34
|
+
encode[A](data, '-', '_', c)
|
|
35
|
+
|
|
36
|
+
# Configurable encoding. The defaults are for RFC 4648.
|
|
37
|
+
encode(
|
|
38
|
+
data: ReadSeq[U8],
|
|
39
|
+
at62: U8 = '+',
|
|
40
|
+
at63: U8 = '/',
|
|
41
|
+
pad: U8 = '=',
|
|
42
|
+
linelen: USize = 0,
|
|
43
|
+
linesep: String = "\r\n"
|
|
44
|
+
) -> String =
|
|
45
|
+
len = ((data.size() + 2) / 3) * 4
|
|
46
|
+
out = A(len)
|
|
47
|
+
lineblocks = linelen / 4
|
|
48
|
+
srclen = data.size()
|
|
49
|
+
blocks = USize(0)
|
|
50
|
+
i = USize(0)
|
|
51
|
+
|
|
52
|
+
while srclen >= 3 do
|
|
53
|
+
let in1 = data(i)?
|
|
54
|
+
let in2 = data(i + 1)?
|
|
55
|
+
let in3 = data(i + 2)?
|
|
56
|
+
|
|
57
|
+
let out1 = in1 >> 2
|
|
58
|
+
let out2 = ((in1 and 0x03) << 4) + (in2 >> 4)
|
|
59
|
+
let out3 = ((in2 and 0x0f) << 2) + (in3 >> 6)
|
|
60
|
+
let out4 = in3 and 0x3f
|
|
61
|
+
|
|
62
|
+
out.push(encodeByte(out1, at62, at63)?)
|
|
63
|
+
out.push(encodeByte(out2, at62, at63)?)
|
|
64
|
+
out.push(encodeByte(out3, at62, at63)?)
|
|
65
|
+
out.push(encodeByte(out4, at62, at63)?)
|
|
66
|
+
|
|
67
|
+
i = i + 3
|
|
68
|
+
blocks = blocks + 1
|
|
69
|
+
srclen = srclen - 3
|
|
70
|
+
|
|
71
|
+
if (lineblocks > 0) and (blocks == lineblocks) then
|
|
72
|
+
out.append(linesep)
|
|
73
|
+
blocks = 0
|
|
74
|
+
|
|
75
|
+
if srclen >= 1 then
|
|
76
|
+
let in1 = data(i)?
|
|
77
|
+
let in2 = if srclen == 2 then data(i + 1)? else 0 end
|
|
78
|
+
|
|
79
|
+
let out1 = in1 >> 2
|
|
80
|
+
let out2 = ((in1 and 0x03) << 4) + (in2 >> 4)
|
|
81
|
+
let out3 = (in2 and 0x0f) << 2
|
|
82
|
+
|
|
83
|
+
out.push(encodeByte(out1, at62, at63)?)
|
|
84
|
+
out.push(encodeByte(out2, at62, at63)?)
|
|
85
|
+
|
|
86
|
+
if srclen == 2 then
|
|
87
|
+
out.push(encodeByte(out3, at62, at63)?)
|
|
88
|
+
else
|
|
89
|
+
out.push(pad)
|
|
90
|
+
|
|
91
|
+
out.push(pad)
|
|
92
|
+
|
|
93
|
+
if lineblocks > 0 then
|
|
94
|
+
out.append(linesep)
|
|
95
|
+
else
|
|
96
|
+
out.clear()
|
|
97
|
+
out
|
|
98
|
+
|
|
99
|
+
fun decode_url[A: Seq[U8] iso = Array[U8] iso](data: ReadSeq[U8]): A^ ? =>
|
|
100
|
+
"""
|
|
101
|
+
Decode for URLs (RFC 4648).
|
|
102
|
+
"""
|
|
103
|
+
decode[A](data, '-', '_')?
|
|
104
|
+
|
|
105
|
+
fun decode[A: Seq[U8] iso = Array[U8] iso](
|
|
106
|
+
data: ReadSeq[U8],
|
|
107
|
+
at62: U8 = '+',
|
|
108
|
+
at63: U8 = '/',
|
|
109
|
+
pad: U8 = '=')
|
|
110
|
+
: A^ ?
|
|
111
|
+
=>
|
|
112
|
+
"""
|
|
113
|
+
Configurable decoding. The defaults are for RFC 4648. Missing padding is
|
|
114
|
+
not an error. Non-base64 data, other than whitespace (which can appear at
|
|
115
|
+
any time), is an error.
|
|
116
|
+
"""
|
|
117
|
+
let len = (data.size() * 4) / 3
|
|
118
|
+
let out = recover A(len) end
|
|
119
|
+
|
|
120
|
+
var state = U8(0)
|
|
121
|
+
var input = U8(0)
|
|
122
|
+
var output = U8(0)
|
|
123
|
+
|
|
124
|
+
for i in Range(0, data.size()) do
|
|
125
|
+
input = data(i)?
|
|
126
|
+
|
|
127
|
+
let value =
|
|
128
|
+
match input
|
|
129
|
+
| ' ' | '\t' | '\r' | '\n' => continue
|
|
130
|
+
| pad => break
|
|
131
|
+
| at62 => 62
|
|
132
|
+
| at63 => 63
|
|
133
|
+
| if (input >= 'A') and (input <= 'Z') =>
|
|
134
|
+
(input - 'A')
|
|
135
|
+
| if (input >= 'a') and (input <= 'z') =>
|
|
136
|
+
((input - 'a') + 26)
|
|
137
|
+
| if (input >= '0') and (input <= '9') =>
|
|
138
|
+
((input - '0') + 52)
|
|
139
|
+
else
|
|
140
|
+
error
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
match state
|
|
144
|
+
| 0 =>
|
|
145
|
+
output = value << 2
|
|
146
|
+
state = 1
|
|
147
|
+
| 1 =>
|
|
148
|
+
out.push(output or (value >> 4))
|
|
149
|
+
output = (value and 0x0f) << 4
|
|
150
|
+
state = 2
|
|
151
|
+
| 2 =>
|
|
152
|
+
out.push(output or (value >> 2))
|
|
153
|
+
output = (value and 0x03) << 6
|
|
154
|
+
state = 3
|
|
155
|
+
| 3 =>
|
|
156
|
+
out.push(output or value)
|
|
157
|
+
state = 0
|
|
158
|
+
else
|
|
159
|
+
error
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
if output != 0 then
|
|
164
|
+
Fact(input != pad)?
|
|
165
|
+
|
|
166
|
+
match state
|
|
167
|
+
| 1 | 2 => out.push(output)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
out
|
|
172
|
+
|
|
173
|
+
# Encode a single byte
|
|
174
|
+
encodeByte(i: Byte, at62: Byte, at63: Byte) -> Byte =
|
|
175
|
+
match
|
|
176
|
+
i == 62 => at62
|
|
177
|
+
i == 63 => at63
|
|
178
|
+
i < 26 => 'A' + i
|
|
179
|
+
i < 52 => ('a' - 26) + i
|
|
180
|
+
i < 62 => ('0' - 52) + i
|
|
181
|
+
|
|
182
|
+
# Test base64 encoding.
|
|
183
|
+
# Using test examples from RFC 4648.
|
|
184
|
+
encodeDecodeTest() =
|
|
185
|
+
assert
|
|
186
|
+
encode(a) == b
|
|
187
|
+
decode(b) == a
|
|
188
|
+
where:
|
|
189
|
+
a | b
|
|
190
|
+
"" | ""
|
|
191
|
+
"f" | "Zg=="
|
|
192
|
+
"fo" | "Zm8="
|
|
193
|
+
"foo" | "Zm9v"
|
|
194
|
+
"foob" | "Zm9vYg=="
|
|
195
|
+
"fooba" | "Zm9vYmE="
|
|
196
|
+
"foobar" | "Zm9vYmFy"
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
# a | b | c << sql.rows("select a, b, c from maxdata")
|
libs/std/err.plum
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
module std
|
|
2
|
+
|
|
3
|
+
# This is used to represent an error value across the language
|
|
4
|
+
Err = (
|
|
5
|
+
code() -> Int
|
|
6
|
+
msg() -> Str
|
|
7
|
+
cause() -> Err | Nil
|
|
8
|
+
)
|
libs/std/float.ks
DELETED
|
File without changes
|
libs/std/float.plum
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Float::PI=3.14
|
|
2
|
+
|
|
3
|
+
fn acosh(v: float): float =
|
|
4
|
+
when
|
|
5
|
+
x < 1 | IsNaN(x) -> // first case is special case
|
|
6
|
+
NaN()
|
|
7
|
+
x == 1 ->
|
|
8
|
+
0
|
|
9
|
+
x >= Large ->
|
|
10
|
+
Log(x) + Ln2 // x > 2**28
|
|
11
|
+
x > 2 ->
|
|
12
|
+
Log(2*x - 1/(x+Sqrt(x*x-1))) // 2**28 > x > 2
|
|
13
|
+
_ ->
|
|
14
|
+
t := x - 1
|
|
15
|
+
// ((2*t+t*t).sqrt() + t).log1p()
|
|
16
|
+
Log1p(t + Sqrt(2*t+t*t)) // 2 >= x > 1
|
|
17
|
+
|
|
18
|
+
fn is_finite(): bool = true
|
|
19
|
+
` Check whether this number is finite, ie not +/-infinity and not NaN.
|
|
20
|
+
` True if exponent is not all 1s
|
|
21
|
+
(bits() and 0x7FF0_0000_0000_0000) != 0x7FF0_0000_0000_0000
|
|
22
|
+
|
|
23
|
+
# Check whether this number is +/-infinity
|
|
24
|
+
is_infinite: Bool =>
|
|
25
|
+
# True if exponent is all 1s and mantissa is 0
|
|
26
|
+
((bits() and 0x7FF0_0000_0000_0000) == 0x7FF0_0000_0000_0000) and # exp
|
|
27
|
+
((bits() and 0x000F_FFFF_FFFF_FFFF) == 0) // mantissa
|
|
28
|
+
|
|
29
|
+
// Check whether this number is NaN.
|
|
30
|
+
fn is_nan(): Bool =>
|
|
31
|
+
// True if exponent is all 1s and mantissa is non-0
|
|
32
|
+
((bits() and 0x7FF0_0000_0000_0000) == 0x7FF0_0000_0000_0000) and // exp
|
|
33
|
+
((bits() and 0x000F_FFFF_FFFF_FFFF) != 0) // mantissa
|
libs/std/html.mi
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
module std
|
|
2
|
-
|
|
3
|
-
test("HTML DSL") {
|
|
4
|
-
val tree = html(class: "123") {
|
|
5
|
-
head {
|
|
6
|
-
title("Pacos")
|
|
7
|
-
link(href: "https://pacos.dev")
|
|
8
|
-
}
|
|
9
|
-
body(class: "bg-white") {
|
|
10
|
-
div(class: "box") {
|
|
11
|
-
text("Hello")
|
|
12
|
-
}
|
|
13
|
-
div {
|
|
14
|
-
text("World")
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
assert tree.to_str() == ```
|
|
19
|
-
<html>
|
|
20
|
-
<head>
|
|
21
|
-
<title>Pacos</title>
|
|
22
|
-
<link href="https://pacos.dev" />
|
|
23
|
-
</head>
|
|
24
|
-
<body>
|
|
25
|
-
<div class="box">
|
|
26
|
-
Hello
|
|
27
|
-
</div>
|
|
28
|
-
<div>
|
|
29
|
-
World
|
|
30
|
-
</div>
|
|
31
|
-
</body>
|
|
32
|
-
</html>
|
|
33
|
-
```
|
|
34
|
-
}
|
libs/std/{http.mi → http.plum}
RENAMED
|
@@ -4,27 +4,24 @@ import std/path
|
|
|
4
4
|
import std/os
|
|
5
5
|
import std/http/content_type
|
|
6
6
|
|
|
7
|
-
#[builder]
|
|
8
|
-
|
|
7
|
+
Response = (
|
|
9
8
|
headers: Map[Str, Str]
|
|
10
|
-
body:
|
|
9
|
+
body: Str | Buffer | IO
|
|
11
|
-
status:
|
|
10
|
+
status: Int
|
|
12
11
|
)
|
|
13
12
|
|
|
14
|
-
|
|
13
|
+
createFileResponse(path: Str) -> Response | IOError =
|
|
15
|
-
content :=
|
|
14
|
+
content := content_type.fromExt(path.ext())
|
|
16
15
|
data := os.readFile(file)?
|
|
17
16
|
Response()
|
|
18
17
|
.header("Content-Type", content)
|
|
19
18
|
.body(data)
|
|
20
19
|
.status(200)
|
|
21
20
|
|
|
22
|
-
#[get("/")]
|
|
23
|
-
|
|
21
|
+
index() -> Response! =
|
|
24
|
-
|
|
22
|
+
createFileResponse("index.html")
|
|
25
23
|
|
|
26
|
-
#[get("/public/<...>")]
|
|
27
|
-
|
|
24
|
+
serveFile(file: Str) -> Response | IOError =
|
|
28
25
|
ext := path::ext(file)
|
|
29
26
|
content := contentTypeFromExt(ext)
|
|
30
27
|
data := os.readFile(file)?
|
libs/std/int.ks
DELETED
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
tuple Int() {
|
|
2
|
-
`Euler's number, the base of natural logarithms, e
|
|
3
|
-
`https://oeis.org/A001113
|
|
4
|
-
const E = 2.718f
|
|
5
|
-
|
|
6
|
-
`The natural logarithm of 10
|
|
7
|
-
`https://oeis.org/A002392
|
|
8
|
-
const LN10 = 2.302f
|
|
9
|
-
|
|
10
|
-
`The natural logarithm of 2
|
|
11
|
-
`https://oeis.org/A002162
|
|
12
|
-
const LN2 = 0.693f
|
|
13
|
-
|
|
14
|
-
`The base 10 logarithm of e
|
|
15
|
-
`formula: 1 / LN10
|
|
16
|
-
const LOG10E = 0.434f
|
|
17
|
-
|
|
18
|
-
`The base 2 logarithm of e
|
|
19
|
-
`formula: 1 / LN2
|
|
20
|
-
const LOG2E = 1.442f
|
|
21
|
-
|
|
22
|
-
`The ratio of the circumference of a circle to its diameter
|
|
23
|
-
`https://oeis.org/A000796
|
|
24
|
-
const PI = 3.14159f
|
|
25
|
-
|
|
26
|
-
`https://oeis.org/A001622
|
|
27
|
-
const PHI = 1.6180f
|
|
28
|
-
|
|
29
|
-
`The square root of 1/2
|
|
30
|
-
const SQRT1_2 = 0.707f
|
|
31
|
-
|
|
32
|
-
`The square root of 2
|
|
33
|
-
`https://oeis.org/A002193
|
|
34
|
-
const SQRT2 = 1.414f
|
|
35
|
-
|
|
36
|
-
`https://oeis.org/A019774
|
|
37
|
-
const SQRT_E = 1.64872f
|
|
38
|
-
|
|
39
|
-
`https://oeis.org/A002161
|
|
40
|
-
const SQRT_PI = 1.77245f
|
|
41
|
-
|
|
42
|
-
`https://oeis.org/A139339
|
|
43
|
-
const SQRT_PHI = 1.27201f
|
|
44
|
-
|
|
45
|
-
`The difference between 1 and the smallest floating point number greater than 1
|
|
46
|
-
`formula: 7/3 - 4/3 - 1
|
|
47
|
-
const EPSILON = 2.220446049250313e-16f
|
|
48
|
-
|
|
49
|
-
`Lowest value of int
|
|
50
|
-
const MIN_INT_VALUE = -0x8000_0000_0000_0000
|
|
51
|
-
|
|
52
|
-
`Highest value of int
|
|
53
|
-
const MAX_INT_VALUE = 0x7FFF_FFFF_FFFF_FFFF
|
|
54
|
-
|
|
55
|
-
`Lowest valur of float
|
|
56
|
-
const MIN_FLOAT_VALUE = 4.9406564584124654417656879286822137236505980e-324
|
|
57
|
-
|
|
58
|
-
`Highest valur of float
|
|
59
|
-
const MAX_FLOAT_VALUE = 1.79769313486231570814527423731704356798070e+308
|
|
60
|
-
|
|
61
|
-
fn abs(v: float): float =
|
|
62
|
-
`returns the absolute value of a number v
|
|
63
|
-
a < 0 ? -a : a
|
|
64
|
-
|
|
65
|
-
fn acos(v: float) =
|
|
66
|
-
if v < 0.1
|
|
67
|
-
asin(v)
|
|
68
|
-
else
|
|
69
|
-
asin(-1v)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
`2**28
|
|
73
|
-
const LARGE = 1 << 28
|
|
74
|
-
|
|
75
|
-
fn acosh(v: float): float =
|
|
76
|
-
when
|
|
77
|
-
x < 1 | IsNaN(x) -> // first case is special case
|
|
78
|
-
NaN()
|
|
79
|
-
x == 1 ->
|
|
80
|
-
0
|
|
81
|
-
x >= Large ->
|
|
82
|
-
Log(x) + Ln2 // x > 2**28
|
|
83
|
-
x > 2 ->
|
|
84
|
-
Log(2*x - 1/(x+Sqrt(x*x-1))) // 2**28 > x > 2
|
|
85
|
-
_ ->
|
|
86
|
-
t := x - 1
|
|
87
|
-
// ((2*t+t*t).sqrt() + t).log1p()
|
|
88
|
-
Log1p(t + Sqrt(2*t+t*t)) // 2 >= x > 1
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
fn asin(v: float) = 0f
|
|
93
|
-
fn asinh(v: float) = 0f
|
|
94
|
-
fn atan(v: float) = 0f
|
|
95
|
-
fn atan2(v: float) = 0f
|
|
96
|
-
fn atanh(v: float) = 0f
|
|
97
|
-
fn cbrt(v: float) = 0f
|
|
98
|
-
fn ceil(v: float) = 0f
|
|
99
|
-
fn clz32(v: float) = 0f
|
|
100
|
-
fn cos(v: float) = 0f
|
|
101
|
-
fn cosh(v: float) = 0f
|
|
102
|
-
fn exp(v: float) = 0f
|
|
103
|
-
fn to_int(): int = 0
|
|
104
|
-
fn to_str(): str = ""
|
|
105
|
-
|
|
106
|
-
fn random(): float =
|
|
107
|
-
pass
|
|
108
|
-
|
|
109
|
-
fn is_int(): bool =
|
|
110
|
-
pass
|
|
111
|
-
|
|
112
|
-
fn is_finite(): bool = true
|
|
113
|
-
` Check whether this number is finite, ie not +/-infinity and not NaN.
|
|
114
|
-
` True if exponent is not all 1s
|
|
115
|
-
(bits() and 0x7FF0_0000_0000_0000) != 0x7FF0_0000_0000_0000
|
|
116
|
-
|
|
117
|
-
// Check whether this number is +/-infinity
|
|
118
|
-
is_infinite: Bool =>
|
|
119
|
-
// True if exponent is all 1s and mantissa is 0
|
|
120
|
-
((bits() and 0x7FF0_0000_0000_0000) == 0x7FF0_0000_0000_0000) and // exp
|
|
121
|
-
((bits() and 0x000F_FFFF_FFFF_FFFF) == 0) // mantissa
|
|
122
|
-
|
|
123
|
-
// Check whether this number is NaN.
|
|
124
|
-
fn is_nan(): Bool =>
|
|
125
|
-
// True if exponent is all 1s and mantissa is non-0
|
|
126
|
-
((bits() and 0x7FF0_0000_0000_0000) == 0x7FF0_0000_0000_0000) and // exp
|
|
127
|
-
((bits() and 0x000F_FFFF_FFFF_FFFF) != 0) // mantissa
|
|
128
|
-
|
|
129
|
-
fn to_exponential(v: float): str = ""
|
|
130
|
-
|
|
131
|
-
fn to_fixed(v: float): str = ""
|
|
132
|
-
|
|
133
|
-
fn to_precision(v: float): str = ""
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
fn abs(): F64 = @"llvm.fabs.f64"(this)
|
|
137
|
-
fn ceil(): F64 = @"llvm.ceil.f64"(this)
|
|
138
|
-
fn floor(): F64 = @"llvm.floor.f64"(this)
|
|
139
|
-
fn round(): F64 = @"llvm.round.f64"(this)
|
|
140
|
-
fn trunc(): F64 = @"llvm.trunc.f64"(this)
|
|
141
|
-
|
|
142
|
-
fun log(): F64 => @"llvm.log.f64"(this)
|
|
143
|
-
fun log2(): F64 => @"llvm.log2.f64"(this)
|
|
144
|
-
fun log10(): F64 => @"llvm.log10.f64"(this)
|
|
145
|
-
fun logb(): F64 => @logb(this)
|
|
146
|
-
|
|
147
|
-
fun pow(y: F64): F64 => @"llvm.pow.f64"(this, y)
|
|
148
|
-
fun powi(y: I32): F64 =>
|
|
149
|
-
ifdef windows then
|
|
150
|
-
pow(y.f64())
|
|
151
|
-
else
|
|
152
|
-
@"llvm.powi.f64"(this, y)
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
fun sqrt(): F64 =>
|
|
156
|
-
if this < 0.0 then
|
|
157
|
-
_nan()
|
|
158
|
-
else
|
|
159
|
-
@"llvm.sqrt.f64"(this)
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
fn abs(a: int): int => a < 0 ? -a : a
|
|
163
|
-
fn to_str(v: int): str = ""
|
|
164
|
-
|
|
165
|
-
fn op_add(x: int, y: int): int =
|
|
166
|
-
@"i64.add"(x, y)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
sub
|
|
170
|
-
mul
|
|
171
|
-
div
|
|
172
|
-
rem
|
|
173
|
-
|
|
174
|
-
min
|
|
175
|
-
max
|
|
176
|
-
|
|
177
|
-
to_float()
|
|
178
|
-
}
|
libs/std/int.plum
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
module std/int
|
|
2
|
+
|
|
3
|
+
# Euler's number, the base of natural logarithms, e, https://oeis.org/A001113
|
|
4
|
+
E = 2.718f
|
|
5
|
+
|
|
6
|
+
# The natural logarithm of 10, https://oeis.org/A002392
|
|
7
|
+
LN10 = 2.302f
|
|
8
|
+
|
|
9
|
+
# The natural logarithm of 2 https://oeis.org/A002162
|
|
10
|
+
LN2 = 0.693f
|
|
11
|
+
|
|
12
|
+
# The base 10 logarithm of e # formula: 1 / LN10
|
|
13
|
+
LOG10E = 0.434f
|
|
14
|
+
|
|
15
|
+
# The base 2 logarithm of e # formula: 1 / LN2
|
|
16
|
+
LOG2E = 1.442f
|
|
17
|
+
|
|
18
|
+
# The ratio of the circumference of a circle to its diameter https://oeis.org/A000796
|
|
19
|
+
PI = 3.14159f
|
|
20
|
+
|
|
21
|
+
# https://oeis.org/A001622
|
|
22
|
+
PHI = 1.6180f
|
|
23
|
+
|
|
24
|
+
# The square root of 1/2
|
|
25
|
+
SQRT1_2 = 0.707f
|
|
26
|
+
|
|
27
|
+
# The square root of 2 https://oeis.org/A002193
|
|
28
|
+
SQRT2 = 1.414f
|
|
29
|
+
|
|
30
|
+
# https://oeis.org/A019774
|
|
31
|
+
SQRT_E = 1.64872f
|
|
32
|
+
|
|
33
|
+
# https://oeis.org/A002161
|
|
34
|
+
SQRT_PI = 1.77245f
|
|
35
|
+
|
|
36
|
+
# https://oeis.org/A139339
|
|
37
|
+
SQRT_PHI = 1.27201f
|
|
38
|
+
|
|
39
|
+
# The difference between 1 and the smallest floating point number greater than 1 formula: 7/3 - 4/3 - 1
|
|
40
|
+
EPSILON = 2.220446049250313e-16f
|
|
41
|
+
|
|
42
|
+
# Lowest value of int
|
|
43
|
+
MIN_INT_VALUE = -0x8000_0000_0000_0000
|
|
44
|
+
|
|
45
|
+
# Highest value of int
|
|
46
|
+
MAX_INT_VALUE = 0x7FFF_FFFF_FFFF_FFFF
|
|
47
|
+
|
|
48
|
+
# Lowest valur of float
|
|
49
|
+
MIN_FLOAT_VALUE = 4.9406564584124654417656879286822137236505980e-324
|
|
50
|
+
|
|
51
|
+
# Highest valur of float
|
|
52
|
+
MAX_FLOAT_VALUE = 1.79769313486231570814527423731704356798070e+308
|
|
53
|
+
|
|
54
|
+
# 2**28
|
|
55
|
+
LARGE = 1 << 28
|
|
56
|
+
|
|
57
|
+
Int: Comparable, ToStr = ByteArray
|
|
58
|
+
|
|
59
|
+
Int::random(): Float =
|
|
60
|
+
todo
|
|
61
|
+
|
|
62
|
+
# returns the absolute value of the Int
|
|
63
|
+
Int\abs() -> Int =
|
|
64
|
+
self < 0 ? -self : self
|
|
65
|
+
|
|
66
|
+
Int\ceil() -> Float =
|
|
67
|
+
todo
|
|
68
|
+
|
|
69
|
+
Int\floor() -> Float =
|
|
70
|
+
todo
|
|
71
|
+
|
|
72
|
+
Int\round() -> Float =
|
|
73
|
+
todo
|
|
74
|
+
|
|
75
|
+
Int\trunc() -> Float =
|
|
76
|
+
todo
|
|
77
|
+
|
|
78
|
+
Int\log() -> Float =
|
|
79
|
+
todo
|
|
80
|
+
|
|
81
|
+
Int\log2() -> Float =
|
|
82
|
+
todo
|
|
83
|
+
|
|
84
|
+
Int\log10() -> Float =
|
|
85
|
+
todo
|
|
86
|
+
|
|
87
|
+
Int\logb() -> Float =
|
|
88
|
+
todo
|
|
89
|
+
|
|
90
|
+
Int\pow(y: Float) -> Float =
|
|
91
|
+
LibM.pow(self, y)
|
|
92
|
+
|
|
93
|
+
Int\pow(y: Int) -> Float =
|
|
94
|
+
pow(y.toFloat())
|
|
95
|
+
|
|
96
|
+
Int\sqrt() -> Float =
|
|
97
|
+
if this < 0.0 then
|
|
98
|
+
_nan()
|
|
99
|
+
else
|
|
100
|
+
LibM.sqrt(self)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
Int\asin(v: Float) =
|
|
104
|
+
todo
|
|
105
|
+
|
|
106
|
+
Int\acos(v: Float) =
|
|
107
|
+
if v < 0.1
|
|
108
|
+
asin(v)
|
|
109
|
+
else
|
|
110
|
+
asin(-v)
|
|
111
|
+
|
|
112
|
+
Int\asinh(v: Float) =
|
|
113
|
+
todo
|
|
114
|
+
|
|
115
|
+
Int\atan(v: Float) =
|
|
116
|
+
todo
|
|
117
|
+
|
|
118
|
+
Int\atan2(v: Float) =
|
|
119
|
+
todo
|
|
120
|
+
|
|
121
|
+
Int\atanh(v: Float) =
|
|
122
|
+
todo
|
|
123
|
+
|
|
124
|
+
Int\cbrt(v: Float) =
|
|
125
|
+
todo
|
|
126
|
+
|
|
127
|
+
Int\ceil(v: Float) =
|
|
128
|
+
todo
|
|
129
|
+
|
|
130
|
+
Int\clz32(v: Float) =
|
|
131
|
+
todo
|
|
132
|
+
|
|
133
|
+
Int\cos(v: Float) =
|
|
134
|
+
todo
|
|
135
|
+
|
|
136
|
+
Int\cosh(v: Float) =
|
|
137
|
+
todo
|
|
138
|
+
|
|
139
|
+
Int\exp(v: Float) =
|
|
140
|
+
todo
|
libs/std/{json.mi → json.plum}
RENAMED
|
@@ -1,59 +1,50 @@
|
|
|
1
1
|
module std/json
|
|
2
2
|
|
|
3
|
-
trait Json permits JsonStr, JsonBool, JsonNull, JsonFloat, JsonInt, JsonObject, JsonArray {
|
|
4
|
-
|
|
3
|
+
Json =
|
|
4
|
+
| None
|
|
5
|
+
| Str
|
|
6
|
+
| Bool
|
|
7
|
+
| Float
|
|
8
|
+
| Int
|
|
9
|
+
| List
|
|
10
|
+
| Map
|
|
11
|
+
|
|
5
|
-
|
|
12
|
+
JsonParseError = {
|
|
13
|
+
line: Int
|
|
14
|
+
pos: Int
|
|
15
|
+
token: Char
|
|
6
16
|
}
|
|
7
17
|
|
|
8
|
-
|
|
18
|
+
Json\\parse(src: Str | Buffer | IO) -> Json | JsonParseError =
|
|
9
|
-
type = JsonObject
|
|
10
|
-
|
|
11
|
-
|
|
19
|
+
JsonParser.withSrc(src).parse()
|
|
12
|
-
|
|
13
|
-
}
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
tuple JsonArray(List[Json]): Json {
|
|
18
|
-
fn parse() {}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
tuple JsonInt(Int): Json {
|
|
22
20
|
|
|
21
|
+
Json\parseNone() -> None | JsonParseError =
|
|
23
|
-
|
|
22
|
+
parser.find("null")
|
|
24
23
|
|
|
24
|
+
Json\parseStr() -> Str | JsonParseError =
|
|
25
|
+
parser.find("null")
|
|
25
26
|
|
|
26
|
-
|
|
27
|
+
Json\parseFloat() -> Float | JsonParseError =
|
|
28
|
+
parser.find("null")
|
|
27
29
|
|
|
30
|
+
Json\parseInt() -> Int | JsonParseError =
|
|
28
|
-
|
|
31
|
+
parser.find("null")
|
|
29
32
|
|
|
33
|
+
Json\parseList() -> List | JsonParseError =
|
|
34
|
+
parser.find("null")
|
|
30
35
|
|
|
36
|
+
Json\parseMap() -> Map | JsonParseError =
|
|
31
|
-
|
|
37
|
+
parser.find("null")
|
|
32
|
-
}
|
|
33
38
|
|
|
34
|
-
tuple JsonBool(Bool): Json {
|
|
35
|
-
}
|
|
36
39
|
|
|
37
|
-
tuple JsonNull: Json {
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
fn Json.parse(src: str | Buffer | IO): Json | ParseError =
|
|
41
|
-
JsonParser.withSrc(src).parse()
|
|
42
|
-
|
|
43
|
-
#[error(400, "Failed to parse json ${object} at: ${line} ${pos}")]
|
|
44
|
-
|
|
40
|
+
JsonParser = (
|
|
45
|
-
|
|
41
|
+
cur: Int = ' '
|
|
46
|
-
|
|
42
|
+
_pos: Int = 0
|
|
43
|
+
_next: Int = ' '
|
|
44
|
+
_buf: Str | Buffer | IO
|
|
47
45
|
)
|
|
48
46
|
|
|
49
|
-
record JsonParser(
|
|
50
|
-
cur: int = ' '
|
|
51
|
-
_pos: int = 0
|
|
52
|
-
_next: int = ' '
|
|
53
|
-
_buf: str | Buffer | IO
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
JsonParser::withSrc(src: Str | Buffer | IO) -> JsonParser =
|
|
57
48
|
JsonParser(_buf = src)
|
|
58
49
|
|
|
59
50
|
fn isSpace(c: U32): Bool => (c == ' ') or ((c >= '\t') and (c <= '\r'))
|
|
@@ -356,29 +347,25 @@ fn _get_fals(): bool? =
|
|
|
356
347
|
error
|
|
357
348
|
end
|
|
358
349
|
|
|
350
|
+
|
|
351
|
+
|
|
359
|
-
test("
|
|
352
|
+
Json\test("parseInt") =
|
|
360
353
|
assert Json.parse("123") == 123
|
|
361
|
-
}
|
|
362
354
|
|
|
363
|
-
test("
|
|
355
|
+
Json\test("parseStr") =
|
|
364
356
|
assert Json.parse(`"hello"`) == "hello"
|
|
365
|
-
}
|
|
366
357
|
|
|
367
|
-
test("
|
|
358
|
+
Json\test("parseBool") =
|
|
368
359
|
assert Json.parse("true") == true
|
|
369
360
|
assert Json.parse("false") == false
|
|
370
|
-
}
|
|
371
361
|
|
|
372
|
-
test("parse null")
|
|
362
|
+
Json\test("parse null") =
|
|
373
363
|
assert Json.parse("null") == nil
|
|
374
|
-
}
|
|
375
364
|
|
|
376
|
-
test("parse array")
|
|
365
|
+
Json\test("parse array") =
|
|
377
366
|
assert Json.parse(`[]`) == List[Json]()
|
|
378
367
|
assert Json.parse(`[1, 2]`) == List.of[Json](1, 2)
|
|
379
|
-
}
|
|
380
368
|
|
|
381
|
-
test("parse object")
|
|
369
|
+
Json\test("parse object") =
|
|
382
370
|
assert Json.parse(`{}`) == Map[str, Json]()
|
|
383
|
-
assert Json.parse(`{"a": 1, "b": 2}`) == Map.of[str, Json]("a" => 1, "b" => 2)
|
|
371
|
+
assert Json.parse(`{"a": 1, "b": 2}`) == Map.of[str, Json]("a" => 1, "b" => 2)
|
|
384
|
-
}
|
libs/std/{list.mi → list.plum}
RENAMED
|
@@ -8,7 +8,6 @@ record List[V](
|
|
|
8
8
|
_size: int
|
|
9
9
|
) {
|
|
10
10
|
fn of(values: ...V) -> List[V] {
|
|
11
|
-
|
|
12
11
|
}
|
|
13
12
|
}
|
|
14
13
|
|
libs/std/map.mi
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
module std
|
|
2
|
-
|
|
3
|
-
record pair[K: Comparable, V] where
|
|
4
|
-
| k: K
|
|
5
|
-
| v: V
|
|
6
|
-
|
|
7
|
-
`A Map is a data structure describing a contiguous section of an array stored separately from the slice variable itself.
|
|
8
|
-
`A Map is not an array. A slice describes a piece of an array.
|
|
9
|
-
struct Map[K, V] where
|
|
10
|
-
|
|
11
|
-
let items: list[pair[K, V]]
|
|
12
|
-
|
|
13
|
-
static fn of[K, V](kvs: ...pair[K, V]): Map[K, V] =
|
|
14
|
-
Map[K, V]().add(kvs)
|
|
15
|
-
|
|
16
|
-
fn add(kvs: ...pair[K, V]) =
|
|
17
|
-
`adds the specified elements to the start of the list
|
|
18
|
-
|
|
19
|
-
fn op_range(yld: fn(k: K, v: V): bool): bool =
|
|
20
|
-
`allows the range operator to iterate over the Map
|
|
21
|
-
for item := range items
|
|
22
|
-
if !yld(item.k, item.v)
|
|
23
|
-
false
|
|
24
|
-
true
|
|
25
|
-
|
|
26
|
-
fn get(k K): Option[V] =
|
|
27
|
-
`get a value from the Map using key k
|
|
28
|
-
for k, v := range m
|
|
29
|
-
if k == k
|
|
30
|
-
return v
|
|
31
|
-
nil
|
|
32
|
-
|
|
33
|
-
fn set(k K, v V) =
|
|
34
|
-
`put a value into the Map
|
|
35
|
-
list.add(pair(k, v))
|
|
36
|
-
|
|
37
|
-
fn putIf(k K, v V) =
|
|
38
|
-
`put a value into the Map if its not already present
|
|
39
|
-
pass
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
`A Map is a data structure describing a contiguous section of an array stored separately from the slice variable itself.
|
|
44
|
-
`A Map is not an array. A slice describes a piece of an array.
|
|
45
|
-
record Map[K, V](
|
|
46
|
-
items: List[Pair[K, V]]
|
|
47
|
-
)
|
|
48
|
-
|
|
49
|
-
fn Map.add(kvs: ...pair[K, V]) =
|
|
50
|
-
`adds the specified elements to the start of the list
|
|
51
|
-
items.add(kvs)
|
|
52
|
-
|
|
53
|
-
fn (Map) get(k K): V? =
|
|
54
|
-
for k, v := range m
|
|
55
|
-
if k == k
|
|
56
|
-
return v
|
|
57
|
-
nil
|
|
58
|
-
|
|
59
|
-
fn (Map) put(k K, v V) =
|
|
60
|
-
list.add(pair(k, v))
|
|
61
|
-
|
|
62
|
-
fn (Map) put_if(k K, v V) =
|
|
63
|
-
if
|
|
64
|
-
|
|
65
|
-
fn (Map) update() =
|
|
66
|
-
pass
|
|
67
|
-
|
|
68
|
-
fn (Map) update_if() =
|
|
69
|
-
pass
|
|
70
|
-
|
|
71
|
-
fn (Map->Range) range(yld: fn(k: K, v: V): bool): bool =
|
|
72
|
-
for item := range items
|
|
73
|
-
if !yld(item.k, item.v)
|
|
74
|
-
false
|
|
75
|
-
true
|
libs/std/map.plum
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module std
|
|
2
|
+
|
|
3
|
+
Pair(a, b) = (
|
|
4
|
+
key: a
|
|
5
|
+
val: b
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
A Map is a data structure describing a contiguous section of an array stored separately from the slice variable itself.
|
|
10
|
+
A Map is not an array. A slice describes a piece of an array.
|
|
11
|
+
```
|
|
12
|
+
Map(a, b) = {
|
|
13
|
+
items: List(Pair(a, b))
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
mapOf(kvs: ...Pair) -> Map =
|
|
17
|
+
Map(a, b)().add(kvs)
|
|
18
|
+
|
|
19
|
+
# adds the specified elements to the start of the list
|
|
20
|
+
Map\add(kvs: ...Pair) =
|
|
21
|
+
items.add(kvs)
|
|
22
|
+
|
|
23
|
+
# Get a value from the Map using key k
|
|
24
|
+
Map\get(k: a) -> b | Nil =
|
|
25
|
+
for k, v in self
|
|
26
|
+
if k == k
|
|
27
|
+
return v
|
|
28
|
+
Nil
|
|
29
|
+
|
|
30
|
+
# Put a value into the Map
|
|
31
|
+
Map\set(k: a, v: b) =
|
|
32
|
+
items.add(pair(k, v))
|
|
33
|
+
|
|
34
|
+
# `put a value into the Map if its not already present
|
|
35
|
+
Map\putIfAbsent(k K, v V) =
|
|
36
|
+
todo
|
|
37
|
+
|
|
38
|
+
Map\map(cb: (Pair(a, b)) -> Pair(c, d)) -> Map(c, d) =
|
|
39
|
+
items.map(cb)
|
libs/std/option.ks
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
module std
|
|
2
|
-
|
|
3
|
-
`Option is a type that represents either value present `Some` or nothing present `None`
|
|
4
|
-
trait Option[T] permits Some, None {
|
|
5
|
-
fn get() -> T
|
|
6
|
-
|
|
7
|
-
`get if present otherwise return default value
|
|
8
|
-
fn getOrElse(default: T) -> T
|
|
9
|
-
|
|
10
|
-
fn toStr() -> Str
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
tuple Some[T](T) : Option[T] {
|
|
14
|
-
fn get() -> T {
|
|
15
|
-
return self.0
|
|
16
|
-
}
|
|
17
|
-
fn getOrElse(default: T) -> T {
|
|
18
|
-
return self.0
|
|
19
|
-
}
|
|
20
|
-
fn toStr() -> Str {
|
|
21
|
-
return "Some(${self.0.toStr()})"
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
tuple None() : Option[_] {
|
|
26
|
-
fn get() -> T {
|
|
27
|
-
fail("called 'Option.get()' on a 'None' value")
|
|
28
|
-
}
|
|
29
|
-
fn getOrElse(default: T) -> T {
|
|
30
|
-
return default
|
|
31
|
-
}
|
|
32
|
-
fn toStr() -> Str {
|
|
33
|
-
return "None"
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
libs/std/result.ks
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
module std
|
|
2
|
-
|
|
3
|
-
`This is used to represent an error value across the language
|
|
4
|
-
trait Error {
|
|
5
|
-
fn code(): Int
|
|
6
|
-
fn msg(): Str
|
|
7
|
-
fn cause(): Option[Error]
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
`Result is a type that represents either success `Ok` or failure `Err`
|
|
11
|
-
trait Result[T, E: Error] permits Ok[T], Err[E] {
|
|
12
|
-
fn get() -> T
|
|
13
|
-
fn getOrElse(default: T) -> T
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
tuple Ok[T](T) : Result[T, _] {
|
|
17
|
-
fn get() -> T {
|
|
18
|
-
return self.0
|
|
19
|
-
}
|
|
20
|
-
fn getOrElse(default: T) -> T {
|
|
21
|
-
return self.0
|
|
22
|
-
}
|
|
23
|
-
fn map(cb: fn(a) -> b) -> Result[b, _] {
|
|
24
|
-
return Ok(cb(self.0))
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
tuple Err[E](E) : Result[_, E] {
|
|
29
|
-
fn get() -> T {
|
|
30
|
-
fail("called 'Result.get()' on an 'Err' value")
|
|
31
|
-
}
|
|
32
|
-
fn getOrElse(default: T) -> T {
|
|
33
|
-
return default
|
|
34
|
-
}
|
|
35
|
-
fn mapErr(cb: fn(a) -> b) -> Result[_, b] {
|
|
36
|
-
return Err(cb(self.0))
|
|
37
|
-
}
|
|
38
|
-
}
|
libs/std/str.mi
DELETED
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
module std
|
|
2
|
-
|
|
3
|
-
`ToStr defines any data that can be converted to a str
|
|
4
|
-
trait ToStr(
|
|
5
|
-
fn toStr(): Str
|
|
6
|
-
)
|
|
7
|
-
|
|
8
|
-
`A str is an array of contiguous data stored in memory with a null termination using hex 0x00 or ASCII 0x00.
|
|
9
|
-
`It is immutable and cannot be modified. It is copied for any changes and saved to a new memory location.
|
|
10
|
-
`The previous str is freed if its reference count is 0 within the block.
|
|
11
|
-
record Str(data: Buffer): Comparable, ToStr {
|
|
12
|
-
fn get(i: int) {
|
|
13
|
-
return data.get(i)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
fn contains(search: Str) -> Bool {
|
|
17
|
-
pass
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
fn index_of(sub: Str) -> Int {
|
|
21
|
-
pass
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
fn test(pattern: Regex) -> Bool {
|
|
25
|
-
pass
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
fn search(key: Str) -> (Int, Bool) {
|
|
29
|
-
val (low, mid, high) = (0, 0, n.numItems)
|
|
30
|
-
while low < high {
|
|
31
|
-
mid = (low + high) / 2
|
|
32
|
-
val cmp := key > n.items[mid].key
|
|
33
|
-
low = cmp > 0 ? mid + 1 : low
|
|
34
|
-
high = cmp < 0 ? mid : high
|
|
35
|
-
if cmp == 0 {
|
|
36
|
-
return (mid, True)
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return (low, False)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
fn (t BTree) delete(key str): bool =
|
|
44
|
-
if t.root == nil
|
|
45
|
-
return false
|
|
46
|
-
deletedItem := t.root.delete(key, false)
|
|
47
|
-
if t.root.numItems == 0
|
|
48
|
-
if t.root.isLeaf()
|
|
49
|
-
t.root = nil
|
|
50
|
-
else
|
|
51
|
-
t.root = t.root.children[0]
|
|
52
|
-
if deletedItem != nil
|
|
53
|
-
return true
|
|
54
|
-
return false
|
|
55
|
-
|
|
56
|
-
fn (str) starts_with(search: str): bool =
|
|
57
|
-
pass
|
|
58
|
-
|
|
59
|
-
fn (str) concat(other: str): str =
|
|
60
|
-
s + other
|
|
61
|
-
|
|
62
|
-
fn (str) to_str(): str = s
|
|
63
|
-
|
|
64
|
-
fn (str) concat(other: str): str =
|
|
65
|
-
s + s
|
|
66
|
-
|
|
67
|
-
fn (str) starts_with(search: str): bool =
|
|
68
|
-
pass
|
|
69
|
-
|
|
70
|
-
fn (str) ends_with(search: str): bool =
|
|
71
|
-
pass
|
|
72
|
-
|
|
73
|
-
fn (str) contains(search: str): bool =
|
|
74
|
-
pass
|
|
75
|
-
|
|
76
|
-
fn (str) index_of(sub: str): int =
|
|
77
|
-
pass
|
|
78
|
-
|
|
79
|
-
fn (str) match(pattern: Regex): []str =
|
|
80
|
-
pass
|
|
81
|
-
|
|
82
|
-
fn (str) match_all(pattern: Regex): []str =
|
|
83
|
-
pass
|
|
84
|
-
|
|
85
|
-
fn (str) pad_start(sub: str, count: int): str =
|
|
86
|
-
pass
|
|
87
|
-
|
|
88
|
-
fn (str) pad_end(sub: str, count: int): str =
|
|
89
|
-
pass
|
|
90
|
-
|
|
91
|
-
fn (str) repeat(count: int): str =
|
|
92
|
-
pass
|
|
93
|
-
|
|
94
|
-
fn (str) replace(pattern: Regex, sub: str): str =
|
|
95
|
-
pass
|
|
96
|
-
|
|
97
|
-
fn (str) replace_all(pattern: Regex, sub: str): str =
|
|
98
|
-
pass
|
|
99
|
-
|
|
100
|
-
fn (str) search(pattern: Regex): str =
|
|
101
|
-
pass
|
|
102
|
-
|
|
103
|
-
fn slice(start: int, end: int): str =
|
|
104
|
-
pass
|
|
105
|
-
|
|
106
|
-
fn split(separator: str, limit: int): []str =
|
|
107
|
-
pass
|
|
108
|
-
|
|
109
|
-
fn sub(start: int, end: int): str =
|
|
110
|
-
pass
|
|
111
|
-
|
|
112
|
-
fn to_lower(): str =
|
|
113
|
-
pass
|
|
114
|
-
|
|
115
|
-
fn to_upper(): str =
|
|
116
|
-
pass
|
|
117
|
-
|
|
118
|
-
fn trim(): str =
|
|
119
|
-
pass
|
|
120
|
-
|
|
121
|
-
fn trim_start(): str =
|
|
122
|
-
pass
|
|
123
|
-
|
|
124
|
-
fn trim_end(): str =
|
|
125
|
-
pass
|
|
126
|
-
|
|
127
|
-
fn reverse(): str
|
|
128
|
-
"""reverses a str
|
|
129
|
-
start := 0
|
|
130
|
-
end := length - 1
|
|
131
|
-
result := []
|
|
132
|
-
while start < end
|
|
133
|
-
const temp = data[start]
|
|
134
|
-
result[start] = data[end]
|
|
135
|
-
result[end] = temp
|
|
136
|
-
end = end - 1
|
|
137
|
-
start = start + 1
|
|
138
|
-
result
|
|
139
|
-
|
|
140
|
-
fn parseInt(): int! =
|
|
141
|
-
0
|
|
142
|
-
|
|
143
|
-
fn parseFloat(): float! =
|
|
144
|
-
0.0
|
|
145
|
-
|
|
146
|
-
fn parseBool(): bool! =
|
|
147
|
-
match to_lower()
|
|
148
|
-
"true" -> bool::true
|
|
149
|
-
"false" -> bool::false
|
|
150
|
-
_ -> error("could not parse bool '${this}'")
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
_.camelCase
|
|
154
|
-
_.capitalize
|
|
155
|
-
_.deburr
|
|
156
|
-
_.endsWith
|
|
157
|
-
_.escape
|
|
158
|
-
_.escapeRegExp
|
|
159
|
-
_.kebabCase
|
|
160
|
-
_.lowerCase
|
|
161
|
-
_.lowerFirst
|
|
162
|
-
_.pad
|
|
163
|
-
_.padEnd
|
|
164
|
-
_.padStart
|
|
165
|
-
_.parseInt
|
|
166
|
-
_.repeat
|
|
167
|
-
_.replace
|
|
168
|
-
_.snakeCase
|
|
169
|
-
_.split
|
|
170
|
-
_.startCase
|
|
171
|
-
_.startsWith
|
|
172
|
-
_.template
|
|
173
|
-
_.toLower
|
|
174
|
-
_.toUpper
|
|
175
|
-
_.trim
|
|
176
|
-
_.trimEnd
|
|
177
|
-
_.trimStart
|
|
178
|
-
_.truncate
|
|
179
|
-
_.unescape
|
|
180
|
-
_.upperCase
|
|
181
|
-
_.upperFirst
|
|
182
|
-
_.words
|
libs/std/str.plum
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
module std/str
|
|
2
|
+
|
|
3
|
+
# ToStr defines any data that can be converted to a str
|
|
4
|
+
ToStr = (
|
|
5
|
+
toStr() -> Str
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
A Str is an array of contiguous data stored in memory with a null termination using hex 0x00 or ASCII 0x00.
|
|
10
|
+
It is immutable and cannot be modified. It is copied for any changes and saved to a new memory location.
|
|
11
|
+
The previous str is freed if its reference count is 0 within the block.
|
|
12
|
+
```
|
|
13
|
+
Str : Comparable + ToStr = {
|
|
14
|
+
data: Buffer
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
Str\get(i: Int) -> Char =
|
|
18
|
+
data.get(i)
|
|
19
|
+
|
|
20
|
+
Str\contains(search: Str) -> Bool =
|
|
21
|
+
todo
|
|
22
|
+
|
|
23
|
+
Str\indexOf(sub: Str) -> Int =
|
|
24
|
+
todo
|
|
25
|
+
|
|
26
|
+
Str\test(pattern: Regex) -> Bool =
|
|
27
|
+
todo
|
|
28
|
+
|
|
29
|
+
Str\search(key: Str) -> (Int, Bool) =
|
|
30
|
+
low, mid, high = 0, 0, n.numItems
|
|
31
|
+
while low < high
|
|
32
|
+
mid = (low + high) / 2
|
|
33
|
+
cmp = key > n.items[mid].key
|
|
34
|
+
low = cmp > 0 ? mid + 1 : low
|
|
35
|
+
high = cmp < 0 ? mid : high
|
|
36
|
+
if cmp == 0 then
|
|
37
|
+
return (mid, True)
|
|
38
|
+
(low, False)
|
|
39
|
+
|
|
40
|
+
Str\startsWith(search: str) -> Bool =
|
|
41
|
+
todo
|
|
42
|
+
|
|
43
|
+
Str\concat(other: Str) -> Str =
|
|
44
|
+
s + other
|
|
45
|
+
|
|
46
|
+
Str\toStr() -> Str =
|
|
47
|
+
self
|
|
48
|
+
|
|
49
|
+
Str\matchPattern(pattern: Regex) -> List<Str> =
|
|
50
|
+
todo
|
|
51
|
+
|
|
52
|
+
Str\matchAll(pattern: Regex) -> List<Str> =
|
|
53
|
+
todo
|
|
54
|
+
|
|
55
|
+
Str\padStart(sub: Str, count: Int) -> Str =
|
|
56
|
+
todo
|
|
57
|
+
|
|
58
|
+
Str\padEnd(sub: Str, count: Int) -> Str =
|
|
59
|
+
todo
|
|
60
|
+
|
|
61
|
+
Str\repeat(count: Int) -> Str =
|
|
62
|
+
todo
|
|
63
|
+
|
|
64
|
+
Str\replace(pattern: Regex, sub: Str) -> Str =
|
|
65
|
+
todo
|
|
66
|
+
|
|
67
|
+
Str\replaceAll(pattern: Regex, sub: Str) -> Str =
|
|
68
|
+
todo
|
|
69
|
+
|
|
70
|
+
Str\search(pattern: Regex) -> Str =
|
|
71
|
+
todo
|
|
72
|
+
|
|
73
|
+
Str\slice(start: Int, e: Int) -> Str =
|
|
74
|
+
todo
|
|
75
|
+
|
|
76
|
+
Str\split(separator: Str, limit: Int) -> []Str =
|
|
77
|
+
todo
|
|
78
|
+
|
|
79
|
+
Str\sub(start: Int, e: Int) -> Str =
|
|
80
|
+
todo
|
|
81
|
+
|
|
82
|
+
Str\toLower() -> Str =
|
|
83
|
+
todo
|
|
84
|
+
|
|
85
|
+
`reverses a Str
|
|
86
|
+
Str\reverse() -> Str =
|
|
87
|
+
start := 0
|
|
88
|
+
end := length - 1
|
|
89
|
+
result := []
|
|
90
|
+
while start < end
|
|
91
|
+
const temp = data[start]
|
|
92
|
+
result[start] = data[end]
|
|
93
|
+
result[end] = temp
|
|
94
|
+
end = end - 1
|
|
95
|
+
start = start + 1
|
|
96
|
+
result
|
|
97
|
+
|
|
98
|
+
Str\parseInt() -> Int =
|
|
99
|
+
0
|
|
100
|
+
|
|
101
|
+
Str\parseFloat() -> Float =
|
|
102
|
+
0.0
|
|
103
|
+
|
|
104
|
+
Str\parseBool() -> Bool =
|
|
105
|
+
match self.to_lower()
|
|
106
|
+
"true" -> True
|
|
107
|
+
"false" -> False
|
|
108
|
+
_ -> error("could not parse bool '${this}'")
|
|
109
|
+
if self.lower() == "true"
|
|
110
|
+
True
|
|
111
|
+
else if self.lower() == "false"
|
|
112
|
+
False
|
|
113
|
+
else
|
|
114
|
+
error("could not parse bool '${this}'")
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
Str\camelCase() -> Str =
|
|
118
|
+
todo
|
|
119
|
+
|
|
120
|
+
Str\snakeCase() -> Str =
|
|
121
|
+
todo
|
|
122
|
+
|
|
123
|
+
Str\capitalize() -> Str =
|
|
124
|
+
todo
|
|
125
|
+
|
|
126
|
+
Str\kebabCase() -> Str =
|
|
127
|
+
todo
|
|
128
|
+
|
|
129
|
+
Str\lowerCase() -> Str =
|
|
130
|
+
todo
|
|
131
|
+
|
|
132
|
+
Str\lowerFirst() -> Str =
|
|
133
|
+
todo
|
|
134
|
+
|
|
135
|
+
Str\upperCase() -> Str =
|
|
136
|
+
todo
|
|
137
|
+
|
|
138
|
+
Str\upperFirst() -> Str =
|
|
139
|
+
todo
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
Str\startCase() -> Str =
|
|
143
|
+
todo
|
|
144
|
+
|
|
145
|
+
Str\deburr() -> Str =
|
|
146
|
+
todo
|
|
147
|
+
|
|
148
|
+
Str\escape() -> Str =
|
|
149
|
+
todo
|
|
150
|
+
|
|
151
|
+
Str\escapeRegExp() -> Str =
|
|
152
|
+
todo
|
|
153
|
+
|
|
154
|
+
Str\pad() -> Str =
|
|
155
|
+
todo
|
|
156
|
+
|
|
157
|
+
Str\template() -> Str =
|
|
158
|
+
todo
|
|
159
|
+
|
|
160
|
+
Str\trim() -> Str =
|
|
161
|
+
todo
|
|
162
|
+
|
|
163
|
+
Str\trimEnd() -> Str =
|
|
164
|
+
todo
|
|
165
|
+
|
|
166
|
+
Str\trimStart() -> Str =
|
|
167
|
+
todo
|
|
168
|
+
|
|
169
|
+
Str\truncate() -> Str =
|
|
170
|
+
todo
|
|
171
|
+
|
|
172
|
+
Str\unescape() -> Str =
|
|
173
|
+
todo
|
|
174
|
+
|
|
175
|
+
Str\words() -> Str =
|
|
176
|
+
todo
|
|
177
|
+
|
test/add.plum
CHANGED
|
@@ -24,7 +24,7 @@ branch(x: Int) -> Int
|
|
|
24
24
|
|
|
25
25
|
main() -> Int =
|
|
26
26
|
result = 0
|
|
27
|
-
for i in 0..10
|
|
27
|
+
for i in 0...10
|
|
28
28
|
result += i
|
|
29
29
|
if i == 4
|
|
30
30
|
continue
|
test/sample.plum
CHANGED
|
@@ -6,425 +6,30 @@ Int.random()
|
|
|
6
6
|
Float.random()
|
|
7
7
|
Float.PI
|
|
8
8
|
|
|
9
|
-
trait Comparable {
|
|
10
|
-
fn compareTo(other: T) -> Compare
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
trait Shape permits Circle, Square, Rectangle {
|
|
14
|
-
fn area() -> Float
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
tuple Circle(Int): Shape {
|
|
18
|
-
fn area() = PI * self.0 * self.0
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
tuple Square(Int): Shape {
|
|
22
|
-
fn area() = self.0 * self.0
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
tuple Rectangle(Int, Int): Shape {
|
|
26
|
-
fn area() = self.0 * self.1
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
tuple Metre(Float): Shape {
|
|
30
|
-
static fn fromInt(v: Int) -> Metre {
|
|
31
|
-
return Metre(v)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
fn toFloat() -> Float {
|
|
35
|
-
return self.0
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
`A Cat is new a new type of animal
|
|
40
|
-
|
|
9
|
+
User = {
|
|
41
|
-
name: Option[Str],
|
|
42
|
-
|
|
10
|
+
name: Str
|
|
43
|
-
|
|
11
|
+
email: Str
|
|
44
|
-
static fn withName(name: Str): Cat(name: name, age: 0)
|
|
45
|
-
static fn withAge(age: Int): Cat(name: "", age: age)
|
|
46
|
-
|
|
47
|
-
fn init() {
|
|
48
|
-
printLn("called init")
|
|
49
|
-
require(name.isNotEmpty()) {
|
|
50
|
-
"name shouldn't be empty"
|
|
51
|
-
}
|
|
52
|
-
ensure(name.size > 20) {
|
|
53
|
-
ValidationErr("name too long")
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
fn deinit() {
|
|
58
|
-
printLn("called deinit")
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
fn fullname() -> Str {
|
|
62
|
-
return "${self.name} ${self.age}"
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
override fn toStr() -> Str {
|
|
66
|
-
return "Cat<${fullname()}, ${age}>"
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
record Response(
|
|
71
|
-
body: Buffer = emptyBuffer(),
|
|
72
|
-
headers: Map[Str, Str] = emptyMap(),
|
|
73
|
-
|
|
12
|
+
todos: List(Todo)
|
|
74
|
-
) {
|
|
75
|
-
|
|
76
|
-
fn header(kv: Pair): Self {
|
|
77
|
-
headers.add(kv)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
fn body(b: Buffer): Self {
|
|
81
|
-
body = b
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
fn status(v int): Self {
|
|
85
|
-
status = v
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
record LoopScope(running: Bool) {
|
|
90
|
-
fn stop() {
|
|
91
|
-
self.running = False
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
fn loop(scope: LoopScope = LoopScope(), cond: Option<() -> Bool> = None(), builder: LoopScope.() -> Unit) {
|
|
96
|
-
scope.apply(builder)
|
|
97
|
-
if cond is Some {
|
|
98
|
-
if cond() == True && scope.running == True {
|
|
99
|
-
loop(scope, cond, builder)
|
|
100
|
-
}
|
|
101
|
-
} else {
|
|
102
|
-
if scope.running == True {
|
|
103
|
-
loop(scope, cond, builder)
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
fn example() {
|
|
109
|
-
val items = listOf(1, 2, 3, 4, 5)
|
|
110
|
-
items.each { i ->
|
|
111
|
-
if i == 2 {
|
|
112
|
-
continue()
|
|
113
|
-
}
|
|
114
|
-
if i == 4 {
|
|
115
|
-
break()
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
range(0, 10).step(1).each { i ->
|
|
119
|
-
print("int ${i}")
|
|
120
|
-
}
|
|
121
|
-
loop().cond({ i < 5 }).do {
|
|
122
|
-
print("forever")
|
|
123
|
-
}
|
|
124
|
-
loop {
|
|
125
|
-
if (a > 5) {
|
|
126
|
-
break()
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
val list = "a b c d e f g h i j".split(" ")
|
|
130
|
-
list.groupBy(3) { group ->
|
|
131
|
-
puts group.join ""
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
@result()
|
|
136
|
-
fn mkPerson(name: Str, age: Int) -> Result<Person, ValidationError> = result {
|
|
137
|
-
Person(validName(name).bind(), validAge(age).bind())
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
@handler("GET", "/posts")
|
|
141
|
-
fn getPosts() -> List<Post> {
|
|
142
|
-
return listOf(Post(id: 123))
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
fn handler(req: Request) -> Response {
|
|
146
|
-
return Response()
|
|
147
|
-
.status(2)
|
|
148
|
-
.body("213")
|
|
149
|
-
.headers("1" => "2")
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
fn hasFlag(b: bool, d: List) {
|
|
153
|
-
return data
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
record Greeter(name: String) {
|
|
157
|
-
fn greet() {
|
|
158
|
-
println("Hello, ${name}")
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
fn main(args: List[String]) {
|
|
163
|
-
let g = Greeter(name: "abc")
|
|
164
|
-
g = g.copy(
|
|
165
|
-
name = "123"
|
|
166
|
-
)
|
|
167
|
-
Greeter(...g, name: "123")
|
|
168
13
|
}
|
|
169
14
|
|
|
170
|
-
|
|
171
|
-
fn main() {
|
|
172
|
-
val a = (1 * 5) + (2 + 3)
|
|
173
|
-
|
|
15
|
+
Todo = {
|
|
174
|
-
case a < b => {
|
|
175
|
-
|
|
16
|
+
title: Str
|
|
176
|
-
}
|
|
177
|
-
case a > 9 => {
|
|
178
|
-
printLn(a == 9)
|
|
179
|
-
}
|
|
180
|
-
case a < 9 => {
|
|
181
|
-
printLn(b == 0)
|
|
182
|
-
}
|
|
183
|
-
case _ => {
|
|
184
|
-
printLn(a == 9)
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
val list = listOf<Shape>(Circle(123), Square(20))
|
|
189
|
-
|
|
190
|
-
match list.get(0) {
|
|
191
|
-
case Circle(c): {
|
|
192
|
-
printLn("${c}")
|
|
193
|
-
}
|
|
194
|
-
case Square(a): {
|
|
195
|
-
printLn("${a}")
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
17
|
}
|
|
199
18
|
|
|
200
|
-
lib LibM
|
|
201
|
-
fun sqrt(x: LibC::Double) -> LibC::Double
|
|
202
|
-
fun pow(x: LibC::Double, y: LibC::Double) -> LibC::Double
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
primitive Int : Comparable, ToStr
|
|
206
|
-
fn abs() -> Float
|
|
207
|
-
fn ceil() -> Float
|
|
208
|
-
fn floor() -> Float
|
|
209
|
-
fn round() -> Float
|
|
210
|
-
fn trunc() -> Float
|
|
211
|
-
fun log() -> Float
|
|
212
|
-
fun log2() -> Float
|
|
213
|
-
fun log10() -> Float
|
|
214
|
-
fun logb() -> Float
|
|
215
|
-
fun pow(y: Float) -> Float
|
|
216
|
-
LibM.pow(self, y)
|
|
217
|
-
end
|
|
218
|
-
fun pow(y: Int) -> Float
|
|
219
|
-
pow(y.toFloat())
|
|
220
|
-
end
|
|
221
|
-
fun sqrt() -> Float
|
|
222
|
-
LibM.sqrt(self)
|
|
223
|
-
end
|
|
224
|
-
end
|
|
225
|
-
|
|
226
|
-
primitive Str : Comparable, ToStr
|
|
227
|
-
val data: Buffer
|
|
228
|
-
|
|
229
|
-
get(i: Int) -> Char =
|
|
230
|
-
data.get(i)
|
|
231
|
-
|
|
232
|
-
contains(search: Str) -> Bool
|
|
233
|
-
|
|
234
|
-
indexOf(sub: Str) -> Int
|
|
235
|
-
|
|
236
|
-
fun test(pattern: Regex) -> Bool
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
fun search(key: Str) -> (Int, Bool)
|
|
240
|
-
val (low, mid, high) = (0, 0, n.numItems)
|
|
241
|
-
while low < high do
|
|
242
|
-
mid = (low + high) / 2
|
|
243
|
-
val cmp = key > n.items[mid].key
|
|
244
|
-
low = cmp > 0 ? mid + 1 : low
|
|
245
|
-
high = cmp < 0 ? mid : high
|
|
246
|
-
if cmp == 0 then
|
|
247
|
-
return (mid, True)
|
|
248
|
-
end
|
|
249
|
-
end
|
|
250
|
-
return (low, False)
|
|
251
|
-
end
|
|
252
|
-
|
|
253
|
-
fun startsWith(search: str) -> Bool
|
|
254
|
-
end
|
|
255
|
-
|
|
256
|
-
fun endsWith(search: Str) -> Bool
|
|
257
|
-
end
|
|
258
|
-
|
|
259
|
-
fun concat(other: Str) -> Str
|
|
260
|
-
s + other
|
|
261
|
-
end
|
|
262
|
-
|
|
263
|
-
fun toStr() -> Str
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
fun matchPattern(pattern: Regex) -> []Str
|
|
267
|
-
end
|
|
268
|
-
|
|
269
|
-
fun matchAll(pattern: Regex) -> []Str
|
|
270
|
-
end
|
|
271
|
-
|
|
272
|
-
fun padStart(sub: Str, count: Int) -> Str
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
fun padEnd(sub: Str, count: Int) -> Str
|
|
276
|
-
end
|
|
277
|
-
|
|
278
|
-
fun repeat(count: Int) -> Str
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
fun replace(pattern: Regex, sub: Str) -> Str
|
|
282
|
-
end
|
|
283
|
-
|
|
284
|
-
fun replaceAll(pattern: Regex, sub: Str) -> Str
|
|
285
|
-
end
|
|
286
|
-
|
|
287
|
-
fun search(pattern: Regex) -> Str
|
|
288
|
-
end
|
|
289
|
-
|
|
290
|
-
fun slice(start: Int, e: Int) -> Str
|
|
291
|
-
end
|
|
292
|
-
|
|
293
|
-
fun split(separator: Str, limit: Int) -> []Str
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
fun sub(start: Int, e: Int) -> Str
|
|
297
|
-
end
|
|
298
|
-
|
|
299
|
-
fun toLower() -> Str
|
|
300
|
-
end
|
|
301
|
-
end
|
|
302
|
-
|
|
303
|
-
record Response(a): Option(a, _)
|
|
304
|
-
val body: Buffer = emptyBuffer()
|
|
305
|
-
val headers: Map(Str, Str) = emptyMap()
|
|
306
|
-
val status: Int = 0
|
|
307
|
-
|
|
308
|
-
fun header(k: Str, v: Str) -> Response
|
|
309
|
-
headers.add(kv)
|
|
310
|
-
end
|
|
311
|
-
|
|
312
|
-
fun body(buf: Buffer) -> Response
|
|
313
|
-
body = buf
|
|
314
|
-
if something > 0 then
|
|
315
|
-
Red
|
|
316
|
-
else if something == 0 then
|
|
317
|
-
Yellow
|
|
318
|
-
else
|
|
319
|
-
Green
|
|
320
|
-
end
|
|
321
|
-
end
|
|
322
|
-
|
|
323
|
-
fun status(v: Int) -> Response
|
|
324
|
-
status = v
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
fun delat()
|
|
328
|
-
|
|
19
|
+
User()
|
|
329
|
-
|
|
20
|
+
.name("John Doe")
|
|
330
|
-
|
|
21
|
+
.email("john@example.com")
|
|
331
|
-
|
|
22
|
+
.todo(Todo().title("Make pizza"))
|
|
332
|
-
|
|
23
|
+
.todo(Todo().title("Finish Toasty"))
|
|
333
|
-
|
|
24
|
+
.todo(Todo().title("Sleep"))
|
|
334
|
-
end
|
|
335
|
-
end
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
trait Result(a, b) permits Ok(a), Err(b)
|
|
341
|
-
fn ok() -> a
|
|
342
|
-
fn err() -> b
|
|
343
|
-
fn okOrElse(default: a) -> a
|
|
344
|
-
fn isOk() -> Bool
|
|
345
|
-
fn isErr() -> Bool
|
|
346
|
-
|
|
347
|
-
tuple Ok(a): Result(a, _)
|
|
348
|
-
fn ok() -> a = self.0
|
|
349
|
-
fn err() -> fail("called 'Result.err()' on an 'Ok' value")
|
|
350
|
-
fn okOrElse(default: a) -> a = self.0
|
|
351
|
-
fn map(cb: fn(a) -> b) -> Result(b) = Ok(cb(self.0))
|
|
352
|
-
|
|
353
|
-
tuple Err(a): Result(_, a)
|
|
354
|
-
fn get() -> a = fail("called 'Result.get()' on an 'Err' value")
|
|
355
|
-
fn err() -> self.1
|
|
356
|
-
fn okOrElse(default: a) -> a = default
|
|
357
|
-
fn mapErr(cb: fn(a) -> b) -> Result(_, b) = Err(cb(self.1))
|
|
358
|
-
|
|
359
|
-
trait Option(a) permits Some(a), None
|
|
360
|
-
fn some() -> a
|
|
361
|
-
fn someOrElse(default: a) -> a
|
|
362
|
-
fn map(cb: fn(a) -> b) -> Option(b)
|
|
363
|
-
|
|
364
|
-
tuple Some(a): Option(a)
|
|
365
|
-
fn some() -> a = self.0
|
|
366
|
-
fn someOrElse(default: a) -> a = self.0
|
|
367
|
-
fn map(cb: fn(a) -> b) -> Option(b) = Some(cb(self.0))
|
|
368
|
-
|
|
369
|
-
tuple None(a): Option(_)
|
|
370
|
-
fn some() -> a = fail("called 'Option.some()' on an 'Some' value")
|
|
371
|
-
fn someOrElse(default: a) -> a = default
|
|
372
|
-
fn stoplightColor(something: Int) -> Color =
|
|
373
|
-
if something > 0 then
|
|
374
|
-
Red
|
|
375
|
-
else if something == 0 then
|
|
376
|
-
Yellow
|
|
377
|
-
else
|
|
378
|
-
Green
|
|
379
|
-
fn stoplightStr(stoplightColor: Color) -> Str
|
|
380
|
-
match stoplightColor
|
|
381
|
-
Red -> "red"
|
|
382
|
-
Green -> "green"
|
|
383
|
-
Yellow -> "yellow"
|
|
384
|
-
|
|
385
|
-
fun stoplightStr(stoplightColor: Color) -> Str
|
|
386
|
-
when stoplightColor is
|
|
387
|
-
Red -> "red"
|
|
388
|
-
Green -> "green"
|
|
389
|
-
Yellow -> "yellow"
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
record Response(a): Option(a, _)
|
|
394
|
-
val body: Buffer = emptyBuffer()
|
|
395
|
-
val headers: Map(Str, Str) = emptyMap()
|
|
396
|
-
val status: Int = 0
|
|
397
|
-
|
|
398
|
-
fn header(k: Str, v: Str) -> Response =
|
|
399
|
-
headers.add(kv)
|
|
400
|
-
self
|
|
401
|
-
|
|
402
|
-
fn body(buf: Buffer) -> Response =
|
|
403
|
-
body = buf
|
|
404
|
-
self
|
|
405
|
-
|
|
406
|
-
fn status(v: Int) -> Response =
|
|
407
|
-
status = v
|
|
408
|
-
self
|
|
409
|
-
|
|
410
|
-
record Response(
|
|
411
|
-
body: Buffer = emptyBuffer()
|
|
412
|
-
headers: Map(Str, Str) = emptyMap()
|
|
413
|
-
status: Int = 0
|
|
414
|
-
): Option(a, _)
|
|
415
|
-
|
|
416
|
-
fn header(k: Str, v: Str) -> Response =
|
|
417
|
-
headers.add(kv)
|
|
418
|
-
self
|
|
419
|
-
|
|
420
|
-
fn body(buf: Buffer) -> Response =
|
|
421
|
-
body = buf
|
|
422
|
-
self
|
|
423
|
-
|
|
424
|
-
fn status(v: Int) -> Response =
|
|
425
|
-
status = v
|
|
426
|
-
self
|
|
427
25
|
|
|
26
|
+
fn stoplightColor(something: Int) -> Color =
|
|
27
|
+
if something > 0 then
|
|
28
|
+
Red
|
|
29
|
+
else if something == 0 then
|
|
30
|
+
Yellow
|
|
31
|
+
else
|
|
32
|
+
Green
|
|
428
33
|
|
|
429
34
|
Response = {
|
|
430
35
|
body: Buffer = emptyBuffer()
|
|
@@ -432,27 +37,15 @@ Response = {
|
|
|
432
37
|
status: Int = 0
|
|
433
38
|
}
|
|
434
39
|
|
|
435
|
-
Response\header(k: Str, v: Str) -> Response =
|
|
436
|
-
headers.add(kv)
|
|
437
|
-
self
|
|
438
|
-
|
|
439
|
-
Response\body(buf: Buffer) -> Response =
|
|
440
|
-
body = buf
|
|
441
|
-
self
|
|
442
|
-
|
|
443
|
-
Response\status(v: Int) -> Response =
|
|
444
|
-
status = v
|
|
445
|
-
self
|
|
446
|
-
|
|
447
40
|
main() -> Unit =
|
|
448
41
|
printLn("123")
|
|
449
42
|
|
|
450
43
|
main() -> Int, Err =
|
|
451
44
|
Stdout.line! "There are $(total) animals."
|
|
452
45
|
|
|
46
|
+
# calculate to str
|
|
453
47
|
Int\toStr() -> Str =
|
|
454
48
|
todo
|
|
455
|
-
# calculate to str
|
|
456
49
|
|
|
457
50
|
Int::random() -> Int =
|
|
458
51
|
24
|
|
@@ -463,10 +56,10 @@ sub(arg1: Int, arg2: Int) -> Int =
|
|
|
463
56
|
local1 - local2
|
|
464
57
|
|
|
465
58
|
addAndStringify(num1: Int, num2: Int) -> Str =
|
|
466
|
-
|
|
59
|
+
(num1 + num2).toStr()
|
|
467
60
|
|
|
468
61
|
factorial(x: Int) -> Int =
|
|
469
|
-
if x < 2
|
|
62
|
+
if x < 2
|
|
470
63
|
x
|
|
471
64
|
else
|
|
472
65
|
x * factorial(x - 1)
|
|
@@ -477,7 +70,6 @@ Result(a, b) =
|
|
|
477
70
|
|
|
478
71
|
```
|
|
479
72
|
Checks whether the result is an `Ok` value
|
|
480
|
-
|
|
481
73
|
isOk(Ok(1)) # => True
|
|
482
74
|
isOk(Err(Nil)) # => False
|
|
483
75
|
```
|
|
@@ -510,7 +102,8 @@ User = {
|
|
|
510
102
|
}
|
|
511
103
|
|
|
512
104
|
user = User(1, 2, 3)
|
|
513
|
-
params =
|
|
105
|
+
params = Map("one" => 1, "two" => 2, "three" => 3)
|
|
106
|
+
arr = List(1, 2, 3, 4)
|
|
514
107
|
|
|
515
108
|
User\isAuthorized() -> Bool =
|
|
516
109
|
False
|
|
@@ -552,4 +145,62 @@ match v
|
|
|
552
145
|
|
|
553
146
|
names = ["Sam", "Lee", "Ari"]
|
|
554
147
|
names.append("Jess")
|
|
555
|
-
names.map(\num -> num * 2)
|
|
148
|
+
names.map(\num -> num * 2)
|
|
149
|
+
|
|
150
|
+
module std/http
|
|
151
|
+
|
|
152
|
+
import std/path
|
|
153
|
+
import std/os
|
|
154
|
+
import std/http/content_type
|
|
155
|
+
import std/libc
|
|
156
|
+
|
|
157
|
+
extern sqrt(x: libc.Double) -> libc.Double
|
|
158
|
+
extern pow(x: libc.Double, y: libc.Double) -> libc.Double
|
|
159
|
+
|
|
160
|
+
WriteError = EOF | Closed
|
|
161
|
+
|
|
162
|
+
Writer = (
|
|
163
|
+
write(p: Str | Buffer) -> Int | WriteError
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
ReadError = EOF | Closed
|
|
167
|
+
|
|
168
|
+
Reader = (
|
|
169
|
+
read(p: Str | Buffer) -> Int | ReadError
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
IO = Reader + Writer
|
|
173
|
+
IOError = ReadError | WriteError
|
|
174
|
+
|
|
175
|
+
Response(
|
|
176
|
+
headers: Map[Str, Str]
|
|
177
|
+
body: Str | Buffer | IO
|
|
178
|
+
status: Int
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
createFileResponse(path: Str) -> Response | IOError =
|
|
182
|
+
content := content_type.fromExt(path.ext())
|
|
183
|
+
data := os.readFile(file)?
|
|
184
|
+
Response()
|
|
185
|
+
.header("Content-Type", content)
|
|
186
|
+
.body(data)
|
|
187
|
+
.status(200)
|
|
188
|
+
|
|
189
|
+
index() -> Response =
|
|
190
|
+
createFileResponse("index.html")
|
|
191
|
+
|
|
192
|
+
serveFile(file: Str) -> Response | IOError =
|
|
193
|
+
ext := path::ext(file)
|
|
194
|
+
content := contentTypeFromExt(ext)
|
|
195
|
+
data := os.readFile(file)?
|
|
196
|
+
Response()
|
|
197
|
+
.header("Content-Type", content)
|
|
198
|
+
.body(data)
|
|
199
|
+
.status(200)
|
|
200
|
+
|
|
201
|
+
http.createFileResponse("./src/sample.plum")
|
|
202
|
+
http.index()
|
|
203
|
+
http.serveFile("./src/sample.plum")
|
|
204
|
+
|
|
205
|
+
g = Greeter(name: "abc")
|
|
206
|
+
g = Greeter(...g, name: "123")
|
tooling/vscode-plum/language-configuration.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"comments": {
|
|
3
3
|
// symbol used for single line comment. Remove this entry if your language does not support line comments
|
|
4
|
-
"lineComment": "
|
|
4
|
+
"lineComment": "#",
|
|
5
|
+
"blockComment": [
|
|
6
|
+
"```",
|
|
7
|
+
"```"
|
|
8
|
+
]
|
|
5
9
|
},
|
|
6
10
|
// symbols used as brackets
|
|
7
11
|
"brackets": [
|
|
@@ -39,7 +43,11 @@
|
|
|
39
43
|
[
|
|
40
44
|
"'",
|
|
41
45
|
"'"
|
|
42
|
-
]
|
|
46
|
+
],
|
|
47
|
+
[
|
|
48
|
+
"```",
|
|
49
|
+
"```"
|
|
50
|
+
],
|
|
43
51
|
],
|
|
44
52
|
// symbols that can be used to surround a selection
|
|
45
53
|
"surroundingPairs": [
|
|
@@ -62,6 +70,10 @@
|
|
|
62
70
|
[
|
|
63
71
|
"'",
|
|
64
72
|
"'"
|
|
65
|
-
]
|
|
73
|
+
],
|
|
74
|
+
[
|
|
75
|
+
"```",
|
|
76
|
+
"```"
|
|
77
|
+
],
|
|
66
78
|
]
|
|
67
79
|
}
|
tooling/vscode-plum/syntaxes/plum.tmLanguage.json
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
|
|
3
|
+
"name": "plum",
|
|
4
|
+
"patterns": [
|
|
5
|
+
{
|
|
6
|
+
"include": "#comments"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"include": "#keywords"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"include": "#strings"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"include": "#constant"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"include": "#entity"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"include": "#discards"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"repository": {
|
|
25
|
+
"keywords": {
|
|
26
|
+
"patterns": [
|
|
27
|
+
{
|
|
28
|
+
"name": "keyword.control.plum",
|
|
29
|
+
"match": "\\b(return|continue|break|match|if|else|while|for|module|as|is|import|assert|todo|crash)\\b"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"name": "keyword.operator.arrow.plum",
|
|
33
|
+
"match": "(<\\-|\\->)"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "keyword.operator.pipe.plum",
|
|
37
|
+
"match": "\\|>"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"name": "keyword.operator.splat.plum",
|
|
41
|
+
"match": "\\.\\."
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"name": "keyword.operator.comparison.plum",
|
|
45
|
+
"match": "(==|!=)"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "keyword.operator.comparison.float.plum",
|
|
49
|
+
"match": "(<=\\.|>=\\.|<\\.|>\\.)"
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
"name": "keyword.operator.comparison.int.plum",
|
|
53
|
+
"match": "(<=|>=|<|>)"
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "keyword.operator.logical.plum",
|
|
57
|
+
"match": "(&&|\\|\\|)"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "keyword.operator.arithmetic.float.plum",
|
|
61
|
+
"match": "(\\+\\.|\\-\\.|/\\.|\\*\\.)"
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"name": "keyword.operator.arithmetic.int.plum",
|
|
65
|
+
"match": "(\\+|\\-|/|\\*|%)"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"name": "keyword.operator.assignment.plum",
|
|
69
|
+
"match": "="
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"strings": {
|
|
74
|
+
"name": "string.quoted.double.plum",
|
|
75
|
+
"begin": "\"",
|
|
76
|
+
"end": "\"",
|
|
77
|
+
"patterns": [
|
|
78
|
+
{
|
|
79
|
+
"name": "constant.character.escape.plum",
|
|
80
|
+
"match": "\\\\."
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
"comments": {
|
|
85
|
+
"patterns": [
|
|
86
|
+
{
|
|
87
|
+
"name": "comment.line.plum",
|
|
88
|
+
"match": "#.*"
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"begin": "```",
|
|
92
|
+
"beginCaptures": {
|
|
93
|
+
"0": {
|
|
94
|
+
"name": "punctuation.definition.comment.begin.plum"
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
"end": "```",
|
|
98
|
+
"endCaptures": {
|
|
99
|
+
"0": {
|
|
100
|
+
"name": "punctuation.definition.comment.end.plum"
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
"name": "comment.block.plum"
|
|
104
|
+
}
|
|
105
|
+
]
|
|
106
|
+
},
|
|
107
|
+
"constant": {
|
|
108
|
+
"patterns": [
|
|
109
|
+
{
|
|
110
|
+
"include": "#binary_number"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"include": "#octal_number"
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"include": "#hexadecimal_number"
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
"include": "#decimal_number"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"include": "#boolean"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"name": "entity.name.type.plum",
|
|
126
|
+
"match": "[[:upper:]][[:alnum:]]*"
|
|
127
|
+
}
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
"binary_number": {
|
|
131
|
+
"name": "constant.numeric.binary.plum",
|
|
132
|
+
"match": "\\b0[bB]0*1[01_]*\\b",
|
|
133
|
+
"patterns": []
|
|
134
|
+
},
|
|
135
|
+
"octal_number": {
|
|
136
|
+
"name": "constant.numeric.octal.plum",
|
|
137
|
+
"match": "\\b0[oO]0*[1-7][0-7]*\\b",
|
|
138
|
+
"patterns": []
|
|
139
|
+
},
|
|
140
|
+
"decimal_number": {
|
|
141
|
+
"name": "constant.numeric.decimal.plum",
|
|
142
|
+
"match": "\\b(0*[1-9][0-9_]*|0)(\\.(0*[1-9][0-9_]*|0)?(e-?0*[1-9][0-9]*)?)?\\b",
|
|
143
|
+
"patterns": []
|
|
144
|
+
},
|
|
145
|
+
"hexadecimal_number": {
|
|
146
|
+
"name": "constant.numeric.hexadecimal.plum",
|
|
147
|
+
"match": "\\b0[xX]0*[1-9a-zA-Z][0-9a-zA-Z]*\\b",
|
|
148
|
+
"patterns": []
|
|
149
|
+
},
|
|
150
|
+
"entity": {
|
|
151
|
+
"patterns": [
|
|
152
|
+
{
|
|
153
|
+
"begin": "\\b([[:lower:]][[:word:]]*)\\b[[:space:]]*\\(",
|
|
154
|
+
"end": "\\)",
|
|
155
|
+
"patterns": [
|
|
156
|
+
{
|
|
157
|
+
"include": "$self"
|
|
158
|
+
}
|
|
159
|
+
],
|
|
160
|
+
"captures": {
|
|
161
|
+
"1": {
|
|
162
|
+
"name": "entity.name.function.plum"
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"name": "variable.parameter.plum",
|
|
168
|
+
"match": "\\b([[:lower:]][[:word:]]*):\\s"
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
"name": "entity.name.namespace.plum",
|
|
172
|
+
"match": "\\b([[:lower:]][[:word:]]*):"
|
|
173
|
+
}
|
|
174
|
+
]
|
|
175
|
+
},
|
|
176
|
+
"discards": {
|
|
177
|
+
"name": "comment.unused.plum",
|
|
178
|
+
"match": "\\b_(?:[[:word:]]+)?\\b"
|
|
179
|
+
}
|
|
180
|
+
},
|
|
181
|
+
"scopeName": "source.plum"
|
|
182
|
+
}
|