diff --git a/Cargo.lock b/Cargo.lock
index e02ca72..986ed6d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -17,6 +17,16 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+[[package]]
+name = "colored"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8"
+dependencies = [
+ "lazy_static",
+ "windows-sys",
+]
+
[[package]]
name = "cpufeatures"
version = "0.2.12"
@@ -56,6 +66,12 @@ dependencies = [
"version_check",
]
+[[package]]
+name = "lazy_static"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
+
[[package]]
name = "libc"
version = "0.2.155"
@@ -85,6 +101,19 @@ dependencies = [
"ucd-trie",
]
+[[package]]
+name = "pest-test"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a426ffa96d4df49eb2a43b010059dc085c4a0b655fd229de11b49340d1deaffe"
+dependencies = [
+ "colored",
+ "pest",
+ "pest_derive",
+ "snailquote",
+ "thiserror",
+]
+
[[package]]
name = "pest_derive"
version = "2.7.11"
@@ -148,11 +177,23 @@ dependencies = [
"digest",
]
+[[package]]
+name = "snailquote"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec62a949bda7f15800481a711909f946e1204f2460f89210eaf7f57730f88f86"
+dependencies = [
+ "thiserror",
+ "unicode_categories",
+]
+
[[package]]
name = "snek-parser"
version = "0.1.0"
dependencies = [
+ "lazy_static",
"pest",
+ "pest-test",
"pest_derive",
]
@@ -205,8 +246,80 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+[[package]]
+name = "unicode_categories"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
+
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "windows-sys"
+version = "0.48.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
diff --git a/Cargo.toml b/Cargo.toml
index c1ca16e..6c8d768 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,5 +6,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
+lazy_static = "1.5.0"
pest = "2.7.11"
+pest-test = "0.1.6"
pest_derive = "2.7.11"
diff --git a/README.md b/README.md
index 38c1f57..cf296db 100644
--- a/README.md
+++ b/README.md
@@ -68,39 +68,38 @@ let complex_addition a b c = {
### Complex types
-All type declarations follow a similar patter.
The value for a type is one of the following:
-- `#[...]` enum
-- `#{...}` record
+- `enum {...}` enum
+- `rec {...}` record
- `#(...)` tuple
These expressions can be nested.
```sk
-type MyEnum = #[
+type MyEnum = enum {
Var1 Int
Var2 Bool
-]
+}
-type MyRec = #{
+type MyRec = rec {
field1: Float
field2: Str
}
// records declared in one line need to put a semicolon after each field declaration
-type MyRecOneline = #{field1: Float; field2: Str}
+type MyRecOneline = rec {field1: Float; field2: Str}
// tuples can be declared in one line without a semicolon because there's no ambiguity
type MyTuple = #(Float Str)
-type Nested = #{
- field1: #[
+type Nested = rec {
+ field1: enum {
Boolean Bool
Number Float
- ]
+ }
field2: #(Bool Bool)
- field3: #{
+ field3: rec {
first: Int
second: Int
}
diff --git a/corpus/types.sk b/corpus/types.sk
index e0552ff..b9b36bf 100644
--- a/corpus/types.sk
+++ b/corpus/types.sk
@@ -1,40 +1,40 @@
-type Food = #[
+type Food = enum {
Apple Num
Banana Num
Cereal Num
Milk #(String Num)
-]
+}
-type Utils = #[
+type Utils = enum {
Paper Num
Detergent Num
Pencils Num
-]
+}
-type Packaging = #[
+type Packaging = enum {
Bag
PlasticBag
-]
+}
-type ShoppingList = #{
+type ShoppingList = rec {
food: Food
utils: Utils
packaging: Packaging
}
-type NestedHell = #[
+type NestedHell = enum {
NoNesting Num
- Nesting #[
- FirstLevel #[
- SecondLevel #[
+ Nesting enum {
+ FirstLevel enum {
+ SecondLevel enum {
Third Lvl
- ]
- Second #{
+ }
+ Second rec {
first: Num
second: Num
}
- ]
+ }
StillFirst Num
- ]
-]
+ }
+}
diff --git a/src/grammar.pest b/src/grammar.pest
index f0d9c13..e99471b 100644
--- a/src/grammar.pest
+++ b/src/grammar.pest
@@ -7,18 +7,21 @@ decl = { "let" ~ #name = ident ~ #args = (ident)* ~ "=" ~ expr }
block = { "{" ~ MLF ~ block_line ~ MLF ~ "}" }
block_line = _{ expr | (statement ~ MLF)* }
-type_decl = { "type" ~ #name = type_ident ~ "=" ~ type_expr }
-type_expr = { tuple | rec | enum | type_ident }
+type_decl = { "type" ~ #name = type_ident ~ "=" ~ type_expr }
+type_expr = { type_term | func | type_ident }
+type_term = _{ tuple | rec | enum | type_ident }
tuple = { "#(" ~ MLF ~ tuple_entry* ~ MLF ~ ")" }
tuple_entry = _{ type_expr ~ MLF }
-rec = { "#{" ~ MLF ~ (rec_field ~ TERMINATE ~ MLF)* ~ rec_field? ~ MLF ~ "}" }
+rec = { "rec" ~ "{" ~ MLF ~ (rec_field ~ TERMINATE ~ MLF)* ~ rec_field? ~ MLF ~ "}" }
rec_field = { #field_name = ident ~ ":" ~ #field_type = type_expr* }
-enum = { "#[" ~ MLF ~ (enum_vrt ~ TERMINATE ~ MLF)* ~ enum_vrt? ~ "]" }
+enum = { "enum" ~ "{" ~ MLF ~ (enum_vrt ~ TERMINATE ~ MLF)* ~ enum_vrt? ~ "}" }
enum_vrt = { #vrt_name = ident ~ type_expr? }
+func = { type_term ~ "->" ~ type_expr }
+
type_ident = ${ #name = ident ~ #args = type_args? }
type_args = { "<" ~ MLF ~ type_ident* ~ MLF ~ ">" }
@@ -48,7 +51,7 @@ float = @{
byte = @{ "0x" ~ ASCII_HEX_DIGIT{1, 2} | "0b" ~ ASCII_BIN_DIGIT{0, 8} }
boolean = @{ "true" | "false" }
-KEYWORD = _{ "let" }
+KEYWORD = _{ "let" | "rec" | "enum" }
TERMINATE = _{ LF | EOI | ";" }
MLF = _{ (LF)* }
LF = _{ "\n" | "\r" }
diff --git a/src/test/mod.rs b/src/test/mod.rs
index b4dfdfa..3feddd1 100644
--- a/src/test/mod.rs
+++ b/src/test/mod.rs
@@ -4,6 +4,21 @@ mod statements;
mod types;
use crate::parse;
+use std::{collections::HashSet, path::PathBuf};
+
+use lazy_static::lazy_static;
+use pest_test::PestTester;
+
+use crate::{Rule, SnekParser};
+
+fn s_tester>(dir: D) -> PestTester {
+ PestTester::new(
+ PathBuf::from("tests/corpus").join(dir.into()),
+ "txt",
+ Rule::file,
+ HashSet::new(),
+ )
+}
#[test]
fn it_parse_types() {
@@ -22,3 +37,12 @@ fn it_parse_declarations() {
panic!("{e}")
}
}
+
+lazy_static! {
+ static ref TESTER: PestTester = PestTester::new(
+ PathBuf::from("test/corpus"),
+ "txt",
+ Rule::file,
+ HashSet::new()
+ );
+}
diff --git a/src/test/types.rs b/src/test/types.rs
index 54c91f6..86a4fef 100644
--- a/src/test/types.rs
+++ b/src/test/types.rs
@@ -1,6 +1,12 @@
use pest::{consumes_to, parses_to};
+use pest_test::PestTester;
use crate::{Rule, SnekParser};
+use lazy_static::lazy_static;
+
+lazy_static! {
+ static ref TESTER: PestTester = super::s_tester("types");
+}
#[test]
fn it_parses_aliases() {
@@ -51,97 +57,21 @@ fn it_parses_tuples() {
#[test]
fn it_parses_recs() {
- parses_to!(parser: SnekParser, input: "type MyRec = #{\nfield1: Num\n field2: Num2 }", rule: Rule::statement, tokens: [
- statement(0, 43, [
- type_decl(0, 43, [
- type_ident(5, 10, [
- ident(5, 10)
- ]),
- type_expr(13, 43, [
- rec(13, 43, [
- rec_field(16, 27, [
- ident(16, 22),
- type_expr(24, 27, [
- type_ident(24, 27, [
- ident(24, 27)
- ])
- ]),
- ]),
- rec_field(29, 41, [
- ident(29, 35),
- type_expr(37, 41, [
- type_ident(37, 41, [
- ident(37, 41)
- ])
- ]),
- ])
- ])
- ])
- ]),
- EOI(43, 43)
- ])
- ]);
+ if let Err(e) = (*TESTER).evaluate_strict("recs") {
+ panic!("{e}")
+ }
}
#[test]
fn it_parses_enums() {
- parses_to!(parser: SnekParser, input: "type MyEnum = #[Var1 Num\nVar2 Type\n]", rule: Rule::statement, tokens: [
- statement(0, 36, [
- type_decl(0, 36, [
- type_ident(5, 11, [
- ident(5, 11)
- ]),
- type_expr(14, 36, [
- r#enum(14, 36, [
- enum_vrt(16, 24, [
- ident(16, 20),
- type_expr(21, 24, [
- type_ident(21, 24, [
- ident(21, 24)
- ])
- ]),
- ]),
- enum_vrt(25, 34, [
- ident(25, 29),
- type_expr(30, 34, [
- type_ident(30, 34, [
- ident(30, 34)
- ])
- ]),
- ]),
- ])
- ])
- ]),
- EOI(36, 36)
- ])
- ]);
+ if let Err(e) = (*TESTER).evaluate_strict("enums") {
+ panic!("{e}")
+ }
}
#[test]
fn it_parses_generics() {
- parses_to!(parser: SnekParser, input: "type MyNum = Num", rule: Rule::statement, tokens: [
- statement(0, 22, [
- type_decl(0, 22, [
- type_ident(5, 13, [
- ident(5, 10),
- type_args(10, 13, [
- type_ident(11, 12, [
- ident(11, 12)
- ])
- ])
- ]),
- type_expr(16, 22, [
- type_ident(16, 22, [
- ident(16, 19),
- type_args(19, 22, [
- type_ident(20, 21, [
- ident(20, 21)
- ])
- ])
- ])
- ])
- ]),
- EOI(22, 22)
- ])
- ]);
+ if let Err(e) = (*TESTER).evaluate_strict("generics") {
+ panic!("{e}")
+ }
}
diff --git a/tests/corpus/types/enums.txt b/tests/corpus/types/enums.txt
new file mode 100644
index 0000000..1bad6b0
--- /dev/null
+++ b/tests/corpus/types/enums.txt
@@ -0,0 +1,41 @@
+Enums Test
+
+======
+
+type MyEnum = enum {
+ First Num
+ Second Str
+}
+
+======
+
+(file
+ (statement
+ (type_decl
+ (type_ident
+ (ident: "MyEnum")
+ )
+ (type_expr
+ (enum
+ (enum_vrt
+ (ident: "First")
+ (type_expr
+ (type_ident
+ (ident: "Num")
+ )
+ )
+ )
+ (enum_vrt
+ (ident: "Second")
+ (type_expr
+ (type_ident
+ (ident: "Str")
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ (EOI: "")
+)
diff --git a/tests/corpus/types/generics.txt b/tests/corpus/types/generics.txt
new file mode 100644
index 0000000..222e654
--- /dev/null
+++ b/tests/corpus/types/generics.txt
@@ -0,0 +1,33 @@
+Generics Test
+
+======
+
+type MyNum = Num
+
+======
+
+(file
+ (statement
+ (type_decl
+ (type_ident
+ (ident: "MyNum")
+ (type_args
+ (type_ident
+ (ident: "a")
+ )
+ )
+ )
+ (type_expr
+ (type_ident
+ (ident: "Num")
+ (type_args
+ (type_ident
+ (ident: "a")
+ )
+ )
+ )
+ )
+ )
+ )
+ (EOI: "")
+)
diff --git a/tests/corpus/types/recs.txt b/tests/corpus/types/recs.txt
new file mode 100644
index 0000000..12ad6fd
--- /dev/null
+++ b/tests/corpus/types/recs.txt
@@ -0,0 +1,41 @@
+Recs Test
+
+======
+
+type MyRec = rec {
+ first: Num
+ second: Str
+}
+
+======
+
+(file
+ (statement
+ (type_decl
+ (type_ident
+ (ident: "MyRec")
+ )
+ (type_expr
+ (rec
+ (rec_field
+ (ident: "first")
+ (type_expr
+ (type_ident
+ (ident: "Num")
+ )
+ )
+ )
+ (rec_field
+ (ident: "second")
+ (type_expr
+ (type_ident
+ (ident: "Str")
+ )
+ )
+ )
+ )
+ )
+ )
+ )
+ (EOI: "")
+)