summaryrefslogtreecommitdiff
path: root/src/tokens
diff options
context:
space:
mode:
Diffstat (limited to 'src/tokens')
-rw-r--r--src/tokens/constant_expression.rs134
-rw-r--r--src/tokens/mod.rs11
-rw-r--r--src/tokens/packed_binary_literal.rs60
-rw-r--r--src/tokens/semantic.rs71
-rw-r--r--src/tokens/syntactic.rs66
5 files changed, 342 insertions, 0 deletions
diff --git a/src/tokens/constant_expression.rs b/src/tokens/constant_expression.rs
new file mode 100644
index 0000000..e4aa099
--- /dev/null
+++ b/src/tokens/constant_expression.rs
@@ -0,0 +1,134 @@
+use crate::*;
+
+
+pub struct ConstantExpression {
+ pub tokens: Vec<ConstantExpressionToken>,
+}
+
+impl ConstantExpression {
+ pub fn from_str(string: &str, tokeniser: &Tokeniser) -> Self {
+ parse_constant_expression(string, tokeniser)
+ }
+}
+
+pub struct ConstantExpressionToken {
+ pub source: SourceSpan,
+ pub variant: ConstantExpressionTokenVariant,
+}
+
+pub enum ConstantExpressionTokenVariant {
+ SymbolReference(String),
+ IntegerLiteral(usize),
+ Operator(Operator),
+ Error(ConstantExpressionParseError),
+}
+
+pub enum Operator {
+ Equal,
+ NotEqual,
+ LessThan,
+ GreaterThan,
+ Add,
+ Subtract,
+ LeftShift,
+ RightShift,
+ And,
+ Or,
+ Xor,
+ Not,
+}
+
+pub enum ConstantExpressionParseError {
+ InvalidHexadecimalLiteral(String),
+}
+
+
+impl ConstantExpression {
+ pub fn evaluate(&self, environment: &Environment) -> Result<usize, ConstantExpressionEvaluationError> {
+ use ConstantExpressionTokenVariant as Token;
+ use ConstantExpressionEvaluationError as EvalErr;
+
+ let mut stack = Vec::new();
+ macro_rules! push {
+ ($value:expr) => { stack.push($value) };
+ }
+ macro_rules! pop {
+ ($name:ident) => { let $name = match stack.pop() {
+ Some(value) => value,
+ None => return Err(EvalErr::StackUnderflow),
+ }; };
+ }
+ macro_rules! truth {
+ ($bool:expr) => { match $bool { true => 1, false => 0 } };
+ }
+
+ for token in &self.tokens {
+ match &token.variant {
+ Token::IntegerLiteral(value) => push!(*value),
+ Token::SymbolReference(name) => match environment.get_integer(name) {
+ Ok(value) => push!(value),
+ Err(_) => todo!(),
+ }
+ Token::Operator(operator) => match operator {
+ Operator::Equal => { pop!(b); pop!(a); push!(truth!(a==b)) },
+ Operator::NotEqual => { pop!(b); pop!(a); push!(truth!(a!=b)) },
+ Operator::LessThan => { pop!(b); pop!(a); push!(truth!(a < b)) },
+ Operator::GreaterThan => { pop!(b); pop!(a); push!(truth!(a > b)) },
+ Operator::Add => { pop!(b); pop!(a); push!(a + b) },
+ Operator::Subtract => { pop!(b); pop!(a); push!(a - b) },
+ Operator::LeftShift => { pop!(b); pop!(a); push!(a << b) },
+ Operator::RightShift => { pop!(b); pop!(a); push!(a >> b) },
+ Operator::And => { pop!(b); pop!(a); push!(a & b) },
+ Operator::Or => { pop!(b); pop!(a); push!(a | b) },
+ Operator::Xor => { pop!(b); pop!(a); push!(a ^ b) },
+ Operator::Not => { pop!(a); push!(!a) },
+ }
+ Token::Error(_) => (),
+ }
+ }
+ match stack.len() {
+ 0 => Err(EvalErr::NoReturnValue),
+ 1 => Ok(stack[0]),
+ _ => Err(EvalErr::MultipleReturnValues),
+ }
+ }
+}
+
+pub enum ConstantExpressionEvaluationError {
+ StackUnderflow,
+ MultipleReturnValues,
+ NoReturnValue,
+}
+
+
+impl std::fmt::Debug for ConstantExpression {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+ use ConstantExpressionTokenVariant as TokenVar;
+ for (i, token) in self.tokens.iter().enumerate() {
+ let string = match &token.variant {
+ TokenVar::SymbolReference(name) => name,
+ TokenVar::IntegerLiteral(value) => &value.to_string(),
+ TokenVar::Operator(operator) => match operator {
+ Operator::Equal => "=",
+ Operator::NotEqual => "!",
+ Operator::LessThan => "<",
+ Operator::GreaterThan => ">",
+ Operator::Add => "+",
+ Operator::Subtract => "-",
+ Operator::LeftShift => "<<",
+ Operator::RightShift => ">>",
+ Operator::And => "&",
+ Operator::Or => "|",
+ Operator::Xor => "^",
+ Operator::Not => "~",
+ }
+ TokenVar::Error(_) => "<error>",
+ };
+ match i {
+ 0 => write!(f, "{string}")?,
+ _ => write!(f, " {string}")?,
+ }
+ }
+ return Ok(());
+ }
+}
diff --git a/src/tokens/mod.rs b/src/tokens/mod.rs
new file mode 100644
index 0000000..65f361c
--- /dev/null
+++ b/src/tokens/mod.rs
@@ -0,0 +1,11 @@
+mod syntactic;
+pub use syntactic::*;
+
+mod semantic;
+pub use semantic::*;
+
+mod constant_expression;
+pub use constant_expression::*;
+
+mod packed_binary_literal;
+pub use packed_binary_literal::*;
diff --git a/src/tokens/packed_binary_literal.rs b/src/tokens/packed_binary_literal.rs
new file mode 100644
index 0000000..1252398
--- /dev/null
+++ b/src/tokens/packed_binary_literal.rs
@@ -0,0 +1,60 @@
+use crate::*;
+
+
+pub struct PackedBinaryLiteral {
+ pub value: usize,
+ pub fields: Vec<BitField>,
+ pub errors: Vec<PackedBinaryLiteralParseError>,
+}
+
+impl PackedBinaryLiteral {
+ pub fn from_str(string: &str, parent: &Tokeniser) -> Self {
+ parse_packed_binary_literal(string, parent)
+ }
+}
+
+pub struct BitField {
+ pub name: char,
+ pub source: SourceSpan,
+ /// Length of field in bits
+ pub bits: usize,
+ /// Distance to left-shift field in value
+ pub shift: usize,
+}
+
+pub struct PackedBinaryLiteralParseError {
+ pub source: SourceSpan,
+ pub variant: PackedBinaryLiteralParseErrorVariant,
+}
+
+pub enum PackedBinaryLiteralParseErrorVariant {
+ DuplicateFieldName(char),
+ InvalidCharacter(char),
+}
+
+
+impl std::fmt::Display for PackedBinaryLiteral {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+ if self.value == 0 {
+ write!(f, "0")?;
+ } else {
+ let bitcount = (self.value.ilog2() + 1) as usize;
+ 'bit: for i in (0..bitcount).rev() {
+ if (i+1) % 4 == 0 {
+ write!(f, "_")?;
+ }
+ for field in &self.fields {
+ if i <= field.bits + field.shift - 1 && i >= field.shift {
+ write!(f, "{}", field.name)?;
+ continue 'bit;
+ }
+ }
+ match (self.value >> i) & 1 {
+ 0 => write!(f, "0")?,
+ _ => write!(f, "1")?,
+ }
+ }
+ }
+ return Ok(());
+ }
+}
diff --git a/src/tokens/semantic.rs b/src/tokens/semantic.rs
new file mode 100644
index 0000000..ed53685
--- /dev/null
+++ b/src/tokens/semantic.rs
@@ -0,0 +1,71 @@
+use crate::*;
+
+
+pub enum SemanticToken {
+ MacroDefinition,
+ Invocation,
+}
+
+pub struct Invocation {
+ pub name: String,
+ pub bytecode: BytecodeSpan,
+ pub arguments: Vec<InvocationArgument>,
+}
+
+pub struct BlockLiteral {
+ pub tokens: Vec<BlockToken>,
+}
+
+pub struct BlockToken {
+ pub source: SourceSpan,
+ pub bytecode: BytecodeSpan,
+ pub variant: BlockTokenVariant,
+}
+
+pub enum BlockTokenVariant {
+ Invocation(Invocation),
+ Word(PackedBinaryLiteral),
+}
+
+pub struct MacroDefinition {
+ pub name: String,
+ pub arguments: Vec<DefinitionArgument>,
+ pub body: BlockLiteral,
+}
+
+// -------------------------------------------------------------------------- //
+
+pub struct SemanticParseError {
+ pub source: SourceSpan,
+ pub variant: SemanticParseErrorVariant,
+}
+
+pub enum SemanticParseErrorVariant {
+
+}
+
+// -------------------------------------------------------------------------- //
+
+pub struct DefinitionArgument {
+ pub name: String,
+ pub source: SourceSpan,
+ pub variant: DefinitionArgumentVariant,
+}
+
+pub enum DefinitionArgumentVariant {
+ Integer,
+ Block,
+}
+
+pub struct InvocationArgument {
+ pub source: SourceSpan,
+ pub variant: InvocationArgumentVariant,
+}
+
+pub enum InvocationArgumentVariant {
+ BlockLiteral(BlockLiteral),
+ IntegerLiteral(usize),
+ ConstantExpression(ConstantExpression),
+ Invocation(Invocation),
+}
+
diff --git a/src/tokens/syntactic.rs b/src/tokens/syntactic.rs
new file mode 100644
index 0000000..000d178
--- /dev/null
+++ b/src/tokens/syntactic.rs
@@ -0,0 +1,66 @@
+use crate::*;
+
+
+pub struct SyntacticToken {
+ pub source: SourceSpan,
+ pub variant: SyntacticTokenVariant,
+}
+
+pub enum SyntacticTokenVariant {
+ LabelDefinition(String),
+ MacroDefinition(String),
+ MacroDefinitionTerminator,
+
+ DecimalLiteral(usize),
+ HexadecimalLiteral(usize),
+ PackedBinaryLiteral(PackedBinaryLiteral),
+
+ Comment(String),
+ ConstantExpression(ConstantExpression),
+
+ BlockOpen,
+ BlockClose,
+ Separator,
+
+ Symbol(String),
+
+ Error(SyntacticParseError),
+}
+
+#[derive(Debug)]
+pub enum SyntacticParseError {
+ InvalidHexadecimalLiteral(String),
+ InvalidSymbolIdentifier(String),
+ UnterminatedComment,
+ UnterminatedConstantExpression,
+}
+
+
+impl std::fmt::Debug for SyntacticToken {
+ fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+ use SyntacticTokenVariant::*;
+ let start = &self.source.in_merged;
+ let name = match &self.variant {
+ LabelDefinition(name) => format!("LabelDefinition({name})"),
+ MacroDefinition(name) => format!("MacroDefinition({name})"),
+ MacroDefinitionTerminator => format!("MacroDefinitionTerminator"),
+
+ DecimalLiteral(value) => format!("DecimalLiteral({value})"),
+ HexadecimalLiteral(value) => format!("HexadecimalLiteral(0x{value:x})"),
+ PackedBinaryLiteral(pbl) => format!("PackedBinaryLiteral({pbl})"),
+
+ Comment(_) => format!("Comment"),
+ ConstantExpression(expr) => format!("ConstantExpression({expr:?})"),
+
+ BlockOpen => format!("BlockOpen"),
+ BlockClose => format!("BlockClose"),
+ Separator => format!("Separator"),
+
+ Symbol(name) => format!("Symbol({name})"),
+
+ Error(error) => format!("Error({error:?})"),
+ };
+
+ write!(f, "{start} {name}")
+ }
+}