diff options
Diffstat (limited to 'src/parsers/semantic.rs')
-rw-r--r-- | src/parsers/semantic.rs | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/src/parsers/semantic.rs b/src/parsers/semantic.rs index 6576b44..44861e1 100644 --- a/src/parsers/semantic.rs +++ b/src/parsers/semantic.rs @@ -1,2 +1,289 @@ 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<syn::Token>, +} + +impl Tokens { + pub fn new<T: Into<VecDeque<syn::Token>>>(tokens: T) -> Self { + Self { tokens: tokens.into() } + } + + pub fn pop(&mut self) -> Option<syn::Token> { + self.tokens.pop_front() + } + + pub fn pop_if(&mut self, predicate: fn(&syn::Token) -> bool) -> Option<syn::Token> { + 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, predicate: fn(&syn::Token) -> bool) -> Result<Self, ()> { + 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<Definition>, + invocations: Vec<Invocation>, + errors: Vec<ParseError>, +} + +impl ProgramParser { + pub fn new(syntactic_tokens: Vec<syn::Token>) -> 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() { + if let SynVar::MacroDefinition(name) = syn.variant { + // Collect all tokens up to the next definition terminator. + let Ok(definition_tokens) = self.tokens.pull_until(is_terminator) else { + let variant = ParseErrorVariant::UnterminatedMacroDefinition; + 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), + }; + } + } + + Program { + definitions: self.definitions, + invocations: self.invocations, + errors: self.errors, + } + } +} + + +pub struct DefinitionParser { + name: String, + source: SourceSpan, + tokens: Tokens, + arguments: Vec<ArgumentDefinition>, + errors: Vec<ParseError>, +} + +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<Definition, Vec<ParseError>> { + 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<ArgumentDefinition> { + // 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<BlockToken>, + errors: Vec<ParseError>, +} + +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 mut arguments = Vec::new(); + while let Some(argument) = self.parse_invocation_argument() { + arguments.push(argument); + } + let invocation = Invocation { name, arguments }; + 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 } + } + + fn parse_invocation_argument(&mut self) -> Option<DefinitionVariant> { + // 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; + if let Ok(block_tokens) = self.tokens.pull_until(is_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 + } + } + + } + } +} |