use crate::*; use syntactic as syn; use syn::TokenVariant as SynVar; use semantic::*; use std::collections::VecDeque; macro_rules! fn_is_syn_variant { ($name:ident, $variant:ty) => { paste::paste! { fn [< is_ $name >](token: &syn::Token) -> bool { match token.variant { $variant => true, _ => false, } } } }; } fn_is_syn_variant!(block_open, syn::TokenVariant::BlockOpen); fn_is_syn_variant!(block_close, syn::TokenVariant::BlockClose); fn_is_syn_variant!(separator, syn::TokenVariant::Separator); fn_is_syn_variant!(terminator, syn::TokenVariant::MacroDefinitionTerminator); pub struct Tokens { tokens: VecDeque, } impl Tokens { pub fn new>>(tokens: T) -> Self { Self { tokens: tokens.into() } } pub fn pop(&mut self) -> Option { self.tokens.pop_front() } pub fn pop_if(&mut self, predicate: fn(&syn::Token) -> bool) -> Option { match predicate(self.tokens.front()?) { true => self.tokens.pop_front(), false => None, } } pub fn unpop(&mut self, token: syn::Token) { self.tokens.push_front(token); } /// Pull tokens until the predicate returns true, otherwise return Err. pub fn pull_until(&mut self, mut predicate: impl FnMut(&syn::Token) -> bool) -> Result { let mut output = VecDeque::new(); while let Some(token) = self.tokens.pop_front() { match predicate(&token) { true => return Ok(Self::new(output)), false => output.push_back(token), }; } return Err(()); } pub fn take(&mut self) -> Self { Self { tokens: std::mem::take(&mut self.tokens) } } pub fn len(&self) -> usize { self.tokens.len() } } pub struct ProgramParser { tokens: Tokens, definitions: Vec, invocations: Vec, errors: Vec, } impl ProgramParser { pub fn new(syntactic_tokens: Vec) -> Self { Self { tokens: Tokens::new(syntactic_tokens), definitions: Vec::new(), invocations: Vec::new(), errors: Vec::new(), } } pub fn parse(mut self) -> Program { while let Some(syn) = self.tokens.pop() { match syn.variant { SynVar::MacroDefinition(name) => { // Collect all tokens up to the next definition terminator. let Ok(definition_tokens) = self.tokens.pull_until(is_terminator) else { let variant = ParseErrorVariant::UnterminatedMacroDefinition(name); self.errors.push(ParseError { source: syn.source, variant}); break; }; // Parse macro definition arguments. match DefinitionParser::new(name, syn.source, definition_tokens).parse() { Ok(definition) => self.definitions.push(definition), Err(errors) => self.errors.extend(errors), }; } SynVar::Comment(_) => (), SynVar::Symbol(name) => { let parser = InvocationParser::new(name, &mut self.tokens); self.invocations.push(parser.parse()); } _ => { let variant = ParseErrorVariant::InvalidToken; self.errors.push(ParseError { source: syn.source, variant}); break; } } } Program { definitions: self.definitions, invocations: self.invocations, errors: self.errors, } } } pub struct DefinitionParser { name: String, source: SourceSpan, tokens: Tokens, arguments: Vec, errors: Vec, } impl DefinitionParser { pub fn new(name: String, source: SourceSpan, tokens: Tokens) -> Self { Self { name, tokens, source, arguments: Vec::new(), errors: Vec::new(), } } pub fn parse(mut self) -> Result> { while let Some(definition) = self.parse_argument_definition() { self.arguments.push(definition) } if self.errors.is_empty() { let variant = self.parse_body(); Ok(Definition { name: self.name, source: self.source, arguments: self.arguments, variant, }) } else { Err(self.errors) } } fn parse_argument_definition(&mut self) -> Option { // Only continue if the first token is a separator. self.tokens.pop_if(is_separator)?; // Pop argument tokens. let is_block = match self.tokens.pop_if(is_block_open) { Some(_) => true, None => false, }; let token = self.tokens.pop(); if is_block { self.tokens.pop_if(is_block_close); } // Parse argument token. let token = token?; let source = token.source; if let SynVar::Symbol(name) = token.variant { let variant = ArgumentDefinitionVariant::Integer; Some(ArgumentDefinition { name, source, variant }) } else { let name = self.name.clone(); let variant = ParseErrorVariant::InvalidArgumentDefinition(name); self.errors.push(ParseError { source, variant}); None } } fn parse_body(&mut self) -> DefinitionVariant { // Attempt to parse an IntegerDefinition. if self.tokens.len() == 1 { let token = self.tokens.pop().unwrap(); match token.variant { SynVar::DecimalLiteral(value) | SynVar::HexadecimalLiteral(value) => { return DefinitionVariant::Integer(IntegerDefinition { source: token.source, variant: IntegerDefinitionVariant::Literal(value), }); } SynVar::ConstantExpression(expr) => { return DefinitionVariant::Integer(IntegerDefinition { source: token.source, variant: IntegerDefinitionVariant::Constant(expr), }); } SynVar::Symbol(name) => { return DefinitionVariant::Reference(ReferenceDefinition { source: token.source, name, }); } _ => (), } self.tokens.unpop(token); } // Parse the remaining tokens as a BlockDefinition. let block = BlockParser::new(self.tokens.take()).parse(); return DefinitionVariant::Block(block); } } /// Parse an entire block, excluding delimiters. pub struct BlockParser { tokens: Tokens, block_tokens: Vec, errors: Vec, } impl BlockParser { pub fn new(tokens: Tokens) -> Self { Self { tokens, block_tokens: Vec::new(), errors: Vec::new() } } pub fn parse(mut self) -> BlockDefinition { while let Some(token) = self.tokens.pop() { let source = token.source; match token.variant { SynVar::Symbol(name) => { let parser = InvocationParser::new(name, &mut self.tokens); let invocation = parser.parse(); let variant = BlockTokenVariant::Invocation(invocation); let block_token = BlockToken { source, variant }; self.block_tokens.push(block_token); } SynVar::PackedBinaryLiteral(pbl) => { let variant = BlockTokenVariant::Word(pbl); let block_token = BlockToken { source, variant }; self.block_tokens.push(block_token); } _ => { let variant = ParseErrorVariant::InvalidToken; self.errors.push(ParseError { source, variant }) } } } BlockDefinition { tokens: self.block_tokens, errors: self.errors } } } struct InvocationParser<'a> { name: String, tokens: &'a mut Tokens, arguments: Vec, errors: Vec, } impl<'a> InvocationParser<'a> { pub fn new(name: String, tokens: &'a mut Tokens) -> Self { Self { name, tokens, arguments: Vec::new(), errors: Vec::new() } } pub fn parse(mut self) -> Invocation { while let Some(argument) = self.parse_invocation_argument() { self.arguments.push(argument); } Invocation { name: self.name, arguments: self.arguments, errors: self.errors, } } fn parse_invocation_argument(&mut self) -> Option { // Only continue if the first token is a separator. self.tokens.pop_if(is_separator)?; if let Some(block_open) = self.tokens.pop_if(is_block_open) { let source = block_open.source; let mut depth = 1; let is_matching_block_close = |token: &syntactic::Token| { match token.variant { syntactic::TokenVariant::BlockOpen => { depth += 1; false } syntactic::TokenVariant::BlockClose => { depth -= 1; depth == 0 } _ => false, } }; if let Ok(block_tokens) = self.tokens.pull_until(is_matching_block_close) { let block = BlockParser::new(block_tokens).parse(); Some(DefinitionVariant::Block(block)) } else { let variant = ParseErrorVariant::UnterminatedBlockDefinition; self.errors.push(ParseError { source, variant }); None } } else { let token = self.tokens.pop()?; let source = token.source; match token.variant { SynVar::Symbol(name) => { let reference = ReferenceDefinition { source, name }; Some(DefinitionVariant::Reference(reference)) } SynVar::DecimalLiteral(value) | SynVar::HexadecimalLiteral(value) => { let variant = IntegerDefinitionVariant::Literal(value); let integer = IntegerDefinition { source, variant }; Some(DefinitionVariant::Integer(integer)) } SynVar::ConstantExpression(expr) => { let variant = IntegerDefinitionVariant::Constant(expr); let integer = IntegerDefinition { source, variant }; Some(DefinitionVariant::Integer(integer)) } _ => { let variant = ParseErrorVariant::InvalidToken; self.errors.push(ParseError { source, variant }); None } } } } }