summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-01-14 20:17:50 +0100
committerLaurenz <laurmaedje@gmail.com>2020-01-14 20:17:50 +0100
commit15ad30555bdad8e7b192fdcf7d4543c0d3fb18ce (patch)
tree814a1863e6a50d433613e5b362d30ede2df0bb21 /tests
parentdde69276d47818174c35523c8ed86b6888b6d02b (diff)
Parser testing prototype 🥥
Diffstat (limited to 'tests')
-rw-r--r--tests/parse.rs171
-rw-r--r--tests/parsing/tokens.rs10
-rw-r--r--tests/parsing/trees.rs20
3 files changed, 176 insertions, 25 deletions
diff --git a/tests/parse.rs b/tests/parse.rs
index 3e46dd4a..616f4d70 100644
--- a/tests/parse.rs
+++ b/tests/parse.rs
@@ -1,47 +1,159 @@
#![allow(unused_imports)]
+#![allow(dead_code)]
#![allow(non_snake_case)]
+use typstc::func::Scope;
use typstc::size::Size;
use typstc::syntax::*;
-use Token::{
- Whitespace as W,
- LineComment as LC, BlockComment as BC, StarSlash as SS,
- LeftBracket as LB, RightBracket as RB,
- LeftParen as LP, RightParen as RP,
- LeftBrace as LBR, RightBrace as RBR,
- Colon as CL, Comma as CM, Equals as EQ,
- ExprIdent as ID, ExprStr as STR, ExprSize as SIZE,
- ExprNumber as NUM, ExprBool as BOOL,
- Star as ST, Underscore as U, Backtick as B, Text as T,
-};
+use typstc::{function, parse};
+
+
+mod token_shorthands {
+ pub use super::Token::{
+ Whitespace as W,
+ LineComment as LC, BlockComment as BC, StarSlash as SS,
+ LeftBracket as LB, RightBracket as RB,
+ LeftParen as LP, RightParen as RP,
+ LeftBrace as LBR, RightBrace as RBR,
+ Colon as CL, Comma as CM, Equals as EQ,
+ ExprIdent as ID, ExprStr as STR, ExprSize as SIZE,
+ ExprNumber as NUM, ExprBool as BOOL,
+ Star as ST, Underscore as U, Backtick as B, Text as T,
+ };
+}
+
+mod node_shorthands {
+ use super::Node;
+ pub use Node::{
+ Space as S, Newline as N, Text,
+ ToggleItalic as I, ToggleBolder as B, ToggleMonospace as M,
+ Func,
+ };
+ pub fn T(text: &str) -> Node { Node::Text(text.to_string()) }
+}
+
+macro_rules! F {
+ (@body None) => (None);
+ (@body Some([$($tts:tt)*])) => ({
+ let nodes = vec![$($tts)*].into_iter()
+ .map(|v| Spanned { v, span: Span::ZERO })
+ .collect();
+
+ Some(SyntaxTree { nodes })
+ });
+
+ ($($body:tt)*) => ({
+ Func(FuncCall(Box::new(DebugFn {
+ pos: vec![],
+ key: vec![],
+ body: F!(@body $($body)*),
+ })))
+ });
+}
+
+function! {
+ #[derive(Debug, PartialEq)]
+ pub struct DebugFn {
+ pos: Vec<Spanned<Expression>>,
+ key: Vec<Pair>,
+ body: Option<SyntaxTree>,
+ }
+
+ parse(args, body, ctx) {
+ DebugFn {
+ pos: args.iter_pos().collect(),
+ key: args.iter_keys().collect(),
+ body: parse!(optional: body, ctx),
+ }
+ }
+
+ layout() { vec![] }
+}
+
+impl DebugFn {
+ fn compare(&self, other: &DebugFn) -> bool {
+ self.pos.iter().zip(&other.pos).all(|(a, b)| a.v == b.v)
+ && self.key.iter().zip(&other.key)
+ .all(|(a, b)| a.key.v == b.key.v && a.value.v == b.value.v)
+ && match (&self.body, &other.body) {
+ (Some(a), Some(b)) => compare(a, b),
+ (None, None) => true,
+ _ => false,
+ }
+ }
+}
+
+fn downcast(func: &FuncCall) -> &DebugFn {
+ func.0.downcast::<DebugFn>().expect("not a debug fn")
+}
+
+fn compare(a: &SyntaxTree, b: &SyntaxTree) -> bool {
+ for (x, y) in a.nodes.iter().zip(&b.nodes) {
+ use node_shorthands::*;
+ let same = match (&x.v, &y.v) {
+ (S, S) | (N, N) | (I, I) | (B, B) | (M, M) => true,
+ (Text(t1), Text(t2)) => t1 == t2,
+ (Func(f1), Func(f2)) => {
+ downcast(f1).compare(downcast(f2))
+ }
+ _ => false,
+ };
+
+ if !same { return false; }
+ }
+ true
+}
/// Parses the test syntax.
macro_rules! tokens {
- ($($task:ident $src:expr =>($line:expr)=> [$($target:tt)*])*) => ({
+ ($($task:ident $src:expr =>($line:expr)=> [$($tts:tt)*])*) => ({
#[allow(unused_mut)]
let mut cases = Vec::new();
- $(cases.push(($line, $src, tokens!(@$task [$($target)*])));)*
+ $(cases.push(($line, $src, tokens!(@$task [$($tts)*])));)*
cases
});
- (@t $tokens:expr) => ({
- Target::Tokenized($tokens.to_vec())
+ (@t [$($tts:tt)*]) => ({
+ use token_shorthands::*;
+ Target::Tokenize(vec![$($tts)*])
});
- (@ts [$(($sl:tt:$sc:tt, $el:tt:$ec:tt, $t:expr)),* $(,)?]) => ({
- Target::TokenizedSpanned(vec![
- $(Spanned { v: $t, span: Span {
+ (@ts [$($tts:tt)*]) => ({
+ use token_shorthands::*;
+ Target::TokenizeSpanned(tokens!(@__spans [$($tts)*]))
+ });
+
+ (@p [$($tts:tt)*]) => ({
+ use node_shorthands::*;
+
+ let nodes = vec![$($tts)*].into_iter()
+ .map(|v| Spanned { v, span: Span::ZERO })
+ .collect();
+
+ Target::Parse(SyntaxTree { nodes })
+ });
+
+ (@ps [$($tts:tt)*]) => ({
+ use node_shorthands::*;
+ Target::ParseSpanned(tokens!(@__spans [$($tts)*]))
+ });
+
+ (@__spans [$(($sl:tt:$sc:tt, $el:tt:$ec:tt, $v:expr)),* $(,)?]) => ({
+ vec![
+ $(Spanned { v: $v, span: Span {
start: Position { line: $sl, column: $sc },
end: Position { line: $el, column: $ec },
}}),*
- ])
+ ]
});
}
#[derive(Debug)]
enum Target {
- Tokenized(Vec<Token<'static>>),
- TokenizedSpanned(Vec<Spanned<Token<'static>>>),
+ Tokenize(Vec<Token<'static>>),
+ TokenizeSpanned(Vec<Spanned<Token<'static>>>),
+ Parse(SyntaxTree),
+ ParseSpanned(SyntaxTree),
}
fn main() {
@@ -75,6 +187,7 @@ fn main() {
println!(" - Source: {:?}", src);
println!(" - Expected: {:?}", expected);
println!(" - Found: {:?}", found);
+ println!();
failed += 1;
errors = true;
@@ -98,14 +211,26 @@ fn main() {
fn test_case(src: &str, target: Target) -> (bool, String, String) {
match target {
- Target::Tokenized(tokens) => {
+ Target::Tokenize(tokens) => {
let found: Vec<_> = tokenize(src).map(Spanned::value).collect();
(found == tokens, format!("{:?}", tokens), format!("{:?}", found))
}
- Target::TokenizedSpanned(tokens) => {
+ Target::TokenizeSpanned(tokens) => {
let found: Vec<_> = tokenize(src).collect();
(found == tokens, format!("{:?}", tokens), format!("{:?}", found))
}
+
+ Target::Parse(tree) => {
+ let scope = Scope::with_debug::<DebugFn>();
+ let (found, _, errs) = parse(src, ParseContext { scope: &scope });
+ (compare(&tree, &found), format!("{:?}", tree), format!("{:?}", found))
+ }
+
+ Target::ParseSpanned(tree) => {
+ let scope = Scope::with_debug::<DebugFn>();
+ let (found, _, _) = parse(src, ParseContext { scope: &scope });
+ (tree == found, format!("{:?}", tree), format!("{:?}", found))
+ }
}
}
diff --git a/tests/parsing/tokens.rs b/tests/parsing/tokens.rs
index 78d891f9..14f4e521 100644
--- a/tests/parsing/tokens.rs
+++ b/tests/parsing/tokens.rs
@@ -46,6 +46,12 @@ t "[func]*bold*" => [LB, ID("func"), RB, ST, T("bold"), ST]
t "[_*`]" => [LB, T("_"), T("*"), T("`"), RB]
t "hi_you_ there" => [T("hi"), U, T("you"), U, W(0), T("there")]
+// Nested functions.
+t "[f: [=][*]]" => [LB, ID("f"), CL, W(0), LB, EQ, RB, LB, ST, RB, RB]
+t "[_][[,],]," => [LB, T("_"), RB, LB, LB, CM, RB, T(","), RB, T(",")]
+t "[=][=][=]" => [LB, EQ, RB, LB, T("="), RB, LB, EQ, RB]
+t "[=][[=][=][=]]" => [LB, EQ, RB, LB, LB, EQ, RB, LB, T("="), RB, LB, EQ, RB, RB]
+
// Escapes.
t r"\[" => [T("[")]
t r"\]" => [T("]")]
@@ -68,7 +74,7 @@ ts "ab\r\nc" => [(0:0, 0:2, T("ab")), (0:2, 1:0, W(1)), (1:0, 1:1, T("c"
ts "[a=10]" => [(0:0, 0:1, LB), (0:1, 0:2, ID("a")), (0:2, 0:3, EQ),
(0:3, 0:5, NUM(10.0)), (0:5, 0:6, RB)]
ts r#"[x = "(1)"]*"# => [(0:0, 0:1, LB), (0:1, 0:2, ID("x")), (0:2, 0:3, W(0)),
- (0:3, 0:4, EQ), (0:4, 0:5, W(0)), (0:5, 0:10, STR("(1)")),
- (0:10, 0:11, RB), (0:11, 0:12, ST)]
+ (0:3, 0:4, EQ), (0:4, 0:5, W(0)), (0:5, 0:10, STR("(1)")),
+ (0:10, 0:11, RB), (0:11, 0:12, ST)]
ts "// ab\r\n\nf" => [(0:0, 0:5, LC(" ab")), (0:5, 2:0, W(2)), (2:0, 2:1, T("f"))]
ts "/*b*/_" => [(0:0, 0:5, BC("b")), (0:5, 0:6, U)]
diff --git a/tests/parsing/trees.rs b/tests/parsing/trees.rs
new file mode 100644
index 00000000..78b16828
--- /dev/null
+++ b/tests/parsing/trees.rs
@@ -0,0 +1,20 @@
+p "" => []
+p "hi" => [T("hi")]
+p "hi you" => [T("hi"), S, T("you")]
+p "❤\n\n 🌍" => [T("❤"), N, T("🌍")]
+p "[func]" => [F!(None)]
+p "[tree][hi *you*]" => [F!(Some([T("hi"), S, B, T("you"), B]))]
+// p "from [align: left] to" => [
+// T("from"), S,
+// F!("align", pos=[ID("left")], None),
+// S, T("to"),
+// ]
+// p "[box: x=1.2pt, false][a b c] bye" => [
+// F!(
+// "box",
+// pos=[BOOL(false)],
+// key=["x": SIZE(Size::pt(1.2))],
+// Some([T("a"), S, T("b"), S, T("c")]),
+// ),
+// S, T("bye"),
+// ]