summaryrefslogtreecommitdiff
path: root/src/tokens/semantic.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tokens/semantic.rs')
-rw-r--r--src/tokens/semantic.rs184
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),
};
}
}