more bitwise ops (shl, shr)
This commit is contained in:
parent
515b3c1037
commit
9d279067ad
7 changed files with 175 additions and 33 deletions
27
src/chunk.rs
27
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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
21
src/lib.rs
21
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<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;
|
||||
|
|
|
|||
|
|
@ -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(())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
@ -243,7 +247,7 @@ mod test {
|
|||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test() {
|
||||
fn test() {
|
||||
let tokens = scan(
|
||||
r#"struct Customer:
|
||||
id: u32,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
130
src/value.rs
130
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<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)
|
||||
}
|
||||
|
|
@ -222,4 +224,122 @@ impl BitXor<&Value> for &Value {
|
|||
_ => Err(anyhow!("Cannot do bitwise-xor on")),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
// }
|
||||
// }
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue