diff --git a/src/chunk.rs b/src/chunk.rs index 5da8f4d..1ac7191 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -3,7 +3,7 @@ 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_RETURN, OP_SUBTRACT, OP_TRUE, OP_NOT, OP_SHL, OP_SHR, OP_LESS, OP_LESS_EQUAL, - OP_GREATER, OP_GREATER_EQUAL, OP_EQUAL, OP_PRINT, OP_POP, OP_DEFINE, OP_GET,OP_DEF_STRING + OP_GREATER, OP_GREATER_EQUAL, OP_EQUAL, OP_PRINT, OP_POP, OP_DEFINE, OP_GET,OP_DEF_STRING, OP_DEF_BOOL }; pub struct Chunk { @@ -75,6 +75,7 @@ impl Chunk { OP_POP => self.simple_inst("POP", offset), OP_DEFINE => self.constant_inst("DEF", offset), OP_DEF_STRING => self.constant_inst("DEFSTR", offset), + OP_DEF_BOOL => self.constant_inst("DEFBOOL", offset), OP_GET => self.constant_inst("GET", offset), _ => { println!("Unknown instruction {}", instruction); @@ -90,12 +91,12 @@ impl Chunk { fn constant_inst(&self, name: &str, offset: usize) -> usize { let constant = self.code[offset + 1]; - print!("{} {} ", name, constant); + print!("{} {}:", name, constant); self.print_value(&self.constants[constant as usize]); offset + 2 } fn print_value(&self, value: &Value) { - println!("{:?}", value); + println!("{}", value); } } diff --git a/src/compiler.rs b/src/compiler.rs index 90a2b03..7611b29 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -4,10 +4,10 @@ use crate::tokens::{Token, TokenType}; use crate::value::Value; use crate::vm::{ OP_ADD, OP_BITAND, OP_BITOR, OP_BITXOR, OP_CONSTANT, OP_DEF_BOOL, OP_DEF_CHAR, OP_DEF_DATE, - OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_MAP, OP_DEF_OBJ, OP_DEF_STRING, OP_DEFINE, - OP_DIVIDE, OP_EQUAL, OP_FALSE, OP_GET, 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, + OP_DEF_F64, OP_DEF_I32, OP_DEF_I64, OP_DEF_LIST, OP_DEF_MAP, OP_DEF_STRUCT, OP_DEF_STRING, + OP_DEFINE, OP_DIVIDE, OP_EQUAL, OP_FALSE, OP_GET, 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 std::collections::HashMap; @@ -70,7 +70,7 @@ impl<'a> Compiler<'a> { fn let_declaration(&mut self) -> anyhow::Result<()> { let index = self.parse_variable("Expect variable name")?; - let mut var_type = None; + let mut declared_type = None; if self.check(TokenType::Colon) { self.consume(TokenType::Colon, "must not happen")?; match self.current_token.token_type { @@ -83,15 +83,16 @@ impl<'a> Compiler<'a> { | TokenType::Char | TokenType::Bool | TokenType::ListType - | TokenType::MapType => var_type = Some(self.current_token.token_type), + | TokenType::MapType => declared_type = Some(self.current_token.token_type), _ => return Err(anyhow!("Invalid type {:?}", self.current_token.token_type)), } self.advance()?; } if self.match_token(TokenType::Equal) { - self.expression(var_type)?; + self.expression(declared_type)?; + let derived_type = Some(&self.previous_token.token_type); self.consume(TokenType::Eol, "Expect end of line")?; - self.define_variable(var_type, index)?; + self.define_variable(declared_type, derived_type, index)?; } else { return Err(anyhow!( "You cannot declare a variable without initializing it." @@ -111,7 +112,12 @@ impl<'a> Compiler<'a> { Ok(index) } - fn define_variable(&mut self, var_type: Option, index: usize) -> anyhow::Result<()> { + fn define_variable( + &mut self, + var_type: Option, + derived_type: Option<&TokenType>, + index: usize, + ) -> anyhow::Result<()> { let def_op = match var_type { Some(TokenType::I32) => OP_DEF_I32, Some(TokenType::I64) => OP_DEF_I64, @@ -123,8 +129,17 @@ impl<'a> Compiler<'a> { Some(TokenType::Bool) => OP_DEF_BOOL, Some(TokenType::ListType) => OP_DEF_LIST, Some(TokenType::MapType) => OP_DEF_MAP, - Some(TokenType::Object) => OP_DEF_OBJ, - _ => OP_DEFINE, + Some(TokenType::Object) => OP_DEF_STRUCT, + _ => match derived_type { + Some(TokenType::Text) => OP_DEF_STRING, + Some(TokenType::Bool) => OP_DEF_BOOL, + Some(TokenType::Char) => OP_DEF_CHAR, + Some(TokenType::F64) => OP_DEF_F64, + Some(TokenType::I64) => OP_DEF_I64, + Some(TokenType::ListType) => OP_DEF_LIST, + Some(TokenType::MapType) => OP_DEF_MAP, + _ => OP_DEFINE, + }, }; self.emit_bytes(def_op, index as u16); @@ -275,17 +290,24 @@ fn number(s: &mut Compiler, expected_type: Option) -> anyhow::Result< TokenType::F32 => Value::U32(number.parse()?), TokenType::F64 => Value::U64(number.parse()?), - _ => {return Err(anyhow!("Invalid type: expected {} value, got {}({})", expected_type, &s.previous_token.token_type, number));} + _ => { + return Err(anyhow!( + "Invalid type: expected {} value, got {}({})", + expected_type, + &s.previous_token.token_type, + number + )); + } } } else { if let TokenType::Number = s.previous_token.token_type { - if number.contains('.'){ + if number.contains('.') { Value::F64(number.parse()?) } else { Value::I64(number.parse()?) } } else { - return Err(anyhow!("I did not think this would happen")) + return Err(anyhow!("I did not think this would happen")); } }; s.emit_constant(value); @@ -293,20 +315,30 @@ fn number(s: &mut Compiler, expected_type: Option) -> anyhow::Result< } fn literal(s: &mut Compiler, expected_type: Option) -> anyhow::Result<()> { + let actual_type = &s.previous_token.token_type; if let Some(expected_type) = expected_type { - if discriminant(&expected_type) != discriminant(&s.previous_token.token_type) { - return Err(anyhow!( - "Cannot assign {:?} to {:?}", - s.previous_token.token_type, - expected_type - )); + match (actual_type, expected_type) { + (TokenType::False, TokenType::Bool) => s.emit_constant(Value::Bool(false)), + (TokenType::True, TokenType::Bool) => s.emit_constant(Value::Bool(true)), + (TokenType::Text, TokenType::String) => { + s.emit_constant(Value::String(s.previous_token.lexeme.clone())) + } + _ => { + return Err(anyhow!( + "Invalid type: expected {} value, got {}({})", + expected_type, + &s.previous_token.token_type, + s.previous_token.lexeme + )); + } + } + } else { + match actual_type { + TokenType::False => s.emit_constant(Value::Bool(false)), + TokenType::True => s.emit_constant(Value::Bool(true)), + TokenType::Text => s.emit_constant(Value::String(s.previous_token.lexeme.clone())), + _ => {} } - } - match s.previous_token.token_type { - TokenType::False => s.emit_constant(Value::Bool(false)), - TokenType::True => s.emit_constant(Value::Bool(true)), - TokenType::Text => s.emit_constant(Value::String(s.previous_token.lexeme.clone())), - _ => {} } Ok(()) } @@ -483,7 +515,7 @@ const PREC_UNARY: usize = 12; const PREC_CALL: usize = 13; const PREC_PRIMARY: usize = 14; -enum ValueType{ +enum ValueType { DateType, BoolType, CharType, @@ -497,4 +529,4 @@ enum ValueType{ StringType, ListType, MapType, -} \ No newline at end of file +} diff --git a/src/main.rs b/src/main.rs index f826fb0..ad924a3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,7 +2,7 @@ fn main() -> anyhow::Result<()> { tracing_subscriber::fmt::init(); let chunk = crudlang::compiler::compile( - r#"let a:bool = 42"#, + r#"let a: string = "koe""#, ); match chunk { Err(e) => { diff --git a/src/value.rs b/src/value.rs index 3d36e00..d379827 100644 --- a/src/value.rs +++ b/src/value.rs @@ -6,6 +6,35 @@ use std::fmt::{write, Display, Formatter}; use std::hash::{Hash, Hasher}; use std::ops::{Add, BitAnd, BitOr, BitXor, Div, Mul, Neg, Not, Shl, Shr, Sub}; +#[derive(Debug, Clone)] +pub struct StructDefinition { + fields: Vec +} + +#[derive(Debug, Clone)] +pub struct Instance { + definition: StructDefinition, + fields: Vec +} + +impl Instance { + pub fn new(definition: StructDefinition) -> Self { + Self { + definition, + fields: Vec::new() + } + } +} + +impl Display for Instance { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + for (i, field) in self.definition.fields.iter().enumerate() { + write!(f, "{}: {}", field, self.fields[i])?; + } + Ok(()) + } +} + #[derive(Debug, Clone)] pub enum Value { U32(u32), @@ -19,9 +48,9 @@ pub enum Value { Bool(bool), Date(DateTime), Enum, - Struct, List(Vec), Map(HashMap), + Struct(Instance), Error(String), Void } @@ -111,7 +140,7 @@ impl Display for Value { &Value::Char(v) => write!(f, "{}", v), &Value::Date(v) => write!(f, "{}", v), &Value::Enum => write!(f, "enum"), - &Value::Struct => write!(f, "struct"), + &Value::Struct(v) => write!(f, "{}", v), &Value::List(v) => write!(f, "{:?}", v), &Value::Map(v) => write!(f, "map"), &Value::Error(v) => write!(f, "{}", v), diff --git a/src/vm.rs b/src/vm.rs index 87e6904..2855380 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -84,8 +84,118 @@ impl Vm { OP_DEF_I32 => { let name = self.read_constant(); let value = self.pop(); - if let Value::I32(v) = value { + if let Value::I32(_) = value { self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected i32, got {:?}", value)); + } + } + OP_DEF_I64 => { + let name = self.read_constant(); + let value = self.pop(); + if let Value::I64(_) = value { + self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected i64, got {:?}", value)); + } + } + OP_DEF_U32 => { + let name = self.read_constant(); + let value = self.pop(); + if let Value::U32(_) = value { + self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected u32, got {:?}", value)); + } + } + OP_DEF_U64 => { + let name = self.read_constant(); + let value = self.pop(); + if let Value::U64(_) = value { + self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected u64, got {:?}", value)); + } + } + OP_DEF_F32 => { + let name = self.read_constant(); + let value = self.pop(); + if let Value::F32(_) = value { + self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected f32, got {:?}", value)); + } + } + OP_DEF_F64 => { + let name = self.read_constant(); + let value = self.pop(); + if let Value::F64(_) = value { + self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected f64, got {:?}", value)); + } + } + OP_DEF_STRING => { + let name = self.read_constant(); + let value = self.pop(); + if let Value::String(_) = &value { + self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected string, got {:?}", value)); + } + } + OP_DEF_CHAR => { + let name = self.read_constant(); + let value = self.pop(); + if let Value::Char(_) = &value { + self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected char, got {:?}", value)); + } + } + OP_DEF_BOOL => { + let name = self.read_constant(); + let value = self.pop(); + if let Value::Bool(_) = &value { + self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected bool, got {:?}", value)); + } + } + OP_DEF_DATE => { + let name = self.read_constant(); + let value = self.pop(); + if let Value::Date(_) = &value { + self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected date, got {:?}", value)); + } + } + OP_DEF_LIST => { + let name = self.read_constant(); + let value = self.pop(); + if let Value::List(_) = &value { + self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected list, got {:?}", value)); + } + } + OP_DEF_MAP => { + let name = self.read_constant(); + let value = self.pop(); + if let Value::Map(_) = &value { + self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected map, got {:?}", value)); + } + } + OP_DEF_STRUCT => { + let name = self.read_constant(); + let value = self.pop(); + if let Value::Struct(_) = &value { + self.local_vars.insert(name, value); + } else { + return Err(anyhow!("Expected object, got {:?}", value)); } } OP_GET => { @@ -170,10 +280,13 @@ pub const OP_GET: u16 = 27; pub const OP_DEF_I32: u16 = 28; pub const OP_DEF_I64: u16 = 29; pub const OP_DEF_U32: u16 = 30; -pub const OP_DEF_DATE: u16 = 31; -pub const OP_DEF_STRING: u16 = 32; -pub const OP_DEF_CHAR: u16 = 33; -pub const OP_DEF_BOOL: u16 = 34; -pub const OP_DEF_LIST: u16 = 35; -pub const OP_DEF_MAP: u16 = 36; -pub const OP_DEF_OBJ: u16 = 37; +pub const OP_DEF_U64: u16 = 31; +pub const OP_DEF_DATE: u16 = 32; +pub const OP_DEF_STRING: u16 = 33; +pub const OP_DEF_CHAR: u16 = 34; +pub const OP_DEF_BOOL: u16 = 35; +pub const OP_DEF_LIST: u16 = 36; +pub const OP_DEF_MAP: u16 = 37; +pub const OP_DEF_STRUCT: u16 = 38; +pub const OP_DEF_F32: u16 = 39; +pub const OP_DEF_F64: u16 = 40;