From 7e0a98ffb4c6b7ee50e1dc2e7b67a73924a36cba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 24 Jan 2021 16:32:49 +0100 Subject: Parse a blob statement --- src/compiler.rs | 25 +++++++++++++++++++++++++ src/tokenizer.rs | 10 ++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/compiler.rs b/src/compiler.rs index 70c9a51..9d9deaa 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -787,6 +787,27 @@ impl Compiler { } } + fn blob_statement(&mut self, _block: &mut Block) { + expect!(self, Token::Blob, "Expected blob when declaring a blob"); + let name = if let Token::Identifier(name) = self.eat() { + name + } else { + error!(self, "Expected identifier after 'blob'."); + return; + }; + + expect!(self, Token::LeftBrace, "Expected 'blob' body. AKA '{'."); + + loop { + if matches!(self.peek(), Token::EOF | Token::RightBrace) { break; } + if matches!(self.peek(), Token::Newline) { self.eat(); continue; } + } + + expect!(self, Token::RightBrace, "Expected '}' 'blob' body. AKA '}'."); + + println!("Blob: {}", name); + } + fn statement(&mut self, block: &mut Block) { self.clear_panic(); @@ -820,6 +841,10 @@ impl Compiler { self.assign(&name, block); } + (Token::Blob, Token::Identifier(name), ..) => { + self.blob_statement(block); + } + (Token::If, ..) => { self.if_statment(block); } diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 54712d0..7bd0849 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -24,10 +24,12 @@ pub enum Token { Else, #[token("for")] For, - #[token("in")] - In, - #[token("loop")] - Loop, + // #[token("in")] + // In, + // #[token("loop")] + // Loop, + #[token("blob")] + Blob, // TODO(ed): Remove #[token("print")] -- cgit v1.2.1 From cf42ef9b25361255ad23ae084164303657473608 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Sun, 24 Jan 2021 16:56:26 +0100 Subject: Parse fields for structs as well! --- src/compiler.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/compiler.rs b/src/compiler.rs index 9d9deaa..9fb7e8c 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -1,6 +1,8 @@ use std::path::{Path, PathBuf}; use std::rc::Rc; use std::cell::RefCell; +use std::collections::HashMap; +use std::collections::hash_map::Entry; use crate::error::{Error, ErrorKind}; use crate::tokenizer::{Token, TokenStream}; @@ -164,6 +166,35 @@ impl Frame { } } +#[derive(Debug, Clone)] +struct Blob { + name: String, + + name_to_field: HashMap, + field: Vec, +} + +impl Blob { + pub fn new(name: &str) -> Self { + Self { + name: String::from(name), + name_to_field: HashMap::new(), + field: Vec::new(), + } + } + + pub fn add_field(&mut self, name: &str, ty: Type) -> Result { + let slot = self.field.len(); + let entry = self.name_to_field.entry(String::from(name)); + if matches!(entry, Entry::Occupied(_)) { + return Err(()); + } + entry.or_insert(slot); + self.field.push(ty); + Ok(slot) + } +} + struct Compiler { curr: usize, tokens: TokenStream, @@ -175,6 +206,7 @@ struct Compiler { errors: Vec, blocks: Vec>>, + blobs: Vec, } macro_rules! push_frame { @@ -237,6 +269,7 @@ impl Compiler { errors: vec![], blocks: Vec::new(), + blobs: Vec::new(), } } @@ -798,14 +831,35 @@ impl Compiler { expect!(self, Token::LeftBrace, "Expected 'blob' body. AKA '{'."); + let mut blob = Blob::new(&name); loop { if matches!(self.peek(), Token::EOF | Token::RightBrace) { break; } if matches!(self.peek(), Token::Newline) { self.eat(); continue; } + + let name = if let Token::Identifier(name) = self.eat() { + name + } else { + error!(self, "Expected identifier for field."); + continue; + }; + + expect!(self, Token::Colon, "Expected ':' after field name."); + + let ty = if let Ok(ty) = self.parse_type() { + ty + } else { + error!(self, "Failed to parse blob-field type."); + continue; + }; + + if let Err(_) = blob.add_field(&name, ty) { + error!(self, format!("A field named '{}' is defined twice for '{}'", name, blob.name)); + } } expect!(self, Token::RightBrace, "Expected '}' 'blob' body. AKA '}'."); - println!("Blob: {}", name); + println!("Blob: {:?}", blob); } fn statement(&mut self, block: &mut Block) { -- cgit v1.2.1 From 92075e6bc23d63d62e2d0caf83acbf81ad0ccd99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Thu, 28 Jan 2021 20:16:08 +0100 Subject: Pass blobs all the way --- src/compiler.rs | 52 ++++++++++++++++++++++++++++++++++++---------------- src/lib.rs | 3 +-- src/vm.rs | 13 ++++++++++--- 3 files changed, 47 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/compiler.rs b/src/compiler.rs index 9fb7e8c..2302e76 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -49,6 +49,13 @@ nextable_enum!(Prec { Factor, }); + +#[derive(Debug, Clone)] +pub struct Prog { + pub blocks: Vec>>, + pub blobs: Vec>, +} + #[derive(Debug, Clone)] pub enum Type { Void, @@ -167,11 +174,10 @@ impl Frame { } #[derive(Debug, Clone)] -struct Blob { +pub struct Blob { name: String, - name_to_field: HashMap, - field: Vec, + name_to_field: HashMap, } impl Blob { @@ -179,19 +185,17 @@ impl Blob { Self { name: String::from(name), name_to_field: HashMap::new(), - field: Vec::new(), } } - pub fn add_field(&mut self, name: &str, ty: Type) -> Result { - let slot = self.field.len(); + pub fn add_field(&mut self, name: &str, ty: Type) -> Result<(), ()> { let entry = self.name_to_field.entry(String::from(name)); if matches!(entry, Entry::Occupied(_)) { - return Err(()); + Err(()) + } else { + entry.or_insert(ty); + Ok(()) } - entry.or_insert(slot); - self.field.push(ty); - Ok(slot) } } @@ -508,6 +512,12 @@ impl Compiler { return Self::find_and_capture_variable(name, self.frames.iter_mut().rev()); } + fn find_blob(&self, name: &str) -> Option { + self.blobs.iter().enumerate() + .find(|(_, x)| x.name == name) + .map(|(i, _)| i) + } + fn call(&mut self, block: &mut Block) { expect!(self, Token::LeftParen, "Expected '(' at start of function call."); @@ -634,6 +644,11 @@ impl Compiler { if self.peek() == Token::LeftParen { self.call(block); } + } else if let Some(blob) = self.find_blob(&name) { + // block.add(Op::Blob(blob)); + if self.peek() == Token::LeftParen { + self.call(block); + } } else { error!(self, format!("Using undefined variable {}.", name)); } @@ -857,9 +872,9 @@ impl Compiler { } } - expect!(self, Token::RightBrace, "Expected '}' 'blob' body. AKA '}'."); + expect!(self, Token::RightBrace, "Expected '}' after 'blob' body. AKA '}'."); - println!("Blob: {:?}", blob); + self.blobs.push(blob); } fn statement(&mut self, block: &mut Block) { @@ -895,7 +910,7 @@ impl Compiler { self.assign(&name, block); } - (Token::Blob, Token::Identifier(name), ..) => { + (Token::Blob, Token::Identifier(_), ..) => { self.blob_statement(block); } @@ -932,7 +947,8 @@ impl Compiler { } - pub fn compile(&mut self, name: &str, file: &Path) -> Result>>, Vec> { + pub fn compile(&mut self, name: &str, file: &Path) -> Result> { + println!("=== START COMPILATION ==="); self.stack_mut().push(Variable { name: String::from("/main/"), typ: Type::Void, @@ -956,14 +972,18 @@ impl Compiler { self.blocks.insert(0, Rc::new(RefCell::new(block))); + println!("=== END COMPILATION ==="); if self.errors.is_empty() { - Ok(self.blocks.clone()) + Ok(Prog { + blocks: self.blocks.clone(), + blobs: Vec::new(), + }) } else { Err(self.errors.clone()) } } } -pub fn compile(name: &str, file: &Path, tokens: TokenStream) -> Result>>, Vec> { +pub fn compile(name: &str, file: &Path, tokens: TokenStream) -> Result> { Compiler::new(file, tokens).compile(name, file) } diff --git a/src/lib.rs b/src/lib.rs index e83d11f..8cf9b36 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,4 @@ use std::path::Path; -use std::rc::Rc; pub mod compiler; pub mod tokenizer; @@ -23,7 +22,7 @@ pub fn run(tokens: TokenStream, path: &Path, print: bool) -> Result<(), Vec { let mut vm = vm::VM::new().print_blocks(print).print_ops(print); vm.typecheck(&blocks)?; - if let Err(e) = vm.run(Rc::clone(&blocks[0])) { + if let Err(e) = vm.run(&blocks) { Err(vec![e]) } else { Ok(()) diff --git a/src/vm.rs b/src/vm.rs index 5f7e0e3..cb30704 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -8,6 +8,7 @@ use std::cell::RefCell; use crate::compiler::Type; use crate::error::{Error, ErrorKind}; +use crate::compiler::{Prog, Blob}; macro_rules! error { ( $thing:expr, $kind:expr) => { @@ -276,6 +277,9 @@ pub struct VM { stack: Vec, frames: Vec, + + blobs: Vec>, + print_blocks: bool, print_ops: bool, } @@ -291,6 +295,7 @@ impl VM { upvalues: HashMap::new(), stack: Vec::new(), frames: Vec::new(), + blobs: Vec::new(), print_blocks: false, print_ops: false, } @@ -620,7 +625,9 @@ impl VM { self.frame().block.borrow().ops[self.frame().ip]); } - pub fn run(&mut self, block: Rc>) -> Result<(), Error>{ + pub fn run(&mut self, prog: &Prog) -> Result<(), Error>{ + let block = Rc::clone(&prog.blocks[0]); + self.blobs = prog.blobs.clone(); self.stack.clear(); self.frames.clear(); @@ -834,10 +841,10 @@ impl VM { errors } - pub fn typecheck(&mut self, blocks: &Vec>>) -> Result<(), Vec> { + pub fn typecheck(&mut self, prog: &Prog) -> Result<(), Vec> { let mut errors = Vec::new(); - for block in blocks.iter() { + for block in prog.blocks.iter() { errors.append(&mut self.typecheck_block(Rc::clone(block))); } -- cgit v1.2.1 From b7e480f93f8ea3feb9155df207bb308b11e79303 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Thu, 28 Jan 2021 20:54:24 +0100 Subject: Creating blobs --- src/compiler.rs | 19 ++++++++++++++----- src/error.rs | 4 ++-- src/vm.rs | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 54 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/compiler.rs b/src/compiler.rs index 2302e76..4dd3517 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -65,12 +65,16 @@ pub enum Type { Bool, String, Function(Vec, Box), + Blob(usize), + BlobInstance(usize), } impl PartialEq for Type { fn eq(&self, other: &Self) -> bool { match (self, other) { (Type::Void, Type::Void) => true, + (Type::BlobInstance(a), Type::BlobInstance(b)) => a == b, + (Type::Blob(a), Type::Blob(b)) => a == b, (Type::Int, Type::Int) => true, (Type::Float, Type::Float) => true, (Type::Bool, Type::Bool) => true, @@ -85,6 +89,8 @@ impl PartialEq for Type { impl From<&Value> for Type { fn from(value: &Value) -> Type { match value { + Value::BlobInstance(i, _) => Type::BlobInstance(*i), + Value::Blob(i) => Type::Blob(*i), Value::Int(_) => Type::Int, Value::Float(_) => Type::Float, Value::Bool(_) => Type::Bool, @@ -106,6 +112,8 @@ impl Type { pub fn as_value(&self) -> Value { match self { Type::Void => Value::Nil, + Type::Blob(i) => Value::Blob(*i), + Type::BlobInstance(i) => Value::BlobInstance(*i, Vec::new()), Type::UnknownType => Value::Unkown, Type::Int => Value::Int(1), Type::Float => Value::Float(1.0), @@ -175,9 +183,9 @@ impl Frame { #[derive(Debug, Clone)] pub struct Blob { - name: String, + pub name: String, - name_to_field: HashMap, + pub name_to_field: HashMap, } impl Blob { @@ -189,11 +197,12 @@ impl Blob { } pub fn add_field(&mut self, name: &str, ty: Type) -> Result<(), ()> { + let size = self.name_to_field.len(); let entry = self.name_to_field.entry(String::from(name)); if matches!(entry, Entry::Occupied(_)) { Err(()) } else { - entry.or_insert(ty); + entry.or_insert((size, ty)); Ok(()) } } @@ -645,7 +654,7 @@ impl Compiler { self.call(block); } } else if let Some(blob) = self.find_blob(&name) { - // block.add(Op::Blob(blob)); + block.add(Op::Constant(Value::Blob(blob)), self.line()); if self.peek() == Token::LeftParen { self.call(block); } @@ -976,7 +985,7 @@ impl Compiler { if self.errors.is_empty() { Ok(Prog { blocks: self.blocks.clone(), - blobs: Vec::new(), + blobs: self.blobs.iter().map(|x| Rc::new(x.clone())).collect(), }) } else { Err(self.errors.clone()) diff --git a/src/error.rs b/src/error.rs index 525dbc6..a8ea730 100644 --- a/src/error.rs +++ b/src/error.rs @@ -33,13 +33,13 @@ impl fmt::Display for ErrorKind { ErrorKind::TypeError(op, types) => { let types = types .iter() - .fold(String::new(), |a, v| { format!("{}, {:?}", a, v) }); + .fold(String::new(), |a, v| { format!("{}{:?}, ", a, v) }); write!(f, "{} Cannot apply {:?} to types {}", "Type Error".bold(), op, types) } ErrorKind::RuntimeTypeError(op, values) => { let values = values .iter() - .fold(String::new(), |a, v| { format!("{}, {:?}", a, v) }); + .fold(String::new(), |a, v| { format!("{}{:?}, ", a, v) }); write!(f, "{} Cannot apply {:?} to values {}", "Runtime Type Error".bold(), op, values) } ErrorKind::Assert => { diff --git a/src/vm.rs b/src/vm.rs index cb30704..df970db 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -21,6 +21,8 @@ macro_rules! error { #[derive(Clone)] pub enum Value { + Blob(usize), + BlobInstance(usize, Vec), Float(f64), Int(i64), Bool(bool), @@ -75,6 +77,8 @@ impl UpValue { impl Debug for Value { fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + Value::Blob(i) => write!(fmt, "(blob {})", i), + Value::BlobInstance(i, v) => write!(fmt, "(inst {} {:?})", i, v), Value::Float(f) => write!(fmt, "(float {})", f), Value::Int(i) => write!(fmt, "(int {})", i), Value::Bool(b) => write!(fmt, "(bool {})", b), @@ -98,6 +102,8 @@ impl Value { fn as_type(&self) -> Type { match self { + Value::BlobInstance(i, _) => Type::BlobInstance(*i), + Value::Blob(i) => Type::Blob(*i), Value::Float(_) => Type::Float, Value::Int(_) => Type::Int, Value::Bool(_) => Type::Bool, @@ -557,7 +563,22 @@ impl VM { Op::Call(num_args) => { let new_base = self.stack.len() - 1 - num_args; - match &self.stack[new_base] { + match self.stack[new_base].clone() { + Value::Blob(blob_id) => { + let blob = &self.blobs[blob_id]; + + let mut values = Vec::with_capacity(blob.name_to_field.len()); + for _ in 0..values.capacity() { + values.push(Value::Nil); + } + + for (slot, ty) in blob.name_to_field.values() { + values[*slot] = ty.as_value(); + } + + self.stack.pop(); + self.stack.push(Value::BlobInstance(blob_id, values)); + } Value::Function(_, block) => { let inner = block.borrow(); let args = inner.args(); @@ -751,6 +772,21 @@ impl VM { Op::Call(num_args) => { let new_base = self.stack.len() - 1 - num_args; match self.stack[new_base].clone() { + Value::Blob(blob_id) => { + let blob = &self.blobs[blob_id]; + + let mut values = Vec::with_capacity(blob.name_to_field.len()); + for _ in 0..values.capacity() { + values.push(Value::Nil); + } + + for (slot, ty) in blob.name_to_field.values() { + values[*slot] = ty.as_value(); + } + + self.stack.pop(); + self.stack.push(Value::BlobInstance(blob_id, values)); + } Value::Function(_, block) => { let inner = block.borrow(); let args = inner.args(); @@ -844,6 +880,7 @@ impl VM { pub fn typecheck(&mut self, prog: &Prog) -> Result<(), Vec> { let mut errors = Vec::new(); + self.blobs = prog.blobs.clone(); for block in prog.blocks.iter() { errors.append(&mut self.typecheck_block(Rc::clone(block))); } -- cgit v1.2.1 From fddd4555f7162fb64b1fa1b57282de63d0f4d452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Edvard=20Th=C3=B6rnros?= Date: Thu, 28 Jan 2021 21:10:48 +0100 Subject: Access fields --- src/compiler.rs | 18 ++++++++++++++++-- src/vm.rs | 11 +++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/compiler.rs b/src/compiler.rs index 4dd3517..256ce49 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -650,8 +650,22 @@ impl Compiler { } else { block.add(Op::ReadLocal(var.slot), self.line()); } - if self.peek() == Token::LeftParen { - self.call(block); + loop { + match self.peek() { + Token::Dot => { + self.eat(); + if let Token::Identifier(field) = self.eat() { + block.add(Op::Get(String::from(field)), self.line()); + } else { + error!(self, "Expected fieldname after '.'"); + break; + } + } + Token::LeftParen => { + self.call(block); + } + _ => { break } + } } } else if let Some(blob) = self.find_blob(&name) { block.add(Op::Constant(Value::Blob(blob)), self.line()); diff --git a/src/vm.rs b/src/vm.rs index df970db..028f2cd 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -122,6 +122,7 @@ pub enum Op { Pop, PopUpvalue, Constant(Value), + Get(String), Add, Sub, @@ -415,6 +416,16 @@ impl VM { self.stack.push(value); } + Op::Get(field) => { + let inst = self.stack.pop(); + if let Some(Value::BlobInstance(ty, values)) = inst { + let slot = self.blobs[ty].name_to_field.get(&field).unwrap().0; + self.stack.push(values[slot].clone()); + } else { + error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst.unwrap()])); + } + } + Op::Neg => { match self.stack.pop().unwrap() { Value::Float(a) => self.stack.push(Value::Float(-a)), -- cgit v1.2.1 From 0159d05e183f58ae81d4697e0b178a487f0bde34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Thu, 28 Jan 2021 21:53:21 +0100 Subject: assign (ish) to blob fields --- src/compiler.rs | 49 +++++++++++++++++++++++++++++++++++++++++++++++-- src/vm.rs | 13 +++++++++++++ 2 files changed, 60 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/compiler.rs b/src/compiler.rs index 256ce49..431a762 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -657,7 +657,7 @@ impl Compiler { if let Token::Identifier(field) = self.eat() { block.add(Op::Get(String::from(field)), self.line()); } else { - error!(self, "Expected fieldname after '.'"); + error!(self, "Expected fieldname after '.'."); break; } } @@ -900,6 +900,47 @@ impl Compiler { self.blobs.push(blob); } + fn blob_field(&mut self, block: &mut Block) { + let name = match self.eat() { + Token::Identifier(name) => name, + _ => unreachable!(), + }; + if let Some(var) = self.find_variable(&name) { + if var.upvalue { + block.add(Op::ReadUpvalue(var.slot), self.line()); + } else { + block.add(Op::ReadLocal(var.slot), self.line()); + } + loop { + match self.peek() { + Token::Dot => { + self.eat(); + let field = if let Token::Identifier(field) = self.eat() { + String::from(field) + } else { + error!(self, "Expected fieldname after '.'."); + return; + }; + + if self.peek() == Token::Equal { + self.eat(); + self.expression(block); + block.add(Op::Set(field), self.line()); + } else { + block.add(Op::Get(field), self.line()); + } + } + Token::LeftParen => { + self.call(block); + } + _ => { break } + } + } + } else { + error!(self, format!("Using undefined variable {}.", name)); + } + } + fn statement(&mut self, block: &mut Block) { self.clear_panic(); @@ -908,7 +949,11 @@ impl Compiler { self.eat(); self.expression(block); block.add(Op::Print, self.line()); - }, + } + + (Token::Identifier(_), Token::Dot, ..) => { + self.blob_field(block); + } (Token::Identifier(name), Token::Colon, ..) => { self.eat(); diff --git a/src/vm.rs b/src/vm.rs index 028f2cd..5b0abae 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -122,7 +122,9 @@ pub enum Op { Pop, PopUpvalue, Constant(Value), + Get(String), + Set(String), Add, Sub, @@ -426,6 +428,17 @@ impl VM { } } + Op::Set(field) => { + let value = self.stack.pop().unwrap(); + let inst = self.stack.pop(); + if let Some(Value::BlobInstance(ty, mut values)) = inst { + let slot = self.blobs[ty].name_to_field.get(&field).unwrap().0; + values[slot] = value; + } else { + error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst.unwrap()])); + } + } + Op::Neg => { match self.stack.pop().unwrap() { Value::Float(a) => self.stack.push(Value::Float(-a)), -- cgit v1.2.1 From 904fd111bcd539190cf6bcf10f60c29813c7012b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Thu, 28 Jan 2021 21:56:51 +0100 Subject: assign to blob fields First try babyyyyyyyyy --- src/compiler.rs | 2 +- src/vm.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/compiler.rs b/src/compiler.rs index 431a762..78b2671 100644 --- a/src/compiler.rs +++ b/src/compiler.rs @@ -113,7 +113,7 @@ impl Type { match self { Type::Void => Value::Nil, Type::Blob(i) => Value::Blob(*i), - Type::BlobInstance(i) => Value::BlobInstance(*i, Vec::new()), + Type::BlobInstance(i) => Value::BlobInstance(*i, Rc::new(RefCell::new(Vec::new()))), Type::UnknownType => Value::Unkown, Type::Int => Value::Int(1), Type::Float => Value::Float(1.0), diff --git a/src/vm.rs b/src/vm.rs index 5b0abae..4e501ba 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -22,7 +22,7 @@ macro_rules! error { #[derive(Clone)] pub enum Value { Blob(usize), - BlobInstance(usize, Vec), + BlobInstance(usize, Rc>>), Float(f64), Int(i64), Bool(bool), @@ -422,7 +422,7 @@ impl VM { let inst = self.stack.pop(); if let Some(Value::BlobInstance(ty, values)) = inst { let slot = self.blobs[ty].name_to_field.get(&field).unwrap().0; - self.stack.push(values[slot].clone()); + self.stack.push(values.borrow()[slot].clone()); } else { error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst.unwrap()])); } @@ -431,9 +431,9 @@ impl VM { Op::Set(field) => { let value = self.stack.pop().unwrap(); let inst = self.stack.pop(); - if let Some(Value::BlobInstance(ty, mut values)) = inst { + if let Some(Value::BlobInstance(ty, values)) = inst { let slot = self.blobs[ty].name_to_field.get(&field).unwrap().0; - values[slot] = value; + values.borrow_mut()[slot] = value; } else { error!(self, ErrorKind::RuntimeTypeError(Op::Get(field.clone()), vec![inst.unwrap()])); } @@ -601,7 +601,7 @@ impl VM { } self.stack.pop(); - self.stack.push(Value::BlobInstance(blob_id, values)); + self.stack.push(Value::BlobInstance(blob_id, Rc::new(RefCell::new(values)))); } Value::Function(_, block) => { let inner = block.borrow(); @@ -809,7 +809,7 @@ impl VM { } self.stack.pop(); - self.stack.push(Value::BlobInstance(blob_id, values)); + self.stack.push(Value::BlobInstance(blob_id, Rc::new(RefCell::new(values)))); } Value::Function(_, block) => { let inner = block.borrow(); -- cgit v1.2.1 From 3a987d3dfe0014bed43151874882c5b4f20eb7af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustav=20S=C3=B6rn=C3=A4s?= Date: Thu, 28 Jan 2021 22:05:06 +0100 Subject: blob tests --- src/lib.rs | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 8cf9b36..c190918 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -272,6 +272,31 @@ a() <=> 4 */ ); + test_multiple!( + blob, + simple: "blob A {}", + instantiate: "blob A {} + a := A()", + field: "blob A { a: int }", + field_assign: "blob A { a: int } + a := A() + a.a = 2", + field_get: "blob A { a: int } + a := A() + a.a = 2 + //TODO a.a <=> 2 + 2 <=> a.a", + multiple_fields: "blob A { + a: int + b: int + } + a := A() + a.a = 2 + a.b = 3 + //TODO a.a + a.b <=> 5 + 5 <=> a.a + a.b" + ); + test_file!(scoping, "tests/scoping.tdy"); test_file!(for_, "tests/for.tdy"); } -- cgit v1.2.1