From 9d279067ad2ba4c2a8d33a13612f55fa69b859f8 Mon Sep 17 00:00:00 2001 From: Shautvast Date: Mon, 20 Oct 2025 20:31:48 +0200 Subject: [PATCH] more bitwise ops (shl, shr) --- src/chunk.rs | 27 ++++++---- src/compiler.rs | 13 +++-- src/lib.rs | 21 ++++---- src/main.rs | 4 +- src/scanner.rs | 10 ++-- src/tokens.rs | 3 ++ src/value.rs | 130 ++++++++++++++++++++++++++++++++++++++++++++++-- 7 files changed, 175 insertions(+), 33 deletions(-) diff --git a/src/chunk.rs b/src/chunk.rs index 956f17f..f7f87e3 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -2,7 +2,7 @@ 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, + OP_NEGATE, OP_RETURN, OP_SUBTRACT, OP_TRUE, OP_NOT, OP_SHL, OP_SHR }; pub struct Chunk { @@ -50,16 +50,21 @@ impl Chunk { } let instruction = self.code[offset]; 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), + OP_CONSTANT => self.constant_inst("LDC", offset), + OP_ADD => self.simple_inst("ADD", offset), + OP_FALSE => self.simple_inst("LDC_false", offset), + OP_TRUE => self.simple_inst("LDC_true", offset), + OP_SUBTRACT => self.simple_inst("SUB", offset), + OP_MULTIPLY => self.simple_inst("MUL", offset), + OP_DIVIDE => self.simple_inst("DIV", offset), + OP_BITAND => self.simple_inst("BITAND", offset), + OP_BITOR => self.simple_inst("BITOR", offset), + OP_BITXOR => self.simple_inst("BITXOR", offset), + OP_NEGATE => self.simple_inst("NEG", offset), + OP_NOT => self.simple_inst("NOT", offset), + OP_RETURN => self.simple_inst("RET", offset), + OP_SHL => self.simple_inst("SHL", offset), + OP_SHR => self.simple_inst("SHR", offset), _ => { println!("Unknown instruction"); offset + 1 diff --git a/src/compiler.rs b/src/compiler.rs index 45efce7..42a82f4 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -2,7 +2,7 @@ use crate::chunk::Chunk; 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 crate::{OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DIVIDE, OP_FALSE, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_RETURN, OP_SHR, OP_SHL, OP_SUBTRACT, OP_TRUE}; use anyhow::anyhow; use std::collections::HashMap; use std::sync::LazyLock; @@ -160,7 +160,10 @@ fn unary(s: &mut Compiler) -> anyhow::Result<()> { TokenType::Minus => { s.emit_byte(OP_NEGATE); } - _ => unimplemented!("unary other than minus"), + TokenType::Bang => { + s.emit_byte(OP_NOT); + } + _ => unimplemented!("unary other than ! and -"), } Ok(()) } @@ -178,6 +181,8 @@ fn binary(s: &mut Compiler) -> anyhow::Result<()> { TokenType::BitAnd => s.emit_byte(OP_BITAND), TokenType::BitOr => s.emit_byte(OP_BITOR), TokenType::BitXor => s.emit_byte(OP_BITXOR), + TokenType::GreaterGreater => s.emit_byte(OP_SHR), + TokenType::LessLess => s.emit_byte(OP_SHL), _ => unimplemented!("binary other than plus, minus, star, slash"), } Ok(()) @@ -209,14 +214,16 @@ static RULES: LazyLock> = LazyLock::new(|| { rules.insert(TokenType::Colon, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::Slash, Rule::new(None, Some(binary), PREC_FACTOR)); rules.insert(TokenType::Star, Rule::new(None, Some(binary), PREC_FACTOR)); - rules.insert(TokenType::Bang, Rule::new(None, None, PREC_NONE)); + rules.insert(TokenType::Bang, Rule::new(Some(unary), None, PREC_UNARY)); rules.insert(TokenType::BangEqual, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::Equal, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::EqualEqual, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::Greater, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::GreaterEqual, Rule::new(None, None, PREC_NONE)); + rules.insert(TokenType::GreaterGreater, Rule::new(None, Some(binary), PREC_BITSHIFT)); rules.insert(TokenType::Less, Rule::new(None, None, PREC_NONE)); rules.insert(TokenType::LessEqual, Rule::new(None, None, PREC_NONE)); + rules.insert(TokenType::LessLess, Rule::new(None, Some(binary), PREC_BITSHIFT)); 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)); diff --git a/src/lib.rs b/src/lib.rs index 3a85d04..4a16f82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,7 @@ -use anyhow::anyhow; -use tracing::debug; use crate::chunk::Chunk; use crate::value::Value; +use anyhow::anyhow; +use tracing::debug; pub mod chunk; pub mod compiler; @@ -62,8 +62,8 @@ impl Vm { Err(anyhow!("Cannot compare")) } }), - OP_NOT => {} - OP_BITAND => binary_op(self, bitand), + OP_NOT => unary_op(self, |a| !a), + OP_BITAND => binary_op(self, |a, b| a & b), 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), @@ -71,6 +71,8 @@ impl Vm { // println!("{:?}", self.pop()); return Result::Ok(self.pop()); } + OP_SHL => binary_op(self, |a, b| a << b), + OP_SHR => binary_op(self, |a, b| a >> b), _ => {} } } @@ -85,7 +87,9 @@ impl Vm { } fn pop(&mut self) -> Value { - self.stack.pop().unwrap_or_else(|| Value::Error("Error occurred".to_string())) + self.stack + .pop() + .unwrap_or_else(|| Value::Error("Error occurred".to_string())) } } @@ -109,11 +113,6 @@ fn unary_op(stack: &mut Vm, op: impl Fn(&Value) -> anyhow::Result + Copy) } } - -fn bitand(a: &Value, b: &Value) -> anyhow::Result { - a& b -} - #[derive(Debug)] pub enum Result { Ok(Value), @@ -143,3 +142,5 @@ 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; +pub const OP_SHR: u16 = 23; +pub const OP_SHL: u16 = 24; diff --git a/src/main.rs b/src/main.rs index c3cf661..fc512e9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ use crudlang::interpret; // use crudlang::scanner::scan; fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt::init(); // let mut chunk = Chunk::new("main"); // let constant = chunk.add_constant(1.2); // chunk.add(crudlang::opcode::OP_CONSTANT, 123); @@ -16,10 +17,11 @@ fn main() -> anyhow::Result<()> { // chunk.add(crudlang::opcode::OP_ADD, 123); // // chunk.add(crudlang::opcode::OP_RETURN, 123); - let chunk = compile("1&3")?; + let chunk = compile("3<<2")?; chunk.disassemble(); let result = interpret(chunk); + println!("{:?}", result); Ok(()) } diff --git a/src/scanner.rs b/src/scanner.rs index 07b6f4d..5a2c1f4 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -1,3 +1,4 @@ +use crate::tokens::TokenType::BitXor; use crate::{ keywords, tokens::{ @@ -5,7 +6,6 @@ use crate::{ TokenType::{self}, }, }; -use crate::tokens::TokenType::BitXor; pub fn scan(source: &str) -> Vec { let scanner = Scanner { @@ -70,6 +70,8 @@ impl Scanner { '<' => { let t = if self.match_next('=') { TokenType::LessEqual + } else if self.match_next('<') { + TokenType::LessLess } else { TokenType::Less }; @@ -78,6 +80,8 @@ impl Scanner { '>' => { let t = if self.match_next('=') { TokenType::GreaterEqual + } else if self.match_next('>') { + TokenType::GreaterGreater } else { TokenType::Greater }; @@ -176,7 +180,7 @@ impl Scanner { } fn peek(&self) -> char { - if self.current>=self.chars.len(){ + if self.current >= self.chars.len() { '\0' } else { self.chars[self.current] @@ -243,7 +247,7 @@ mod test { use super::*; #[test] - fn test() { + fn test() { let tokens = scan( r#"struct Customer: id: u32, diff --git a/src/tokens.rs b/src/tokens.rs index 2cf3e1c..26eda9b 100644 --- a/src/tokens.rs +++ b/src/tokens.rs @@ -36,6 +36,7 @@ pub(crate) enum TokenType { Slash, Plus, Minus, + Not, Hash, Bang, BangEqual, @@ -44,6 +45,8 @@ pub(crate) enum TokenType { Greater, Less, GreaterEqual, + GreaterGreater, + LessLess, LessEqual, Indent, Identifier, diff --git a/src/value.rs b/src/value.rs index 706edb4..0b56c67 100644 --- a/src/value.rs +++ b/src/value.rs @@ -1,7 +1,9 @@ use anyhow::anyhow; -use chrono::Utc; +use chrono::{DateTime, Utc}; +use std::cmp::Ordering; use std::collections::HashMap; -use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Sub}; +use std::hash::{Hash, Hasher}; +use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub}; #[derive(Debug, Clone)] pub enum Value { @@ -14,7 +16,7 @@ pub enum Value { String(String), Char(char), Bool(bool), - Date(Utc), + Date(DateTime), Enum, Struct, List(Vec), @@ -75,7 +77,7 @@ impl Into for bool { } } -impl Into for Utc { +impl Into for DateTime { fn into(self) -> Value { Value::Date(self) } @@ -222,4 +224,122 @@ impl BitXor<&Value> for &Value { _ => Err(anyhow!("Cannot do bitwise-xor on")), } } -} \ No newline at end of file +} + +impl Not for &Value { + type Output = anyhow::Result; + + fn not(self) -> Self::Output { + match (self) { + Value::Bool(b) => Ok(Value::Bool(!b)), + Value::I32(i32) => Ok(Value::I32(!i32)), + Value::I64(i64) => Ok(Value::I64(!i64)), + Value::U32(u32) => Ok(Value::U32(!u32)), + Value::U64(u64) => Ok(Value::U64(!u64)), + _ => Err(anyhow!("Cannot calculate not")), + } + } +} + +impl Shl<&Value> for &Value { + type Output = anyhow::Result; + fn shl(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 shift left on")), + } + } +} + +impl Shr<&Value> for &Value { + type Output = anyhow::Result; + fn shr(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 shift right on")), + } + } +} + +impl PartialEq for Value { + fn eq(&self, rhs: &Self) -> bool { + match (self, rhs) { + (Value::I32(a), Value::I32(b)) => a == b, + (Value::I64(a), Value::I64(b)) => a == b, + (Value::U32(a), Value::U32(b)) => a == b, + (Value::U64(a), Value::U64(b)) => a == b, + (Value::F32(a), Value::F32(b)) => a == b, + (Value::F64(a), Value::F64(b)) => a == b, + (Value::Bool(a), Value::Bool(b)) => a == b, + (Value::String(a), Value::String(b)) => a == b, + (Value::Char(a), Value::Char(b)) => a == b, + (Value::Date(a), Value::Date(b)) => a == b, + (Value::List(a), Value::List(b)) => a == b, + (Value::Map(a), Value::Map(b)) => { + let mut equal = true; + for (k, v) in a.iter() { + if !b.contains_key(k) || b.get(k).unwrap() != v { //safe unwrap + equal = false; + break; + } + } + equal + } + // struct? + _ => false, //? + } + } +} + +impl Eq for Value {} + +impl PartialOrd for Value { + fn partial_cmp(&self, rhs: &Self) -> Option { + match (self, rhs) { + (Value::I32(a), Value::I32(b)) => Some(a.partial_cmp(b)?), + (Value::I64(a), Value::I64(b)) => Some(a.partial_cmp(b)?), + (Value::U32(a), Value::U32(b)) => Some(a.partial_cmp(b)?), + (Value::U64(a), Value::U64(b)) =>Some(a.partial_cmp(b)?), + (Value::F32(a), Value::F32(b)) =>Some(a.partial_cmp(b)?), + (Value::F64(a), Value::F64(b)) => Some(a.partial_cmp(b)?), + (Value::String(a), Value::String(b)) => Some(a.partial_cmp(b)?), + (Value::Char(a), Value::Char(b)) => Some(a.partial_cmp(b)?), + (Value::Date(a), Value::Date(b)) => Some(a.partial_cmp(b)?), + _ => None, + } + } +} + +impl Hash for Value{ + fn hash(&self, state: &mut H) { + std::mem::discriminant(self).hash(state); + + // Then hash the fields + match self { + Value::I32(i32) => i32.hash(state), + Value::I64(i64) => i64.hash(state), + Value::U32(u32) => u32.hash(state), + Value::U64(u64) => u64.hash(state), + Value::F32(f32) => f32.to_bits().hash(state), + Value::F64(f64) => f64.to_bits().hash(state), + Value::String(s) => s.hash(state), + Value::Char(c) => c.hash(state), + Value::Bool(b) => b.hash(state), + Value::Date(d) => d.hash(state), + Value::List(l) => l.hash(state), + _ => {} + } + } +} + +// impl Ord for Value { +// fn cmp(&self, rhs: &Self) -> Ordering { +// self.partial_cmp(rhs).unwrap() +// } +// }