diff options
Diffstat (limited to 'src/tokens')
-rw-r--r-- | src/tokens/assembler.rs | 140 | ||||
-rw-r--r-- | src/tokens/bytecode.rs | 49 | ||||
-rw-r--r-- | src/tokens/constant_expression.rs | 134 | ||||
-rw-r--r-- | src/tokens/expression.rs | 74 | ||||
-rw-r--r-- | src/tokens/mod.rs | 22 | ||||
-rw-r--r-- | src/tokens/packed_binary_literal.rs | 11 | ||||
-rw-r--r-- | src/tokens/semantic.rs | 184 | ||||
-rw-r--r-- | src/tokens/syntactic.rs | 32 | ||||
-rw-r--r-- | src/tokens/tracked.rs | 47 | ||||
-rw-r--r-- | src/tokens/tracked_integer.rs | 14 |
10 files changed, 461 insertions, 246 deletions
diff --git a/src/tokens/assembler.rs b/src/tokens/assembler.rs new file mode 100644 index 0000000..04ecd38 --- /dev/null +++ b/src/tokens/assembler.rs @@ -0,0 +1,140 @@ +use crate::*; + + +#[derive(Clone)] +pub enum AssembledToken { + Word(AssembledWord), + LabelDefinition(LabelDefinition), + PinnedAddress(PinnedAddress), + Error(AssemblerError), +} + +#[derive(Clone)] +pub struct AssembledWord { + pub source: SourceSpan, + pub value: usize, + pub bits: usize, + pub fields: Vec<AssembledField>, + pub errors: Vec<AssemblerError>, +} + +#[derive(Clone)] +pub struct AssembledField { + pub source: SourceSpan, + pub value: IntegerArgument, + /// Length of field in bits + pub bits: usize, + /// Distance to left-shift field in value + pub shift: usize, +} + +#[derive(Clone)] +pub struct AssembledExpression { + pub source: SourceSpan, + pub tokens: Vec<AssembledExpressionToken>, +} + +#[derive(Clone)] +pub enum AssembledExpressionToken { + Integer(TrackedInteger), + LabelReference(Tracked<String>), + Operator(Operator), + Expression(Box<AssembledExpression>), +} + +#[derive(Clone)] +pub enum Argument { + Integer(IntegerArgument), + Block(Vec<AssembledToken>), +} + +#[derive(Clone)] +pub enum IntegerArgument { + LabelReference(Tracked<String>), + Integer(TrackedInteger), + Expression(AssembledExpression), +} + +#[derive(Clone)] +pub struct AssemblerError { + pub source: SourceSpan, + pub variant: AssemblerErrorVariant, +} + +#[derive(Clone, Debug)] +pub enum AssemblerErrorVariant { + DefinitionNotFound(String), + NotAnInteger, + NotABlock, + IntegerInBlock, + /// expected, received + IncorrectArgumentCount(usize, usize), + /// expected, received, index + IncorrectArgumentType(ArgumentVariant, ArgumentVariant), +} + +// ------------------------------------------------------------------------ // + +macro_rules! indent { + ($indent:expr => $($tokens:tt)*) => {{ + for _ in 0..$indent { print!(" "); } + println!($($tokens)*); + }}; +} + +pub fn print_assembled_tokens(tokens: &[AssembledToken]) { + println!(); + println!("--------------------------------------------------------------"); + println!(); + for token in tokens { + match token { + AssembledToken::LabelDefinition(definition) => { + println!("LABEL {}", definition.name) + } + AssembledToken::PinnedAddress(address) => { + println!("PINNED {}", address.address) + } + AssembledToken::Word(word) => { + println!("WORD {:b}", word.value); + for field in &word.fields { + print!(" FIELD ({} << {}) ", field.bits, field.shift); + match &field.value { + IntegerArgument::LabelReference(name) => { + println!("LABEL '{name}'"); + } + IntegerArgument::Integer(integer) => { + println!("INTEGER '{}'", integer.value); + } + IntegerArgument::Expression(expr) => { + println!("EXPRESSION"); + print_assembled_expression(2, expr); + } + } + } + } + AssembledToken::Error(error) => { + println!("ERROR {:?}", error.variant) + } + } + } +} + +fn print_assembled_expression(indent: usize, expr: &AssembledExpression) { + for token in &expr.tokens { + match token { + AssembledExpressionToken::Integer(integer) => { + indent!(indent => "INTEGER {}", integer.value) + } + AssembledExpressionToken::LabelReference(name) => { + indent!(indent => "LABEL '{name}'") + } + AssembledExpressionToken::Operator(operator) => { + indent!(indent => "OPERATOR {operator:?}") + } + AssembledExpressionToken::Expression(expr) => { + indent!(indent => "EXPRESSION"); + print_assembled_expression(indent+1, expr); + } + } + } +} diff --git a/src/tokens/bytecode.rs b/src/tokens/bytecode.rs new file mode 100644 index 0000000..9ac340e --- /dev/null +++ b/src/tokens/bytecode.rs @@ -0,0 +1,49 @@ +use crate::*; + + +pub struct Bytecode { + pub words: Vec<Word>, + pub errors: Vec<BytecodeError>, +} + +#[derive(Clone, Copy)] +pub struct Word { + pub bits: usize, + pub value: usize, +} + +impl std::fmt::Display for Word { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + for i in (0..self.bits).rev() { + let is_first_bit = i+1 == self.bits; + if !is_first_bit && (i+1) % 4 == 0 { + write!(f, "_")?; + } + match (self.value >> i) & 1 { + 0 => write!(f, "0")?, + _ => write!(f, "1")?, + } + } + if self.bits == 0 { + write!(f, "0")?; + } + return Ok(()); + } +} + +pub struct BytecodeError { + pub source: SourceSpan, + pub variant: BytecodeErrorVariant, +} + +pub enum BytecodeErrorVariant { + DefinitionNotFound(String), + DuplicateLabelDefinition(String), + /// pin, real + PinnedAddressBacktrack(usize, usize), + /// expected, received + ValueTooLarge(usize, usize), + StackUnderflow, + MultipleReturnValues, + NoReturnValue, +} diff --git a/src/tokens/constant_expression.rs b/src/tokens/constant_expression.rs deleted file mode 100644 index e4aa099..0000000 --- a/src/tokens/constant_expression.rs +++ /dev/null @@ -1,134 +0,0 @@ -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/expression.rs b/src/tokens/expression.rs new file mode 100644 index 0000000..ff2d82d --- /dev/null +++ b/src/tokens/expression.rs @@ -0,0 +1,74 @@ +use crate::*; + + +#[derive(Clone)] +pub struct Expression { + pub source: SourceSpan, + pub tokens: Vec<ExpressionToken>, +} + +#[derive(Clone)] +pub struct ExpressionToken { + pub source: SourceSpan, + pub variant: ExpressionTokenVariant, +} + +#[derive(Clone)] +pub enum ExpressionTokenVariant { + Invocation(String), + Literal(isize), + Operator(Operator), + Error(ExpressionParseError), +} + +#[derive(Clone, Copy, Debug)] +pub enum Operator { + Equal, + NotEqual, + LessThan, + GreaterThan, + Add, + Subtract, + LeftShift, + RightShift, + And, + Or, + Xor, + Not, +} + +#[derive(Clone)] +pub enum ExpressionParseError { + InvalidHexadecimalLiteral(String), +} + +impl std::fmt::Debug for Expression { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + for (i, token) in self.tokens.iter().enumerate() { + let string = match &token.variant { + ExpressionTokenVariant::Invocation(name) => name, + ExpressionTokenVariant::Literal(value) => &value.to_string(), + ExpressionTokenVariant::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 => "~", + } + ExpressionTokenVariant::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 index edb7c19..53ccc6e 100644 --- a/src/tokens/mod.rs +++ b/src/tokens/mod.rs @@ -1,9 +1,19 @@ -pub mod syntactic; +mod expression; +mod packed_binary_literal; +mod tracked_integer; +mod tracked; -pub mod semantic; +pub use expression::*; +pub use packed_binary_literal::*; +pub use tracked_integer::*; +pub use tracked::*; -mod constant_expression; -pub use constant_expression::*; +mod syntactic; +mod semantic; +mod assembler; +mod bytecode; -mod packed_binary_literal; -pub use packed_binary_literal::*; +pub use syntactic::*; +pub use semantic::*; +pub use assembler::*; +pub use bytecode::*; diff --git a/src/tokens/packed_binary_literal.rs b/src/tokens/packed_binary_literal.rs index 1252398..a2720b7 100644 --- a/src/tokens/packed_binary_literal.rs +++ b/src/tokens/packed_binary_literal.rs @@ -2,17 +2,13 @@ use crate::*; pub struct PackedBinaryLiteral { + pub source: SourceSpan, pub value: usize, + pub bits: 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, @@ -40,7 +36,8 @@ impl std::fmt::Display for PackedBinaryLiteral { } else { let bitcount = (self.value.ilog2() + 1) as usize; 'bit: for i in (0..bitcount).rev() { - if (i+1) % 4 == 0 { + let is_first_bit = i+1 == bitcount; + if !is_first_bit && (i+1) % 4 == 0 { write!(f, "_")?; } for field in &self.fields { 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), }; } } diff --git a/src/tokens/syntactic.rs b/src/tokens/syntactic.rs index 162f1c0..eb33806 100644 --- a/src/tokens/syntactic.rs +++ b/src/tokens/syntactic.rs @@ -1,22 +1,21 @@ use crate::*; -pub struct Token { +pub struct SyntacticToken { pub source: SourceSpan, - pub variant: TokenVariant, + pub variant: SyntacticTokenVariant, } -pub enum TokenVariant { +pub enum SyntacticTokenVariant { LabelDefinition(String), MacroDefinition(String), MacroDefinitionTerminator, - DecimalLiteral(usize), - HexadecimalLiteral(usize), + IntegerLiteral(isize), PackedBinaryLiteral(PackedBinaryLiteral), + PinnedAddress(usize), - Comment(String), - ConstantExpression(ConstantExpression), + Expression(Expression), BlockOpen, BlockClose, @@ -24,33 +23,34 @@ pub enum TokenVariant { Symbol(String), - Error(ParseError), + Error(SyntacticParseError), } #[derive(Debug)] -pub enum ParseError { +pub enum SyntacticParseError { InvalidHexadecimalLiteral(String), + InvalidDecimalLiteral(String), InvalidSymbolIdentifier(String), UnterminatedComment, - UnterminatedConstantExpression, + UnterminatedExpression, + LabelInMacroDefinition, } -impl std::fmt::Debug for Token { +impl std::fmt::Debug for SyntacticToken { fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { - use TokenVariant::*; + 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})"), + IntegerLiteral(value) => format!("IntegerLiteral({value})"), PackedBinaryLiteral(pbl) => format!("PackedBinaryLiteral({pbl})"), + PinnedAddress(value) => format!("PinnedAddress({value})"), - Comment(_) => format!("Comment"), - ConstantExpression(expr) => format!("ConstantExpression({expr:?})"), + Expression(expr) => format!("Expression({expr:?})"), BlockOpen => format!("BlockOpen"), BlockClose => format!("BlockClose"), diff --git a/src/tokens/tracked.rs b/src/tokens/tracked.rs new file mode 100644 index 0000000..049c8f8 --- /dev/null +++ b/src/tokens/tracked.rs @@ -0,0 +1,47 @@ +use crate::*; + + +#[derive(Clone)] +pub struct Tracked<T> { + pub source: SourceSpan, + pub value: T, +} + +impl<T> Tracked<T> { + pub fn from(value: T, source: &SourceSpan) -> Self { + Self { source: source.clone(), value } + } +} + +impl<T> std::ops::Deref for Tracked<T> { + type Target = T; + fn deref(&self) -> &T { + &self.value + } +} + +impl<T> std::ops::DerefMut for Tracked<T> { + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} + +impl<T: std::fmt::Display> std::fmt::Display for Tracked<T> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!(f, "{}", self.value) + } +} + +impl<T: std::fmt::Debug> std::fmt::Debug for Tracked<T> { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!(f, "{:?}", self.value) + } +} + +impl<T: PartialEq> PartialEq for Tracked<T> { + fn eq(&self, other: &Tracked<T>) -> bool { + self.value.eq(&other.value) + } +} + +impl<T: Eq> Eq for Tracked<T> {} diff --git a/src/tokens/tracked_integer.rs b/src/tokens/tracked_integer.rs new file mode 100644 index 0000000..fa55f09 --- /dev/null +++ b/src/tokens/tracked_integer.rs @@ -0,0 +1,14 @@ +use crate::*; + + +#[derive(Clone)] +pub struct TrackedInteger { + pub source: SourceSpan, + pub value: isize, +} + +impl std::fmt::Display for TrackedInteger { + fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + write!(f, "{}", self.value) + } +} |