From e56414c2516b575a88c33a61fa8ab64cc4643a9f Mon Sep 17 00:00:00 2001 From: Devin Bidwell Date: Thu, 1 Jan 2026 03:05:21 -0700 Subject: [PATCH] First pass with bitwise --- rust_compiler/libs/compiler/src/v1.rs | 67 ++++++++++++++++++++ rust_compiler/libs/il/src/lib.rs | 21 ++++++- rust_compiler/libs/parser/src/lib.rs | 73 ++++++++++++++++++++-- rust_compiler/libs/parser/src/tree_node.rs | 15 ++++- rust_compiler/libs/tokenizer/src/token.rs | 60 +++++++++++++++--- 5 files changed, 218 insertions(+), 18 deletions(-) diff --git a/rust_compiler/libs/compiler/src/v1.rs b/rust_compiler/libs/compiler/src/v1.rs index d5daaa5..6c5dd43 100644 --- a/rust_compiler/libs/compiler/src/v1.rs +++ b/rust_compiler/libs/compiler/src/v1.rs @@ -525,6 +525,28 @@ impl<'a> Compiler<'a> { temp_name: Some(result_name), })) } + Expression::BitwiseNot(inner_expr) => { + // Compile bitwise NOT using the NOT instruction + let (inner_str, cleanup) = self.compile_operand(*inner_expr, scope)?; + let result_name = self.next_temp_name(); + let result_loc = + scope.add_variable(result_name.clone(), LocationRequest::Temp, None)?; + let result_reg = self.resolve_register(&result_loc)?; + + self.write_instruction( + Instruction::Not(Operand::Register(result_reg), inner_str), + Some(expr.span), + )?; + + if let Some(name) = cleanup { + scope.free_temp(name, None)?; + } + + Ok(Some(CompileLocation { + location: result_loc, + temp_name: Some(result_name), + })) + } Expression::TupleDeclaration(tuple_decl) => { self.expression_tuple_declaration(tuple_decl.node, scope)?; Ok(None) @@ -889,6 +911,32 @@ impl<'a> Compiler<'a> { } (var_loc, None) } + Expression::BitwiseNot(_) => { + // Compile the bitwise NOT expression + let result = self.expression(expr, scope)?; + let var_loc = scope.add_variable( + name_str.clone(), + LocationRequest::Persist, + Some(name_span), + )?; + + if let Some(res) = result { + // Move result from temp to new persistent variable + let result_reg = self.resolve_register(&res.location)?; + self.emit_variable_assignment(&var_loc, Operand::Register(result_reg))?; + + // Free the temp result + if let Some(name) = res.temp_name { + scope.free_temp(name, None)?; + } + } else { + return Err(Error::Unknown( + format!("`{name_str}` bitwise NOT expression did not produce a value"), + Some(name_span), + )); + } + (var_loc, None) + } _ => { return Err(Error::Unknown( format!("`{name_str}` declaration of this type is not supported/implemented."), @@ -2121,6 +2169,7 @@ impl<'a> Compiler<'a> { | BinaryExpression::Divide(l, r) | BinaryExpression::Exponent(l, r) | BinaryExpression::Modulo(l, r) => (fold_expression(l)?, fold_expression(r)?), + _ => return None, }; match expr { @@ -2189,6 +2238,24 @@ impl<'a> Compiler<'a> { BinaryExpression::Modulo(l, r) => { (|into, lhs, rhs| Instruction::Mod(into, lhs, rhs), l, r) } + BinaryExpression::BitwiseAnd(l, r) => { + (|into, lhs, rhs| Instruction::And(into, lhs, rhs), l, r) + } + BinaryExpression::BitwiseOr(l, r) => { + (|into, lhs, rhs| Instruction::Or(into, lhs, rhs), l, r) + } + BinaryExpression::BitwiseXor(l, r) => { + (|into, lhs, rhs| Instruction::Xor(into, lhs, rhs), l, r) + } + BinaryExpression::LeftShift(l, r) => { + (|into, lhs, rhs| Instruction::Sll(into, lhs, rhs), l, r) + } + BinaryExpression::RightShiftArithmetic(l, r) => { + (|into, lhs, rhs| Instruction::Sra(into, lhs, rhs), l, r) + } + BinaryExpression::RightShiftLogical(l, r) => { + (|into, lhs, rhs| Instruction::Srl(into, lhs, rhs), l, r) + } }; let span = Self::merge_spans(left_expr.span, right_expr.span); diff --git a/rust_compiler/libs/il/src/lib.rs b/rust_compiler/libs/il/src/lib.rs index 54aadfb..7a0554d 100644 --- a/rust_compiler/libs/il/src/lib.rs +++ b/rust_compiler/libs/il/src/lib.rs @@ -232,12 +232,22 @@ pub enum Instruction<'a> { /// `sle dst a b` - Set if Less or Equal SetLe(Operand<'a>, Operand<'a>, Operand<'a>), - /// `and dst a b` - Logical AND + /// `and dst a b` - Bitwise AND And(Operand<'a>, Operand<'a>, Operand<'a>), - /// `or dst a b` - Logical OR + /// `or dst a b` - Bitwise OR Or(Operand<'a>, Operand<'a>, Operand<'a>), - /// `xor dst a b` - Logical XOR + /// `xor dst a b` - Bitwise XOR Xor(Operand<'a>, Operand<'a>, Operand<'a>), + /// `nor dst a b` - Bitwise NOR + Nor(Operand<'a>, Operand<'a>, Operand<'a>), + /// `not dst a` - Bitwise NOT + Not(Operand<'a>, Operand<'a>), + /// `sll dst a b` - Logical Left Shift + Sll(Operand<'a>, Operand<'a>, Operand<'a>), + /// `sra dst a b` - Arithmetic Right Shift + Sra(Operand<'a>, Operand<'a>, Operand<'a>), + /// `srl dst a b` - Logical Right Shift + Srl(Operand<'a>, Operand<'a>, Operand<'a>), /// `push val` - Push to Stack Push(Operand<'a>), @@ -338,6 +348,11 @@ impl<'a> fmt::Display for Instruction<'a> { Instruction::And(dst, a, b) => write!(f, "and {} {} {}", dst, a, b), Instruction::Or(dst, a, b) => write!(f, "or {} {} {}", dst, a, b), Instruction::Xor(dst, a, b) => write!(f, "xor {} {} {}", dst, a, b), + Instruction::Nor(dst, a, b) => write!(f, "nor {} {} {}", dst, a, b), + Instruction::Not(dst, a) => write!(f, "not {} {}", dst, a), + Instruction::Sll(dst, a, b) => write!(f, "sll {} {} {}", dst, a, b), + Instruction::Sra(dst, a, b) => write!(f, "sra {} {} {}", dst, a, b), + Instruction::Srl(dst, a, b) => write!(f, "srl {} {} {}", dst, a, b), Instruction::Push(val) => write!(f, "push {}", val), Instruction::Pop(dst) => write!(f, "pop {}", dst), Instruction::Peek(dst) => write!(f, "peek {}", dst), diff --git a/rust_compiler/libs/parser/src/lib.rs b/rust_compiler/libs/parser/src/lib.rs index 2c45cdc..5e67e8d 100644 --- a/rust_compiler/libs/parser/src/lib.rs +++ b/rust_compiler/libs/parser/src/lib.rs @@ -294,12 +294,12 @@ impl<'a> Parser<'a> { // Handle Infix operators (Binary, Logical, Assignment) if self_matches_peek!( self, - TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() || matches!(s, Symbol::Assign | Symbol::Question) + TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() || s.is_bitwise() || matches!(s, Symbol::Assign | Symbol::Question) ) { return Ok(Some(self.infix(lhs)?)); } else if self_matches_current!( self, - TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() || matches!(s, Symbol::Assign | Symbol::Question) + TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() || s.is_bitwise() || matches!(s, Symbol::Assign | Symbol::Question) ) { self.tokenizer.seek(SeekFrom::Current(-1))?; return Ok(Some(self.infix(lhs)?)); @@ -608,6 +608,23 @@ impl<'a> Parser<'a> { }) } + TokenType::Symbol(Symbol::BitwiseNot) => { + let start_span = self.current_span(); + self.assign_next()?; + let inner_expr = self.unary()?.ok_or(Error::UnexpectedEOF)?; + let inner_with_postfix = self.parse_postfix(inner_expr)?; + let combined_span = Span { + start_line: start_span.start_line, + start_col: start_span.start_col, + end_line: inner_with_postfix.span.end_line, + end_col: inner_with_postfix.span.end_col, + }; + Some(Spanned { + span: combined_span, + node: Expression::BitwiseNot(boxed!(inner_with_postfix)), + }) + } + _ => { return Err(Error::UnexpectedToken( self.current_span(), @@ -699,6 +716,20 @@ impl<'a> Parser<'a> { }), } } + TokenType::Symbol(Symbol::BitwiseNot) => { + self.assign_next()?; + let inner = self.get_infix_child_node()?; + let span = Span { + start_line: start_span.start_line, + start_col: start_span.start_col, + end_line: inner.span.end_line, + end_col: inner.span.end_col, + }; + Spanned { + span, + node: Expression::BitwiseNot(boxed!(inner)), + } + } _ => { return Err(Error::UnexpectedToken( self.current_span(), @@ -777,6 +808,7 @@ impl<'a> Parser<'a> { | Expression::Variable(_) | Expression::Ternary(_) | Expression::Negation(_) + | Expression::BitwiseNot(_) | Expression::MemberAccess(_) | Expression::MethodCall(_) | Expression::Tuple(_) => {} @@ -796,7 +828,7 @@ impl<'a> Parser<'a> { // Include Assign in the operator loop while token_matches!( temp_token, - TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() || matches!(s, Symbol::Assign | Symbol::Question | Symbol::Colon) + TokenType::Symbol(s) if s.is_operator() || s.is_comparison() || s.is_logical() || s.is_bitwise() || matches!(s, Symbol::Assign | Symbol::Question | Symbol::Colon) ) { let operator = match temp_token.token_type { TokenType::Symbol(s) => s, @@ -869,6 +901,24 @@ impl<'a> Parser<'a> { Symbol::Minus => { BinaryExpression::Subtract(boxed!(left), boxed!(right)) } + Symbol::LeftShift => { + BinaryExpression::LeftShift(boxed!(left), boxed!(right)) + } + Symbol::RightShiftArithmetic => { + BinaryExpression::RightShiftArithmetic(boxed!(left), boxed!(right)) + } + Symbol::RightShiftLogical => { + BinaryExpression::RightShiftLogical(boxed!(left), boxed!(right)) + } + Symbol::BitwiseAnd => { + BinaryExpression::BitwiseAnd(boxed!(left), boxed!(right)) + } + Symbol::BitwiseOr => { + BinaryExpression::BitwiseOr(boxed!(left), boxed!(right)) + } + Symbol::Caret => { + BinaryExpression::BitwiseXor(boxed!(left), boxed!(right)) + } _ => unreachable!(), }; @@ -895,7 +945,22 @@ impl<'a> Parser<'a> { // --- PRECEDENCE LEVEL 3: Additive (+, -) --- process_binary_ops!(Symbol::Plus | Symbol::Minus, BinaryExpression); - // --- PRECEDENCE LEVEL 4: Comparison (<, >, <=, >=) --- + // --- PRECEDENCE LEVEL 4: Shift Operations (<<, >>, >>>) --- + process_binary_ops!( + Symbol::LeftShift | Symbol::RightShiftArithmetic | Symbol::RightShiftLogical, + BinaryExpression + ); + + // --- PRECEDENCE LEVEL 5: Bitwise AND (&) --- + process_binary_ops!(Symbol::BitwiseAnd, BinaryExpression); + + // --- PRECEDENCE LEVEL 6: Bitwise XOR (^) --- + process_binary_ops!(Symbol::Caret, BinaryExpression); + + // --- PRECEDENCE LEVEL 7: Bitwise OR (|) --- + process_binary_ops!(Symbol::BitwiseOr, BinaryExpression); + + // --- PRECEDENCE LEVEL 8: Comparison (<, >, <=, >=) --- let mut current_iteration = 0; for (i, operator) in operators.iter().enumerate() { if operator.is_comparison() && !matches!(operator, Symbol::Equal | Symbol::NotEqual) { diff --git a/rust_compiler/libs/parser/src/tree_node.rs b/rust_compiler/libs/parser/src/tree_node.rs index 3da1305..18e6bff 100644 --- a/rust_compiler/libs/parser/src/tree_node.rs +++ b/rust_compiler/libs/parser/src/tree_node.rs @@ -45,6 +45,12 @@ pub enum BinaryExpression<'a> { Subtract(Box>>, Box>>), Exponent(Box>>, Box>>), Modulo(Box>>, Box>>), + BitwiseAnd(Box>>, Box>>), + BitwiseOr(Box>>, Box>>), + BitwiseXor(Box>>, Box>>), + LeftShift(Box>>, Box>>), + RightShiftArithmetic(Box>>, Box>>), + RightShiftLogical(Box>>, Box>>), } impl<'a> std::fmt::Display for BinaryExpression<'a> { @@ -56,6 +62,12 @@ impl<'a> std::fmt::Display for BinaryExpression<'a> { BinaryExpression::Subtract(l, r) => write!(f, "({} - {})", l, r), BinaryExpression::Exponent(l, r) => write!(f, "({} ** {})", l, r), BinaryExpression::Modulo(l, r) => write!(f, "({} % {})", l, r), + BinaryExpression::BitwiseAnd(l, r) => write!(f, "({} & {})", l, r), + BinaryExpression::BitwiseOr(l, r) => write!(f, "({} | {})", l, r), + BinaryExpression::BitwiseXor(l, r) => write!(f, "({} ^ {})", l, r), + BinaryExpression::LeftShift(l, r) => write!(f, "({} << {})", l, r), + BinaryExpression::RightShiftArithmetic(l, r) => write!(f, "({} >> {})", l, r), + BinaryExpression::RightShiftLogical(l, r) => write!(f, "({} >>> {})", l, r), } } } @@ -367,6 +379,7 @@ pub enum Expression<'a> { Binary(Spanned>), Block(Spanned>), Break(Span), + BitwiseNot(Box>>), ConstDeclaration(Spanned>), Continue(Span), Declaration(Spanned>, Box>>), @@ -398,6 +411,7 @@ impl<'a> std::fmt::Display for Expression<'a> { Expression::Binary(e) => write!(f, "{}", e), Expression::Block(e) => write!(f, "{}", e), Expression::Break(_) => write!(f, "break"), + Expression::BitwiseNot(e) => write!(f, "(~{})", e), Expression::ConstDeclaration(e) => write!(f, "{}", e), Expression::Continue(_) => write!(f, "continue"), Expression::Declaration(id, e) => write!(f, "(let {} = {})", id, e), @@ -439,4 +453,3 @@ impl<'a> std::fmt::Display for Expression<'a> { } } } - diff --git a/rust_compiler/libs/tokenizer/src/token.rs b/rust_compiler/libs/tokenizer/src/token.rs index 8ca6e21..2290b97 100644 --- a/rust_compiler/libs/tokenizer/src/token.rs +++ b/rust_compiler/libs/tokenizer/src/token.rs @@ -172,6 +172,23 @@ pub enum TokenType<'a> { #[token(";", symbol!(Semicolon))] #[token(":", symbol!(Colon))] #[token(",", symbol!(Comma))] + #[token("?", symbol!(Question))] + #[token(".", symbol!(Dot))] + #[token("%", symbol!(Percent))] + #[token("~", symbol!(BitwiseNot))] + // Multi-character tokens must be defined before their single-character prefixes + // For tokens like >> and >>>, define >>> before >> to ensure correct matching + #[token(">>>", symbol!(RightShiftLogical))] + #[token(">>", symbol!(RightShiftArithmetic))] + #[token("<<", symbol!(LeftShift))] + #[token("==", symbol!(Equal))] + #[token("!=", symbol!(NotEqual))] + #[token("&&", symbol!(LogicalAnd))] + #[token("||", symbol!(LogicalOr))] + #[token("<=", symbol!(LessThanOrEqual))] + #[token(">=", symbol!(GreaterThanOrEqual))] + #[token("**", symbol!(Exp))] + // Single-character tokens #[token("+", symbol!(Plus))] #[token("-", symbol!(Minus))] #[token("*", symbol!(Asterisk))] @@ -180,17 +197,9 @@ pub enum TokenType<'a> { #[token(">", symbol!(GreaterThan))] #[token("=", symbol!(Assign))] #[token("!", symbol!(LogicalNot))] - #[token(".", symbol!(Dot))] #[token("^", symbol!(Caret))] - #[token("%", symbol!(Percent))] - #[token("?", symbol!(Question))] - #[token("==", symbol!(Equal))] - #[token("!=", symbol!(NotEqual))] - #[token("&&", symbol!(LogicalAnd))] - #[token("||", symbol!(LogicalOr))] - #[token("<=", symbol!(LessThanOrEqual))] - #[token(">=", symbol!(GreaterThanOrEqual))] - #[token("**", symbol!(Exp))] + #[token("&", symbol!(BitwiseAnd))] + #[token("|", symbol!(BitwiseOr))] /// Represents a symbol token Symbol(Symbol), @@ -615,6 +624,12 @@ pub enum Symbol { Percent, /// Represents the `?` symbol Question, + /// Represents the `&` symbol (bitwise AND) + BitwiseAnd, + /// Represents the `|` symbol (bitwise OR) + BitwiseOr, + /// Represents the `~` symbol (bitwise NOT) + BitwiseNot, // Double Character Symbols /// Represents the `==` symbol @@ -629,6 +644,12 @@ pub enum Symbol { LessThanOrEqual, /// Represents the `>=` symbol GreaterThanOrEqual, + /// Represents the `<<` symbol (left shift) + LeftShift, + /// Represents the `>>` symbol (arithmetic right shift) + RightShiftArithmetic, + /// Represents the `>>>` symbol (logical right shift) + RightShiftLogical, /// Represents the `**` symbol Exp, } @@ -643,6 +664,19 @@ impl Symbol { | Symbol::Slash | Symbol::Exp | Symbol::Percent + | Symbol::Caret + ) + } + + pub fn is_bitwise(&self) -> bool { + matches!( + self, + Symbol::BitwiseAnd + | Symbol::BitwiseOr + | Symbol::BitwiseNot + | Symbol::LeftShift + | Symbol::RightShiftArithmetic + | Symbol::RightShiftLogical ) } @@ -693,6 +727,12 @@ impl std::fmt::Display for Symbol { Self::NotEqual => write!(f, "!="), Self::Dot => write!(f, "."), Self::Caret => write!(f, "^"), + Self::BitwiseAnd => write!(f, "&"), + Self::BitwiseOr => write!(f, "|"), + Self::BitwiseNot => write!(f, "~"), + Self::LeftShift => write!(f, "<<"), + Self::RightShiftArithmetic => write!(f, ">>"), + Self::RightShiftLogical => write!(f, ">>>"), Self::Exp => write!(f, "**"), } }