diff options
Diffstat (limited to 'tests/parse.rs')
| -rw-r--r-- | tests/parse.rs | 171 |
1 files changed, 148 insertions, 23 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)) + } } } |
