diff options
| author | Laurenz <laurmaedje@gmail.com> | 2020-01-14 20:17:50 +0100 |
|---|---|---|
| committer | Laurenz <laurmaedje@gmail.com> | 2020-01-14 20:17:50 +0100 |
| commit | 15ad30555bdad8e7b192fdcf7d4543c0d3fb18ce (patch) | |
| tree | 814a1863e6a50d433613e5b362d30ede2df0bb21 /tests | |
| parent | dde69276d47818174c35523c8ed86b6888b6d02b (diff) | |
Parser testing prototype 🥥
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/parse.rs | 171 | ||||
| -rw-r--r-- | tests/parsing/tokens.rs | 10 | ||||
| -rw-r--r-- | tests/parsing/trees.rs | 20 |
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"), +// ] |
