~repos /plum

#treesitter#compiler#wasm

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

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


5de508e7 pyrossh

11 months ago
changes
libs/std/bool.plum CHANGED
@@ -1,57 +1,40 @@
1
1
  module std
2
2
 
3
- type Int =
3
+ type Int
4
- add(b: Int) -> Int = this + b
5
- sub(b: Int) -> Int = this - b
6
4
 
5
+ fn (i: Int) add(b: Int) -> Int =
6
+ return this + b
7
+
8
+ fn (i: Int) sub(b: Int) -> Int =
9
+ return this - b
7
10
 
8
11
  enum Bool =
9
12
  | True
10
13
  | False
11
14
 
15
+ fromStr(s: Str) -> Result[Bool, Err] =>
16
+ if s == "true"
17
+ True
18
+ else if s == "false"
19
+ False
20
+ else
21
+ Err("could not parse bool from '{s}'")
22
+
12
- and(other: Bool) -> Bool =
23
+ and(self, o: Bool) -> Bool =>
13
- match this, other
24
+ match this, o
14
25
  True, True => True
15
26
  True, False => False
16
27
  False, True => False
17
28
  False, False => False
18
29
 
19
- or(other: Bool) -> Bool =
30
+ or(self, o: Bool) -> Bool =>
20
- match this, other
31
+ match this, o
21
32
  True, True => True
22
33
  True, False => True
23
34
  False, True => True
24
35
  False, False => False
25
36
 
26
- toStr() -> Str =
37
+ toStr(self) -> Str =>
27
38
  match this
28
39
  True => "True"
29
40
  False => "False"
30
-
31
- fromStr(s: Str) -> Result(Bool, Err) =
32
- if s == "true"
33
- True
34
- else if s == "false"
35
- False
36
- else
37
- Err("could not parse bool from '{s}'")
38
-
39
- readFile() -> Result(String, Err) =
40
- return Err
41
-
42
- data = try readFile()
43
-
44
- if Ok(d) = readFile()
45
- println(d)
46
-
47
- match readFile()
48
- Ok(d) =>
49
- printLn(d)
50
- Err(e) =>
51
- printErr(e)
52
-
53
- enum List =
54
- | Empty
55
- | Node(a)
56
-
57
- add() =
libs/std/{encode/base64.plum → encoding/Base64.plum} RENAMED
@@ -1,39 +1,20 @@
1
- ```
2
- # Base64 package
3
-
4
- The Base64 package contains support for doing Base64 binary-to-text encodings.
1
+ `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
2
+ module Base64
22
-
3
+
23
- # Encode for PEM (RFC 1421).
4
+ `Encode for PEM (RFC 1421).
24
5
  encodePEM(data: ReadSeq[U8]) -> String =
25
6
  encode(data, '+', '/', '=', 64)
26
7
 
27
- # Encode for MIME (RFC 2045).
8
+ `Encode for MIME (RFC 2045).
28
9
  encodeMIME(data: ReadSeq[U8]) -> String =
29
10
  encode(data, '+', '/', '=', 76)
30
11
 
