~repos /plum

#treesitter#compiler#wasm

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 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
- "version": "0.2.0",
6
+ "version": "0.2.0",
7
- "configurations": [
7
+ "configurations": [
8
- {
8
+ {
9
- "name": "Extension",
9
+ "name": "Extension",
10
- "type": "extensionHost",
10
+ "type": "extensionHost",
11
- "request": "launch",
11
+ "request": "launch",
12
- "args": [
12
+ "args": [
13
- "--extensionDevelopmentPath=${workspaceFolder}/vscode-kestrel"
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
- record Response(
7
+ Response = (
9
8
  headers: Map[Str, Str]
10
- body: str | Buffer | IO
9
+ body: Str | Buffer | IO
11
- status: int
10
+ status: Int
12
11
  )
13
12
 
14
- fn file_response(path: str): Response | IOError =
13
+ createFileResponse(path: Str) -> Response | IOError =
15
- content := contentTypeFromExt(path.ext())
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
- fn index(): Response! =
21
+ index() -> Response! =
24
- file_response("index.html")
22
+ createFileResponse("index.html")
25
23
 
26
- #[get("/public/<...>")]
27
- fn public(file: str): Response | IOError =
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
- type = T
3
+ Json =
4
+ | None
5
+ | Str
6
+ | Bool
7
+ | Float
8
+ | Int
9
+ | List
10
+ | Map
11
+
5
- fn parse() -> T
12
+ JsonParseError = {
13
+ line: Int
14
+ pos: Int
15
+ token: Char
6
16
  }
7
17
 
8
- tuple JsonObject(Map[str, Json]): Json {
18
+ Json\\parse(src: Str | Buffer | IO) -> Json | JsonParseError =
9
- type = JsonObject
10
-
11
- fn parse() -> JsonObject {
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
- tuple JsonFloat(Float): Json {
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
- tuple JsonString(Str): Json {
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
- record ParseError(
40
+ JsonParser = (
45
- line: str
41
+ cur: Int = ' '
46
- pos: str
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
- fn JsonParser.withSrc(src: str | Buffer | IO): JsonParser =
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("parse int") {
352
+ Json\test("parseInt") =
360
353
  assert Json.parse("123") == 123
361
- }
362
354
 
363
- test("parse str") {
355
+ Json\test("parseStr") =
364
356
  assert Json.parse(`"hello"`) == "hello"
365
- }
366
357
 
367
- test("parse bool") {
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
- record Cat(
9
+ User = {
41
- name: Option[Str],
42
- age: Int
10
+ name: Str
43
- ): ToStr {
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
- status: Int = 0,
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
- match a {
15
+ Todo = {
174
- case a < b => {
175
- printLn(a != b)
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
- User::create()
19
+ User()
329
- .name("John Doe")
20
+ .name("John Doe")
330
- .email("john@example.com")
21
+ .email("john@example.com")
331
- .todo(Todo::create().title("Make pizza"))
22
+ .todo(Todo().title("Make pizza"))
332
- .todo(Todo::create().title("Finish Toasty"))
23
+ .todo(Todo().title("Finish Toasty"))
333
- .todo(Todo::create().title("Sleep"))
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
- (num1 + num2).toStr()
59
+ (num1 + num2).toStr()
467
60
 
468
61
  factorial(x: Int) -> Int =
469
- if x < 2 then
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 = {"one" => 1, "two" => 2, "three" => 3}
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
+ }