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<String, MacroDefinition>,
label_definitions: IndexMap<String, LabelDefinition>,
body: Vec<SemanticToken>,
}
impl SemanticParser {
pub fn new(syntactic_tokens: Vec<SyntacticToken>) -> 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));
}
SynVar::PackedBinaryLiteral(pbl) => {
self.body.push(SemanticToken::Word(pbl));
}
_ => {
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<ArgumentDefinition>,
errors: Vec<SemanticParseError>,
}
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<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 = 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<SemanticToken>,
}
impl BlockParser {
pub fn new(tokens: Tokens) -> Self {
Self { tokens, semantic_tokens: Vec::new() }
}
pub fn parse(mut self) -> Vec<SemanticToken> {
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<ArgumentInvocation>,
errors: Vec<SemanticParseError>,
}
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<ArgumentInvocation> {
// 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::String(string) => {
let value = Value::Integer(Integer::String(string));
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<SyntacticToken>,
}
impl Tokens {
pub fn new<T: Into<VecDeque<SyntacticToken>>>(tokens: T) -> Self {
Self { tokens: tokens.into() }
}
pub fn pop(&mut self) -> Option<SyntacticToken> {
self.tokens.pop_front()
}
pub fn pop_if(&mut self, predicate: fn(&SyntacticToken) -> bool) -> Option<SyntacticToken> {
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<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()
}
}