31
- # Encode for URLs (RFC 4648). Padding characters are stripped by default.
12
+ `Encode for URLs (RFC 4648). Padding characters are stripped by default.
32
13
  encodeURL(data: ReadSeq[U8], pad: Bool = False) -> String =
33
14
  let c: U8 = if pad then '=' else 0 end
34
15
  encode[A](data, '-', '_', c)
35
16
 
36
- # Configurable encoding. The defaults are for RFC 4648.
17
+ `Configurable encoding. The defaults are for RFC 4648.
37
18
  encode(
38
19
  data: ReadSeq[U8],
39
20
  at62: U8 = '+',
@@ -96,32 +77,21 @@ encode(
96
77
  out.clear()
97
78
  out
98
79
 
99
- fun decode_url[A: Seq[U8] iso = Array[U8] iso](data: ReadSeq[U8]): A^ ? =>
100
- """
101
- Decode for URLs (RFC 4648).
80
+ `Decode for URLs (RFC 4648).
102
- """
81
+ decode_url(data: ReadSeq[U8]) -> Option[A] =
103
82
  decode[A](data, '-', '_')?
104
83
 
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
84
+ `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
85
+ `not an error. Non-base64 data, other than whitespace (which can appear at
115
- any time), is an error.
86
+ `any time), is an error.
116
- """
87
+ decode(data: ReadSeq[U8], at62: U8 = '+', at63: U8 = '/', pad: U8 = '=') -> Option[A] =
117
- let len = (data.size() * 4) / 3
88
+ len = (data.size() * 4) / 3
118
- let out = recover A(len) end
89
+ out = recover A(len) end
119
-
120
- var state = U8(0)
90
+ state = U8(0)
121
- var input = U8(0)
91
+ input = U8(0)
122
- var output = U8(0)
92
+ output = U8(0)
123
-
93
+
124
- for i in Range(0, data.size()) do
94
+ for i in Range(0, data.size())
125
95
  input = data(i)?
126
96
 
127
97
  let value =
@@ -170,23 +140,12 @@ encode(
170
140
 
171
141
  out
172
142
 
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.
143
+ test "encode and decode" =>
184
- encodeDecodeTest() =
185
- assert
144
+ expect:
186
145
  encode(a) == b
187
146
  decode(b) == a
188
147
  where:
189
- a | b
148
+ a | b
190
149
  "" | ""
191
150
  "f" | "Zg=="
192
151
  "fo" | "Zm8="
@@ -195,5 +154,21 @@ encodeDecodeTest() =
195
154
  "fooba" | "Zm9vYmE="
196
155
  "foobar" | "Zm9vYmFy"
197
156
 
198
-
157
+ encodeByte(i: Byte, at62: Byte, at63: Byte) -> Byte =
199
- # a | b | c << sql.rows("select a, b, c from maxdata")
158
+ doc: "encode a single byte"
159
+ match i
160
+ i == 62 => at62
161
+ i == 63 => at63
162
+ i < 26 => 'A' + i
163
+ i < 52 => ('a' - 26) + i
164
+ i < 62 => ('0' - 52) + i
165
+ check:
166
+ expect:
167
+ encodeByte(i, at62, at63) == b
168
+ where:
169
+ i | at62 | at63
170
+ 1 | 0 | 0
171
+ 2 | 0 | 0
172
+ 3 | 0 | 0
173
+ 62 | 0 | 0
174
+ 63 | 0 | 0
libs/std/err.plum CHANGED
@@ -1,8 +1,7 @@
1
1
  module std
2
2
 
3
- # This is used to represent an error value across the language
3
+ `This is used to represent an error value across the language
4
- Err = (
4
+ trait Err =
5
5
  code() -> Int
6
6
  msg() -> Str
7
- cause() -> Err | Nil
7
+ cause() -> Err | Nil
8
- )
libs/std/float.plum CHANGED
@@ -1,24 +1,24 @@
1
1
  module std
2
2
 
3
3
  type Float =
4
- E = 2.718f # Euler's number, the base of natural logarithms, e, https://oeis.org/A001113
4
+ E = 2.718f `Euler's number, the base of natural logarithms, e, https://oeis.org/A001113
5
- LN10 = 2.302f # The natural logarithm of 10, https://oeis.org/A002392
5
+ LN10 = 2.302f `The natural logarithm of 10, https://oeis.org/A002392
6
- LN2 = 0.693f # The natural logarithm of 2 https://oeis.org/A002162
6
+ LN2 = 0.693f `The natural logarithm of 2 https://oeis.org/A002162
7
- LOG10E = 0.434f # The base 10 logarithm of e # formula: 1 / LN10
7
+ LOG10E = 0.434f `The base 10 logarithm of e `formula: 1 / LN10
8
- LOG2E = 1.442f # The base 2 logarithm of e # formula: 1 / LN2
8
+ LOG2E = 1.442f `The base 2 logarithm of e `formula: 1 / LN2
9
- PI = 3.14159f # The ratio of the circumference of a circle to its diameter https://oeis.org/A000796
9
+ PI = 3.14159f `The ratio of the circumference of a circle to its diameter https://oeis.org/A000796
10
- PHI = 1.6180f # https://oeis.org/A001622
10
+ PHI = 1.6180f `https://oeis.org/A001622
11
- SQRT1_2 = 0.707f # The square root of 1/2
11
+ SQRT1_2 = 0.707f `The square root of 1/2
12
- SQRT2 = 1.414f # The square root of 2 https://oeis.org/A002193
12
+ SQRT2 = 1.414f `The square root of 2 https://oeis.org/A002193
13
- SQRT_E = 1.64872f # https://oeis.org/A019774
13
+ SQRT_E = 1.64872f `https://oeis.org/A019774
14
- SQRT_PI = 1.77245f # https://oeis.org/A002161
14
+ SQRT_PI = 1.77245f `https://oeis.org/A002161
15
- SQRT_PHI = 1.27201f # https://oeis.org/A139339
15
+ SQRT_PHI = 1.27201f `https://oeis.org/A139339
16
- EPSILON = 2.220446049250313e-16f # The difference between 1 and the smallest floating point number greater than 1 formula: 7/3 - 4/3 - 1
16
+ EPSILON = 2.220446049250313e-16f `The difference between 1 and the smallest floating point number greater than 1 formula: 7/3 - 4/3 - 1
17
- MIN_FLOAT_VALUE = 4.9406564584124654417656879286822137236505980e-324 # Lowest value of float
17
+ MIN_FLOAT_VALUE = 4.9406564584124654417656879286822137236505980e-324 `Lowest value of float
18
- MAX_FLOAT_VALUE = 1.79769313486231570814527423731704356798070e+308 # Highest value of float
18
+ MAX_FLOAT_VALUE = 1.79769313486231570814527423731704356798070e+308 `Highest value of float
19
-
20
-
19
+
20
+
21
- ::fromStr(s: Str) -> Result(Float, Err) =
21
+ static fromStr(s: Str) -> Result(Float, Err) =
22
22
  todo
23
23
 
24
24
  acosh(v: Float) -> Float =
@@ -31,19 +31,19 @@ type Float =
31
31
  t =
32
32
  ((2*t+t*t).sqrt() + t).log1p() 2 >= x > 1
33
33
 
34
- # Check whether this number is finite, ie not +/-infinity and not NaN.
34
+ `Check whether this number is finite, ie not +/-infinity and not NaN.
35
- # True if exponent is not all 1s
35
+ `True if exponent is not all 1s
36
36
  isFinite() -> Bool =
37
37
  (bits() && 0x7FF0_0000_0000_0000) != 0x7FF0_0000_0000_0000
38
38
 
39
- # Check whether this number is +/-infinity
39
+ `Check whether this number is +/-infinity
40
- # True if exponent is all 1s and mantissa is 0
40
+ `True if exponent is all 1s and mantissa is 0
41
41
  isInfinite() -> Bool =
42
42
  ((bits() && 0x7FF0_0000_0000_0000) == 0x7FF0_0000_0000_0000) && # exp
43
43
  ((bits() && 0x000F_FFFF_FFFF_FFFF) == 0) # mantissa
44
44
 
45
- # Check whether this number is NaN.
45
+ `Check whether this number is NaN.
46
- # True if exponent is all 1s and mantissa is non-0
46
+ `True if exponent is all 1s and mantissa is non-0
47
47
  isNaN() -> Bool =
48
48
  ((bits() && 0x7FF0_0000_0000_0000) == 0x7FF0_0000_0000_0000) && # exp
49
49
  ((bits() && 0x000F_FFFF_FFFF_FFFF) != 0) # mantissa
libs/std/http.plum CHANGED
@@ -4,29 +4,28 @@ import std/path
4
4
  import std/os
5
5
  import std/http/content_type
6
6
 
7
- Response = (
7
+ type Response =
8
- headers: Map(Str, Str)
8
+ headers: Map[Str, Str]
9
9
  body: Str | Buffer | IO
10
10
  status: Int
11
- )
12
11
 
13
- createFileResponse(path: Str) -> Response | IOError =
12
+ createFileResponse(path: Str) -> Response | IOError =
14
- content = content_type.fromExt(path.ext())
13
+ content = content_type.fromExt(path.ext())
15
- data = os.readFile(file)?
14
+ data = os.readFile(file)?
16
- Response()
15
+ Response::create()
17
- .header("Content-Type", content)
16
+ .header("Content-Type", content)
18
- .contentType(.ApplicationJS)
17
+ .contentType(.ApplicationJS)
19
- .body(data)
18
+ .body(data)
20
- .status(200)
19
+ .status(200)
21
20
 
22
- index() -> Response | IOError =
21
+ index() -> Response | IOError =
23
- createFileResponse("index.html")
22
+ createFileResponse("index.html")
24
23
 
25
- serveFile(file: Str) -> Response | IOError =
24
+ serveFile(file: Str) -> Response | IOError =
26
- ext := path::ext(file)
25
+ ext := path::ext(file)
27
- content := contentTypeFromExt(ext)
26
+ content := contentTypeFromExt(ext)
28
- data := os.readFile(file)?
27
+ data := os.readFile(file)?
29
- Response()
28
+ Response()
30
- .header("Content-Type", content)
29
+ .header("Content-Type", content)
31
- .body(data)
30
+ .body(data)
32
- .status(200)
31
+ .status(200)
libs/std/json.plum CHANGED
@@ -1,64 +1,97 @@
1
1
  module std/json
2
2
 
3
+ import std.{Option, Bool, Float, Str, List, Map, Result}
4
+
3
- Json =
5
+ enum Json =
4
6
  | None
5
- | Str
6
7
  | Bool
7
8
  | Float
8
- | Int
9
+ | Str
9
10
  | List
10
11
  | Map
11
12
 
13
+ ^parse(src: Readable) -> Result(Json, JsonParseError) =
14
+ JsonParser.withSrc(src).parse()
15
+
12
- JsonParseError = {
16
+ class JsonParseError(Error) =
13
17
  line: Int
14
18
  pos: Int
15
19
  token: Char
16
- }
17
-
18
- Json::parse(src: Str | Buffer | IO) -> Json | JsonParseError =
19
- JsonParser.withSrc(src).parse()
20
-
21
- Json\parseNone() -> None | JsonParseError =
22
- parser.find("null")
23
-
24
- Json\parseStr() -> Str | JsonParseError =
25
- parser.find("null")
26
-
27
- Json\parseFloat() -> Float | JsonParseError =
28
- parser.find("null")
29
-
30
- Json\parseInt() -> Int | JsonParseError =
31
- parser.find("null")
32
-
33
- Json\parseList() -> List | JsonParseError =
34
- parser.find("null")
35
-
36
- Json\parseMap() -> Map | JsonParseError =
37
- parser.find("null")
38
-
39
-
40
- JsonParser = (
41
- cur: Int = ' '
42
- _pos: Int = 0
43
- _next: Int = ' '
44
- _buf: Str | Buffer | IO
45
- )
46
-
47
- JsonParser::withSrc(src: Str | Buffer | IO) -> JsonParser =
48
- JsonParser(_buf = src)
49
-
50
- fn isSpace(c: U32): Bool => (c == ' ') or ((c >= '\t') and (c <= '\r'))
51
-
52
- fn isDelim(c: U32): Bool =>
53
- (c == ',') || (c == '}') || (c == ':') || (c == ']') || (_is_space(c)) || (c == 0)
54
20
 
21
+ data JsonParser =
22
+ cur: Int = ""
23
+ pos: Int = 0
24
+ next: Int = ""
25
+ src: Readable
26
+
27
+ ^withSrc(src: Readable) =
28
+ JsonParser::create()
29
+ .src(src)
30
+
31
+ parse() -> Result(Json, JsonParseError) =
32
+ match getNext()
33
+ '{' -> parseObject()
34
+ '[' -> parseList()
35
+ `"` -> parseStr()
36
+ 'n' -> parseNone()
37
+ `t` | `f` -> parseBool()
38
+ 0..9 -> parseFloat()
39
+ _ -> Err(createErr())
40
+
41
+ createErr() =
42
+ JsonParseError::create()
43
+ .line(0)
44
+ .pos(pos)
45
+ .token(cur)
46
+
47
+ parseNone() -> Result[None, JsonParseError] =
48
+ find("null")
49
+ check:
50
+ assert Json.parse("null") == None
51
+
52
+ parseBool() -> Result[Bool, JsonParseError] =
53
+ if find("true")
54
+ True
55
+ else if find("false")
56
+ False
57
+ check:
58
+ assert Json.parse("true") == True
59
+ assert Json.parse("false") == False
60
+
61
+ parseStr() -> Result[Str, JsonParseError] =
62
+ find("null")
63
+ check:
64
+ assert Json.parse(`"hello"`) == "hello"
65
+
66
+ parseFloat() -> Result[Float, JsonParseError] =
67
+ find("null")
68
+
69
+ parseInt() -> Result[Int, JsonParseError] =
70
+ find("Int")
71
+ check:
72
+ assert Json.parse("123") == 123
73
+
74
+ parseList() -> Result[List, JsonParseError] =
75
+ find("null")
76
+ check:
77
+ assert Json.parse("[]") == List[Json]()
78
+ assert Json.parse("[1, 2]") == List[Json](1, 2)
79
+
80
+ parseMap() -> Result[Map, JsonParseError] =
81
+ find("null")
82
+ check:
83
+ assert Json.parse("{}") == Map[Str, Json]()
84
+ assert Json.parse(`{"a": 1, "b": 2}`) == Map[Str, Json]("a" => 1, "b" => 2)
85
+
86
+
87
+ isSpace(c: Int) -> Bool =
88
+ {c == ' '} || {{c >= '\t'} && {c <= '\r'}}
89
+
90
+ isDelim(c: Int) -> Bool =
91
+ (c == ',') || (c == '}') || (c == ':') || (c == ']') || (_is_space(c)) || (c == 0)
92
+
55
- fn isDigit(c: U32) -> Bool {
93
+ isDigit(c: Int) -> Bool =
56
- return (c >= '0') && (c <= '9')
94
+ (c >= '0') && (c <= '9')
57
- }
58
-
59
- fn _is_digit(c: U32): Bool => (c >= '0') and (c <= '9')
60
-
61
- fn (p: Parser) _err(msg: str) => printLn(msg)
62
95
 
63
96
  fn _get_next_raw(): U32 =>
64
97
  try
@@ -94,16 +127,10 @@ fn _expect(chr: U32, msg: String): Bool =>
94
127
 
95
128
  fn _inc_pos(i: ISize = 1) => _pos = _pos.add(i)
96
129
 
97
- fn (p JsonParser) parse(): Json =
98
- match parser.get_next()
99
- '{' -> p.parseObject()
100
- '[' -> p.parseList()
101
- _ -> nil
102
-
103
130
  fn (p JsonParser) parseObject(): Map[str, Json] =
104
131
  object := Map[str, Json]()
105
- p._get_next() // '{'
132
+ p.getNext() # '{'
106
- while true
133
+ while True
107
134
  if p.cur != '"'
108
135
  p._err("JSON: Object: expected '\"'\n")
109
136
  break
@@ -113,7 +140,7 @@ fn (p JsonParser) parseObject(): Map[str, Json] =
113
140
  break
114
141
 
115
142
  val_val := Json(nil)
116
- when p.cur
143
+ match p.cur
117
144
  '{' ->
118
145
  val_val = parse_object(p)
119
146
  p._expect('}', "JSON: Object: expected '}'\n")
@@ -175,9 +202,9 @@ fn (p: Parser) parseUtf16(): int =
175
202
  p._get_next_raw()
176
203
  if _is_digit(cur)
177
204
  result = ((result << 4) or (cur - '0').i32())
178
- else if (cur >= 'a') and (cur <= 'f')
205
+ else if {cur >= 'a'} && {cur <= 'f'}
179
206
  result = ((result << 4) or ((cur - 'a').i32() + 10))
180
- else if (cur >= 'A') and (cur <= 'F')
207
+ else if (cur >= 'A') && (cur <= 'F')
181
208
  result = ((result << 4) or ((cur - 'A').i32() + 10))
182
209
  count = count+1
183
210
  result
@@ -345,27 +372,4 @@ fn _get_fals(): bool? =
345
372
  false
346
373
  else
347
374
  error
348
- end
375
+ end
349
-
350
-
351
-
352
- Json\test("parseInt") =
353
- assert Json.parse("123") == 123
354
-
355
- Json\test("parseStr") =
356
- assert Json.parse(`"hello"`) == "hello"
357
-
358
- Json\test("parseBool") =
359
- assert Json.parse("true") == true
360
- assert Json.parse("false") == false
361
-
362
- Json\test("parse null") =
363
- assert Json.parse("null") == nil
364
-
365
- Json\test("parse array") =
366
- assert Json.parse(`[]`) == List[Json]()
367
- assert Json.parse(`[1, 2]`) == List.of[Json](1, 2)
368
-
369
- Json\test("parse object") =
370
- assert Json.parse(`{}`) == Map[str, Json]()
371
- assert Json.parse(`{"a": 1, "b": 2}`) == Map.of[str, Json]("a" => 1, "b" => 2)
libs/std/option.plum CHANGED
@@ -1,12 +1,7 @@
1
1
  module std
2
2
 
3
- import std.{
3
+ import std.{Int, Str, Result, Option}
4
- Int,
5
- Str,
6
- Result,
7
- Option
8
- }
9
4
 
10
- type Option =
5
+ enum Option =
11
6
  | Some(a)
12
7
  | None
libs/std/result.plum CHANGED
@@ -1,6 +1,15 @@
1
1
  module std
2
2
 
3
- type Result =
3
+ enum Result =
4
4
  | Ok(a)
5
5
  | Err(b)
6
+
6
-
7
+ isOk() -> Bool =
8
+ doc: "Checks whether the result is an `Ok` value"
9
+ if Ok(_) == this
10
+ True
11
+ else if Err(_) = this
12
+ False
13
+ check:
14
+ Ok("data").isOk() == True
15
+ Err("no data").isOk() == False
test/add.plum CHANGED
@@ -5,7 +5,7 @@ import fs
5
5
  add(a: Int, b: Int) -> Int =
6
6
  a + b
7
7
 
8
- give_42() -> Int =
8
+ give42() -> Int =
9
9
  42
10
10
 
11
11
  main() -> Int =
@@ -61,8 +61,9 @@ factorial(num: Int) -> Int =
61
61
  main() -> Bool
62
62
  5.squared() == 25
63
63
 
64
+ extend Int
64
- Int\squared(): Int =
65
+ squared() -> Int =
65
- self * self
66
+ this * this
66
67
 
67
68
  main() -> Unit =
68
69
  input = fs::readFile("./examples/test/demos/aoc2023/1.txt")
test/aoc_2020_1.plum CHANGED
@@ -11,8 +11,8 @@ main() -> Unit =
11
11
  printLn(a * b)
12
12
  return
13
13
 
14
- fn parseNumbers(input: Str) -> List<Int> =
14
+ parseNumbers(input: Str) -> List<Int> =
15
- numbers = listOf<Int>()
15
+ numbers = List<Int>()
16
16
  current_number = 0
17
17
  for i in 0..input.len()
18
18
  c = input.charAt(i)
test/aoc_2020_2.plum CHANGED
@@ -1,16 +1,15 @@
1
- Step =
1
+ enum Step =
2
2
  | READ_MIN_OCCURANCES = 0
3
3
  | READ_MAX_OCCURANCES = 1
4
4
  | READ_CHAR_TO_COUNT = 2
5
5
  | COUNT_OCCURANCES = 3
6
6
 
7
- PasswordCheckState = {
7
+ class PasswordCheckState =
8
8
  step: Step
9
9
  min_occurances: Int
10
10
  max_occurances: Int
11
11
  current_occurances: Int
12
12
  char_to_counst: Int
13
- }
14
13
 
15
14
  initialCheckState() -> PasswordCheckState =
16
15
  PasswordCheckState(
test/sample.plum CHANGED
@@ -1,126 +1,225 @@
1
1
  module sample
2
2
 
3
- import std.{List, Map, Math, Random}
3
+ import std.(List, Map, Math)
4
+ import std/encoding.(Base64)
4
5
 
5
6
  Int.random()
6
7
  Float.random()
7
8
  Float.PI
8
9
 
9
- User = {
10
+ type Int =
11
+ random() -> Int = 20
12
+ add(self, other: Int) -> Int = self + other
13
+ sub(self, other: Int) -> Int = self - other
14
+
15
+ type User(ToStr) =
10
16
  name: Str
11
- email: Str
17
+ age: Int
12
18
  todos: List(Todo)
13
- }
14
19
 
20
+ fromJson(s: Str) -> Result(Self, Err) =
21
+ v = try Json.parse(s) as Map(Str, Json)
22
+ User::create()
23
+ .name(v.get("name").asStr())
24
+ .email(v.get("email").asStr())
25
+ .todos(v.get("todos").asList().map(\t ->
26
+ Todo::create().title(t.get("title").asStr()))
27
+ )
28
+
29
+ queryAll(self, noise: Int) -> Str =
30
+ printLn(noise)
15
- Todo = {
31
+ ""
32
+
33
+ findOne(self) -> Self =
34
+ printLn(noise)
35
+
36
+ toStr(self) -> Str =
37
+ "User({u.name}, {u.age})"
38
+
39
+ type Cat(ToStr) =
16
- title: Str
40
+ name: Str
17
- }
41
+ age: Int
42
+
43
+ fromJson(s: Str) -> Result(Self, Err) =
44
+ v = try Json.parse(s) as Map(Str, Json)
45
+ Cat::create()
46
+ .name(v.get("name").asStr())
47
+ .age(v.get("age").asInt())
48
+
49
+ withName(self, name: Str) -> Cat =
50
+ Cat(name = name, age = self.age)
51
+
52
+ withAge(self, age: Int) -> Cat =
53
+ Cat(name = self.name, age = age)
18
54
 
55
+ toStr(self) -> Str =
56
+ "Cat(1, 2)"
57
+
58
+
59
+ 2.sqrt().sin().cos()
60
+
61
+ # Less indentation
62
+
19
- User()
63
+ u = User::create()
20
64
  .name("John Doe")
21
65
  .email("john@example.com")
22
- .todo(Todo().title("Make pizza"))
66
+ .todos(Todo::create().title("Make pizza"))
23
- .todo(Todo().title("Finish Toasty"))
67
+ .todos(Todo::create().title("Finish Toasty"))
24
- .todo(Todo().title("Sleep"))
68
+ .todos(Todo::create().title("Sleep"))
69
+
25
-
70
+ # User(
71
+ # name: "John Doe",
72
+ # email: "john@example.com",
73
+ # todos: List(
74
+ # Todo(title: "Make pizza"),
75
+ # Todo(title: "Finish Toasty"),
76
+ # Todo(title: "Sleep"),
77
+ # )
78
+ # )
79
+
80
+ u2 = try User.fromJson(`{
81
+ "name": "John Doe",
82
+ "email": "john@example.com",
83
+ "todos": [
84
+ {"title": "Make pizza"},
85
+ {"title": "Finish Toasty"},
86
+ {"title": "Sleep"}
87
+ ]
88
+ }`)
89
+
90
+
91
+
26
- stoplightColor(something: Int) -> Color =
92
+ func stoplightColor(something: Int) -> Color =
27
93
  if something > 0
28
- Red
94
+ Red
29
95
  else if something == 0
30
- Yellow
96
+ Yellow
31
97
  else
32
- Green
98
+ Green
99
+
100
+ func toCelsius(f: Float) -> Float =
101
+ doc: "Convert fahrenheit temperature reading to celsius"
102
+ return {f - 32} * {5 / 9}
103
+ check:
104
+ toCelsius(0) == 32
105
+ toCelsius(100) == 212
106
+ toCelsius(100) == 392
107
+
108
+ type Response(Reader, Writer) =
109
+ val body: Buffer = Buffer()
110
+ val headers: Map(Str, Str) = Map()
111
+ val status: Int = 0
112
+
113
+ static fn empty() -> Self =
114
+ Response::create()
115
+ .body(Buffer())
116
+ .headers(Map())
117
+ .status(0)
118
+
119
+ fn createFileResponse(path: Str) -> Result(Response, IOError) =
120
+ content_type = try Mime::fromExt(path.ext())
121
+ body = try os.readFile(file)
122
+ Response::create()
123
+ .header("Content-Type", content_type)
124
+ .body(body)
125
+ .status(200)
126
+
127
+ fn serveFile(file: Str) -> Result(Response, IOError) =
128
+ ext = try Path::fromExt(file)
129
+ content_type = try Mime::fromExt(ext)
130
+ body = os.readFile(file)
131
+ Response::create()
132
+ .header("Content-Type", content_type)
133
+ .body(body)
134
+ .status(200)
135
+
136
+ fn index() -> Result(Response, IOError) =
137
+ createFileResponse("index.html")
33
138
 
34
- Response = {
35
- body: Buffer = emptyBuffer()
36
- headers: Map(Str, Str) = emptyMap()
139
+ g = Greeter(name: "abc")
37
- status: Int = 0
140
+ g = Greeter(...g, name: "123")
38
- }
39
141
 
40
- main() -> Unit =
142
+ func readFile() -> Result(String, Err) =
41
- printLn("123")
143
+ return Err("123")
42
144
 
43
- main() -> Int, Err =
145
+ func main() -> Unit =
146
+ printLn("123")
147
+ createFileResponse("./src/sample.plum")
148
+ index()
44
- Stdout.line! "There are $(total) animals."
149
+ serveFile("./src/sample.plum")
150
+ content = try readFile()
45
151
 
46
- # calculate to str
152
+ if Ok(d) = readFile()
47
- Int\toStr() -> Str =
48
- todo
153
+ println(d)
49
154
 
155
+ match readFile()
156
+ Ok(d) =>
157
+ printLn(d)
50
- Int::random() -> Int =
158
+ Err(e) =>
51
- 24
159
+ printErr(e)
52
160
 
53
- sub(arg1: Int, arg2: Int) -> Int =
161
+ func sub(arg1: Int, arg2: Int) -> Int =
54
162
  local1 = arg1
55
163
  local2 = arg2
56
164
  local1 - local2
57
165
 
58
- addAndStringify(num1: Int, num2: Int) -> Str =
166
+ func addAndStringify(num1: Int, num2: Int) -> Str =
59
- (num1 + num2).toStr()
167
+ return (num1 + num2).toStr()
60
168
 
61
- factorial(x: Int) -> Int =
169
+ func factorial(x: Int) -> Int =
62
170
  if x < 2
63
171
  x
64
172
  else
65
173
  x * factorial(x - 1)
66
174
 
67
- Result(a, b) =
68
- | Ok(a)
69
- | Err(b)
70
-
71
- ```
72
- Checks whether the result is an `Ok` value
73
- isOk(Ok(1)) # => True
74
- isOk(Err(Nil)) # => False
75
- ```
76
- Result\isOk() -> Bool =
77
- r! # will bubble back the result similar to try catch
78
- o! # will bubble back the option/result
79
- if self == Ok(v) then
80
- True
81
- else if self == Err(_) then
82
- False
83
-
84
- birds = 3
175
+ var birds = 3
85
- iguanas = 2
176
+ var iguanas = 2
86
- total = addAndStringify(birds, iguanas)
177
+ var total = addAndStringify(birds, iguanas)
87
-
178
+
88
- pluralize(singular: Str, plural: Str, count: Int) -> Str =
179
+ func pluralize(singular: Str, plural: Str, count: Int) -> Str =
89
180
  countstr = Num.toStr(count)
90
181
  if count == 1 then
91
182
  "$(countstr) $(singular)"
92
183
  else
93
184
  "$(countstr) $(plural)"
94
185
 
95
- pluralize_test(t: Test) -> Unit =
186
+ func pluralize_test(t: Test) -> Unit =
96
187
  assert pluralize("cactus", "cacti", 1) == "1 cactus"
97
188
  assert pluralize("cactus", "cacti", 2) == "2 cacti"
98
189
 
99
- User = {
190
+ type User =
100
191
  name: String
101
192
  age: String
102
- }
103
193
 
104
- user = User(1, 2, 3)
105
- params = Map("one" => 1, "two" => 2, "three" => 3)
106
- arr = List(1, 2, 3, 4)
107
-
108
- User\isAuthorized() -> Bool =
194
+ isAuthorized() -> Bool =
109
195
  False
110
196
 
111
- User\map(cb: (a: User) -> b) -> b =
197
+ map(cb: (a: User) -> b) -> b =
112
198
  cb(u)
113
199
 
200
+
201
+ type Teacher(
202
+ name: String,
203
+ subject: String
204
+ )
205
+
206
+ user = User(
207
+ name: "John Doe",
208
+ age: 30
209
+ )
210
+ params = Map("one" => 1, "two" => 2, "three" => 3)
211
+ arr = List(1, 2, 3, 4)
212
+
114
- name(data: Option(Str)) -> Str =
213
+ func name(d: Option(Str)) -> Str =
115
- if data == Some(v) then
214
+ if d == Some(v) then
116
215
  v.subString(0, 3)
117
216
  else if a == b then
118
217
  "123"
119
218
  else
120
219
  "1231"
121
220
 
122
- delta(data: Option(Str)) -> Str =
221
+ delta(d: Option(Str)) -> Str =
123
- if data == Some(v)
222
+ if d == Some(v)
124
223
  v.subString(0, 3)
125
224
  else if a == b
126
225
  "123"
@@ -130,20 +229,19 @@ delta(data: Option(Str)) -> Str =
130
229
  else
131
230
  println("No Data")
132
231
 
133
-
134
- data.price?.takeIf(\a -> a != "")
232
+ d.price?.takeIf(\a -> a != "")
135
233
  (1 + 2).mod(3).pow(2).sqrt()
136
234
 
137
235
  if v == None
138
236
  error.Error
139
- else if v == Some(c)
237
+ else if Some(c) = v
140
238
  c * 20
141
239
 
142
240
  match v
143
241
  None -> error.Error
144
242
  Some(c) -> c * 20
145
243
 
146
- names = ["Sam", "Lee", "Ari"]
244
+ names = List("Sam", "Lee", "Ari")
147
245
  names.append("Jess")
148
246
  names.map(\num -> num * 2)
149
247
 
@@ -157,50 +255,20 @@ import std/libc
157
255
  extern sqrt(x: libc.Double) -> libc.Double
158
256
  extern pow(x: libc.Double, y: libc.Double) -> libc.Double
159
257
 
160
- WriteError = EOF | Closed
161
-
162
- Writer = (
163
- write(p: Str | Buffer) -> Int | WriteError
164
- )
165
-
166
- ReadError = EOF | Closed
167
258
 
168
- Reader = (
259
+ trait Writer =
169
- read(p: Str | Buffer) -> Int | ReadError
260
+ write(p: Str | Buffer) -> Result[Int, WriteError]
170
- )
171
261
 
172
- IO = Reader + Writer
262
+ enum ReadError =
263
+ | EOF
173
- IOError = ReadError | WriteError
264
+ | Closed
174
265
 
266
+ enum WriteError =
267
+ | EOF
175
- Response(
268
+ | Closed
176
- headers: Map[Str, Str]
177
- body: Str | Buffer | IO
178
- status: Int
179
- )
180
269
 
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 =
270
+ trait Reader =
190
- createFileResponse("index.html")
191
-
192
- serveFile(file: Str) -> Response | IOError =
271
+ read(p: Str | Buffer) -> Result[Int, ReadError]
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
272
 
205
- g = Greeter(name: "abc")
273
+ trait IO(Reader, Writer) =
206
- g = Greeter(...g, name: "123")
274
+ pass
tooling/tree-sitter-plum/grammar.js CHANGED
@@ -90,17 +90,22 @@ module.exports = grammar({
90
90
  seq(
91
91
  "type",
92
92
  field("name", $.type_identifier),
93
- field("implements", optional(seq(":", sep1($.type_identifier, "+")))),
93
+ field("implements", optional(seq("(", commaSep1($.type_identifier), ")"))),
94
94
  field("generics", optional($.generics)),
95
95
  "=",
96
96
  $._indent,
97
- optional(repeat($.record_field)),
97
+ field("fields", optional(repeat(alias($.record_field, $.field)))),
98
- optional(repeat($.method)),
98
+ field("methods", optional(repeat($.method))),
99
99
  $._dedent,
100
100
  ),
101
101
 
102
102
  record_field: ($) => seq(field("name", $.identifier), ":", field("type", $.type)),
103
- method: ($) => alias($.fn, "method"),
103
+ method: ($) => seq(
104
+ field("name", $.identifier),
105
+ field("params", seq("(", optional(commaSep1($.param)), ")")),
106
+ field("returns", optional(seq("->", $.return_type))),
107
+ field("body", seq("=", choice($.expression, $.body))),
108
+ ),
104
109
  trait: ($) =>
105
110
  seq(
106
111
  "trait",
@@ -119,11 +124,14 @@ module.exports = grammar({
119
124
  ),
120
125
 
121
126
  param: ($) =>
127
+ choice(
128
+ seq("self"),
122
- seq(
129
+ seq(
123
- field("name", $.var_identier),
130
+ field("name", $.var_identier),
124
- ":",
131
+ ":",
125
- field("type", choice($.type, $.variadic_type)),
132
+ field("type", choice($.type, $.variadic_type)),
126
- optional(seq("=", field("value", $.expression))),
133
+ optional(seq("=", field("value", $.expression))),
134
+ ),
127
135
  ),
128
136
 
129
137
  return_type: ($) =>
@@ -135,7 +143,7 @@ module.exports = grammar({
135
143
  field("name", $.type_identifier),
136
144
  "=",
137
145
  $._indent,
138
- optional(repeat($.enum_field)),
146
+ optional(repeat(alias($.enum_field, $.field))),
139
147
  optional(repeat($.method)),
140
148
  $._dedent,
141
149
  ),
@@ -513,4 +521,4 @@ function newlineSep1(rule) {
513
521
 
514
522
  function sep1(rule, separator) {
515
523
  return seq(rule, repeat(seq(separator, rule)));
516
- }
524
+ }
tooling/tree-sitter-plum/src/grammar.json CHANGED
Binary file
tooling/tree-sitter-plum/src/node-types.json CHANGED
Binary file
tooling/tree-sitter-plum/src/parser.c CHANGED
Binary file
tooling/tree-sitter-plum/test/corpus/assert.txt CHANGED
@@ -13,7 +13,7 @@ main() =
13
13
 
14
14
  (source
15
15
  (fn
16
- (fn_identifier)
16
+ (identifier)
17
17
  (body
18
18
  (assert
19
19
  (expression
tooling/tree-sitter-plum/test/corpus/enum.txt CHANGED
@@ -2,11 +2,11 @@
2
2
  enum
3
3
  ================================================================================
4
4
 
5
- enum Bool
5
+ enum Bool =
6
6
  | True
7
7
  | False
8
8
 
9
- toStr() -> Str =
9
+ toStr(self) -> Str =
10
10
  "Bool"
11
11
 
12
12
  --------------------------------------------------------------------------------
@@ -14,12 +14,13 @@ enum Bool
14
14
  (source
15
15
  (enum
16
16
  (type_identifier)
17
- (enum_field
17
+ (field
18
18
  (type_identifier))
19
- (enum_field
19
+ (field
20
20
  (type_identifier))
21
21
  (method
22
22
  (identifier)
23
+ (param)
23
24
  (return_type
24
25
  (type_identifier))
25
26
  (body
tooling/tree-sitter-plum/test/corpus/if.txt CHANGED
@@ -19,7 +19,7 @@ main() =
19
19
 
20
20
  (source
21
21
  (fn
22
- (fn_identifier)
22
+ (identifier)
23
23
  (body
24
24
  (if
25
25
  (expression
tooling/tree-sitter-plum/test/corpus/match.txt CHANGED
@@ -15,55 +15,4 @@ main() =
15
15
 
16
16
  --------------------------------------------------------------------------------
17
17
 
18
- (source
19
- (test
18
+ ()
20
- (string
21
- (string_start)
22
- (string_end))
23
- (lambda
24
- (identifier)
25
- (body
26
- (assignment_statement
27
- (identifier)
28
- (binary_operator
29
- (parenthesized_expression
30
- (binary_operator
31
- (integer)
32
- (integer)))
33
- (parenthesized_expression
34
- (binary_operator
35
- (integer)
36
- (integer)))))
37
- (if_statement
38
- (comparison_operator
39
- (identifier)
40
- (identifier))
41
- (block
42
- (assert_statement
43
- (comparison_operator
44
- (identifier)
45
- (identifier))))
46
- (else_if_clause
47
- (comparison_operator
48
- (identifier)
49
- (integer))
50
- (block
51
- (assert_statement
52
- (comparison_operator
53
- (identifier)
54
- (integer)))))
55
- (else_if_clause
56
- (comparison_operator
57
- (identifier)
58
- (integer))
59
- (block
60
- (assert_statement
61
- (comparison_operator
62
- (identifier)
63
- (integer)))))
64
- (else_clause
65
- (block
66
- (assert_statement
67
- (comparison_operator
68
- (identifier)
69
- (integer))))))))))
tooling/tree-sitter-plum/test/corpus/type.txt CHANGED
@@ -1,79 +1,54 @@
1
1
  ================================================================================
2
- type - definition
2
+ type
3
3
  ================================================================================
4
4
 
5
- type Cat is Stringable =
6
- name: Str
7
- age: Int
8
-
9
5
  type Dog =
10
- name: a
6
+ name: Str
11
- age: b
7
+ age: b
12
-
13
- type Dog(a: Compare + Stringable, b) is Stringable =
14
- name: a
15
- age: b
16
8
 
17
9
  type Int =
10
+ random() -> Int = 20
18
- add(other: Int) -> Int = this + other
11
+ add(self, other: Int) -> Int = self + other
19
- sub(other: Int) -> Int = this - other
12
+ sub(self, other: Int) -> Int = self - other
20
13
 
21
- type Cat is Stringable =
14
+ type Cat(Stringable) =
22
15
  name: Str
23
16
  age: Int
24
17
 
25
- withName(name: Str) -> Cat =
18
+ withName(self, name: Str) -> Cat =
26
19
  Cat(name = name, age = 0)
27
20
 
28
- withAge(age: Int) -> Cat =
21
+ withAge(self, age: Int) -> Cat =
29
22
  Cat(name = "", age = age)
30
23
 
31
- Stringable() -> Str =
24
+ toStr(self) -> Str =
32
- "Cat"
25
+ "Cat(1, 2)"
33
26
 
34
27
  --------------------------------------------------------------------------------
35
28
 
36
29
  (source
37
30
  (record
38
31
  (type_identifier)
39
- (type_identifier)
40
- (record_field
32
+ (field
41
33
  (identifier)
42
34
  (type
43
35
  (type_identifier)))
44
- (record_field
36
+ (field
45
- (identifier)
46
- (type
47
- (type_identifier))))
48
- (record
49
- (type_identifier)
50
- (record_field
51
- (identifier)
52
- (type
53
- (a)))
54
- (record_field
55
37
  (identifier)
56
38
  (type
57
39
  (b))))
58
40
  (record
59
41
  (type_identifier)
60
- (generics
61
- (a)
62
- (type_identifier)
63
- (type_identifier)
64
- (b))
65
- (record_field
66
- (identifier)
67
- (type
42
+ (method
68
- (a)))
69
- (record_field
70
43
  (identifier)
71
- (type
44
+ (return_type
72
- (b))))
73
- (record
74
- (type_identifier)
45
+ (type_identifier))
46
+ (expression
47
+ (primary_expression
48
+ (integer))))
75
49
  (method
76
50
  (identifier)
51
+ (param)
77
52
  (param
78
53
  (var_identier)
79
54
  (type
@@ -84,11 +59,12 @@ type Cat is Stringable =
84
59
  (primary_expression
85
60
  (binary_operator
86
61
  (primary_expression
87
- (this))
62
+ (identifier))
88
63
  (primary_expression
89
64
  (identifier))))))
90
65
  (method
91
66
  (identifier)
67
+ (param)
92
68
  (param
93
69
  (var_identier)
94
70
  (type
@@ -99,22 +75,23 @@ type Cat is Stringable =
99
75
  (primary_expression
100
76
  (binary_operator
101
77
  (primary_expression
102
- (this))
78
+ (identifier))
103
79
  (primary_expression
104
80
  (identifier)))))))
105
81
  (record
106
82
  (type_identifier)
107
83
  (type_identifier)
108
- (record_field
84
+ (field
109
85
  (identifier)
110
86
  (type
111
87
  (type_identifier)))
112
- (record_field
88
+ (field
113
89
  (identifier)
114
90
  (type
115
91
  (type_identifier)))
116
92
  (method
117
93
  (identifier)
94
+ (param)
118
95
  (param
119
96
  (var_identier)
120
97
  (type
@@ -138,6 +115,7 @@ type Cat is Stringable =
138
115
  (integer)))))))))
139
116
  (method
140
117
  (identifier)
118
+ (param)
141
119
  (param
142
120
  (var_identier)
143
121
  (type
@@ -163,6 +141,7 @@ type Cat is Stringable =
163
141
  (identifier)))))))))
164
142
  (method
165
143
  (identifier)
144
+ (param)
166
145
  (return_type
167
146
  (type_identifier))
168
147
  (body
tooling/vscode-plum/syntaxes/plum.tmLanguage.json CHANGED
@@ -19,6 +19,9 @@
19
19
  },
20
20
  {
21
21
  "include": "#discards"
22
+ },
23
+ {
24
+ "include": "#raw_string_literals"
22
25
  }
23
26
  ],
24
27
  "repository": {
@@ -26,7 +29,7 @@
26
29
  "patterns": [
27
30
  {
28
31
  "name": "keyword.control.plum",
29
- "match": "\\b(module|import|trait|type|enum|fn|in|this|return|continue|break|match|if|else|while|for|as|is|assert|crash|todo)\\b"
32
+ "match": "\\b(self|this|fn|impl|where|extern|func|try|var|val|module|import|trait|type|enum|in|return|continue|break|match|if|else|while|for|as|is|assert|panic)\\b"
30
33
  },
31
34
  {
32
35
  "name": "keyword.operator.arrow.plum",
@@ -67,6 +70,10 @@
67
70
  {
68
71
  "name": "keyword.operator.assignment.plum",
69
72
  "match": "="
73
+ },
74
+ {
75
+ "name": "keyword.operator.comparison.plum",
76
+ "match": "(<|>)"
70
77
  }
71
78
  ]
72
79
  },
@@ -85,7 +92,7 @@
85
92
  "patterns": [
86
93
  {
87
94
  "name": "comment.line.plum",
88
- "match": "`.*"
95
+ "match": "#.*"
89
96
  }
90
97
  ]
91
98
  },
@@ -132,6 +139,35 @@
132
139
  "match": "\\b0[xX]0*[1-9a-zA-Z][0-9a-zA-Z]*\\b",
133
140
  "patterns": []
134
141
  },
142
+ "string_placeholder": {
143
+ "patterns": [
144
+ {
145
+ "match": "%(\\[\\d+\\])?([\\+#\\-0\\x20]{,2}((\\d+|\\*)?(\\.?(\\d+|\\*|(\\[\\d+\\])\\*?)?(\\[\\d+\\])?)?))?[vT%tbcdoqxXUbeEfFgGspw]",
146
+ "name": "constant.other.placeholder.go"
147
+ }
148
+ ]
149
+ },
150
+ "raw_string_literals": {
151
+ "comment": "Raw string literals",
152
+ "begin": "`",
153
+ "beginCaptures": {
154
+ "0": {
155
+ "name": "punctuation.definition.string.begin.go"
156
+ }
157
+ },
158
+ "end": "`",
159
+ "endCaptures": {
160
+ "0": {
161
+ "name": "punctuation.definition.string.end.go"
162
+ }
163
+ },
164
+ "name": "string.quoted.raw.go",
165
+ "patterns": [
166
+ {
167
+ "include": "#string_placeholder"
168
+ }
169
+ ]
170
+ },
135
171
  "entity": {
136
172
  "patterns": [
137
173
  {
@@ -155,6 +191,10 @@
155
191
  {
156
192
  "name": "entity.name.namespace.plum",
157
193
  "match": "\\b([[:lower:]][[:word:]]*):"
194
+ },
195
+ {
196
+ "name": "entity.name.namespace.plum",
197
+ "match": "\\b(doc|check|expect|where)\\b"
158
198
  }
159
199
  ]
160
200
  },