From 515b3c1037c21873e5c196e7e5651672701b0a0b Mon Sep 17 00:00:00 2001 From: Shautvast Date: Mon, 20 Oct 2025 10:38:46 +0200 Subject: [PATCH] bitwise ops --- src/chunk.rs | 13 ++++-- src/compiler.rs | 45 +++++++++++++------ src/keywords.rs | 4 +- src/lib.rs | 112 +++++++++++++++++++++++++++++++----------------- src/main.rs | 3 +- src/opcode.rs | 11 +---- src/scanner.rs | 18 ++++++++ src/tokens.rs | 7 ++- src/value.rs | 43 ++++++++++++++++++- 9 files changed, 182 insertions(+), 74 deletions(-) diff --git a/src/chunk.rs b/src/chunk.rs index c40d7b3..956f17f 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -1,5 +1,9 @@ -use crate::opcode::{OP_CONSTANT, OP_RETURN, OP_NEGATE, OP_ADD, OP_SUBTRACT, OP_MULTIPLY, OP_DIVIDE}; +use tracing::debug; use crate::value::Value; +use crate::{ + OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DIVIDE, OP_FALSE, OP_MULTIPLY, + OP_NEGATE, OP_RETURN, OP_SUBTRACT, OP_TRUE, +}; pub struct Chunk { name: String, @@ -34,7 +38,7 @@ impl Chunk { while offset < self.code.len() { offset = self.disassemble_inst(offset); } - println!("== {} ==", self.name); + println!(); } fn disassemble_inst(&self, offset: usize) -> usize { @@ -48,9 +52,12 @@ impl Chunk { match instruction { OP_CONSTANT => self.constant_inst("OP_CONSTANT", offset), OP_ADD => self.simple_inst("OP_ADD", offset), + OP_FALSE => self.simple_inst("OP_FALSE", offset), + OP_TRUE => self.simple_inst("OP_TRUE", offset), OP_SUBTRACT => self.simple_inst("OP_SUBTRACT", offset), OP_MULTIPLY => self.simple_inst("OP_MULTIPLY", offset), OP_DIVIDE => self.simple_inst("OP_DIVIDE", offset), + OP_BITAND => self.simple_inst("OP_BITAND", offset), OP_NEGATE => self.simple_inst("OP_NEGATE", offset), OP_RETURN => self.simple_inst("OP_RETURN", offset), _ => { @@ -67,7 +74,7 @@ impl Chunk { fn constant_inst(&self, name: &str, offset: usize) -> usize { let constant = self.code[offset + 1]; - print!("{} {} ", name, constant); + debug!("{} {} ", name, constant); self.print_value(&self.constants[constant as usize]); offset + 2 } diff --git a/src/compiler.rs b/src/compiler.rs index dfc5f0d..45efce7 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,14 +1,16 @@ use crate::chunk::Chunk; -use crate::opcode::{OP_ADD, OP_CONSTANT, OP_DIVIDE, OP_FALSE, OP_MULTIPLY, OP_NEGATE, OP_RETURN, OP_SUBTRACT, OP_TRUE}; use crate::scanner::scan; use crate::tokens::{Token, TokenType}; use crate::value::Value; +use crate::{OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DIVIDE, OP_FALSE, OP_MULTIPLY, OP_NEGATE, OP_RETURN, OP_SUBTRACT, OP_TRUE}; use anyhow::anyhow; use std::collections::HashMap; use std::sync::LazyLock; +use tracing::debug; pub fn compile(source: &str) -> anyhow::Result { let tokens = scan(source); + // println!("{:?}", tokens); let mut compiler = Compiler { chunk: Chunk::new("main"), @@ -74,8 +76,9 @@ impl<'a> Compiler<'a> { fn parse_precedence(&mut self, precedence: usize) -> anyhow::Result<()> { self.advance()?; - let prefix_rule = get_rule(&self.previous_token.tokentype).prefix; - if let Some(prefix) = prefix_rule { + let rule = get_rule(&self.previous_token.tokentype); + debug!("{:?}",rule); + if let Some(prefix) = rule.prefix { prefix(self)?; while precedence <= get_rule(&self.current_token.tokentype).precedence { self.advance()?; @@ -107,6 +110,7 @@ impl<'a> Compiler<'a> { type ParseFn = fn(&mut Compiler) -> anyhow::Result<()>; +#[derive(Debug)] struct Rule { prefix: Option, infix: Option, @@ -133,11 +137,11 @@ fn number(s: &mut Compiler) -> anyhow::Result<()> { Ok(()) } -fn literal(s: &mut Compiler) -> anyhow::Result<()>{ +fn literal(s: &mut Compiler) -> anyhow::Result<()> { match s.previous_token.tokentype { TokenType::False => s.emit_byte(OP_FALSE), TokenType::True => s.emit_byte(OP_TRUE), - _ =>{} + _ => {} } Ok(()) } @@ -163,6 +167,7 @@ fn unary(s: &mut Compiler) -> anyhow::Result<()> { fn binary(s: &mut Compiler) -> anyhow::Result<()> { let operator_type = &s.previous_token.tokentype; + debug!("{:?}",operator_type); let rule = get_rule(operator_type); s.parse_precedence(rule.precedence + 1)?; match operator_type { @@ -170,12 +175,16 @@ fn binary(s: &mut Compiler) -> anyhow::Result<()> { TokenType::Minus => s.emit_byte(OP_SUBTRACT), TokenType::Star => s.emit_byte(OP_MULTIPLY), TokenType::Slash => s.emit_byte(OP_DIVIDE), + TokenType::BitAnd => s.emit_byte(OP_BITAND), + TokenType::BitOr => s.emit_byte(OP_BITOR), + TokenType::BitXor => s.emit_byte(OP_BITXOR), _ => unimplemented!("binary other than plus, minus, star, slash"), } Ok(()) } fn get_rule(operator_type: &TokenType) -> &'static Rule { + debug!("{:?}", operator_type); RULES.get(operator_type).unwrap() } @@ -211,13 +220,16 @@ static RULES: LazyLock> = LazyLock::new(|| { rules.insert(TokenType::Identifier, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::String, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::Number, Rule::new(Some(number), None, PREC_NONE)); - rules.insert(TokenType::And, Rule::new(None, None, PREC_NONE)); + rules.insert(TokenType::LogicalAnd, Rule::new(None, Some(binary), PREC_AND)); + rules.insert(TokenType::LogicalOr, Rule::new(None, Some(binary), PREC_OR)); + rules.insert(TokenType::BitAnd, Rule::new(None, Some(binary), PREC_BITAND)); + rules.insert(TokenType::BitOr, Rule::new(None, Some(binary), PREC_BITOR)); + rules.insert(TokenType::BitXor, Rule::new(None, Some(binary), PREC_BITXOR)); rules.insert(TokenType::Fn, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::Struct, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::Else, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::False, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::True, Rule::new(None, None, PREC_NONE)); - rules.insert(TokenType::Or, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::While, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::Print, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::Return, Rule::new(None, None, PREC_NONE)); @@ -230,6 +242,7 @@ static RULES: LazyLock> = LazyLock::new(|| { rules.insert(TokenType::StringType, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::False, Rule::new(Some(literal), None, PREC_NONE)); rules.insert(TokenType::True, Rule::new(Some(literal), None, PREC_NONE)); + rules.insert(TokenType::Indent, Rule::new(None, None, PREC_NONE)); rules }); @@ -238,10 +251,14 @@ const PREC_NONE: usize = 0; const PREC_ASSIGNMENT: usize = 1; const PREC_OR: usize = 2; const PREC_AND: usize = 3; -const PREC_EQUALITY: usize = 4; -const PREC_COMPARISON: usize = 5; -const PREC_TERM: usize = 6; -const PREC_FACTOR: usize = 7; -const PREC_UNARY: usize = 8; -const PREC_CALL: usize = 9; -const PREC_PRIMARY: usize = 10; +const PREC_BITAND: usize = 4; +const PREC_BITOR: usize = 5; +const PREC_BITXOR: usize = 6; +const PREC_EQUALITY: usize = 7; +const PREC_COMPARISON: usize = 8; +const PREC_BITSHIFT: usize = 9; +const PREC_TERM: usize = 10; +const PREC_FACTOR: usize = 11; +const PREC_UNARY: usize = 12; +const PREC_CALL: usize = 13; +const PREC_PRIMARY: usize = 14; diff --git a/src/keywords.rs b/src/keywords.rs index 21ee78e..dae20cf 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -8,13 +8,13 @@ pub(crate) fn get_keyword(lexeme: &str) -> Option { "string" => Some(TokenType::StringType), "date" => Some(TokenType::DateType), "print" => Some(TokenType::Print), - "and" => Some(TokenType::And), + "and" => Some(TokenType::LogicalAnd), "else" => Some(TokenType::Else), "false" => Some(TokenType::False), "true" => Some(TokenType::True), "for" => Some(TokenType::For), "if" => Some(TokenType::If), - "or" => Some(TokenType::Or), + "or" => Some(TokenType::LogicalOr), "while" => Some(TokenType::While), _ => None, diff --git a/src/lib.rs b/src/lib.rs index 7136e54..3a85d04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,6 @@ +use anyhow::anyhow; +use tracing::debug; use crate::chunk::Chunk; -use crate::opcode::{ - OP_ADD, OP_CONSTANT, OP_DIVIDE, OP_FALSE, OP_MULTIPLY, OP_NEGATE, OP_RETURN, OP_SUBTRACT, - OP_TRUE, -}; use crate::value::Value; pub mod chunk; @@ -31,11 +29,11 @@ pub struct Vm { impl Vm { fn run(&mut self) -> Result { loop { - print!("["); + debug!("["); for value in self.stack.iter() { - print!("{:?} ", value); + debug!("{:?} ", value); } - println!("]"); + debug!("]"); let opcode = self.chunk.code[self.ip]; self.ip += 1; match opcode { @@ -46,21 +44,32 @@ impl Vm { } OP_FALSE => self.push(Value::Bool(false)), OP_TRUE => self.push(Value::Bool(true)), - OP_ADD => binary_op(self, add), - OP_SUBTRACT => binary_op(self, sub), - OP_MULTIPLY => binary_op(self, mul), - OP_DIVIDE => binary_op(self, div), - OP_NEGATE => { - let value = &self.pop(); - let result = -value; - match result { - Ok(result) => self.push(result), - Err(e) => panic!("Error: {:?} {:?}", e, value), + OP_ADD => binary_op(self, |a, b| a + b), + OP_SUBTRACT => binary_op(self, |a, b| a - b), + OP_MULTIPLY => binary_op(self, |a, b| a * b), + OP_DIVIDE => binary_op(self, |a, b| a / b), + OP_AND => binary_op(self, |a, b| { + if let (Value::Bool(a), Value::Bool(b)) = (a, b) { + Ok(Value::Bool(*a && *b)) + } else { + Err(anyhow!("Cannot and")) } - } + }), + OP_OR => binary_op(self, |a, b| { + if let (Value::Bool(a), Value::Bool(b)) = (a, b) { + Ok(Value::Bool(*a || *b)) + } else { + Err(anyhow!("Cannot compare")) + } + }), + OP_NOT => {} + OP_BITAND => binary_op(self, bitand), + OP_BITOR => binary_op(self, |a, b| a | b), + OP_BITXOR => binary_op(self, |a, b| a ^ b), + OP_NEGATE => unary_op(self, |a| -a), OP_RETURN => { - println!("return {:?}", self.pop()); - return Result::Ok; + // println!("{:?}", self.pop()); + return Result::Ok(self.pop()); } _ => {} } @@ -76,36 +85,61 @@ impl Vm { } fn pop(&mut self) -> Value { - self.stack.pop().unwrap() //? + self.stack.pop().unwrap_or_else(|| Value::Error("Error occurred".to_string())) } } -fn binary_op(stack: &mut Vm, op: impl Fn(&Value, &Value) -> anyhow::Result + Copy) { - let a = stack.pop(); - let b = stack.pop(); +fn binary_op(vm: &mut Vm, op: impl Fn(&Value, &Value) -> anyhow::Result + Copy) { + let a = vm.pop(); + let b = vm.pop(); + let result = op(&a, &b); match result { - Ok(result) => stack.push(result), - Err(e) => panic!("Error: {:?} {:?} and {:?}", e, a, b), + Ok(result) => vm.push(result), + Err(e) => println!("Error: {} {:?} and {:?}", e.to_string(), a, b), } } -fn add(a: &Value, b: &Value) -> anyhow::Result { - a + b -} -fn sub(a: &Value, b: &Value) -> anyhow::Result { - a - b -} -fn mul(a: &Value, b: &Value) -> anyhow::Result { - a * b -} -fn div(a: &Value, b: &Value) -> anyhow::Result { - a / b +fn unary_op(stack: &mut Vm, op: impl Fn(&Value) -> anyhow::Result + Copy) { + let a = stack.pop(); + let result = op(&a); + match result { + Ok(result) => stack.push(result), + Err(e) => panic!("Error: {:?} {:?}", e, a), + } } -#[derive(Debug, PartialEq)] + +fn bitand(a: &Value, b: &Value) -> anyhow::Result { + a& b +} + +#[derive(Debug)] pub enum Result { - Ok, + Ok(Value), CompileError, Error, } + +pub const OP_CONSTANT: u16 = 1; +pub const OP_ADD: u16 = 2; +pub const OP_SUBTRACT: u16 = 3; +pub const OP_MULTIPLY: u16 = 4; +pub const OP_DIVIDE: u16 = 5; +pub const OP_NEGATE: u16 = 6; +pub const OP_PRINT: u16 = 7; +pub const OP_RETURN: u16 = 8; +pub const OP_TRUE: u16 = 9; +pub const OP_FALSE: u16 = 10; +pub const OP_AND: u16 = 11; +pub const OP_OR: u16 = 12; +pub const OP_NOT: u16 = 13; +pub const OP_EQUAL: u16 = 14; +pub const OP_GREATER: u16 = 15; +pub const OP_LESS: u16 = 16; +pub const OP_NOT_EQUAL: u16 = 17; +pub const OP_GREATER_EQUAL: u16 = 18; +pub const OP_LESS_EQUAL: u16 = 19; +pub const OP_BITAND: u16 = 20; +pub const OP_BITOR: u16 = 21; +pub const OP_BITXOR: u16 = 22; diff --git a/src/main.rs b/src/main.rs index ce087e4..c3cf661 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,11 +16,10 @@ fn main() -> anyhow::Result<()> { // chunk.add(crudlang::opcode::OP_ADD, 123); // // chunk.add(crudlang::opcode::OP_RETURN, 123); - let chunk = compile("-true")?; + let chunk = compile("1&3")?; chunk.disassemble(); let result = interpret(chunk); - println!("{:?}",result); Ok(()) } diff --git a/src/opcode.rs b/src/opcode.rs index afaead5..8b13789 100644 --- a/src/opcode.rs +++ b/src/opcode.rs @@ -1,10 +1 @@ -pub const OP_CONSTANT: u16 = 1; -pub const OP_ADD: u16 = 2; -pub const OP_SUBTRACT: u16 = 3; -pub const OP_MULTIPLY: u16 = 4; -pub const OP_DIVIDE: u16 = 5; -pub const OP_NEGATE: u16 = 6; -pub const OP_PRINT: u16 = 7; -pub const OP_RETURN: u16 = 8; -pub const OP_TRUE: u16 = 9; -pub const OP_FALSE: u16 = 10; + diff --git a/src/scanner.rs b/src/scanner.rs index 9a3f0ec..07b6f4d 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -5,6 +5,7 @@ use crate::{ TokenType::{self}, }, }; +use crate::tokens::TokenType::BitXor; pub fn scan(source: &str) -> Vec { let scanner = Scanner { @@ -98,6 +99,23 @@ impl Scanner { self.line += 1; self.new_line = true; } + '&' => { + let t = if self.match_next('&') { + TokenType::LogicalAnd + } else { + TokenType::BitAnd + }; + self.add_token(t); + } + '|' => { + let t = if self.match_next('|') { + TokenType::LogicalOr + } else { + TokenType::BitOr + }; + self.add_token(t); + } + '^' => self.add_token(BitXor), _ => { if is_digit(c) { self.number(); diff --git a/src/tokens.rs b/src/tokens.rs index f2431f6..2cf3e1c 100644 --- a/src/tokens.rs +++ b/src/tokens.rs @@ -49,7 +49,11 @@ pub(crate) enum TokenType { Identifier, String, Number, - And, + LogicalAnd, + LogicalOr, + BitAnd, + BitOr, + BitXor, Fn, Struct, Else, @@ -57,7 +61,6 @@ pub(crate) enum TokenType { True, Null, If, - Or, While, For, Return, diff --git a/src/value.rs b/src/value.rs index 4f770fd..706edb4 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,7 +1,7 @@ use anyhow::anyhow; use chrono::Utc; use std::collections::HashMap; -use std::ops::{Add, Div, Mul, Neg, Sub}; +use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Sub}; #[derive(Debug, Clone)] pub enum Value { @@ -19,6 +19,7 @@ pub enum Value { Struct, List(Vec), Map(HashMap), + Error(String), } impl Into for i32 { @@ -179,8 +180,46 @@ impl Div<&Value> for &Value { (Value::U64(a), Value::U64(b)) => Ok(Value::U64(a / b)), (Value::F32(a), Value::F32(b)) => Ok(Value::F32(a / b)), (Value::F64(a), Value::F64(b)) => Ok(Value::F64(a / b)), - //enum? _ => Err(anyhow!("Cannot divide")), } } } + +impl BitAnd<&Value> for &Value { + type Output = anyhow::Result; + fn bitand(self, rhs: &Value) -> Self::Output { + match (self, rhs) { + (Value::I32(a), Value::I32(b)) => Ok(Value::I32(a & b)), + (Value::I64(a), Value::I64(b)) => Ok(Value::I64(a & b)), + (Value::U32(a), Value::U32(b)) => Ok(Value::U32(a & b)), + (Value::U64(a), Value::U64(b)) => Ok(Value::U64(a & b)), + _ => Err(anyhow!("Cannot do bitwise-and on")), + } + } +} + +impl BitOr<&Value> for &Value { + type Output = anyhow::Result; + fn bitor(self, rhs: &Value) -> Self::Output { + match (self, rhs) { + (Value::I32(a), Value::I32(b)) => Ok(Value::I32(a | b)), + (Value::I64(a), Value::I64(b)) => Ok(Value::I64(a | b)), + (Value::U32(a), Value::U32(b)) => Ok(Value::U32(a | b)), + (Value::U64(a), Value::U64(b)) => Ok(Value::U64(a | b)), + _ => Err(anyhow!("Cannot do bitwise-or on")), + } + } +} + +impl BitXor<&Value> for &Value { + type Output = anyhow::Result; + fn bitxor(self, rhs: &Value) -> Self::Output { + match (self, rhs) { + (Value::I32(a), Value::I32(b)) => Ok(Value::I32(a ^ b)), + (Value::I64(a), Value::I64(b)) => Ok(Value::I64(a ^ b)), + (Value::U32(a), Value::U32(b)) => Ok(Value::U32(a ^ b)), + (Value::U64(a), Value::U64(b)) => Ok(Value::U64(a ^ b)), + _ => Err(anyhow!("Cannot do bitwise-xor on")), + } + } +} \ No newline at end of file