diff options
Diffstat (limited to 'src/tokens/semantic.rs')
-rw-r--r-- | src/tokens/semantic.rs | 184 |
1 files changed, 101 insertions, 83 deletions
diff --git a/src/tokens/semantic.rs b/src/tokens/semantic.rs index 7d5d327..d61ad8e 100644 --- a/src/tokens/semantic.rs +++ b/src/tokens/semantic.rs @@ -1,90 +1,100 @@ use crate::*; +use indexmap::IndexMap; + /// The entire semantic program, ready to generate bytecode. -pub struct Program { - pub definitions: Vec<Definition>, - pub invocations: Vec<Invocation>, - pub errors: Vec<ParseError>, +pub struct SemanticProgram { + pub macro_definitions: IndexMap<String, MacroDefinition>, + pub label_definitions: IndexMap<String, LabelDefinition>, + pub body: Vec<SemanticToken>, } /// A symbol definition. -pub struct Definition { - pub name: String, +pub struct MacroDefinition { pub source: SourceSpan, pub arguments: Vec<ArgumentDefinition>, - pub variant: DefinitionVariant, + pub value: Value, + pub errors: Vec<SemanticParseError>, } pub struct ArgumentDefinition { pub name: String, pub source: SourceSpan, - pub variant: ArgumentDefinitionVariant, + pub variant: ArgumentVariant, } -pub enum ArgumentDefinitionVariant { +#[derive(PartialEq, Clone, Copy, Debug)] +pub enum ArgumentVariant { Integer, Block, } -pub enum DefinitionVariant { - Integer(IntegerDefinition), - Block(BlockDefinition), - Reference(ReferenceDefinition), -} - -pub struct IntegerDefinition { +pub struct ArgumentInvocation { pub source: SourceSpan, - pub variant: IntegerDefinitionVariant, + pub value: Value, } -pub enum IntegerDefinitionVariant { - Literal(usize), - Constant(ConstantExpression), +pub enum Value { + Integer(Integer), + Block(Vec<SemanticToken>), + Invocation(Invocation), } -pub struct BlockDefinition { - pub tokens: Vec<BlockToken>, - pub errors: Vec<ParseError>, +pub enum Integer { + Literal(TrackedInteger), + Expression(Expression), + LabelReference(Tracked<String>), } -pub struct BlockToken { - pub source: SourceSpan, - pub variant: BlockTokenVariant, +pub enum SemanticToken { + Word(PackedBinaryLiteral), + Invocation(Invocation), + LabelDefinition(LabelDefinition), + PinnedAddress(PinnedAddress), + Error(SemanticParseError), } -pub enum BlockTokenVariant { - Invocation(Invocation), - Comment(String), - Word(PackedBinaryLiteral), +pub struct Invocation { + pub name: String, + pub source: SourceSpan, + pub arguments: Vec<ArgumentInvocation>, + pub errors: Vec<SemanticParseError>, } -/// References aren't necessarily an integer or a block -pub struct ReferenceDefinition { +#[derive(Clone)] +pub struct LabelDefinition { pub source: SourceSpan, pub name: String, } -pub struct Invocation { - pub name: String, - pub arguments: Vec<DefinitionVariant>, - pub errors: Vec<ParseError>, +#[derive(Clone)] +pub struct PinnedAddress { + pub source: SourceSpan, + pub address: usize, } -pub struct ParseError { +pub struct SemanticParseError { pub source: SourceSpan, - pub variant: ParseErrorVariant, + pub variant: SemanticParseErrorVariant, } -pub enum ParseErrorVariant { +pub enum SemanticParseErrorVariant { UnterminatedMacroDefinition(String), - UnterminatedBlockDefinition, - /// Name of the macro. - InvalidArgumentDefinition(String), + UnterminatedBlock, InvalidToken, } +impl std::fmt::Display for ArgumentVariant { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + match self { + ArgumentVariant::Integer => write!(f, "integer"), + ArgumentVariant::Block => write!(f, "block"), + } + } +} + // ------------------------------------------------------------------------ // macro_rules! indent { @@ -94,77 +104,85 @@ macro_rules! indent { }}; } -impl Program { +impl SemanticProgram { pub fn print_definitions(&self) { - for definition in &self.definitions { - let variant = match &definition.variant { - DefinitionVariant::Integer(_) => "INTEGER", - DefinitionVariant::Block(_) => "BLOCK", - DefinitionVariant::Reference(_) => "REFERENCE", + for (name, definition) in &self.macro_definitions { + let variant = match &definition.value { + Value::Integer(_) => "INTEGER", + Value::Block(_) => "BLOCK", + Value::Invocation(_) => "INVOCATION", }; - println!("DEFINE {variant} '{}'", definition.name); + println!("DEFINE {variant} '{name}'"); for argument in &definition.arguments { self.print_argument_definition(argument); } - match &definition.variant { - DefinitionVariant::Integer(integer) => - self.print_integer_definition(1, integer), - DefinitionVariant::Block(block) => - self.print_block_definition(1, block), - DefinitionVariant::Reference(reference) => - indent!(1 => "REFERENCE '{}'", reference.name), + match &definition.value { + Value::Integer(integer) => + self.print_integer(1, integer), + Value::Block(block) => + self.print_block(1, block), + Value::Invocation(invocation) => + indent!(1 => "INVOCATION '{}'", invocation.name), }; println!(); } - for invocation in &self.invocations { - self.print_invocation(0, invocation); + println!("LABELS"); + for (name, _) in &self.label_definitions { + println!(" @{name}"); } + println!(); + + self.print_block(0, &self.body); } fn print_argument_definition(&self, argument: &ArgumentDefinition) { let variant = match argument.variant { - ArgumentDefinitionVariant::Integer => "INTEGER", - ArgumentDefinitionVariant::Block => "BLOCK", + ArgumentVariant::Integer => "INTEGER", + ArgumentVariant::Block => "BLOCK", }; println!(" ARGUMENT {variant} '{}'", argument.name); } - fn print_integer_definition(&self, indent: usize, definition: &IntegerDefinition) { - match &definition.variant { - IntegerDefinitionVariant::Literal(value) => + fn print_integer(&self, indent: usize, integer: &Integer) { + match &integer { + Integer::Literal(value) => indent!(indent => "LITERAL {value}"), - IntegerDefinitionVariant::Constant(expr) => - indent!(indent => "CONSTANT [{expr:?}]"), + Integer::Expression(expr) => + indent!(indent => "EXPRESSION [{expr:?}]"), + Integer::LabelReference(name) => + indent!(indent => "LABEL REFERENCE '{name}'"), } } - fn print_block_definition(&self, indent: usize, definition: &BlockDefinition) { + fn print_block(&self, indent: usize, block: &[SemanticToken]) { indent!(indent => "BLOCK"); - let indent = indent + 1; - for token in &definition.tokens { - match &token.variant { - BlockTokenVariant::Invocation(invocation) => - self.print_invocation(indent, invocation), - BlockTokenVariant::Comment(_) => - indent!(indent => "COMMENT"), - BlockTokenVariant::Word(word) => - indent!(indent => "WORD #{word}"), + for semantic_token in block { + match &semantic_token { + SemanticToken::Word(word) => + indent!(indent+1 => "WORD #{word}"), + SemanticToken::Invocation(invocation) => + self.print_invocation(indent+1, invocation), + SemanticToken::LabelDefinition(definition) => + indent!(indent+1 => "LABEL DEFINITION @{}", definition.name), + SemanticToken::PinnedAddress(addr) => + indent!(indent+1 => "PINNED ADDRESS {}", addr.address), + SemanticToken::Error(_) => + indent!(indent+1 => "ERROR"), } } } fn print_invocation(&self, indent: usize, invocation: &Invocation) { indent!(indent => "INVOCATION '{}'", invocation.name); - let indent = indent + 1; for argument in &invocation.arguments { - match &argument { - DefinitionVariant::Integer(integer) => - self.print_integer_definition(indent, integer), - DefinitionVariant::Block(block) => - self.print_block_definition(indent, block), - DefinitionVariant::Reference(reference) => - indent!(indent => "REFERENCE '{}'", reference.name), + match &argument.value { + Value::Integer(integer) => + self.print_integer(indent+1, integer), + Value::Block(block) => + self.print_block(indent+1, block), + Value::Invocation(invocation) => + self.print_invocation(indent+1, invocation), }; } } |