print statements
This commit is contained in:
parent
215ffb298e
commit
6dd22f5e4e
7 changed files with 148 additions and 38 deletions
|
|
@ -3,7 +3,7 @@ use crate::value::Value;
|
||||||
use crate::vm::{
|
use crate::vm::{
|
||||||
OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DIVIDE, OP_FALSE, OP_MULTIPLY,
|
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_NOT, OP_SHL, OP_SHR, OP_LESS, OP_LESS_EQUAL,
|
OP_NEGATE, OP_RETURN, OP_SUBTRACT, OP_TRUE, OP_NOT, OP_SHL, OP_SHR, OP_LESS, OP_LESS_EQUAL,
|
||||||
OP_GREATER, OP_GREATER_EQUAL, OP_EQUAL
|
OP_GREATER, OP_GREATER_EQUAL, OP_EQUAL, OP_PRINT, OP_POP,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Chunk {
|
pub struct Chunk {
|
||||||
|
|
@ -71,6 +71,8 @@ impl Chunk {
|
||||||
OP_GREATER => self.simple_inst("GT", offset),
|
OP_GREATER => self.simple_inst("GT", offset),
|
||||||
OP_GREATER_EQUAL => self.simple_inst("GTE", offset),
|
OP_GREATER_EQUAL => self.simple_inst("GTE", offset),
|
||||||
OP_EQUAL => self.simple_inst("EQ", offset),
|
OP_EQUAL => self.simple_inst("EQ", offset),
|
||||||
|
OP_PRINT => self.simple_inst("PRT", offset),
|
||||||
|
OP_POP => self.simple_inst("POP", offset),
|
||||||
_ => {
|
_ => {
|
||||||
println!("Unknown instruction");
|
println!("Unknown instruction");
|
||||||
offset + 1
|
offset + 1
|
||||||
|
|
@ -85,7 +87,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];
|
||||||
debug!("{} {} ", name, constant);
|
print!("{} {} ", name, constant);
|
||||||
self.print_value(&self.constants[constant as usize]);
|
self.print_value(&self.constants[constant as usize]);
|
||||||
offset + 2
|
offset + 2
|
||||||
}
|
}
|
||||||
|
|
|
||||||
125
src/compiler.rs
125
src/compiler.rs
|
|
@ -2,7 +2,7 @@ use crate::chunk::Chunk;
|
||||||
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::vm::{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, OP_EQUAL, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL};
|
use crate::vm::{OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DIVIDE, OP_EQUAL, OP_FALSE, OP_GREATER, OP_GREATER_EQUAL, OP_LESS, OP_LESS_EQUAL, OP_MULTIPLY, OP_NEGATE, OP_NOT, OP_POP, OP_PRINT, OP_RETURN, OP_SHL, OP_SHR, 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;
|
||||||
|
|
@ -36,12 +36,44 @@ struct Compiler<'a> {
|
||||||
|
|
||||||
impl<'a> Compiler<'a> {
|
impl<'a> Compiler<'a> {
|
||||||
fn compile(mut self) -> anyhow::Result<Chunk> {
|
fn compile(mut self) -> anyhow::Result<Chunk> {
|
||||||
self.expression()?;
|
|
||||||
self.consume(TokenType::Eof, "Expect end of expression.")?;
|
|
||||||
|
while !self.match_token(TokenType::Eof) {
|
||||||
|
self.declaration()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// self.expression()?;
|
||||||
|
|
||||||
|
// self.consume(TokenType::Eof, "Expect end of expression.")?;
|
||||||
self.emit_byte(OP_RETURN);
|
self.emit_byte(OP_RETURN);
|
||||||
Ok(self.chunk)
|
Ok(self.chunk)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn declaration(&mut self) -> anyhow::Result<()> {
|
||||||
|
self.statement()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn statement(&mut self) -> anyhow::Result<()> {
|
||||||
|
if self.match_token(TokenType::Print) {
|
||||||
|
self.print_statement()
|
||||||
|
} else {
|
||||||
|
self.expression_statement()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expression_statement(&mut self) -> anyhow::Result<()>{
|
||||||
|
self.expression()?;
|
||||||
|
self.emit_byte(OP_POP);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_statement(&mut self) -> anyhow::Result<()> {
|
||||||
|
self.expression()?;
|
||||||
|
// self.consume(TokenType::Semicolon, "Expect ';' after value.")?;
|
||||||
|
self.emit_byte(OP_PRINT);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn advance(&mut self) -> anyhow::Result<()> {
|
fn advance(&mut self) -> anyhow::Result<()> {
|
||||||
if self.current < self.tokens.len() - 1 {
|
if self.current < self.tokens.len() - 1 {
|
||||||
self.previous = self.current;
|
self.previous = self.current;
|
||||||
|
|
@ -49,7 +81,7 @@ impl<'a> Compiler<'a> {
|
||||||
self.current += 1;
|
self.current += 1;
|
||||||
self.current_token = &self.tokens[self.current];
|
self.current_token = &self.tokens[self.current];
|
||||||
}
|
}
|
||||||
if let TokenType::Error = self.current_token.tokentype {
|
if let TokenType::Error = self.current_token.token_type {
|
||||||
self.had_error = true;
|
self.had_error = true;
|
||||||
Err(anyhow!(
|
Err(anyhow!(
|
||||||
"Error at {} on line {}",
|
"Error at {} on line {}",
|
||||||
|
|
@ -62,13 +94,26 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn consume(&mut self, token_type: TokenType, message: &str) -> anyhow::Result<()> {
|
fn consume(&mut self, token_type: TokenType, message: &str) -> anyhow::Result<()> {
|
||||||
if token_type == self.current_token.tokentype {
|
if token_type == self.current_token.token_type {
|
||||||
self.advance()
|
self.advance()
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!("{}", message))
|
Err(anyhow!("{}", message))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn match_token(&mut self, token_type: TokenType) -> bool {
|
||||||
|
if !self.check(token_type) {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
self.advance().expect("token expected");
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check(&mut self, token_type: TokenType) -> bool {
|
||||||
|
self.current_token.token_type == token_type
|
||||||
|
}
|
||||||
|
|
||||||
fn expression(&mut self) -> anyhow::Result<()> {
|
fn expression(&mut self) -> anyhow::Result<()> {
|
||||||
self.parse_precedence(PREC_ASSIGNMENT)?;
|
self.parse_precedence(PREC_ASSIGNMENT)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -76,13 +121,13 @@ 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 rule = get_rule(&self.previous_token.tokentype);
|
let rule = get_rule(&self.previous_token.token_type);
|
||||||
debug!("Precedence rule: {:?}", rule);
|
debug!("Precedence rule: {:?}", rule);
|
||||||
if let Some(prefix) = rule.prefix {
|
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.token_type).precedence {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
let infix_rule = get_rule(&self.previous_token.tokentype).infix;
|
let infix_rule = get_rule(&self.previous_token.token_type).infix;
|
||||||
if let Some(infix) = infix_rule {
|
if let Some(infix) = infix_rule {
|
||||||
infix(self)?;
|
infix(self)?;
|
||||||
}
|
}
|
||||||
|
|
@ -128,17 +173,15 @@ impl Rule {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn number(s: &mut Compiler) -> anyhow::Result<()> {
|
fn number(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
let tt = s.previous_token.tokentype;
|
s.emit_constant(match s.previous_token.token_type {
|
||||||
let value = s.previous_token.lexeme.clone();
|
TokenType::Number => Value::F64(s.previous_token.lexeme.parse()?),
|
||||||
s.emit_constant(match tt {
|
|
||||||
TokenType::Number => Value::F64(value.parse().unwrap()),
|
|
||||||
_ => unimplemented!(), // TODO numeric types
|
_ => unimplemented!(), // TODO numeric types
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn literal(s: &mut Compiler) -> anyhow::Result<()> {
|
fn literal(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
match s.previous_token.tokentype {
|
match s.previous_token.token_type {
|
||||||
TokenType::False => s.emit_byte(OP_FALSE),
|
TokenType::False => s.emit_byte(OP_FALSE),
|
||||||
TokenType::True => s.emit_byte(OP_TRUE),
|
TokenType::True => s.emit_byte(OP_TRUE),
|
||||||
TokenType::String => s.emit_constant(Value::String(s.previous_token.lexeme.clone())),
|
TokenType::String => s.emit_constant(Value::String(s.previous_token.lexeme.clone())),
|
||||||
|
|
@ -153,7 +196,7 @@ fn grouping(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unary(s: &mut Compiler) -> anyhow::Result<()> {
|
fn unary(s: &mut Compiler) -> anyhow::Result<()> {
|
||||||
let operator_type = s.previous_token.tokentype;
|
let operator_type = s.previous_token.token_type;
|
||||||
|
|
||||||
s.parse_precedence(PREC_UNARY)?;
|
s.parse_precedence(PREC_UNARY)?;
|
||||||
|
|
||||||
|
|
@ -170,7 +213,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.token_type;
|
||||||
debug!("operator {:?}", operator_type);
|
debug!("operator {:?}", 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)?;
|
||||||
|
|
@ -221,23 +264,53 @@ static RULES: LazyLock<HashMap<TokenType, Rule>> = LazyLock::new(|| {
|
||||||
rules.insert(TokenType::Slash, Rule::new(None, Some(binary), PREC_FACTOR));
|
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::Star, Rule::new(None, Some(binary), PREC_FACTOR));
|
||||||
rules.insert(TokenType::Bang, Rule::new(Some(unary), None, PREC_UNARY));
|
rules.insert(TokenType::Bang, Rule::new(Some(unary), None, PREC_UNARY));
|
||||||
rules.insert(TokenType::BangEqual, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::BangEqual, Rule::new(None, None, PREC_EQUALITY));
|
||||||
rules.insert(TokenType::Equal, Rule::new(None, None, PREC_NONE));
|
rules.insert(TokenType::Equal, Rule::new(None, None, PREC_NONE));
|
||||||
rules.insert(TokenType::EqualEqual, Rule::new(None, Some(binary), PREC_COMPARISON));
|
rules.insert(
|
||||||
rules.insert(TokenType::Greater, Rule::new(None, Some(binary), PREC_COMPARISON));
|
TokenType::EqualEqual,
|
||||||
rules.insert(TokenType::GreaterEqual, Rule::new(None, Some(binary), PREC_COMPARISON));
|
Rule::new(None, Some(binary), PREC_EQUALITY),
|
||||||
rules.insert(TokenType::GreaterGreater, Rule::new(None, Some(binary), PREC_BITSHIFT));
|
);
|
||||||
rules.insert(TokenType::Less, Rule::new(None, Some(binary), PREC_COMPARISON));
|
rules.insert(
|
||||||
rules.insert(TokenType::LessEqual, Rule::new(None, Some(binary), PREC_COMPARISON));
|
TokenType::Greater,
|
||||||
rules.insert(TokenType::LessLess, Rule::new(None, Some(binary), PREC_BITSHIFT));
|
Rule::new(None, Some(binary), PREC_COMPARISON),
|
||||||
|
);
|
||||||
|
rules.insert(
|
||||||
|
TokenType::GreaterEqual,
|
||||||
|
Rule::new(None, Some(binary), PREC_COMPARISON),
|
||||||
|
);
|
||||||
|
rules.insert(
|
||||||
|
TokenType::GreaterGreater,
|
||||||
|
Rule::new(None, Some(binary), PREC_BITSHIFT),
|
||||||
|
);
|
||||||
|
rules.insert(
|
||||||
|
TokenType::Less,
|
||||||
|
Rule::new(None, Some(binary), PREC_COMPARISON),
|
||||||
|
);
|
||||||
|
rules.insert(
|
||||||
|
TokenType::LessEqual,
|
||||||
|
Rule::new(None, Some(binary), PREC_COMPARISON),
|
||||||
|
);
|
||||||
|
rules.insert(
|
||||||
|
TokenType::LessLess,
|
||||||
|
Rule::new(None, Some(binary), PREC_BITSHIFT),
|
||||||
|
);
|
||||||
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(Some(literal), None, PREC_NONE));
|
rules.insert(TokenType::String, Rule::new(Some(literal), 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::LogicalAnd, Rule::new(None, Some(binary), PREC_AND));
|
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::LogicalOr, Rule::new(None, Some(binary), PREC_OR));
|
||||||
rules.insert(TokenType::BitAnd, Rule::new(None, Some(binary), PREC_BITAND));
|
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::BitOr, Rule::new(None, Some(binary), PREC_BITOR));
|
||||||
rules.insert(TokenType::BitXor, Rule::new(None, Some(binary), PREC_BITXOR));
|
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));
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt::init();
|
||||||
|
|
||||||
let chunk = crudlang::compiler::compile("\"1\"+\"2\"")?;
|
let chunk = crudlang::compiler::compile("\"hello \" + 42")?;
|
||||||
chunk.disassemble();
|
chunk.disassemble();
|
||||||
|
|
||||||
let result = crudlang::vm::interpret(chunk);
|
let result = crudlang::vm::interpret(chunk);
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ impl Scanner {
|
||||||
'-' => self.add_token(TokenType::Minus),
|
'-' => self.add_token(TokenType::Minus),
|
||||||
'+' => self.add_token(TokenType::Plus),
|
'+' => self.add_token(TokenType::Plus),
|
||||||
':' => self.add_token(TokenType::Colon),
|
':' => self.add_token(TokenType::Colon),
|
||||||
|
';' => self.add_token(TokenType::Semicolon),
|
||||||
'*' => self.add_token(TokenType::Star),
|
'*' => self.add_token(TokenType::Star),
|
||||||
'!' => {
|
'!' => {
|
||||||
let t = if self.match_next('=') {
|
let t = if self.match_next('=') {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Token {
|
pub struct Token {
|
||||||
pub tokentype: TokenType,
|
pub token_type: TokenType,
|
||||||
pub lexeme: String,
|
pub lexeme: String,
|
||||||
pub line: usize,
|
pub line: usize,
|
||||||
}
|
}
|
||||||
|
|
@ -8,7 +8,7 @@ pub struct Token {
|
||||||
impl Token {
|
impl Token {
|
||||||
pub(crate) fn new(tokentype: TokenType, lexeme: String, line: usize) -> Self {
|
pub(crate) fn new(tokentype: TokenType, lexeme: String, line: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
tokentype,
|
token_type: tokentype,
|
||||||
lexeme,
|
lexeme,
|
||||||
line,
|
line,
|
||||||
}
|
}
|
||||||
|
|
@ -30,6 +30,7 @@ pub(crate) enum TokenType {
|
||||||
LeftBracket,
|
LeftBracket,
|
||||||
RightBracket,
|
RightBracket,
|
||||||
Colon,
|
Colon,
|
||||||
|
Semicolon,
|
||||||
Comma,
|
Comma,
|
||||||
Dot,
|
Dot,
|
||||||
Star,
|
Star,
|
||||||
|
|
|
||||||
25
src/value.rs
25
src/value.rs
|
|
@ -2,6 +2,7 @@ use anyhow::anyhow;
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::fmt::{write, Display, Formatter};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub};
|
use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub};
|
||||||
|
|
||||||
|
|
@ -22,6 +23,7 @@ pub enum Value {
|
||||||
List(Vec<Value>),
|
List(Vec<Value>),
|
||||||
Map(HashMap<Value, Value>),
|
Map(HashMap<Value, Value>),
|
||||||
Error(String),
|
Error(String),
|
||||||
|
Void
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Value> for i32 {
|
impl Into<Value> for i32 {
|
||||||
|
|
@ -95,6 +97,29 @@ impl Into<Value> for HashMap<Value, Value> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Display for Value {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match &self {
|
||||||
|
&Value::U32(v) => write!(f, "{}", v),
|
||||||
|
&Value::U64(v) => write!(f, "{}", v),
|
||||||
|
&Value::String(v) => write!(f, "{}", v),
|
||||||
|
&Value::Bool(v) => write!(f, "{}", v),
|
||||||
|
&Value::I32(v) => write!(f, "{}", v),
|
||||||
|
&Value::I64(v) => write!(f, "{}", v),
|
||||||
|
&Value::F32(v) => write!(f, "{}", v),
|
||||||
|
&Value::F64(v) => write!(f, "{}", v),
|
||||||
|
&Value::Char(v) => write!(f, "{}", v),
|
||||||
|
&Value::Date(v) => write!(f, "{}", v),
|
||||||
|
&Value::Enum => write!(f, "enum"),
|
||||||
|
&Value::Struct => write!(f, "struct"),
|
||||||
|
&Value::List(v) => write!(f, "{:?}", v),
|
||||||
|
&Value::Map(v) => write!(f, "map"),
|
||||||
|
&Value::Error(v) => write!(f, "{}", v),
|
||||||
|
&Value::Void => write!(f, "()"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Neg for &Value {
|
impl Neg for &Value {
|
||||||
type Output = anyhow::Result<Value>;
|
type Output = anyhow::Result<Value>;
|
||||||
|
|
||||||
|
|
|
||||||
14
src/vm.rs
14
src/vm.rs
|
|
@ -1,7 +1,7 @@
|
||||||
use anyhow::anyhow;
|
|
||||||
use tracing::debug;
|
|
||||||
use crate::chunk::Chunk;
|
use crate::chunk::Chunk;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
use anyhow::anyhow;
|
||||||
|
use tracing::debug;
|
||||||
|
|
||||||
pub fn interpret(chunk: Chunk) -> Result {
|
pub fn interpret(chunk: Chunk) -> Result {
|
||||||
let mut vm = Vm {
|
let mut vm = Vm {
|
||||||
|
|
@ -60,8 +60,11 @@ impl Vm {
|
||||||
OP_BITXOR => binary_op(self, |a, b| a ^ b),
|
OP_BITXOR => binary_op(self, |a, b| a ^ b),
|
||||||
OP_NEGATE => unary_op(self, |a| -a),
|
OP_NEGATE => unary_op(self, |a| -a),
|
||||||
OP_RETURN => {
|
OP_RETURN => {
|
||||||
// println!("{:?}", self.pop());
|
return if self.stack.is_empty() {
|
||||||
|
Result::Ok(Value::Void)
|
||||||
|
} else {
|
||||||
return Result::Ok(self.pop());
|
return Result::Ok(self.pop());
|
||||||
|
};
|
||||||
}
|
}
|
||||||
OP_SHL => binary_op(self, |a, b| a << b),
|
OP_SHL => binary_op(self, |a, b| a << b),
|
||||||
OP_SHR => binary_op(self, |a, b| a >> b),
|
OP_SHR => binary_op(self, |a, b| a >> b),
|
||||||
|
|
@ -70,6 +73,10 @@ impl Vm {
|
||||||
OP_GREATER_EQUAL => binary_op(self, |a, b| Ok(Value::Bool(a >= b))),
|
OP_GREATER_EQUAL => binary_op(self, |a, b| Ok(Value::Bool(a >= b))),
|
||||||
OP_LESS => binary_op(self, |a, b| Ok(Value::Bool(a < b))),
|
OP_LESS => binary_op(self, |a, b| Ok(Value::Bool(a < b))),
|
||||||
OP_LESS_EQUAL => binary_op(self, |a, b| Ok(Value::Bool(a <= b))),
|
OP_LESS_EQUAL => binary_op(self, |a, b| Ok(Value::Bool(a <= b))),
|
||||||
|
OP_PRINT => {
|
||||||
|
let v = self.pop();
|
||||||
|
println!("{}", v);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -141,3 +148,4 @@ pub const OP_BITOR: u16 = 21;
|
||||||
pub const OP_BITXOR: u16 = 22;
|
pub const OP_BITXOR: u16 = 22;
|
||||||
pub const OP_SHR: u16 = 23;
|
pub const OP_SHR: u16 = 23;
|
||||||
pub const OP_SHL: u16 = 24;
|
pub const OP_SHL: u16 = 24;
|
||||||
|
pub const OP_POP: u16 = 25;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue