bitwise ops
This commit is contained in:
parent
aa24a006ce
commit
515b3c1037
9 changed files with 182 additions and 74 deletions
13
src/chunk.rs
13
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<Chunk> {
|
||||
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<ParseFn>,
|
||||
infix: Option<ParseFn>,
|
||||
|
|
@ -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<HashMap<TokenType, Rule>> = 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<HashMap<TokenType, Rule>> = 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;
|
||||
|
|
|
|||
|
|
@ -8,13 +8,13 @@ pub(crate) fn get_keyword(lexeme: &str) -> Option<TokenType> {
|
|||
"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,
|
||||
|
|
|
|||
112
src/lib.rs
112
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<Value> + Copy) {
|
||||
let a = stack.pop();
|
||||
let b = stack.pop();
|
||||
fn binary_op(vm: &mut Vm, op: impl Fn(&Value, &Value) -> anyhow::Result<Value> + 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<Value> {
|
||||
a + b
|
||||
}
|
||||
fn sub(a: &Value, b: &Value) -> anyhow::Result<Value> {
|
||||
a - b
|
||||
}
|
||||
fn mul(a: &Value, b: &Value) -> anyhow::Result<Value> {
|
||||
a * b
|
||||
}
|
||||
fn div(a: &Value, b: &Value) -> anyhow::Result<Value> {
|
||||
a / b
|
||||
fn unary_op(stack: &mut Vm, op: impl Fn(&Value) -> anyhow::Result<Value> + 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<Value> {
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ use crate::{
|
|||
TokenType::{self},
|
||||
},
|
||||
};
|
||||
use crate::tokens::TokenType::BitXor;
|
||||
|
||||
pub fn scan(source: &str) -> Vec<Token> {
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
43
src/value.rs
43
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<Value>),
|
||||
Map(HashMap<Value, Value>),
|
||||
Error(String),
|
||||
}
|
||||
|
||||
impl Into<Value> 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<Value>;
|
||||
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<Value>;
|
||||
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<Value>;
|
||||
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")),
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue