use crate::*; use SyntacticTokenVariant as SynVar; use std::collections::VecDeque; use indexmap::IndexMap; macro_rules! fn_is_syn_variant { ($name:ident, $variant:ty) => { paste::paste! { fn [< is_ $name >](token: &SyntacticToken) -> bool { match token.variant { $variant => true, _ => false, } } } }; } fn_is_syn_variant!(block_open, SyntacticTokenVariant::BlockOpen); fn_is_syn_variant!(block_close, SyntacticTokenVariant::BlockClose); fn_is_syn_variant!(separator, SyntacticTokenVariant::Separator); fn_is_syn_variant!(terminator, SyntacticTokenVariant::MacroDefinitionTerminator); pub struct SemanticParser { tokens: Tokens, macro_definitions: IndexMap, label_definitions: IndexMap, body: Vec, } impl SemanticParser { pub fn new(syntactic_tokens: Vec) -> Self { // Gather all labels ahead of time. let mut label_definitions = IndexMap::new(); for token in &syntactic_tokens { if let SyntacticTokenVariant::LabelDefinition(name) = &token.variant { let definition = LabelDefinition { source: token.source.clone(), name: name.clone(), }; let None = label_definitions.insert(name.to_string(), definition) else { unreachable!("Duplicate definition for label {name:?}"); }; } } Self { tokens: Tokens::new(syntactic_tokens), macro_definitions: IndexMap::new(), label_definitions, body: Vec::new(), } } pub fn parse(mut self) -> SemanticProgram { while let Some(syn) = self.tokens.pop() { match syn.variant { SynVar::MacroDefinition(name) => { let Ok(definition_tokens) = self.tokens.pull_until(is_terminator) else { let variant = SemanticParseErrorVariant::UnterminatedMacroDefinition(name); let error = SemanticParseError { source: syn.source, variant }; self.body.push(SemanticToken::Error(error)); break; }; let definition = MacroDefinitionParser::new(syn.source, definition_tokens).parse(); let None = self.macro_definitions.insert(name.clone(), definition) else { unreachable!("Duplicate definition for macro {name}"); }; } SynVar::LabelDefinition(name) => { let label_definition = LabelDefinition { source: syn.source, name }; self.body.push(SemanticToken::LabelDefinition(label_definition)); } SynVar::PinnedAddress(address) => { let pinned_address = PinnedAddress { source: syn.source, address }; self.body.push(SemanticToken::PinnedAddress(pinned_address)); } SynVar::Symbol(name) => { let invocation = InvocationParser::new(name, syn.source, &mut self.tokens).parse(); self.body.push(SemanticToken::Invocation(invocation)); } _ => { let variant = SemanticParseErrorVariant::InvalidToken; let error = SemanticParseError { source: syn.source, variant }; self.body.push(SemanticToken::Error(error)); } } } SemanticProgram { macro_definitions: self.macro_definitions, label_definitions: self.label_definitions, body: self.body, } } } pub struct MacroDefinitionParser { source: SourceSpan, tokens: Tokens, arguments: Vec, errors: Vec, } impl MacroDefinitionParser { pub fn new(source: SourceSpan, tokens: Tokens) -> Self { Self { tokens, source, arguments: Vec::new(), errors: Vec::new(), } } pub fn parse(mut self) -> MacroDefinition { while let Some(definition) = self.parse_argument_definition() { self.arguments.push(definition) } MacroDefinition { value: self.parse_body(), source: self.source, arguments: self.arguments, errors: 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 = match is_block { true => ArgumentVariant::Block, false => ArgumentVariant::Integer, }; Some(ArgumentDefinition { name, source, variant }) } else { let variant = SemanticParseErrorVariant::InvalidToken; self.errors.push(SemanticParseError { source, variant}); None } } fn parse_body(&mut self) -> Value { // Attempt to parse an Integer. if self.tokens.len() == 1 { let token = self.tokens.pop().unwrap(); match token.variant { SynVar::IntegerLiteral(value) => { let integer = TrackedInteger { source: token.source, value }; return Value::Integer(Integer::Literal(integer)); } SynVar::Expression(expr) => { return Value::Integer(Integer::Expression(expr)); } _ => (), } self.tokens.unpop(token); } // Parse a Block. let mut block = BlockParser::new(self.tokens.take()).parse(); // If the block contains a single invocation, unwrap it. if block.len() == 1 { match block.pop() { Some(SemanticToken::Invocation(invocation)) => return Value::Invocation(invocation), Some(other) => block.push(other), None => (), }; } return Value::Block(block); } } /// Parse an entire block, excluding delimiters. pub struct BlockParser { tokens: Tokens, semantic_tokens: Vec, } impl BlockParser { pub fn new(tokens: Tokens) -> Self { Self { tokens, semantic_tokens: Vec::new() } } pub fn parse(mut self) -> Vec { while let Some(token) = self.tokens.pop() { let source = token.source; match token.variant { SynVar::Symbol(name) => { let invocation = InvocationParser::new(name, source, &mut self.tokens).parse(); self.semantic_tokens.push(SemanticToken::Invocation(invocation)); } SynVar::PackedBinaryLiteral(pbl) => { self.semantic_tokens.push(SemanticToken::Word(pbl)); } SynVar::LabelDefinition(name) => { let label_definition = LabelDefinition { source, name }; self.semantic_tokens.push(SemanticToken::LabelDefinition(label_definition)); } _ => { let variant = SemanticParseErrorVariant::InvalidToken; let error = SemanticParseError { source, variant }; self.semantic_tokens.push(SemanticToken::Error(error)); } } } return self.semantic_tokens; } } struct InvocationParser<'a> { name: String, source: SourceSpan, tokens: &'a mut Tokens, arguments: Vec, errors: Vec, } impl<'a> InvocationParser<'a> { pub fn new(name: String, source: SourceSpan, tokens: &'a mut Tokens) -> Self { Self { name, source, 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, source: self.source, 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: &SyntacticToken| { match token.variant { SyntacticTokenVariant::BlockOpen => { depth += 1; false } SyntacticTokenVariant::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(ArgumentInvocation { source, value: Value::Block(block) }) } else { let variant = SemanticParseErrorVariant::UnterminatedBlock; self.errors.push(SemanticParseError { source, variant }); None } } else { let token = self.tokens.pop()?; let source = token.source; match token.variant { SynVar::Symbol(name) => { let arguments = Vec::new(); let errors = Vec::new(); let invocation = Invocation { source: source.clone(), name, arguments, errors }; let value = Value::Invocation(invocation); Some(ArgumentInvocation { source, value }) } SynVar::IntegerLiteral(value) => { let integer = TrackedInteger { source: source.clone(), value }; let value = Value::Integer(Integer::Literal(integer)); Some(ArgumentInvocation { source, value }) } SynVar::Expression(expr) => { let value = Value::Integer(Integer::Expression(expr)); Some(ArgumentInvocation { source, value }) } _ => { let variant = SemanticParseErrorVariant::InvalidToken; self.errors.push(SemanticParseError { source, variant }); None } } } } } 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(&SyntacticToken) -> bool) -> Option { match predicate(self.tokens.front()?) { true => self.tokens.pop_front(), false => None, } } pub fn unpop(&mut self, token: SyntacticToken) { 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(&SyntacticToken) -> 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() } }