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::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 {
|
pub struct Chunk {
|
||||||
name: String,
|
name: String,
|
||||||
|
|
@ -34,7 +38,7 @@ impl Chunk {
|
||||||
while offset < self.code.len() {
|
while offset < self.code.len() {
|
||||||
offset = self.disassemble_inst(offset);
|
offset = self.disassemble_inst(offset);
|
||||||
}
|
}
|
||||||
println!("== {} ==", self.name);
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn disassemble_inst(&self, offset: usize) -> usize {
|
fn disassemble_inst(&self, offset: usize) -> usize {
|
||||||
|
|
@ -48,9 +52,12 @@ impl Chunk {
|
||||||
match instruction {
|
match instruction {
|
||||||
OP_CONSTANT => self.constant_inst("OP_CONSTANT", offset),
|
OP_CONSTANT => self.constant_inst("OP_CONSTANT", offset),
|
||||||
OP_ADD => self.simple_inst("OP_ADD", 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_SUBTRACT => self.simple_inst("OP_SUBTRACT", offset),
|
||||||
OP_MULTIPLY => self.simple_inst("OP_MULTIPLY", offset),
|
OP_MULTIPLY => self.simple_inst("OP_MULTIPLY", offset),
|
||||||
OP_DIVIDE => self.simple_inst("OP_DIVIDE", 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_NEGATE => self.simple_inst("OP_NEGATE", offset),
|
||||||
OP_RETURN => self.simple_inst("OP_RETURN", offset),
|
OP_RETURN => self.simple_inst("OP_RETURN", offset),
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -67,7 +74,7 @@ impl Chunk {
|
||||||
|
|
||||||
fn constant_inst(&self, name: &str, offset: usize) -> usize {
|
fn constant_inst(&self, name: &str, offset: usize) -> usize {
|
||||||
let constant = self.code[offset + 1];
|
let constant = self.code[offset + 1];
|
||||||
print!("{} {} ", name, constant);
|
debug!("{} {} ", name, constant);
|
||||||
self.print_value(&self.constants[constant as usize]);
|
self.print_value(&self.constants[constant as usize]);
|
||||||
offset + 2
|
offset + 2
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,16 @@
|
||||||
use crate::chunk::Chunk;
|
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::scanner::scan;
|
||||||
use crate::tokens::{Token, TokenType};
|
use crate::tokens::{Token, TokenType};
|
||||||
use crate::value::Value;
|
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 anyhow::anyhow;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
pub fn compile(source: &str) -> anyhow::Result<Chunk> {
|
pub fn compile(source: &str) -> anyhow::Result<Chunk> {
|
||||||
let tokens = scan(source);
|
let tokens = scan(source);
|
||||||
|
// println!("{:?}", tokens);
|
||||||
|
|
||||||
let mut compiler = Compiler {
|
let mut compiler = Compiler {
|
||||||
chunk: Chunk::new("main"),
|
chunk: Chunk::new("main"),
|
||||||
|
|
@ -74,8 +76,9 @@ impl<'a> Compiler<'a> {
|
||||||
|
|
||||||
fn parse_precedence(&mut self, precedence: usize) -> anyhow::Result<()> {
|
fn parse_precedence(&mut self, precedence: usize) -> anyhow::Result<()> {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
let prefix_rule = get_rule(&self.previous_token.tokentype).prefix;
|
let rule = get_rule(&self.previous_token.tokentype);
|
||||||
if let Some(prefix) = prefix_rule {
|
debug!("{:?}",rule);
|
||||||
|
if let Some(prefix) = rule.prefix {
|
||||||
prefix(self)?;
|
prefix(self)?;
|
||||||
while precedence <= get_rule(&self.current_token.tokentype).precedence {
|
while precedence <= get_rule(&self.current_token.tokentype).precedence {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
@ -107,6 +110,7 @@ impl<'a> Compiler<'a> {
|
||||||
|
|
||||||
type ParseFn = fn(&mut Compiler) -> anyhow::Result<()>;
|
type ParseFn = fn(&mut Compiler) -> anyhow::Result<()>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
struct Rule {
|
struct Rule {
|
||||||
prefix: Option<ParseFn>,
|
prefix: Option<ParseFn>,
|
||||||
infix: Option<ParseFn>,
|
infix: Option<ParseFn>,
|
||||||
|
|
@ -163,6 +167,7 @@ fn unary(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
|
|
||||||
fn binary(s: &mut Compiler) -> anyhow::Result<()> {
|
fn binary(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
let operator_type = &s.previous_token.tokentype;
|
let operator_type = &s.previous_token.tokentype;
|
||||||
|
debug!("{:?}",operator_type);
|
||||||
let rule = get_rule(operator_type);
|
let rule = get_rule(operator_type);
|
||||||
s.parse_precedence(rule.precedence + 1)?;
|
s.parse_precedence(rule.precedence + 1)?;
|
||||||
match operator_type {
|
match operator_type {
|
||||||
|
|
@ -170,12 +175,16 @@ fn binary(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
TokenType::Minus => s.emit_byte(OP_SUBTRACT),
|
TokenType::Minus => s.emit_byte(OP_SUBTRACT),
|
||||||
TokenType::Star => s.emit_byte(OP_MULTIPLY),
|
TokenType::Star => s.emit_byte(OP_MULTIPLY),
|
||||||
TokenType::Slash => s.emit_byte(OP_DIVIDE),
|
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"),
|
_ => unimplemented!("binary other than plus, minus, star, slash"),
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_rule(operator_type: &TokenType) -> &'static Rule {
|
fn get_rule(operator_type: &TokenType) -> &'static Rule {
|
||||||
|
debug!("{:?}", operator_type);
|
||||||
RULES.get(operator_type).unwrap()
|
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::Identifier, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::String, 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::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::Fn, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::Struct, 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::Else, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::False, 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::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::While, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::Print, 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));
|
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::StringType, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::False, Rule::new(Some(literal), 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::True, Rule::new(Some(literal), None, PREC_NONE));
|
||||||
|
rules.insert(TokenType::Indent, Rule::new(None, None, PREC_NONE));
|
||||||
|
|
||||||
rules
|
rules
|
||||||
});
|
});
|
||||||
|
|
@ -238,10 +251,14 @@ const PREC_NONE: usize = 0;
|
||||||
const PREC_ASSIGNMENT: usize = 1;
|
const PREC_ASSIGNMENT: usize = 1;
|
||||||
const PREC_OR: usize = 2;
|
const PREC_OR: usize = 2;
|
||||||
const PREC_AND: usize = 3;
|
const PREC_AND: usize = 3;
|
||||||
const PREC_EQUALITY: usize = 4;
|
const PREC_BITAND: usize = 4;
|
||||||
const PREC_COMPARISON: usize = 5;
|
const PREC_BITOR: usize = 5;
|
||||||
const PREC_TERM: usize = 6;
|
const PREC_BITXOR: usize = 6;
|
||||||
const PREC_FACTOR: usize = 7;
|
const PREC_EQUALITY: usize = 7;
|
||||||
const PREC_UNARY: usize = 8;
|
const PREC_COMPARISON: usize = 8;
|
||||||
const PREC_CALL: usize = 9;
|
const PREC_BITSHIFT: usize = 9;
|
||||||
const PREC_PRIMARY: usize = 10;
|
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),
|
"string" => Some(TokenType::StringType),
|
||||||
"date" => Some(TokenType::DateType),
|
"date" => Some(TokenType::DateType),
|
||||||
"print" => Some(TokenType::Print),
|
"print" => Some(TokenType::Print),
|
||||||
"and" => Some(TokenType::And),
|
"and" => Some(TokenType::LogicalAnd),
|
||||||
"else" => Some(TokenType::Else),
|
"else" => Some(TokenType::Else),
|
||||||
"false" => Some(TokenType::False),
|
"false" => Some(TokenType::False),
|
||||||
"true" => Some(TokenType::True),
|
"true" => Some(TokenType::True),
|
||||||
"for" => Some(TokenType::For),
|
"for" => Some(TokenType::For),
|
||||||
"if" => Some(TokenType::If),
|
"if" => Some(TokenType::If),
|
||||||
"or" => Some(TokenType::Or),
|
"or" => Some(TokenType::LogicalOr),
|
||||||
"while" => Some(TokenType::While),
|
"while" => Some(TokenType::While),
|
||||||
|
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
||||||
108
src/lib.rs
108
src/lib.rs
|
|
@ -1,8 +1,6 @@
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use tracing::debug;
|
||||||
use crate::chunk::Chunk;
|
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;
|
use crate::value::Value;
|
||||||
|
|
||||||
pub mod chunk;
|
pub mod chunk;
|
||||||
|
|
@ -31,11 +29,11 @@ pub struct Vm {
|
||||||
impl Vm {
|
impl Vm {
|
||||||
fn run(&mut self) -> Result {
|
fn run(&mut self) -> Result {
|
||||||
loop {
|
loop {
|
||||||
print!("[");
|
debug!("[");
|
||||||
for value in self.stack.iter() {
|
for value in self.stack.iter() {
|
||||||
print!("{:?} ", value);
|
debug!("{:?} ", value);
|
||||||
}
|
}
|
||||||
println!("]");
|
debug!("]");
|
||||||
let opcode = self.chunk.code[self.ip];
|
let opcode = self.chunk.code[self.ip];
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
match opcode {
|
match opcode {
|
||||||
|
|
@ -46,21 +44,32 @@ impl Vm {
|
||||||
}
|
}
|
||||||
OP_FALSE => self.push(Value::Bool(false)),
|
OP_FALSE => self.push(Value::Bool(false)),
|
||||||
OP_TRUE => self.push(Value::Bool(true)),
|
OP_TRUE => self.push(Value::Bool(true)),
|
||||||
OP_ADD => binary_op(self, add),
|
OP_ADD => binary_op(self, |a, b| a + b),
|
||||||
OP_SUBTRACT => binary_op(self, sub),
|
OP_SUBTRACT => binary_op(self, |a, b| a - b),
|
||||||
OP_MULTIPLY => binary_op(self, mul),
|
OP_MULTIPLY => binary_op(self, |a, b| a * b),
|
||||||
OP_DIVIDE => binary_op(self, div),
|
OP_DIVIDE => binary_op(self, |a, b| a / b),
|
||||||
OP_NEGATE => {
|
OP_AND => binary_op(self, |a, b| {
|
||||||
let value = &self.pop();
|
if let (Value::Bool(a), Value::Bool(b)) = (a, b) {
|
||||||
let result = -value;
|
Ok(Value::Bool(*a && *b))
|
||||||
match result {
|
} else {
|
||||||
Ok(result) => self.push(result),
|
Err(anyhow!("Cannot and"))
|
||||||
Err(e) => panic!("Error: {:?} {:?}", e, value),
|
|
||||||
}
|
}
|
||||||
|
}),
|
||||||
|
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 => {
|
OP_RETURN => {
|
||||||
println!("return {:?}", self.pop());
|
// println!("{:?}", self.pop());
|
||||||
return Result::Ok;
|
return Result::Ok(self.pop());
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -76,36 +85,61 @@ impl Vm {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pop(&mut self) -> Value {
|
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) {
|
fn binary_op(vm: &mut Vm, op: impl Fn(&Value, &Value) -> anyhow::Result<Value> + Copy) {
|
||||||
let a = stack.pop();
|
let a = vm.pop();
|
||||||
let b = stack.pop();
|
let b = vm.pop();
|
||||||
|
|
||||||
let result = op(&a, &b);
|
let result = op(&a, &b);
|
||||||
|
match result {
|
||||||
|
Ok(result) => vm.push(result),
|
||||||
|
Err(e) => println!("Error: {} {:?} and {:?}", e.to_string(), 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 {
|
match result {
|
||||||
Ok(result) => stack.push(result),
|
Ok(result) => stack.push(result),
|
||||||
Err(e) => panic!("Error: {:?} {:?} and {:?}", e, a, b),
|
Err(e) => panic!("Error: {:?} {:?}", e, a),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add(a: &Value, b: &Value) -> anyhow::Result<Value> {
|
|
||||||
a + b
|
fn bitand(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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug)]
|
||||||
pub enum Result {
|
pub enum Result {
|
||||||
Ok,
|
Ok(Value),
|
||||||
CompileError,
|
CompileError,
|
||||||
Error,
|
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_ADD, 123);
|
||||||
//
|
//
|
||||||
// chunk.add(crudlang::opcode::OP_RETURN, 123);
|
// chunk.add(crudlang::opcode::OP_RETURN, 123);
|
||||||
let chunk = compile("-true")?;
|
let chunk = compile("1&3")?;
|
||||||
chunk.disassemble();
|
chunk.disassemble();
|
||||||
|
|
||||||
let result = interpret(chunk);
|
let result = interpret(chunk);
|
||||||
println!("{:?}",result);
|
|
||||||
Ok(())
|
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},
|
TokenType::{self},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use crate::tokens::TokenType::BitXor;
|
||||||
|
|
||||||
pub fn scan(source: &str) -> Vec<Token> {
|
pub fn scan(source: &str) -> Vec<Token> {
|
||||||
let scanner = Scanner {
|
let scanner = Scanner {
|
||||||
|
|
@ -98,6 +99,23 @@ impl Scanner {
|
||||||
self.line += 1;
|
self.line += 1;
|
||||||
self.new_line = true;
|
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) {
|
if is_digit(c) {
|
||||||
self.number();
|
self.number();
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,11 @@ pub(crate) enum TokenType {
|
||||||
Identifier,
|
Identifier,
|
||||||
String,
|
String,
|
||||||
Number,
|
Number,
|
||||||
And,
|
LogicalAnd,
|
||||||
|
LogicalOr,
|
||||||
|
BitAnd,
|
||||||
|
BitOr,
|
||||||
|
BitXor,
|
||||||
Fn,
|
Fn,
|
||||||
Struct,
|
Struct,
|
||||||
Else,
|
Else,
|
||||||
|
|
@ -57,7 +61,6 @@ pub(crate) enum TokenType {
|
||||||
True,
|
True,
|
||||||
Null,
|
Null,
|
||||||
If,
|
If,
|
||||||
Or,
|
|
||||||
While,
|
While,
|
||||||
For,
|
For,
|
||||||
Return,
|
Return,
|
||||||
|
|
|
||||||
43
src/value.rs
43
src/value.rs
|
|
@ -1,7 +1,7 @@
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use chrono::Utc;
|
use chrono::Utc;
|
||||||
use std::collections::HashMap;
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
|
|
@ -19,6 +19,7 @@ pub enum Value {
|
||||||
Struct,
|
Struct,
|
||||||
List(Vec<Value>),
|
List(Vec<Value>),
|
||||||
Map(HashMap<Value, Value>),
|
Map(HashMap<Value, Value>),
|
||||||
|
Error(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Value> for i32 {
|
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::U64(a), Value::U64(b)) => Ok(Value::U64(a / b)),
|
||||||
(Value::F32(a), Value::F32(b)) => Ok(Value::F32(a / b)),
|
(Value::F32(a), Value::F32(b)) => Ok(Value::F32(a / b)),
|
||||||
(Value::F64(a), Value::F64(b)) => Ok(Value::F64(a / b)),
|
(Value::F64(a), Value::F64(b)) => Ok(Value::F64(a / b)),
|
||||||
//enum?
|
|
||||||
_ => Err(anyhow!("Cannot divide")),
|
_ => 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