more bitwise ops (shl, shr)

This commit is contained in:
Shautvast 2025-10-20 20:31:48 +02:00
parent 515b3c1037
commit 9d279067ad
7 changed files with 175 additions and 33 deletions

View file

@ -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

View file

@ -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<HashMap<TokenType, Rule>> = 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));

View file

@ -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<Value> + Copy)
}
}
fn bitand(a: &Value, b: &Value) -> anyhow::Result<Value> {
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;

View file

@ -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(())
}

View file

@ -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<Token> {
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]

View file

@ -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,

View file

@ -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<Utc>),
Enum,
Struct,
List(Vec<Value>),
@ -75,7 +77,7 @@ impl Into<Value> for bool {
}
}
impl Into<Value> for Utc {
impl Into<Value> for DateTime<Utc> {
fn into(self) -> Value {
Value::Date(self)
}
@ -223,3 +225,121 @@ impl BitXor<&Value> for &Value {
}
}
}
impl Not for &Value {
type Output = anyhow::Result<Value>;
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<Value>;
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<Value>;
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<Ordering> {
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<H: Hasher>(&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()
// }
// }