├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md ├── examples ├── atto.rs └── mini.rs └── src ├── compiler ├── compiler.rs └── mod.rs ├── ir ├── builder.rs ├── ir.rs ├── mod.rs └── types.rs ├── lib.rs └── vm ├── chunk.rs ├── disassembler.rs ├── gc ├── mod.rs ├── tag.rs └── trace.rs ├── interop.rs ├── mod.rs ├── value ├── mod.rs ├── object.rs └── value.rs └── vm.rs /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | flamegraph.html 10 | 11 | # These are backup files generated by rustfmt 12 | **/*.rs.bk 13 | 14 | 15 | #Added by cargo 16 | # 17 | #already existing elements were commented out 18 | 19 | /target 20 | #Cargo.lock 21 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "zubbers" 3 | version = "0.0.1" 4 | authors = ["nilq ", "sawcce "] 5 | edition = "2018" 6 | homepage = "https://github.com/sawcce/zubbers" 7 | repository = "https://github.com/sawcce/zubbers" 8 | readme = "README.md" 9 | license = "MIT" 10 | description = "A fast, stack-based virtual machine for dynamic languages, with an intuitive IR-builder, garbage collection and NaN-tagging." 11 | 12 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 13 | 14 | [dependencies] 15 | hashbrown = "0.7.2" 16 | fnv = "1.0.3" 17 | colored = "1.9.3" 18 | flame = "0.2.2" 19 | flamer = "0.3" 20 | im-rc = "14.3.0" 21 | 22 | [dev-dependencies] 23 | logos = "0.11.4" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Niels Horn 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Zub VM 2 | > A super-fast, stack-based virtual machine for dynamic languages 3 | 4 | # Warning 5 | This library has recently been forked and is being reworked on to add new features, don't expect a lot of stuff to be stable. 6 | 7 | ## Features 8 | 9 | - NaN-tagging value representation 10 | - Mark n' sweep garbage collection 11 | - Compact bytecode format 12 | - Easy-to-use intermediate representation 13 | 14 | ## Milestones 15 | 16 | - [x] Refined VM based on work by [Mr Briones](https://github.com/cwbriones) 17 | - [x] Tracing garbage collector 18 | - [x] High-level IR 19 | - [x] Compilation of IR 20 | - [ ] Optimizer (currently 80-90% Python speed, aiming for much faster) 21 | - [x] Profiler and disassembler 22 | 23 | ## Example 24 | 25 | ### Building IR is easy 26 | 27 | Getting your backend up and running shouldn't have to be hard. 28 | 29 | The following code builds IR for evaluating `sum = 20.0 + 30.0`: 30 | 31 | ```rust 32 | let mut builder = IrBuilder::new(); 33 | 34 | let a = builder.number(20.0); 35 | let b = builder.number(30.0); 36 | 37 | let sum = builder.binary(a, BinaryOp::Add, b); 38 | 39 | builder.bind(Binding::global("sum"), sum); 40 | ``` 41 | 42 | When you feel like the IR is looking smooth. Simply let VM throw it through the compiler, and run it. 43 | 44 | ```rust 45 | let mut vm = VM::new(); 46 | vm.exec(&builder.build()); 47 | ``` 48 | 49 | ## Languages 50 | 51 | ### Hugorm 52 | 53 | Hugorm is a dynamic, python-like language being built for small data science and game projects. 54 | 55 | [https://github.com/nilq/hugorm](https://github.com/nilq/Hugorm) 56 | 57 | ### Examples 58 | 59 | The `examples/` folder includes two small language implementations running on the ZubVM. 60 | 61 | #### Atto 62 | 63 | Atto is a functional, minimal language that showcases how little code is needed to implement a working, Turing-complete language. The syntax can be seen in the following teaser: 64 | 65 | ```hs 66 | fn sum x is 67 | if = x 0 68 | 1 69 | + sum - x 1 sum - x 1 70 | 71 | fn main is 72 | sum 12 73 | ``` 74 | 75 | #### Mini 76 | 77 | Mini is a simple language that looks basically like a mix of Rust and JavaScript. It covers a bit wider set of features than Atto. This does show in the size of the language though. 78 | 79 | ```rust 80 | let bar = 13.37; 81 | 82 | fn foo() { 83 | fn baz(c) { 84 | return c + bar; 85 | } 86 | 87 | return baz(10); 88 | } 89 | 90 | global gangster = foo(); 91 | ``` 92 | 93 | 94 | ## Special thanks 95 | 96 | - [zesterer](https://github.com/zesterer) 97 | - [cwbriones](https://github.com/cwbriones) 98 | - [evolbug](https://github.com/evolbug) 99 | -------------------------------------------------------------------------------- /examples/atto.rs: -------------------------------------------------------------------------------- 1 | use zubbers::{ir::*, vm::*}; 2 | 3 | fn parse_expr( 4 | builder: &mut IrBuilder, 5 | slice: &mut &[&str], 6 | get_binding: &impl Fn(&str) -> Option<(Binding, usize)>, 7 | ) -> Option> { 8 | match *slice { 9 | [] => None, 10 | [ident, ..] => { 11 | *slice = &slice[1..]; 12 | if *ident == "if" { 13 | let cond = parse_expr(builder, slice, get_binding)?; 14 | let a = parse_expr(builder, slice, get_binding)?; 15 | let b = parse_expr(builder, slice, get_binding)?; 16 | Some(builder.ternary(cond, a, Some(b))) 17 | } else if let Some(op) = match *ident { 18 | "+" => Some(BinaryOp::Add), 19 | "-" => Some(BinaryOp::Sub), 20 | "*" => Some(BinaryOp::Mul), 21 | "/" => Some(BinaryOp::Div), 22 | //"%" => Some(BinaryOp::Rem), 23 | "=" => Some(BinaryOp::Equal), 24 | ">" => Some(BinaryOp::Gt), 25 | "<" => Some(BinaryOp::Lt), 26 | ">=" => Some(BinaryOp::GtEqual), 27 | "<=" => Some(BinaryOp::LtEqual), 28 | "&" => Some(BinaryOp::And), 29 | "|" => Some(BinaryOp::Or), 30 | _ => None, 31 | } { 32 | let a = parse_expr(builder, slice, get_binding)?; 33 | let b = parse_expr(builder, slice, get_binding)?; 34 | Some(builder.binary(a, op, b)) 35 | } else if let Ok(n) = ident.parse() { 36 | Some(builder.number(n)) 37 | } else if let Some(val) = match *ident { 38 | "true" => Some(builder.bool(true)), 39 | "false" => Some(builder.bool(false)), 40 | //"null" => Some(builder.nil()), 41 | _ => None, 42 | } { 43 | Some(val) 44 | } else if let Some((binding, args)) = get_binding(ident) { 45 | let args = (0..args).map(|_| parse_expr(builder, slice, get_binding)).collect::>()?; 46 | 47 | let mut inner_binding = binding.clone(); 48 | 49 | if inner_binding.depth == Some(0) { 50 | inner_binding.depth = Some(binding.depth.unwrap_or(0) + 1); 51 | } else if inner_binding.name() == "sum" { 52 | 53 | inner_binding.function_depth = 0; // Atto needs to be able to tell where the variable we're referencing is. If the depth and function depth is equal, we're in the same scope as the variable. 54 | // This specifically shouldn't be the case for upvalues. `sum` should be @ depth 1, func_depth 1 55 | // For the parameter `x` is at depth 1, func_depth 1 56 | // So just to make it work right now ... 57 | // if sum { let's go with upvalue ... limiting param names for now } 58 | } 59 | 60 | Some(builder.call( 61 | builder.var(inner_binding), 62 | args, 63 | None, 64 | )) 65 | } else { 66 | None 67 | } 68 | }, 69 | } 70 | } 71 | 72 | fn parse_fn<'a>( 73 | builder: &mut IrBuilder, 74 | slice: &mut &'a [&'a str], 75 | get_binding: &impl Fn(&str) -> Option, 76 | ) -> Option<(&'a str, usize)> { 77 | match *slice { 78 | [] => None, 79 | ["fn", name, ..] => { 80 | let params = slice[2..] 81 | .into_iter() 82 | .take_while(|token| **token != "is") 83 | .copied() 84 | .collect::>(); 85 | 86 | *slice = &slice[3 + params.len()..]; 87 | 88 | let func = builder.function( 89 | Binding::local(*name, 0, 0), 90 | ¶ms, 91 | |builder| { 92 | let body = parse_expr(builder, slice, &|ident| if ident == *name { 93 | Some((Binding::local(ident, 1, 0), params.len())) 94 | } else if params.contains(&&ident) { 95 | Some((Binding::local(ident, 1, 1), 0)) 96 | } else { 97 | get_binding(ident) 98 | .map(|args| (Binding::local(ident, 1, 1), args)) 99 | }); 100 | 101 | builder.ret(Some(body.unwrap())); 102 | }, 103 | ); 104 | 105 | builder.emit(func); 106 | 107 | Some((*name, params.len())) 108 | }, 109 | _ => panic!("Not a function: {:?}", slice), 110 | } 111 | } 112 | 113 | const CODE: &'static str = r#" 114 | fn sum x is 115 | if = x 0 116 | 1 117 | + sum - x 1 sum - x 1 118 | 119 | fn main is 120 | sum 12 121 | "#; 122 | 123 | fn main() { 124 | let tokens = CODE.split_whitespace().collect::>(); 125 | 126 | let mut builder = IrBuilder::new(); 127 | let mut fns = Vec::<(&str, usize)>::new(); 128 | let mut token_slice = &tokens[..]; 129 | 130 | while let Some((name, args)) = parse_fn(&mut builder, &mut token_slice, &|ident| { 131 | fns.iter().rev().find(|f| f.0 == ident).map(|f| f.1) 132 | }) { 133 | fns.push((name, args)); 134 | } 135 | 136 | let main_var = builder.var(Binding::local("main", 0, 0)); 137 | let main_call = builder.call(main_var, vec![], None); 138 | 139 | builder.bind(Binding::global("entry"), main_call); 140 | 141 | let build = builder.build(); 142 | 143 | let mut vm = VM::new(); 144 | 145 | vm.exec(&build, false); 146 | println!("{:?}", vm.globals["entry"]); 147 | } 148 | -------------------------------------------------------------------------------- /examples/mini.rs: -------------------------------------------------------------------------------- 1 | // Mini Rust language 2 | use zubbers::{ir::*, vm::*}; 3 | 4 | extern crate logos; 5 | use logos::Logos; 6 | 7 | use std::collections::HashMap; 8 | 9 | #[derive(Logos, Debug, PartialEq, Clone)] 10 | enum Token<'t> { 11 | #[regex("[0-9.]+")] 12 | Number(&'t str), 13 | #[regex("[a-zA-Z]+")] 14 | Ident(&'t str), 15 | #[token("fn")] 16 | Fun, 17 | #[token("global")] 18 | Global, 19 | #[token("let")] 20 | Let, 21 | #[token("if")] 22 | If, 23 | #[token("while")] 24 | While, 25 | #[token("return")] 26 | Return, 27 | #[token("(")] 28 | LParen, 29 | #[token(")")] 30 | RParen, 31 | #[token("[")] 32 | LBracket, 33 | #[token("]")] 34 | RBracket, 35 | #[token("{")] 36 | LCurly, 37 | #[token("}")] 38 | RCurly, 39 | #[token("@")] 40 | Period, 41 | #[token(",")] 42 | Comma, 43 | #[token(":")] 44 | Colon, 45 | #[token(";")] 46 | Semicolon, 47 | #[token("+")] 48 | Add, 49 | #[token("-")] 50 | Sub, 51 | #[token("*")] 52 | Mul, 53 | #[token("/")] 54 | Div, 55 | #[token("=")] 56 | Assign, 57 | #[token("%")] 58 | Rem, 59 | #[error] 60 | #[regex(r"[ \t\n\f]+", logos::skip)] 61 | Error, 62 | } 63 | 64 | impl<'t> Token<'t> { 65 | fn to_op(&self) -> Option { 66 | use self::Token::*; 67 | 68 | Some( 69 | match *self { 70 | Add => Op::Add, 71 | Sub => Op::Sub, 72 | Mul => Op::Mul, 73 | Div => Op::Div, 74 | Rem => Op::Rem, 75 | Period => Op::Index, 76 | 77 | _ => return None 78 | } 79 | ) 80 | } 81 | } 82 | 83 | #[derive(Debug, Clone)] 84 | enum Op { 85 | Add, 86 | Sub, 87 | Mul, 88 | Div, 89 | Rem, 90 | Index, 91 | } 92 | 93 | impl Op { 94 | pub fn prec(&self) -> usize { 95 | use self::Op::*; 96 | 97 | match self { 98 | Add => 0, 99 | Sub => 0, 100 | Mul => 1, 101 | Div => 1, 102 | Rem => 1, 103 | Index => 4, 104 | } 105 | } 106 | 107 | pub fn to_ir(&self) -> BinaryOp { 108 | use self::Op::*; 109 | 110 | match self { 111 | Add => BinaryOp::Add, 112 | Sub => BinaryOp::Sub, 113 | Mul => BinaryOp::Mul, 114 | Div => BinaryOp::Div, 115 | Rem => BinaryOp::Rem, 116 | // TODO: Index BinOp deprecated 117 | _ => panic!("Index deprecated"), 118 | } 119 | } 120 | } 121 | 122 | #[derive(Debug, Clone)] 123 | enum Statement { 124 | Let(String, Expression, Binding), 125 | Global(String, Expression), 126 | 127 | Fun(String, Vec, Vec, Binding), 128 | If(Expression, Vec, Option>), 129 | While(Expression, Vec), 130 | Assign(Expression, Expression), 131 | Return(Option), 132 | 133 | Expression(Expression) 134 | } 135 | 136 | #[derive(Debug, Clone)] 137 | enum Expression { 138 | Number(f64), 139 | Binary(Box, Op, Box), 140 | Array(Vec), 141 | Dict(Vec, Vec), // Don't care about hashmaps :p 142 | Var(String, Binding), // It will store the proper relative depth 143 | Call(Box, Vec), 144 | } 145 | 146 | struct Parser<'p> { 147 | tokens: Vec>, 148 | ast: Vec, 149 | 150 | top: usize, 151 | 152 | depth_table: HashMap, 153 | depth: usize, 154 | function_depth: usize, 155 | 156 | in_operation: bool, 157 | } 158 | 159 | impl<'p> Parser<'p> { 160 | pub fn new(tokens: Vec>) -> Self { 161 | Parser { 162 | tokens, 163 | ast: Vec::new(), 164 | top: 0, 165 | 166 | depth_table: HashMap::new(), 167 | depth: 0, 168 | function_depth: 0, 169 | 170 | in_operation: false 171 | } 172 | } 173 | 174 | pub fn parse(&mut self) -> Vec { 175 | while self.remaining() > 0 { 176 | let statement = self.parse_statement(); 177 | 178 | if let Some(s) = statement { 179 | self.ast.push(s) 180 | } 181 | } 182 | 183 | self.ast.clone() 184 | } 185 | 186 | fn parse_statement(&mut self) -> Option { 187 | use self::Token::*; 188 | 189 | match self.current() { 190 | Global => { 191 | self.next(); 192 | 193 | let name = self.current_slice().unwrap().to_string(); 194 | 195 | self.next(); 196 | 197 | if self.current() == Assign { 198 | self.next(); 199 | 200 | let right = self.parse_expression().unwrap(); 201 | 202 | self.depth_table.insert(name.clone(), Binding::global(name.as_str())); 203 | 204 | Some( 205 | Statement::Global( 206 | name, 207 | right, 208 | ) 209 | ) 210 | } else { 211 | panic!("Expected `=`") 212 | } 213 | }, 214 | 215 | Let => { 216 | self.next(); 217 | 218 | let name = self.current_slice().unwrap().to_string(); 219 | 220 | self.next(); 221 | 222 | if self.current() == Assign { 223 | self.next(); 224 | 225 | let right = self.parse_expression().unwrap(); 226 | 227 | let binding = Binding::local(name.as_str(), self.depth, self.function_depth); 228 | self.depth_table.insert(name.clone(), binding.clone()); 229 | 230 | Some( 231 | Statement::Let( 232 | name, 233 | right, 234 | binding 235 | ) 236 | ) 237 | } else { 238 | panic!("Expected `=`") 239 | } 240 | }, 241 | 242 | Fun => { 243 | self.next(); 244 | let name = self.current_slice().unwrap().to_string(); 245 | 246 | let binding = Binding::local(name.as_str(), self.depth, self.function_depth); 247 | self.depth_table.insert(name.clone(), binding.clone()); 248 | 249 | self.next(); 250 | 251 | if self.current() == LParen { 252 | self.next(); 253 | 254 | self.depth += 1; 255 | self.function_depth += 1; 256 | 257 | let mut params = Vec::new(); 258 | 259 | while self.current() != RParen { 260 | let name = self.current_slice().unwrap().to_string(); 261 | params.push(name.clone()); 262 | 263 | let binding = Binding::local(name.clone().as_str(), self.depth, self.function_depth); 264 | self.depth_table.insert(name, binding.clone()); 265 | 266 | self.next(); 267 | 268 | if self.current() == RParen { 269 | break 270 | } 271 | 272 | if self.current() != Comma{ 273 | panic!("Expected `,` in function params, found {:?}", self.current()) 274 | } 275 | 276 | self.next() 277 | } 278 | 279 | self.next(); // RParen 280 | 281 | 282 | let body = self.parse_body(); 283 | 284 | self.depth -= 1; 285 | self.function_depth -= 1; 286 | 287 | Some( 288 | Statement::Fun( 289 | name, 290 | params, 291 | body, 292 | binding 293 | ) 294 | ) 295 | 296 | } else { 297 | panic!("Expected `(` in function") 298 | } 299 | }, 300 | 301 | Return => { 302 | self.next(); 303 | 304 | if self.current() == Semicolon { 305 | Some( 306 | Statement::Return(None) 307 | ) 308 | } else { 309 | let a = Some( 310 | Statement::Return(Some(self.parse_expression().unwrap())) 311 | ); 312 | 313 | a 314 | } 315 | } 316 | 317 | Semicolon => { 318 | self.next(); 319 | None 320 | } 321 | 322 | c => { 323 | let a = Some( 324 | Statement::Expression( 325 | self.parse_expression().unwrap() 326 | ) 327 | ); 328 | 329 | a 330 | }, 331 | } 332 | } 333 | 334 | fn parse_body(&mut self) -> Vec { 335 | use self::Token::*; 336 | 337 | if self.current() != LCurly { 338 | panic!("Expected `{`") 339 | } 340 | 341 | self.next(); 342 | 343 | let mut body = Vec::new(); 344 | 345 | while self.current() != RCurly { 346 | let statement = self.parse_statement(); 347 | 348 | if let Some(s) = statement { 349 | body.push(s) 350 | } 351 | } 352 | 353 | self.next(); 354 | 355 | body 356 | } 357 | 358 | fn parse_expression(&mut self) -> Option { 359 | use self::Token::*; 360 | 361 | let cur = self.current(); 362 | 363 | let expr = match cur { 364 | Number(ref n) => { 365 | Expression::Number( 366 | n.clone().parse::().unwrap() 367 | ) 368 | }, 369 | Ident(ref n) => { 370 | if let Some(depth) = self.depth_table.get(&n.to_string()) { 371 | let mut binding = depth.clone(); 372 | 373 | if binding.depth.is_some() { 374 | binding.depth = Some(self.depth); 375 | } 376 | 377 | let var = Expression::Var( 378 | n.to_string(), 379 | binding, 380 | ); 381 | 382 | self.next(); 383 | 384 | if self.current() == LParen { 385 | self.next(); 386 | 387 | let mut args = Vec::new(); 388 | 389 | while self.current() != RParen { 390 | args.push(self.parse_expression().unwrap()); 391 | 392 | if self.current() == RParen { 393 | break 394 | } 395 | 396 | if self.current() != Comma{ 397 | panic!("Expected `,` in call args, found {:?}", self.current()) 398 | } 399 | 400 | self.next(); 401 | } 402 | 403 | self.next(); 404 | 405 | Expression::Call( 406 | Box::new(var), 407 | args 408 | ) 409 | } else { 410 | var 411 | } 412 | } else { 413 | panic!("Can't find variable `{}`", n) 414 | } 415 | }, 416 | 417 | LParen => { 418 | self.next(); 419 | 420 | let flag = self.in_operation; 421 | self.in_operation = false; 422 | 423 | let expr = self.parse_expression().unwrap(); 424 | 425 | self.in_operation = flag; 426 | 427 | if self.current() != RParen { 428 | panic!("Expected `)` to close `(`"); 429 | } 430 | 431 | expr 432 | }, 433 | 434 | LCurly => { 435 | self.next(); 436 | 437 | let mut keys = Vec::new(); 438 | let mut vals = Vec::new(); 439 | 440 | while self.current() != RCurly { 441 | keys.push(self.parse_expression().unwrap()); 442 | 443 | if self.current() != Colon { 444 | panic!("Expected `:` after key") 445 | } 446 | 447 | self.next(); 448 | 449 | vals.push(self.parse_expression().unwrap()); 450 | 451 | if self.current() == RCurly { 452 | break 453 | } 454 | 455 | if self.current() != Comma { 456 | panic!("Expected `,` after value but found `{:?}`", self.current()) 457 | } 458 | 459 | self.next(); 460 | } 461 | 462 | Expression::Dict(keys, vals) 463 | } 464 | 465 | c => { println!("{:?}", c); self.next(); return None}, 466 | }; 467 | 468 | self.next(); 469 | 470 | if self.remaining() == 0 { 471 | return Some(expr) 472 | } 473 | 474 | if self.current().to_op().is_some() && !self.in_operation { 475 | Some( 476 | self.parse_binary(expr) 477 | ) 478 | } else { 479 | Some(expr) 480 | } 481 | } 482 | 483 | fn parse_binary(&mut self, left: Expression) -> Expression { 484 | use self::Token::*; 485 | 486 | let mut expr_stack = vec!(left); 487 | let mut op_stack = vec!(self.current().to_op().unwrap()); 488 | self.next(); 489 | 490 | self.in_operation = true; // Don't want to chain operations 491 | 492 | expr_stack.push(self.parse_expression().unwrap()); 493 | 494 | while op_stack.len() > 0 { 495 | while let Some(op) = self.current().to_op() { 496 | self.next(); 497 | let precedence = op.prec(); 498 | 499 | if precedence <= op_stack.last().unwrap().prec() { 500 | let right = expr_stack.pop().unwrap(); 501 | let left = expr_stack.pop().unwrap(); 502 | 503 | expr_stack.push( 504 | Expression::Binary( 505 | Box::new(left), 506 | op_stack.pop().unwrap(), 507 | Box::new(right) 508 | ) 509 | ); 510 | 511 | if self.remaining() > 0 { 512 | expr_stack.push(self.parse_expression().unwrap()); 513 | op_stack.push(op); 514 | } else { 515 | panic!("Reached EOF in binary operation") 516 | } 517 | } else { 518 | expr_stack.push(self.parse_expression().unwrap()); 519 | op_stack.push(op) 520 | } 521 | } 522 | 523 | let right = expr_stack.pop().unwrap(); 524 | let left = expr_stack.pop().unwrap(); 525 | 526 | expr_stack.push( 527 | Expression::Binary( 528 | Box::new(left), 529 | op_stack.pop().unwrap(), 530 | Box::new(right) 531 | ) 532 | ); 533 | } 534 | 535 | self.in_operation = false; 536 | 537 | expr_stack.pop().unwrap() 538 | } 539 | 540 | fn remaining(&self) -> usize { 541 | if self.top > self.tokens.len() { 542 | return 0 543 | } 544 | 545 | self.tokens.len() - self.top 546 | } 547 | 548 | fn next(&mut self) { 549 | self.top += 1 550 | } 551 | 552 | fn current(&self) -> Token { 553 | self.tokens[self.top.clone()].clone() 554 | } 555 | 556 | fn current_slice(&self) -> Option<&str> { 557 | use self::Token::*; 558 | 559 | match self.current() { 560 | Number(ref s) | 561 | Ident(ref s) => Some(s), 562 | _ => None 563 | } 564 | } 565 | 566 | fn peek(&self) -> Token { 567 | self.tokens[self.top + 1].clone() 568 | } 569 | } 570 | 571 | fn codegen_expr(builder: &IrBuilder, expr: &Expression) -> ExprNode { 572 | use self::Expression::*; 573 | 574 | match expr { 575 | Number(ref n) => { 576 | builder.number(*n) 577 | }, 578 | 579 | Var(name, depth) => { 580 | builder.var(depth.clone()) 581 | }, 582 | 583 | Call(ref callee, ref args) => { 584 | let mut args_ir = Vec::new(); 585 | 586 | for arg in args.iter() { 587 | args_ir.push(codegen_expr(&builder, arg)) 588 | } 589 | 590 | let callee_ir = codegen_expr(&builder, callee); 591 | 592 | builder.call(callee_ir, args_ir, None) 593 | }, 594 | 595 | Binary(left, op, right) => { 596 | let left = codegen_expr(&builder, left); 597 | let right = codegen_expr(&builder, right); 598 | 599 | builder.binary(left, op.to_ir(), right) 600 | }, 601 | 602 | Dict(keys, values) => { 603 | let mut keys_ir = Vec::new(); 604 | let mut vals_ir = Vec::new(); 605 | 606 | for key in keys.iter() { 607 | keys_ir.push(codegen_expr(&builder, key)) 608 | } 609 | 610 | for value in values.iter() { 611 | vals_ir.push(codegen_expr(&builder, value)) 612 | } 613 | 614 | builder.dict(keys_ir, vals_ir) 615 | }, 616 | 617 | _ => todo!() 618 | } 619 | } 620 | 621 | fn codegen(builder: &mut IrBuilder, ast: &Vec) { 622 | use self::Statement::*; 623 | 624 | for s in ast.iter() { 625 | match s { 626 | Let(name, expr, var) => { 627 | let right = codegen_expr(&builder, expr); 628 | builder.bind(var.clone(), right) 629 | }, 630 | 631 | Global(name, expr) => { 632 | let right = codegen_expr(&builder, expr); 633 | builder.bind(Binding::global(name), right) 634 | }, 635 | 636 | Fun(name, params, body, var) => { 637 | let params = params.iter().map(|x| x.as_str()).collect::>(); 638 | 639 | let fun = builder.function(var.clone(), ¶ms.as_slice(), |mut builder| { 640 | codegen(&mut builder, body) 641 | }); 642 | 643 | builder.emit(fun); 644 | }, 645 | 646 | Return(ref val) => { 647 | let value = if let Some(v) = val { 648 | Some( 649 | codegen_expr(&builder, v) 650 | ) 651 | } else { 652 | None 653 | }; 654 | 655 | builder.ret(value) 656 | }, 657 | 658 | Expression(ref expr) => { 659 | let expr = codegen_expr(&builder, expr); 660 | builder.emit(expr) 661 | }, 662 | 663 | c => todo!("{:#?}", c) 664 | } 665 | } 666 | } 667 | 668 | const TEST: &'static str = r#" 669 | let bar = 13.37; 670 | 671 | fn foo() { 672 | fn baz(c) { 673 | return c + bar; 674 | } 675 | 676 | return baz(10); 677 | } 678 | 679 | global gangster = foo(); 680 | "#; 681 | 682 | fn main() { 683 | let lex = Token::lexer(TEST); 684 | 685 | let mut parser = Parser::new(lex.collect::>()); 686 | 687 | let ast = parser.parse(); 688 | 689 | let mut builder = IrBuilder::new(); 690 | codegen(&mut builder, &ast); 691 | 692 | let ir = builder.build(); 693 | 694 | println!("{:#?}", ir); 695 | 696 | let mut vm = VM::new(); 697 | vm.exec(&ir, true); 698 | 699 | println!("{:#?}", vm.globals) 700 | } -------------------------------------------------------------------------------- /src/compiler/compiler.rs: -------------------------------------------------------------------------------- 1 | use super::chunk::{Chunk, Op}; 2 | use super::*; 3 | 4 | #[derive(Debug, Clone)] 5 | pub struct Local { 6 | pub name: String, 7 | pub depth: usize, 8 | pub captured: bool, 9 | pub reserved: bool, 10 | } 11 | 12 | #[derive(Debug, Clone)] 13 | struct UpValue { 14 | pub index: u8, 15 | pub is_local: bool, 16 | } 17 | 18 | #[derive(Debug)] 19 | pub struct CompileState { 20 | line: usize, 21 | pub locals: Vec, 22 | upvalues: Vec, 23 | function: FunctionBuilder, 24 | scope_depth: usize, 25 | breaks: Vec, 26 | method: bool, 27 | } 28 | 29 | impl CompileState { 30 | pub fn new( 31 | method: bool, 32 | reserved: &str, 33 | function: FunctionBuilder, 34 | scope_depth: usize, 35 | ) -> Self { 36 | let locals = vec![Local { 37 | name: reserved.into(), 38 | depth: 1, 39 | captured: false, 40 | reserved: true, 41 | }]; 42 | 43 | CompileState { 44 | line: 0, 45 | locals, 46 | upvalues: Vec::new(), 47 | function, 48 | scope_depth, 49 | breaks: Vec::new(), 50 | method, 51 | } 52 | } 53 | 54 | fn capture_local(&mut self, var: &str) -> Option { 55 | for (i, local) in self.locals.iter_mut().enumerate().rev() { 56 | if local.name == var { 57 | local.captured = true; 58 | 59 | return Some(i as u8); 60 | } 61 | } 62 | 63 | None 64 | } 65 | 66 | fn add_local(&mut self, var: &str, depth: usize) -> u8 { 67 | let depth = self.scope_depth - (depth); 68 | 69 | if self.locals.len() == std::u8::MAX as usize { 70 | panic!("local variable overflow") 71 | } 72 | 73 | self.locals.push(Local { 74 | name: var.into(), 75 | depth, 76 | captured: false, 77 | reserved: false, 78 | }); 79 | 80 | (self.locals.len() - 1) as u8 81 | } 82 | 83 | fn resolve_local(&mut self, var: &str) -> u8 { 84 | for (i, local) in self.locals.iter().enumerate().rev() { 85 | if local.name == var { 86 | return i as u8; 87 | } 88 | } 89 | 90 | panic!("TODO: unresolved var: {} in {:#?}", var, self.locals) 91 | } 92 | 93 | fn add_upvalue(&mut self, index: u8, is_local: bool) -> u8 { 94 | for (i, upval) in self.upvalues.iter().enumerate() { 95 | if upval.index == index && upval.is_local == is_local { 96 | return i as u8; 97 | } 98 | } 99 | 100 | if self.upvalues.len() == std::u8::MAX as usize { 101 | panic!("too many upvalues, not cool") 102 | } else { 103 | self.upvalues.push(UpValue { index, is_local }); 104 | 105 | (self.upvalues.len() - 1) as u8 106 | } 107 | } 108 | 109 | fn begin_scope(&mut self) { 110 | self.scope_depth += 1; 111 | } 112 | 113 | fn end_scope(&mut self) { 114 | let last = self.scope_depth; 115 | 116 | self.scope_depth -= 1; 117 | 118 | let mut ops = Vec::new(); 119 | 120 | self.locals.retain(|local| { 121 | if local.depth < last || local.reserved { 122 | return true; 123 | } 124 | 125 | if local.captured { 126 | ops.push(Op::CloseUpValue) 127 | } else { 128 | ops.push(Op::Pop) 129 | } 130 | 131 | false 132 | }); 133 | 134 | ops.into_iter().rev().for_each(|op| self.emit(op)) 135 | } 136 | 137 | fn emit(&mut self, op: Op) { 138 | self.function.chunk_mut().write(op, self.line); 139 | } 140 | 141 | fn add_break(&mut self, jmp: usize) { 142 | self.breaks.push(jmp); 143 | } 144 | 145 | fn breaks(&mut self) -> Vec { 146 | let bs = self.breaks.clone(); 147 | self.breaks.clear(); 148 | 149 | bs 150 | } 151 | } 152 | 153 | pub struct Compiler<'g> { 154 | heap: &'g mut Heap, 155 | pub states: Vec, 156 | pub locals_cache: Vec, 157 | } 158 | 159 | impl<'g> Compiler<'g> { 160 | pub fn new(heap: &'g mut Heap) -> Self { 161 | Compiler { 162 | heap, 163 | states: Vec::new(), 164 | locals_cache: Vec::new(), 165 | } 166 | } 167 | 168 | pub fn compile(&mut self, exprs: &[ExprNode]) -> Function { 169 | self.start_function(false, "", 0, 0); 170 | 171 | for expr in exprs.iter() { 172 | self.compile_expr(expr) 173 | } 174 | 175 | self.emit_return(None); 176 | self.end_function() 177 | } 178 | 179 | pub fn compile_from(&mut self, exprs: &[ExprNode], locals: Vec) -> Function { 180 | self.start_function(false, "", 0, 0); 181 | self.states.last_mut().unwrap().locals = locals; 182 | 183 | for expr in exprs.iter() { 184 | self.compile_expr(expr) 185 | } 186 | 187 | self.emit_return(None); 188 | self.end_function() 189 | } 190 | 191 | fn compile_expr(&mut self, expr: &ExprNode) { 192 | use self::Expr::*; 193 | 194 | match expr.inner() { 195 | Literal(ref lit) => self.emit_constant(lit), 196 | Unary(ref op, ref node) => { 197 | self.compile_expr(node); 198 | 199 | use self::UnaryOp::*; 200 | 201 | match op { 202 | Neg => self.emit(Op::Neg), 203 | Not => self.emit(Op::Not), 204 | } 205 | } 206 | 207 | Var(ref var) => self.var_get(var), 208 | Mutate(ref lhs, ref rhs) => { 209 | // Currently just handling Var 210 | if let Var(ref var) = lhs.inner() { 211 | self.compile_expr(rhs); 212 | 213 | if var.is_upvalue() { 214 | let idx = self.resolve_upvalue(var.name()); 215 | 216 | self.emit(Op::SetUpValue); 217 | self.emit_byte(idx) 218 | } else { 219 | if var.depth.is_none() { 220 | // Global 221 | self.set_global(var.name()) 222 | } else { 223 | let idx = self.state_mut().resolve_local(var.name()); 224 | 225 | self.emit(Op::SetLocal); 226 | self.emit_byte(idx) 227 | } 228 | } 229 | } else { 230 | // When classes are a thing, this is where we handle setting properties 231 | panic!("can't mutate non-variable") 232 | } 233 | } 234 | 235 | Return(val) => self.emit_return((*val).clone()), 236 | 237 | Function(ref ir_func) => { 238 | let idx = if let Some(depth) = ir_func.var.depth { 239 | self.state_mut().add_local(ir_func.var.name(), depth); 240 | self.state_mut().resolve_local(ir_func.var.name()); 241 | None 242 | } else { 243 | self.emit(Op::DefineGlobal); 244 | let idx = self.string_constant(ir_func.var.name()); 245 | Some(idx) 246 | }; 247 | 248 | self.function_decl(ir_func); 249 | /* self.var_define(&ir_func.var, None); */ 250 | 251 | if let Some(idx) = idx { 252 | self.emit_byte(idx) 253 | } 254 | } 255 | 256 | AnonFunction(ref ir_func) => { 257 | self.function_decl(ir_func); 258 | } 259 | 260 | Not(ref expr) => { 261 | self.compile_expr(expr); 262 | self.emit(Op::Not) 263 | } 264 | 265 | Neg(ref expr) => { 266 | self.compile_expr(expr); 267 | self.emit(Op::Neg) 268 | } 269 | 270 | Call(ref call) => { 271 | let arity = call.args.len(); 272 | 273 | if arity > 8 { 274 | panic!("That's a lot of arguments. But I will fix this limitation asap.") 275 | } 276 | 277 | self.compile_expr(&call.callee); 278 | 279 | for arg in call.args.iter() { 280 | self.compile_expr(arg) 281 | } 282 | 283 | self.emit(Op::Call(arity as u8)) 284 | } 285 | 286 | List(ref content) => { 287 | for el in content.iter().rev() { 288 | self.compile_expr(el) 289 | } 290 | 291 | self.emit(Op::List); 292 | self.emit_byte(content.len() as u8) 293 | } 294 | 295 | SetElement(ref list, ref index, ref value) => { 296 | self.compile_expr(value); 297 | self.compile_expr(index); 298 | self.compile_expr(list); 299 | 300 | self.emit(Op::SetElement); 301 | } 302 | 303 | GetElement(ref list, ref index) => { 304 | self.compile_expr(index); 305 | self.compile_expr(list); 306 | 307 | self.emit(Op::GetElement); 308 | } 309 | 310 | Dict(keys, values) => { 311 | for (key, val) in keys.iter().zip(values.iter()) { 312 | self.compile_expr(key); 313 | self.compile_expr(val); 314 | } 315 | 316 | self.emit(Op::Dict); 317 | self.emit_byte(keys.len() as u8); 318 | } 319 | 320 | If(ref cond, ref then, ref els) => { 321 | self.compile_expr(cond); 322 | 323 | let else_jmp = self.emit_jze(); 324 | 325 | self.emit(Op::Pop); 326 | self.compile_expr(then); 327 | 328 | let end_jmp = self.emit_jmp(); 329 | 330 | self.patch_jmp(else_jmp); 331 | self.emit(Op::Pop); 332 | 333 | if let &Some(ref els) = els { 334 | self.compile_expr(els) 335 | } 336 | 337 | self.patch_jmp(end_jmp) 338 | } 339 | 340 | While(ref cond, ref body) => { 341 | let ip = self.ip(); 342 | 343 | self.compile_expr(cond); 344 | 345 | let end_jmp = self.emit_jze(); 346 | 347 | self.emit(Op::Pop); 348 | self.compile_expr(body); 349 | 350 | self.emit_loop(ip); 351 | self.patch_jmp(end_jmp); 352 | 353 | self.emit(Op::Pop); 354 | 355 | for b in self.state_mut().breaks() { 356 | self.patch_jmp(b) 357 | } 358 | } 359 | 360 | Break => { 361 | let jmp = self.emit_jmp(); 362 | self.state_mut().add_break(jmp) 363 | } 364 | 365 | Pop => self.emit(Op::Pop), 366 | 367 | Binary(lhs, op, rhs) => { 368 | use self::BinaryOp::*; 369 | 370 | match op { 371 | And => { 372 | self.compile_expr(lhs); 373 | 374 | let short_circuit_jmp = self.emit_jze(); 375 | 376 | self.emit(Op::Pop); 377 | self.compile_expr(rhs); 378 | 379 | self.patch_jmp(short_circuit_jmp); 380 | } 381 | 382 | Or => { 383 | self.compile_expr(lhs); 384 | 385 | let else_jmp = self.emit_jze(); 386 | let end_jmp = self.emit_jmp(); 387 | 388 | self.patch_jmp(else_jmp); 389 | self.emit(Op::Pop); 390 | 391 | self.compile_expr(rhs); 392 | 393 | self.patch_jmp(end_jmp) 394 | } 395 | 396 | _ => { 397 | // This looks kinda funny, but it's an ok way of matching I guess 398 | 399 | self.compile_expr(lhs); // will handle type in the future :) 400 | self.compile_expr(rhs); 401 | 402 | match op { 403 | Add => self.emit(Op::Add), 404 | Sub => self.emit(Op::Sub), 405 | Rem => self.emit(Op::Rem), 406 | Mul => self.emit(Op::Mul), 407 | Div => self.emit(Op::Div), 408 | 409 | Equal => self.emit(Op::Equal), 410 | Gt => self.emit(Op::Greater), 411 | Lt => self.emit(Op::Less), 412 | Pow => self.emit(Op::Pow), 413 | 414 | GtEqual => { 415 | self.emit(Op::Less); 416 | self.emit(Op::Not) 417 | } 418 | 419 | LtEqual => { 420 | self.emit(Op::Greater); 421 | self.emit(Op::Not) 422 | } 423 | 424 | NEqual => { 425 | self.emit(Op::Equal); 426 | self.emit(Op::Not) 427 | } 428 | 429 | _ => {} 430 | } 431 | } 432 | } 433 | } 434 | 435 | Bind(ref var, ref init) => { 436 | self.compile_expr(init); 437 | self.var_define(var, None); 438 | } 439 | 440 | BindGlobal(ref var, ref init) => { 441 | self.compile_expr(init); 442 | self.var_define(var, None) 443 | } 444 | 445 | Block(ref body) => { 446 | for node in body { 447 | self.compile_expr(node) 448 | } 449 | } 450 | 451 | Tuple(ref members) => { 452 | for member in members.iter().rev() { 453 | self.compile_expr(member); 454 | } 455 | 456 | self.emit(Op::Tuple); 457 | self.emit_byte(members.len() as u8); 458 | } 459 | 460 | _ => todo!(), 461 | } 462 | } 463 | 464 | fn var_get(&mut self, var: &Binding) { 465 | if var.is_upvalue() { 466 | let idx = self.resolve_upvalue(var.name()); 467 | 468 | self.emit(Op::GetUpValue); 469 | self.emit_byte(idx); 470 | } else { 471 | // local time B) 472 | if var.depth.is_none() { 473 | self.emit(Op::GetGlobal); 474 | let idx = self.string_constant(var.name()); 475 | self.emit_byte(idx) 476 | } else { 477 | let idx = self.state_mut().resolve_local(var.name()); 478 | 479 | self.emit(Op::GetLocal); 480 | self.emit_byte(idx) 481 | } 482 | } 483 | } 484 | 485 | fn var_define(&mut self, var: &Binding, constant: Option) { 486 | // If there's depth, it's a local 487 | if let Some(depth) = var.depth { 488 | self.state_mut().add_local(var.name(), depth); 489 | self.state_mut().resolve_local(var.name()); 490 | } else { 491 | self.emit(Op::DefineGlobal); 492 | 493 | let idx = constant.unwrap_or_else(|| self.string_constant(var.name())); 494 | 495 | self.emit_byte(idx) 496 | } 497 | } 498 | 499 | fn set_global(&mut self, name: &str) { 500 | self.emit(Op::SetGlobal); 501 | 502 | let idx = { 503 | let chunk = self.states.last_mut().unwrap().function.chunk_mut(); 504 | 505 | chunk.string_constant(self.heap, name) 506 | }; 507 | 508 | self.emit_byte(idx) 509 | } 510 | 511 | fn function_decl(&mut self, f: &IrFunction) { 512 | let name = f.var.name(); 513 | let decl = f.body.borrow(); 514 | 515 | let params = &decl.params; 516 | let body = &decl.inner; 517 | let arity = params.len() as u8; 518 | 519 | self.start_function(decl.method, name, arity, 1); 520 | 521 | for p in params { 522 | self.state_mut().add_local(p.name(), 1); 523 | self.state_mut().resolve_local(p.name()); 524 | } 525 | 526 | for expr in body.iter() { 527 | self.compile_expr(expr) 528 | } 529 | 530 | self.state_mut().end_scope(); 531 | 532 | let upvalues = self.state_mut().upvalues.clone(); 533 | 534 | let function = self.end_function(); // Might delete later, felt cute 535 | let handle = self.heap.insert(Object::Function(function)).into_handle(); 536 | 537 | let value = Value::object(handle); 538 | 539 | self.emit(Op::Closure); 540 | 541 | for upvalue in upvalues { 542 | self.emit_byte(if upvalue.is_local { 1 } else { 0 }); 543 | 544 | self.emit_byte(upvalue.index) 545 | } 546 | 547 | let idx = self.chunk_mut().add_constant(value); 548 | self.emit_byte(idx); 549 | } 550 | 551 | fn start_function(&mut self, method: bool, name: &str, arity: u8, scope: usize) { 552 | let next_function = FunctionBuilder::new(name, arity); 553 | let reserved_var = if method { "self" } else { "" }; 554 | let state = CompileState::new(method, reserved_var, next_function, scope); 555 | 556 | self.states.push(state) 557 | } 558 | 559 | fn end_function(&mut self) -> Function { 560 | // self.emit_return(None); 561 | 562 | let mut state: CompileState = self.states.pop().expect("states can't be empty"); 563 | 564 | self.locals_cache.extend(state.locals.clone()); 565 | 566 | state.function.set_upvalue_count(state.upvalues.len()); 567 | state.function.build() 568 | } 569 | 570 | fn resolve_upvalue(&mut self, name: &str) -> u8 { 571 | let end = self.states.len() - 1; 572 | 573 | let (scope, mut index) = self.states[..end] 574 | .iter_mut() 575 | .enumerate() 576 | .rev() 577 | .filter_map(|(i, enclosing)| enclosing.capture_local(name).map(|local| (i, local))) 578 | .next() 579 | .expect(&format!( 580 | "upvalue marked during resolution, but wasn't found: {}", 581 | name 582 | )); 583 | 584 | index = self.states[scope + 1].add_upvalue(index, true); 585 | 586 | if scope >= self.states.len() - 2 { 587 | // if we're one scope from current function 588 | index 589 | } else { 590 | for enclosing in &mut self.states[scope + 2..] { 591 | index = enclosing.add_upvalue(index, false) 592 | } 593 | 594 | index 595 | } 596 | } 597 | 598 | fn emit_return(&mut self, ret: Option) { 599 | let state = self.state_mut(); 600 | let initializer = state.function.name() == "init" && state.method; 601 | 602 | if initializer { 603 | self.emit(Op::GetLocal); 604 | self.emit_byte(0) 605 | } else if let Some(ref expr) = ret { 606 | self.compile_expr(expr) 607 | } else { 608 | self.emit(Op::Nil) 609 | } 610 | 611 | self.emit(Op::Return) 612 | } 613 | 614 | fn state_mut(&mut self) -> &mut CompileState { 615 | self.states.last_mut().expect("states can't be empty") 616 | } 617 | 618 | fn chunk_mut(&mut self) -> &mut Chunk { 619 | self.states 620 | .last_mut() 621 | .expect("states to be non-empty") 622 | .function 623 | .chunk_mut() 624 | } 625 | 626 | fn chunk(&self) -> &Chunk { 627 | &self 628 | .states 629 | .last() 630 | .expect("states to be non-empty") 631 | .function 632 | .chunk 633 | } 634 | 635 | fn line(&mut self) -> usize { 636 | self.states.last_mut().expect("states to be non-empty").line 637 | } 638 | 639 | fn string_constant(&mut self, s: &str) -> u8 { 640 | let chunk = self.states.last_mut().unwrap().function.chunk_mut(); 641 | 642 | chunk.string_constant(self.heap, s) 643 | } 644 | 645 | fn emit(&mut self, op: Op) { 646 | let line = self.line(); 647 | self.chunk_mut().write(op, line); 648 | } 649 | 650 | fn emit_byte(&mut self, byte: u8) { 651 | self.chunk_mut().write_byte(byte); 652 | } 653 | 654 | fn emit_constant(&mut self, lit: &Literal) { 655 | use self::Literal::*; 656 | 657 | match *lit { 658 | Nil => self.emit(Op::Nil), 659 | Boolean(b) => self.emit(if b { Op::True } else { Op::False }), 660 | Number(n) => self.emit_number_literal(n), 661 | String(ref s) => { 662 | let idx = { 663 | let chunk = self.states.last_mut().unwrap().function.chunk_mut(); 664 | chunk.string_constant(self.heap, s) 665 | }; 666 | 667 | self.emit(Op::Constant(idx)) 668 | } 669 | 670 | _ => panic!("not a constant"), 671 | } 672 | } 673 | 674 | fn emit_number_literal(&mut self, n: f64) { 675 | self.emit(Op::Immediate); 676 | 677 | let value = Value::float(n).to_raw(); 678 | let chunk = self.chunk_mut(); 679 | 680 | chunk.write_u64(value) 681 | } 682 | 683 | fn emit_jze(&mut self) -> usize { 684 | let line = self.line(); 685 | let chunk = self.chunk_mut(); 686 | 687 | chunk.write(Op::JumpIfFalse, line); 688 | chunk.write_byte(0xff); 689 | chunk.write_byte(0xff); 690 | 691 | chunk.len() - 2 692 | } 693 | 694 | fn emit_jmp(&mut self) -> usize { 695 | let line = self.line(); 696 | let chunk = self.chunk_mut(); 697 | 698 | chunk.write(Op::Jump, line); 699 | chunk.write_byte(0xff); 700 | chunk.write_byte(0xff); 701 | chunk.len() - 2 702 | } 703 | 704 | fn emit_loop(&mut self, ip: usize) { 705 | let line = self.line(); 706 | let chunk = self.chunk_mut(); 707 | let sub = chunk.len() - ip + 3; 708 | 709 | let lo = (sub & 0xff) as u8; 710 | let hi = ((sub >> 8) & 0xff) as u8; 711 | 712 | chunk.write(Op::Loop, line); 713 | chunk.write_byte(lo); 714 | chunk.write_byte(hi); 715 | } 716 | 717 | fn ip(&self) -> usize { 718 | self.chunk().len() 719 | } 720 | 721 | /// Patches jump instruction to jump to current 722 | /// Instruction Pointer (IP) 723 | fn patch_jmp(&mut self, idx: usize) { 724 | let jmp = self.ip(); 725 | let lo = (jmp & 0xff) as u8; 726 | let hi = ((jmp >> 8) & 0xff) as u8; 727 | 728 | self.chunk_mut().write_byte_at(idx, lo); 729 | self.chunk_mut().write_byte_at(idx + 1, hi); 730 | } 731 | } 732 | -------------------------------------------------------------------------------- /src/compiler/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod compiler; 2 | 3 | use super::vm::*; 4 | use super::ir::*; 5 | 6 | pub use self::compiler::*; -------------------------------------------------------------------------------- /src/ir/builder.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | use std::cell::RefCell; 4 | use std::collections::HashMap; 5 | use std::rc::Rc; 6 | 7 | #[derive(Clone, Debug)] 8 | pub struct IrBuilder { 9 | program: Vec, 10 | types: Vec>, 11 | } 12 | 13 | impl IrBuilder { 14 | pub fn new() -> Self { 15 | IrBuilder { 16 | program: Vec::new(), 17 | types: vec![HashMap::new()], 18 | } 19 | } 20 | 21 | pub fn bind(&mut self, binding: Binding, rhs: ExprNode) { 22 | let map = self.types 23 | .get_mut(binding.clone().depth.unwrap_or(0) + binding.function_depth) 24 | .unwrap(); 25 | map.insert(binding.name().into(), rhs.type_info().clone()); 26 | 27 | let bind = Expr::Bind(binding.clone(), rhs); 28 | self.emit(bind.node(TypeInfo::nil())); 29 | } 30 | 31 | 32 | pub fn scope_in(&mut self) { 33 | self.types.push(HashMap::new()); 34 | } 35 | 36 | pub fn scope_out(&mut self) { 37 | self.types.pop(); 38 | } 39 | 40 | pub fn mutate(&mut self, lhs: ExprNode, rhs: ExprNode) { 41 | let mutate = Expr::Mutate(lhs, rhs); 42 | 43 | self.emit(mutate.clone().node(TypeInfo::nil())) 44 | } 45 | 46 | pub fn ret_(&mut self, value: Option) -> ExprNode { 47 | let info = if let Some(ref value) = value { 48 | value.type_info().clone() 49 | } else { 50 | TypeInfo::nil() 51 | }; 52 | 53 | Expr::Return(value).node(info) 54 | } 55 | 56 | pub fn ret(&mut self, value: Option) { 57 | let node = self.ret_(value); 58 | self.emit(node); 59 | } 60 | 61 | pub fn break_(&mut self) { 62 | self.emit(Expr::Break.node(TypeInfo::nil())) 63 | } 64 | 65 | pub fn list(&self, content: Vec) -> ExprNode { 66 | Expr::List(content).node(TypeInfo::nil()) 67 | } 68 | 69 | pub fn set_element(&self, list: ExprNode, index: ExprNode, value: ExprNode) -> ExprNode { 70 | Expr::SetElement(list, index, value).node(TypeInfo::nil()) 71 | } 72 | 73 | pub fn get_element(&self, list: ExprNode, index: ExprNode) -> ExprNode { 74 | Expr::GetElement(list, index).node(TypeInfo::nil()) 75 | } 76 | 77 | pub fn tuple(&self, members: Vec) -> ExprNode { 78 | Expr::Tuple(members).node(TypeInfo::nil()) 79 | } 80 | 81 | pub fn structure(&self, keys: Vec, values: Vec) -> ExprNode { 82 | Expr::Tuple(values).node(TypeInfo::structure(keys)) 83 | } 84 | 85 | pub fn get_member(&self, key: String, structure: ExprNode) -> ExprNode { 86 | use types::Type::Struct; 87 | 88 | if let Some(Struct(ref keys)) = structure.type_info().kind() { 89 | let index = keys.iter().position(|e| e == &key).unwrap(); 90 | let index = self.number(index as f64); 91 | Expr::GetElement(structure, index).node(TypeInfo::nil()) 92 | } else { 93 | panic!("Expected struct!"); 94 | } 95 | } 96 | 97 | pub fn set_member(&self, key: String, structure: ExprNode, value: ExprNode) -> ExprNode { 98 | use types::Type::Struct; 99 | 100 | if let Some(Struct(ref keys)) = structure.type_info().kind() { 101 | let index = keys.iter().position(|e| e == &key).unwrap(); 102 | let index = self.number(index as f64); 103 | Expr::SetElement(structure, index, value).node(TypeInfo::nil()) 104 | } else { 105 | panic!("Expected struct!"); 106 | } 107 | } 108 | 109 | pub fn dict(&self, keys: Vec, values: Vec) -> ExprNode { 110 | Expr::Dict(keys, values).node(TypeInfo::nil()) 111 | } 112 | 113 | pub fn empty_dict(&self) -> ExprNode { 114 | Expr::Dict(Vec::new(), Vec::new()).node(TypeInfo::nil()) 115 | } 116 | 117 | pub fn var(&self, binding: Binding) -> ExprNode { 118 | let a = self.types.last().unwrap().get(binding.name()).unwrap_or(&TypeInfo::nil()).clone(); 119 | Expr::Var(binding).node(a) 120 | } 121 | 122 | pub fn call(&self, callee: ExprNode, args: Vec, retty: Option) -> ExprNode { 123 | let call = Call { callee, args }; 124 | 125 | Expr::Call(call).node(if let Some(info) = retty { 126 | info 127 | } else { 128 | TypeInfo::nil() 129 | }) 130 | } 131 | 132 | pub fn binary(&self, lhs: ExprNode, op: BinaryOp, rhs: ExprNode) -> ExprNode { 133 | Expr::Binary(lhs, op, rhs).node(TypeInfo::nil()) 134 | } 135 | 136 | pub fn unary(op: UnaryOp, rhs: ExprNode) -> Expr { 137 | Expr::Unary(op, rhs) 138 | } 139 | 140 | pub fn int(&self, n: i32) -> ExprNode { 141 | let info = TypeInfo::new(Type::Int); 142 | let lit = Literal::Number(n as f64); 143 | 144 | Expr::Literal(lit).node(info) 145 | } 146 | 147 | pub fn number(&self, n: f64) -> ExprNode { 148 | let info = TypeInfo::new(Type::Float); 149 | let lit = Literal::Number(n); 150 | 151 | Expr::Literal(lit).node(info) 152 | } 153 | 154 | pub fn string(&self, s: &str) -> ExprNode { 155 | let info = TypeInfo::new(Type::String); 156 | let lit = Literal::String(s.to_owned()); 157 | 158 | Expr::Literal(lit).node(info) 159 | } 160 | 161 | pub fn bool(&self, b: bool) -> ExprNode { 162 | let info = TypeInfo::new(Type::Bool); 163 | let lit = Literal::Boolean(b); 164 | 165 | Expr::Literal(lit).node(info) 166 | } 167 | 168 | pub fn nil(&self) -> ExprNode { 169 | let info = TypeInfo::new(Type::Nil); 170 | let lit = Literal::Nil; 171 | 172 | Expr::Literal(lit).node(info) 173 | } 174 | 175 | pub fn function( 176 | &mut self, 177 | var: Binding, 178 | params: &[&str], 179 | mut body_build: impl FnMut(&mut IrBuilder), 180 | ) -> ExprNode { 181 | let mut body_builder = IrBuilder::new(); 182 | 183 | body_build(&mut body_builder); 184 | 185 | self.scope_in(); 186 | let body = body_builder.build(); 187 | self.scope_out(); 188 | 189 | let func_body = IrFunctionBody { 190 | params: params 191 | .iter() 192 | .cloned() 193 | .map(|x: &str| { 194 | Binding::local(x, var.depth.unwrap_or(0) + 1, var.function_depth + 1) 195 | }) 196 | .collect::>(), 197 | method: false, 198 | inner: body, 199 | }; 200 | 201 | let ir_func = IrFunction { 202 | var, 203 | body: Rc::new(RefCell::new(func_body)), 204 | }; 205 | 206 | Expr::Function(ir_func).node(TypeInfo::nil()) 207 | } 208 | 209 | pub fn ternary( 210 | &mut self, 211 | cond: ExprNode, 212 | then_body: ExprNode, 213 | else_body: Option, 214 | ) -> ExprNode { 215 | Expr::If(cond, then_body, else_body).node(TypeInfo::nil()) 216 | } 217 | 218 | pub fn block(&mut self, body: Vec) -> ExprNode { 219 | Expr::Block(body).node(TypeInfo::nil()) 220 | } 221 | 222 | pub fn block_(&mut self, build: impl FnOnce(&mut IrBuilder)) -> ExprNode { 223 | let builder = &mut IrBuilder::new(); 224 | build(builder); 225 | 226 | Expr::Block(builder.build()).node(TypeInfo::nil()) 227 | } 228 | 229 | pub fn if_( 230 | &mut self, 231 | cond: ExprNode, 232 | then_build: impl FnOnce(&mut IrBuilder), 233 | else_build: Option, 234 | ) -> ExprNode { 235 | let mut then_builder = IrBuilder::new(); 236 | 237 | then_build(&mut then_builder); 238 | 239 | let then_body = Expr::Block(then_builder.build()).node(TypeInfo::nil()); 240 | 241 | let else_body = if let Some(else_build) = else_build { 242 | let mut else_builder = IrBuilder::new(); 243 | 244 | else_build(&mut else_builder); 245 | 246 | Some(Expr::Block(else_builder.build()).node(TypeInfo::nil())) 247 | } else { 248 | None 249 | }; 250 | 251 | Expr::If(cond, then_body, else_body).node(TypeInfo::nil()) 252 | } 253 | 254 | pub fn while_(&mut self, cond: ExprNode, then_build: fn(&mut IrBuilder)) -> ExprNode { 255 | let mut then_builder = IrBuilder::new(); 256 | 257 | then_build(&mut then_builder); 258 | 259 | let then_body = Expr::Block(then_builder.build()).node(TypeInfo::nil()); 260 | 261 | Expr::While(cond, then_body).node(TypeInfo::nil()) 262 | } 263 | 264 | pub fn build(&self) -> Vec { 265 | self.program.clone() 266 | } 267 | 268 | pub fn emit(&mut self, atom: ExprNode) { 269 | self.program.push(atom) 270 | } 271 | } 272 | -------------------------------------------------------------------------------- /src/ir/ir.rs: -------------------------------------------------------------------------------- 1 | use super::TypeInfo; 2 | 3 | use std::{ 4 | collections::HashMap, 5 | rc::Rc, 6 | cell::RefCell, 7 | fmt, 8 | }; 9 | 10 | pub type LocalId = usize; 11 | pub type DataId = usize; 12 | 13 | #[derive(Clone, Debug)] 14 | pub enum Literal { 15 | Number(f64), 16 | String(String), 17 | Boolean(bool), 18 | Nil, 19 | } 20 | 21 | // When depth is None, we're dealing with a global. 22 | #[derive(Clone, Debug, PartialEq)] 23 | pub struct Binding { 24 | pub name: String, 25 | pub depth: Option, 26 | pub function_depth: usize, 27 | } 28 | 29 | impl Binding { 30 | // Define to be resolved later 31 | pub fn define_local(name: &str) -> Self { 32 | Binding { 33 | name: name.to_string(), 34 | depth: Some(0), 35 | function_depth: 0 36 | } 37 | } 38 | 39 | pub fn global(name: &str) -> Self { 40 | Binding { 41 | name: name.to_string(), 42 | depth: None, 43 | function_depth: 0 44 | } 45 | } 46 | 47 | pub fn local(name: &str, depth: usize, function_depth: usize) -> Self { 48 | Binding { 49 | name: name.to_string(), 50 | depth: Some(depth), 51 | function_depth: function_depth 52 | } 53 | } 54 | 55 | pub fn resolve(&mut self, depth: usize, function_depth: usize) { 56 | self.depth = Some(depth); 57 | self.function_depth = function_depth 58 | } 59 | 60 | #[inline] 61 | pub fn is_upvalue(&self) -> bool { 62 | self.depth 63 | .map(|d| d > self.function_depth) 64 | .unwrap_or(false) 65 | } 66 | 67 | pub fn upvalue_depth(&self) -> Option { 68 | self.depth.and_then(|d| 69 | if self.is_upvalue() { 70 | Some(d - self.function_depth) 71 | } else { 72 | None 73 | }) 74 | } 75 | 76 | pub fn name(&self) -> &str { 77 | &self.name 78 | } 79 | } 80 | 81 | #[derive(Clone, Debug)] 82 | pub enum BinaryOp { 83 | Add, 84 | Sub, 85 | Mul, 86 | Div, 87 | Rem, 88 | Equal, 89 | NEqual, 90 | GtEqual, 91 | LtEqual, 92 | Gt, 93 | Lt, 94 | And, 95 | Or, 96 | Pow, 97 | } 98 | 99 | #[derive(Clone, Debug)] 100 | pub enum UnaryOp { 101 | Neg, 102 | Not, 103 | } 104 | 105 | #[derive(Clone, Debug)] 106 | pub struct IrFunctionBody { 107 | pub params: Vec, 108 | pub method: bool, 109 | pub inner: Vec, // the actual function body 110 | } 111 | 112 | #[derive(Clone, Debug)] 113 | pub struct IrFunction { 114 | pub var: Binding, 115 | pub body: Rc>, // A Literal/Constant 116 | } 117 | 118 | #[derive(Clone, Debug)] 119 | pub struct Call { 120 | pub callee: Node, 121 | pub args: Vec>, 122 | } 123 | 124 | #[derive(Clone)] 125 | pub struct Node { 126 | inner: Box, 127 | type_info: TypeInfo, 128 | } 129 | 130 | impl Node { 131 | pub fn new(inner: T, type_info: TypeInfo) -> Self { 132 | Node { 133 | inner: Box::new(inner), 134 | type_info 135 | } 136 | } 137 | 138 | pub fn inner(&self) -> &T { 139 | &self.inner 140 | } 141 | 142 | pub fn inner_mut(&mut self) -> &mut T { 143 | &mut self.inner 144 | } 145 | 146 | pub fn type_info(&self) -> &TypeInfo { 147 | &self.type_info 148 | } 149 | } 150 | 151 | impl fmt::Debug for Node { 152 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 153 | write!(f, "{:#?}", self.inner) 154 | } 155 | } 156 | 157 | pub type ExprNode = Node; 158 | 159 | // NOTE: LocalId removed for now, as it wasn't used in the compiler 160 | 161 | 162 | #[derive(Clone, Debug)] 163 | pub enum Expr { 164 | Data(DataId), 165 | 166 | Literal(Literal), 167 | 168 | Bind(Binding, ExprNode), // @zesterer: like `with` 169 | BindGlobal(Binding, ExprNode), 170 | 171 | Var(Binding), // access binding 172 | 173 | Mutate(ExprNode, ExprNode), 174 | Binary(ExprNode, BinaryOp, ExprNode), 175 | Call(Call), 176 | Function(IrFunction), 177 | AnonFunction(IrFunction), // variable here will be unique id 178 | Unary(UnaryOp, ExprNode), 179 | Return(Option), 180 | 181 | Not(ExprNode), 182 | Neg(ExprNode), 183 | 184 | If(ExprNode, ExprNode, Option), 185 | While(ExprNode, ExprNode), 186 | 187 | List(Vec), 188 | Tuple(Vec), 189 | Dict(Vec, Vec), // They need to be the same size, funny enough 190 | SetElement(ExprNode, ExprNode, ExprNode), 191 | GetElement(ExprNode, ExprNode), 192 | 193 | Block(Vec), 194 | 195 | Break, 196 | Pop, 197 | } 198 | 199 | impl Expr { 200 | pub fn node(self, type_info: TypeInfo) -> ExprNode { 201 | Node::new(self, type_info) 202 | } 203 | } 204 | 205 | #[derive(Debug)] 206 | pub struct Program { 207 | data: HashMap, 208 | entry: Option 209 | } 210 | 211 | impl Program { 212 | pub fn empty() -> Self { 213 | Program { 214 | data: HashMap::new(), 215 | entry: None, 216 | } 217 | } 218 | 219 | pub fn with_entry(entry: DataId) -> Self { 220 | Program { 221 | data: HashMap::new(), 222 | entry: Some(entry) 223 | } 224 | } 225 | 226 | pub fn insert(&mut self, id: DataId, atom: ExprNode) { 227 | self.data.insert(id, atom); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/ir/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod types; 2 | pub mod ir; 3 | pub mod builder; 4 | 5 | 6 | pub use self::types::*; 7 | pub use self::ir::*; 8 | pub use self::builder::*; -------------------------------------------------------------------------------- /src/ir/types.rs: -------------------------------------------------------------------------------- 1 | #[derive(Clone, Debug)] 2 | pub enum Type { 3 | Float, 4 | Int, 5 | Bool, 6 | String, 7 | Struct(Vec), 8 | Nil 9 | } 10 | 11 | #[derive(Clone, Debug)] 12 | pub struct TypeInfo { 13 | kind: Option 14 | } 15 | 16 | impl TypeInfo { 17 | pub fn new(kind: Type) -> Self { 18 | TypeInfo { 19 | kind: Some(kind), 20 | } 21 | } 22 | 23 | pub fn kind(&self) -> &Option { 24 | &self.kind 25 | } 26 | 27 | pub fn structure(keys: Vec) -> Self { 28 | TypeInfo { 29 | kind: Some(Type::Struct(keys)), 30 | } 31 | } 32 | 33 | pub fn nil() -> Self { 34 | TypeInfo { 35 | kind: None, 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![feature(vec_drain_as_slice)] 2 | 3 | extern crate flame; 4 | #[macro_use] 5 | extern crate flamer; 6 | extern crate im_rc; 7 | 8 | pub mod compiler; 9 | pub mod ir; 10 | pub mod vm; 11 | 12 | #[cfg(test)] 13 | mod tests { 14 | use super::ir::*; 15 | use super::vm::*; 16 | 17 | #[test] 18 | fn globals() { 19 | let mut builder = IrBuilder::new(); 20 | 21 | let value = builder.number(42.0); 22 | builder.bind(Binding::global("foo"), value); 23 | 24 | let mut vm = VM::new(); 25 | 26 | vm.exec(&builder.build(), true); 27 | 28 | println!("{:#?}", vm.globals) 29 | } 30 | 31 | #[test] 32 | fn locals() { 33 | let mut builder = IrBuilder::new(); 34 | 35 | let value = builder.number(42.0); 36 | builder.bind(Binding::local("foo", 0, 0), value); 37 | 38 | builder.bind( 39 | Binding::global("FOO"), 40 | builder.var(Binding::local("foo", 0, 0)), 41 | ); 42 | 43 | let mut vm = VM::new(); 44 | 45 | vm.exec(&builder.build(), true); 46 | 47 | println!("{:#?}", vm.globals) 48 | } 49 | 50 | #[test] 51 | fn binary() { 52 | let mut builder = IrBuilder::new(); 53 | 54 | let a = builder.number(20.0); 55 | let b = builder.number(30.0); 56 | 57 | let sum = builder.binary(a, BinaryOp::Add, b); 58 | 59 | builder.bind(Binding::global("sum"), sum); 60 | 61 | let mut vm = VM::new(); 62 | vm.exec(&builder.build(), true); 63 | 64 | println!("{:#?}", vm.globals) 65 | } 66 | 67 | #[test] 68 | fn get_element() { 69 | let mut builder = IrBuilder::new(); 70 | let list = builder.list(vec![ 71 | builder.number(0f64), 72 | builder.number(10f64), 73 | builder.number(89f64), 74 | ]); 75 | builder.bind(Binding::global("list"), list); 76 | 77 | let var = builder.var(Binding::global("list")); 78 | let element = builder.get_element(var, builder.number(1f64)); 79 | builder.bind(Binding::global("result"), element); 80 | 81 | let mut vm = VM::new(); 82 | vm.exec(&builder.build(), true); 83 | println!("{:#?}", vm.globals) 84 | } 85 | 86 | #[test] 87 | fn actual_real_functions() { 88 | /* 89 | function foo(a, b) { 90 | return a + b 91 | } 92 | 93 | global bar = foo(10.0, 30.0) 94 | */ 95 | 96 | let mut builder = IrBuilder::new(); 97 | 98 | let foo = builder.function(Binding::local("foo", 0, 0), &["a", "b"], |builder| { 99 | let a = builder.var(Binding::local("a", 1, 1)); 100 | let b = builder.var(Binding::local("b", 1, 1)); 101 | 102 | let sum = builder.binary(a, BinaryOp::Add, b); 103 | 104 | builder.ret(Some(sum)) 105 | }); 106 | 107 | builder.emit(foo); 108 | 109 | let args = vec![builder.number(10.0), builder.number(30.0)]; 110 | 111 | let callee = builder.var(Binding::local("foo", 0, 0)); 112 | let call = builder.call(callee, args, None); 113 | 114 | builder.bind(Binding::global("bar"), call); // assign "bar" to call here 115 | 116 | let built = builder.build(); 117 | 118 | let mut vm = VM::new(); 119 | vm.exec(&built, true); 120 | 121 | println!("{:#?}", vm.globals) 122 | } 123 | 124 | #[test] 125 | fn ffi() { 126 | let mut builder = IrBuilder::new(); 127 | 128 | let hello = Expr::Literal(Literal::String("Hello from Rust :D".to_string())) 129 | .node(TypeInfo::new(Type::String)); 130 | 131 | let callee = builder.var(Binding::global("print")); 132 | 133 | let call = builder.call(callee, vec![hello], None); 134 | 135 | builder.emit(call); 136 | 137 | let mut vm = VM::new(); 138 | 139 | vm.add_native("print", print_native, 1); 140 | vm.exec(&builder.build(), true); 141 | } 142 | 143 | #[test] 144 | fn tuple() { 145 | let mut builder = IrBuilder::new(); 146 | 147 | let members = vec![ 148 | builder.number(11.0), 149 | builder.number(22.0), 150 | builder.number(33.0), 151 | ]; 152 | 153 | let tuple = builder.tuple(members); 154 | builder.bind(Binding::global("tuple"), tuple.clone()); 155 | 156 | let var = builder.var(Binding::global("tuple")); 157 | builder.bind( 158 | Binding::global("value"), 159 | builder.get_element(var.clone(), builder.number(0.0)), 160 | ); 161 | 162 | let callee = builder.var(Binding::global("print")); 163 | let call = builder.call(callee, vec![builder.var(Binding::global("value"))], None); 164 | builder.emit(call); 165 | 166 | builder.emit(builder.set_element(var.clone(), builder.number(0.0), builder.number(18.0))); 167 | builder.bind( 168 | Binding::global("value"), 169 | builder.get_element(var, builder.number(0.0)), 170 | ); 171 | 172 | let callee = builder.var(Binding::global("print")); 173 | let call = builder.call(callee, vec![builder.var(Binding::global("tuple"))], None); 174 | builder.emit(call); 175 | 176 | let mut vm = VM::new(); 177 | vm.add_native("print", print_native, 1); 178 | vm.exec(&builder.build(), true); 179 | let a = vm.globals 180 | .get("tuple") 181 | .unwrap() 182 | .as_object() 183 | .unwrap(); 184 | let a = unsafe { 185 | a.get_unchecked() 186 | }; 187 | println!("A: {:#?}", a) 188 | } 189 | 190 | #[test] 191 | fn structure() { 192 | let mut builder = IrBuilder::new(); 193 | 194 | let members = vec![ 195 | builder.string("Sawcce"), 196 | builder.number(16.0), 197 | ]; 198 | 199 | let keys = vec![ 200 | "name".into(), 201 | "age".into(), 202 | ]; 203 | 204 | let structure = builder.structure(keys, members); 205 | builder.bind(Binding::global("struct"), structure.clone()); 206 | let var = builder.var(Binding::global("struct")); 207 | 208 | builder.bind( 209 | Binding::global("value"), 210 | builder.get_member("name".into(), var.clone()), 211 | ); 212 | 213 | let callee = builder.var(Binding::global("print")); 214 | let call = builder.call(callee.clone(), vec![builder.var(Binding::global("value"))], None); 215 | builder.emit(call); 216 | 217 | let b = builder.set_member("name".into(), var.clone(), builder.string("Hello, world!")); 218 | builder.emit(b); 219 | 220 | builder.bind( 221 | Binding::global("value"), 222 | builder.get_member("name".into(), var), 223 | ); 224 | 225 | let call = builder.call(callee, vec![builder.var(Binding::global("value"))], None); 226 | builder.emit(call); 227 | 228 | let mut vm = VM::new(); 229 | vm.add_native("print", print_native, 1); 230 | vm.exec(&builder.build(), true); 231 | let a = vm.globals 232 | .get("struct") 233 | .unwrap() 234 | .as_object() 235 | .unwrap(); 236 | let a = unsafe { 237 | a.get_unchecked() 238 | }; 239 | println!("A: {:#?}", a) 240 | } 241 | 242 | #[test] 243 | fn list() { 244 | let mut builder = IrBuilder::new(); 245 | 246 | let content = vec![ 247 | builder.number(11.0), 248 | builder.number(22.0), 249 | builder.number(33.0), 250 | ]; 251 | 252 | let list = builder.list(content); 253 | 254 | builder.bind(Binding::local("bob", 0, 0), list); 255 | 256 | let var = builder.var(Binding::local("bob", 0, 0)); 257 | 258 | let index = builder.int(0); 259 | 260 | let new_element = builder.number(777.0); 261 | let set_list_element = builder.set_element(var.clone(), index.clone(), new_element); 262 | builder.emit(set_list_element); 263 | 264 | let right = builder.get_element(var, index); 265 | 266 | builder.bind(Binding::global("element"), right); // expect 777.0 267 | 268 | let mut vm = VM::new(); 269 | vm.exec(&builder.build(), true); 270 | 271 | println!("{:#?}", vm.globals) 272 | } 273 | 274 | #[test] 275 | fn recursion() { 276 | let mut builder = IrBuilder::new(); 277 | 278 | // This binding is used as the actual binding of the function fib, in the root scope. 279 | // The function is defined at a depth of 0, and a function depth of 0. 280 | let fib_binding = Binding::local("fib", 0, 0); 281 | 282 | let fib = builder.function(fib_binding.clone(), &["n"], |builder| { 283 | // This is where things get funky. Here we want to access fib from inside its own scope. 284 | // Thus it has to be made clear that we're upvalueing fib for this binding. 285 | // ... An *upvalue* is made when depth > function_depth 286 | // In conclusion, we're accessing fib from a depth of one, whereas fib is at function depth 0, 0 287 | let upvalue_fib = Binding::local("fib", 1, 0); 288 | 289 | // Here we're simply accessing acessing the parameter n, which will be bound at depth 1 and function_depth 1 290 | let n = builder.var(Binding::local("n", 1, 1)); 291 | 292 | let one = builder.number(1.0); 293 | let two = builder.number(2.0); 294 | 295 | let binary_0 = builder.binary(n.clone(), BinaryOp::Sub, one); 296 | let binary_1 = builder.binary(n.clone(), BinaryOp::Sub, two); 297 | 298 | println!("{}", upvalue_fib.is_upvalue()); 299 | 300 | // Here we're generating a reference based on the upvalue binding 301 | // This is used inside this scope, and will be cloned a couple of times. 302 | let fib_var = builder.var(upvalue_fib.clone()); // Fine for now, always pointing in the right direction :D 303 | 304 | let call_0 = builder.call(fib_var.clone(), vec![binary_0], None); 305 | let call_1 = builder.call(fib_var, vec![binary_1], None); 306 | 307 | let final_binary = builder.binary(call_0, BinaryOp::Add, call_1); 308 | 309 | let three = builder.number(3.0); 310 | let n_less_than_3 = builder.binary(n.clone(), BinaryOp::LtEqual, three); 311 | let ternary = builder.ternary(n_less_than_3, n.clone(), Some(final_binary)); 312 | 313 | builder.ret(Some(ternary)) 314 | }); 315 | 316 | // We don't have to bind fib as this is already done during function compilation. 317 | // In the future, anonymous functions will be easier to make. :D 318 | builder.emit(fib); 319 | 320 | let ten = builder.number(10.0); 321 | let fib_var = builder.var(fib_binding); 322 | 323 | let fib_call = builder.call(fib_var, vec![ten], None); 324 | 325 | let print = builder.var(Binding::global("print")); 326 | let call = builder.call(print, vec![fib_call], None); 327 | 328 | builder.emit(call); // :D 329 | 330 | let mut vm = VM::new(); 331 | vm.add_native("print", print_native, 1); 332 | vm.exec(&builder.build(), true); 333 | } 334 | 335 | #[test] 336 | fn dict() { 337 | let mut builder = IrBuilder::new(); 338 | 339 | let fruit = builder.string("fruit"); 340 | let apple = builder.string("Æble"); 341 | 342 | let dict = builder.empty_dict(); 343 | builder.bind(Binding::local("stuff", 0, 0), dict); 344 | 345 | let var = builder.var(Binding::local("stuff", 0, 0)); 346 | 347 | let set_fruit = builder.set_element(var.clone(), fruit.clone(), apple); 348 | 349 | builder.emit(set_fruit); 350 | 351 | let get_fruit = builder.get_element(var.clone(), fruit); 352 | 353 | builder.bind(Binding::global("test"), get_fruit); 354 | 355 | let mut vm = VM::new(); 356 | vm.exec(&builder.build(), true); 357 | 358 | println!(" sad sad {:#?}", vm.globals) 359 | } 360 | 361 | fn print_native(context: &mut CallContext) -> Value { 362 | println!("{}", context.get_arg_with_heap(1)); 363 | Value::nil() 364 | } 365 | } 366 | -------------------------------------------------------------------------------- /src/vm/chunk.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use gc::trace::{ Trace, Tracer }; 3 | 4 | #[derive(Debug, Clone)] 5 | pub struct Chunk { 6 | code: Vec, 7 | name: String, 8 | constants: Vec, 9 | lines: Vec, 10 | } 11 | 12 | impl Trace for Chunk { 13 | fn trace(&self, tracer: &mut Tracer) { 14 | self.constants.trace(tracer); 15 | } 16 | } 17 | 18 | #[derive(Debug, Copy, Clone)] 19 | struct Line { 20 | pub start: usize, 21 | pub line: usize, 22 | } 23 | 24 | impl Chunk { 25 | pub fn new(name: String) -> Self { 26 | Chunk { 27 | code: Vec::new(), 28 | name, 29 | constants: Vec::new(), 30 | lines: Vec::new() 31 | } 32 | } 33 | 34 | pub fn write(&mut self, op: Op, line: usize) { 35 | self.add_line(line); 36 | op.write(&mut self.code); 37 | } 38 | 39 | pub fn write_byte(&mut self, byte: u8) { 40 | self.code.push(byte); 41 | } 42 | 43 | pub fn write_byte_at(&mut self, idx: usize, byte: u8) { 44 | self.code[idx] = byte; 45 | } 46 | 47 | pub fn write_u64(&mut self, val: u64) { 48 | (0..8).for_each(|i| self.write_byte(((val >> i * 8) & 0xFF) as u8)) 49 | } 50 | 51 | #[inline] 52 | pub fn add_constant(&mut self, constant: Value) -> u8 { 53 | for (i, c) in self.constants.iter().enumerate() { 54 | if *c == constant { 55 | return i as u8; 56 | } 57 | } 58 | 59 | if self.constants.len() == 1028 { 60 | panic!("A chunk cannot have more than 1028 constants"); 61 | } 62 | 63 | self.constants.push(constant); 64 | self.constants.len() as u8 - 1 65 | } 66 | 67 | #[inline] 68 | pub fn string_constant(&mut self, heap: &mut Heap, string: &str) -> u8 { 69 | for (i, c) in self.constants().enumerate() { 70 | let obj = c 71 | .as_object() 72 | .and_then(|o| heap.get(o)) 73 | .and_then(|o| o.as_string()); 74 | 75 | if let Some(s) = obj { 76 | if s == string { 77 | return i as u8 78 | } 79 | } 80 | } 81 | 82 | let handle = heap.insert(Object::String(string.to_owned())).into_handle(); 83 | self.add_constant(handle.into()) 84 | } 85 | 86 | pub fn constants(&self) -> Constants { 87 | Constants::new(self.constants.iter()) 88 | } 89 | 90 | pub fn len(&self) -> usize { 91 | self.code.len() 92 | } 93 | 94 | fn add_line(&mut self, line: usize) { 95 | match self.lines.last().cloned() { 96 | Some(last) if last.line >= line => return, 97 | _ => (), 98 | } 99 | 100 | self.lines.push(Line { 101 | start: self.code.len(), 102 | line: line, 103 | }); 104 | } 105 | 106 | #[inline] 107 | pub fn get(&self, ip: usize) -> u8 { 108 | self.code[ip] 109 | } 110 | 111 | #[inline] 112 | pub fn get_constant(&self, idx: u8) -> Option<&Value> { 113 | self.constants.get(idx as usize) 114 | } 115 | 116 | pub fn line(&self, offset: usize) -> usize { 117 | let idx = 118 | self.lines 119 | .binary_search_by_key(&offset, |line_info| line_info.start) 120 | .map_err(|idx| idx - 1) // on failure we want the earlier line 121 | .unwrap_or_else(|idx| idx); 122 | self.lines[idx].line 123 | } 124 | 125 | #[inline] 126 | pub fn read_byte(&self, idx: usize) -> u8 { 127 | self.code[idx] 128 | } 129 | 130 | #[inline] 131 | pub fn read_u16(&self, idx: usize) -> u16 { 132 | let mut t = 0u16; 133 | let size = ::std::mem::size_of::(); 134 | 135 | unsafe { 136 | ::std::ptr::copy_nonoverlapping( 137 | &self.code[idx], 138 | &mut t as *mut u16 as *mut u8, 139 | size); 140 | } 141 | 142 | t.to_le() 143 | } 144 | 145 | #[inline] 146 | pub fn read_u64(&self, idx: usize) -> u64 { 147 | let mut t = 0u64; 148 | let size = ::std::mem::size_of::(); 149 | 150 | unsafe { 151 | ::std::ptr::copy_nonoverlapping( 152 | &self.code[idx], 153 | &mut t as *mut u64 as *mut u8, 154 | size); 155 | } 156 | 157 | t.to_le() 158 | } 159 | 160 | pub fn name(&self) -> &str { 161 | &self.name 162 | } 163 | } 164 | 165 | pub struct Constants<'c> { 166 | iter: ::std::slice::Iter<'c, Value> 167 | } 168 | 169 | impl<'c> Constants<'c> { 170 | fn new(iter: ::std::slice::Iter<'c, Value>) -> Self { 171 | Constants { iter } 172 | } 173 | } 174 | 175 | impl<'c> Iterator for Constants<'c> { 176 | type Item = Value; 177 | 178 | #[inline] 179 | fn next(&mut self) -> Option { 180 | self.iter.next().map(|v| *v) 181 | } 182 | } 183 | 184 | impl AsRef<[u8]> for Chunk { 185 | fn as_ref(&self) -> &[u8] { 186 | &self.code[..] 187 | } 188 | } 189 | 190 | #[repr(u8)] 191 | #[derive(Copy, Clone, Debug, PartialEq)] 192 | pub enum Op { 193 | Return, 194 | Constant(u8), 195 | Nil, 196 | True, 197 | False, 198 | Pop, 199 | GetLocal, 200 | SetLocal, 201 | GetGlobal, 202 | DefineGlobal, 203 | SetGlobal, 204 | GetUpValue, 205 | SetUpValue, 206 | 207 | Equal, 208 | Less, 209 | Greater, 210 | 211 | Add, 212 | Sub, 213 | Mul, 214 | Div, 215 | Rem, 216 | Pow, 217 | 218 | Not, 219 | Neg, 220 | 221 | Print, 222 | Jump, 223 | JumpIfFalse, 224 | Loop, 225 | Immediate, 226 | 227 | Call(u8), 228 | Closure, 229 | CloseUpValue, 230 | 231 | List, 232 | Tuple, 233 | Dict, 234 | GetElement, 235 | SetElement, 236 | } 237 | 238 | impl Op { 239 | fn write(&self, buf: &mut Vec) { 240 | use self::Op::*; 241 | 242 | match *self { 243 | Return => buf.push(0x00), 244 | Constant(idx) => { buf.push(0x01); buf.push(idx); } 245 | Print => buf.push(0x02), 246 | Add => buf.push(0x03), 247 | Sub => buf.push(0x04), 248 | Mul => buf.push(0x05), 249 | Div => buf.push(0x06), 250 | Not => buf.push(0x07), 251 | Neg => buf.push(0x08), 252 | Equal => buf.push(0x09), 253 | Greater => buf.push(0x0a), 254 | Less => buf.push(0x0b), 255 | Jump => buf.push(0x0c), 256 | JumpIfFalse => buf.push(0x0d), 257 | Pop => buf.push(0x0e), 258 | GetGlobal => buf.push(0x0f), 259 | SetGlobal => buf.push(0x10), 260 | GetLocal => buf.push(0x11), 261 | SetLocal => buf.push(0x12), 262 | Immediate => buf.push(0x13), 263 | Nil => buf.push(0x14), 264 | True => buf.push(0x15), 265 | False => buf.push(0x16), 266 | Call(a) => buf.push(0x17 + a), 267 | Loop => buf.push(0x20), 268 | CloseUpValue => buf.push(0x21), 269 | GetUpValue => buf.push(0x22), 270 | SetUpValue => buf.push(0x23), 271 | Closure => buf.push(0x24), 272 | DefineGlobal => buf.push(0x25), 273 | 274 | List => buf.push(0x26), 275 | Rem => buf.push(0x27), 276 | Dict => buf.push(0x28), 277 | SetElement => buf.push(0x29), 278 | GetElement => buf.push(0x30), 279 | Pow => buf.push(0x31), 280 | Tuple => buf.push(0x36), 281 | } 282 | } 283 | } 284 | 285 | macro_rules! decode_op { 286 | ($op:expr, $this:ident) => { 287 | match $op { 288 | 0x00 => $this.ret(), 289 | 0x01 => { let idx = $this.read_byte(); $this.constant(idx); } 290 | 0x02 => $this.print(), 291 | 0x03 => $this.add(), 292 | 0x04 => $this.sub(), 293 | 0x05 => $this.mul(), 294 | 0x06 => $this.div(), 295 | 0x07 => $this.not(), 296 | 0x08 => $this.neg(), 297 | 0x09 => $this.eq(), 298 | 0x0a => $this.gt(), 299 | 0x0b => $this.lt(), 300 | 0x0c => $this.jmp(), 301 | 0x0d => $this.jze(), 302 | 0x0e => { $this.pop(); }, 303 | 0x0f => $this.get_global(), 304 | 0x10 => $this.set_global(), 305 | 0x11 => $this.get_local(), 306 | 0x12 => $this.set_local(), 307 | 0x13 => $this.immediate(), 308 | 0x14 => $this.imm_nil(), 309 | 0x15 => $this.imm_true(), 310 | 0x16 => $this.imm_false(), 311 | a @ 0x17..=0x1f => { 312 | $this.call(a - 0x17) 313 | }, 314 | 0x20 => $this.op_loop(), 315 | 0x21 => $this.close_upvalue(), 316 | 0x22 => $this.get_upvalue(), 317 | 0x23 => $this.set_upvalue(), 318 | 0x24 => $this.closure(), 319 | 0x25 => $this.define_global(), 320 | 0x26 => $this.list(), 321 | 0x27 => $this.rem(), 322 | 0x28 => $this.dict(), 323 | 0x29 => $this.set_element(), 324 | 0x30 => $this.get_element(), 325 | 0x31 => $this.pow(), 326 | 0x36 => $this.tuple(), 327 | _ => { 328 | panic!("Unknown op {}", $op); 329 | } 330 | } 331 | } 332 | } -------------------------------------------------------------------------------- /src/vm/disassembler.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use colored::Colorize; 3 | use gc::trace::{Trace, Tracer}; 4 | 5 | pub struct Disassembler<'c> { 6 | offset: usize, 7 | line: usize, 8 | chunk: &'c Chunk, 9 | heap: &'c Heap, 10 | } 11 | 12 | impl<'c> Disassembler<'c> { 13 | pub fn new(chunk: &'c Chunk, heap: &'c Heap) -> Self { 14 | Disassembler { 15 | offset: 0, 16 | line: 0, 17 | chunk, 18 | heap, 19 | } 20 | } 21 | 22 | pub fn disassemble(mut self) { 23 | let bytes = self.chunk.as_ref(); 24 | 25 | println!(); 26 | let name = format!("== {} ==", self.chunk.name()); 27 | eprint!("{}", name.cyan()); 28 | 29 | while self.offset < bytes.len() { 30 | self.disassemble_instruction(); 31 | } 32 | 33 | println!(); 34 | } 35 | 36 | fn disassemble_instruction(&mut self) { 37 | let line = self.chunk.line(self.offset); 38 | if self.line == line { 39 | } else { 40 | self.line = line; 41 | } 42 | let inst = self.read_byte(); 43 | println!(); 44 | let off = format!("{:04} | ", self.offset); 45 | 46 | eprint!("{}", off.blue()); 47 | decode_op!(inst, self); 48 | } 49 | 50 | fn constant(&mut self, idx: u8) { 51 | let val = self.chunk.get_constant(idx); 52 | eprint!("CONSTANT\t{}\t{:?}", idx, val); 53 | } 54 | 55 | fn ret(&self) { 56 | eprint!("RETURN"); 57 | } 58 | fn print(&self) { 59 | eprint!("PRINT"); 60 | } 61 | fn add(&self) { 62 | eprint!("ADD"); 63 | } 64 | fn sub(&self) { 65 | eprint!("SUB"); 66 | } 67 | fn mul(&self) { 68 | eprint!("MUL"); 69 | } 70 | fn rem(&self) { 71 | eprint!("REM"); 72 | } 73 | fn pow(&self) { 74 | eprint!("POW"); 75 | } 76 | fn div(&self) { 77 | eprint!("DIV"); 78 | } 79 | fn neg(&self) { 80 | eprint!("NEG"); 81 | } 82 | fn not(&self) { 83 | eprint!("NOT"); 84 | } 85 | fn eq(&self) { 86 | eprint!("EQ"); 87 | } 88 | fn gt(&self) { 89 | eprint!("GT"); 90 | } 91 | fn lt(&self) { 92 | eprint!("LT"); 93 | } 94 | fn pop(&self) { 95 | eprint!("POP"); 96 | } 97 | 98 | fn list(&mut self) { 99 | eprint!("LIST"); 100 | self.read_byte(); 101 | } 102 | 103 | fn tuple(&mut self) { 104 | let size = self.read_byte(); 105 | eprint!("TUPLE\t{}", size); 106 | } 107 | 108 | fn get_element(&mut self) { 109 | eprint!("GET_ELEMENT"); 110 | } 111 | 112 | fn dict(&mut self) { 113 | eprint!("DICT"); 114 | self.read_byte(); 115 | } 116 | 117 | fn set_element(&mut self) { 118 | eprint!("SET_ELEMENT") 119 | } 120 | 121 | fn jmp(&mut self) { 122 | let offset = self.offset - 1; 123 | let ip = self.read_u16(); 124 | eprint!("JUMP\t{} -> {}", offset, ip); 125 | } 126 | 127 | fn jze(&mut self) { 128 | let offset = self.offset - 1; 129 | let ip = self.read_u16(); 130 | eprint!("JUMP_IF_FALSE\t{} -> {}", offset, ip); 131 | } 132 | 133 | fn op_loop(&mut self) { 134 | let sub = self.read_u16() as usize; 135 | eprint!("LOOP\t{} -> {}", self.offset, self.offset - sub); 136 | } 137 | 138 | fn get_global(&mut self) { 139 | let val = self.read_constant(); 140 | eprint!("GET_GLOBAL\t{}", val.with_heap(self.heap)); 141 | } 142 | 143 | fn set_global(&mut self) { 144 | let val = self.read_constant(); 145 | eprint!("SET_GLOBAL\t{}", val.with_heap(self.heap)); 146 | } 147 | 148 | fn define_global(&mut self) { 149 | let name = self.read_constant(); 150 | eprint!("DEFINE_GLOBAL\t{}", name.with_heap(self.heap)); 151 | } 152 | 153 | fn get_local(&mut self) { 154 | let val = self.read_byte(); 155 | eprint!("GET_LOCAL\t{}", val); 156 | } 157 | 158 | fn set_local(&mut self) { 159 | let val = self.read_byte(); 160 | eprint!("SET_LOCAL\t{}", val); 161 | } 162 | 163 | fn immediate(&mut self) { 164 | self.offset += 8; 165 | let b1 = self.chunk.get(self.offset - 8) as u64; 166 | let b2 = self.chunk.get(self.offset - 7) as u64; 167 | let b3 = self.chunk.get(self.offset - 6) as u64; 168 | let b4 = self.chunk.get(self.offset - 5) as u64; 169 | let b5 = self.chunk.get(self.offset - 4) as u64; 170 | let b6 = self.chunk.get(self.offset - 3) as u64; 171 | let b7 = self.chunk.get(self.offset - 2) as u64; 172 | let b8 = self.chunk.get(self.offset - 1) as u64; 173 | let raw = b1 174 | + (b2 << 8) 175 | + (b3 << 16) 176 | + (b4 << 24) 177 | + (b5 << 32) 178 | + (b6 << 40) 179 | + (b7 << 48) 180 | + (b8 << 56); 181 | let val = unsafe { Value::from_raw(raw) }; 182 | eprint!("FLOAT\t{}", val.with_heap(self.heap)); 183 | } 184 | 185 | fn imm_nil(&self) { 186 | eprint!("NIL"); 187 | } 188 | 189 | fn imm_true(&self) { 190 | eprint!("TRUE"); 191 | } 192 | 193 | fn imm_false(&self) { 194 | eprint!("FALSE"); 195 | } 196 | 197 | fn call(&self, arity: u8) { 198 | eprint!("CALL_{}", arity); 199 | } 200 | 201 | fn invoke(&mut self, arity: u8) { 202 | let idx = self.read_byte(); 203 | let val = self 204 | .chunk 205 | .get_constant(idx) 206 | .expect("invalid constant segment index"); 207 | eprint!("INVOKE_{} {}", arity, val.with_heap(&self.heap)); 208 | } 209 | 210 | fn close_upvalue(&self) { 211 | eprint!("CLOSE_UPVALUE"); 212 | } 213 | 214 | fn get_upvalue(&mut self) { 215 | let index = self.read_byte(); 216 | eprint!("GET_UPVALUE\t{}", index); 217 | } 218 | 219 | fn set_upvalue(&mut self) { 220 | let index = self.read_byte(); 221 | eprint!("SET_UPVALE\t{}", index); 222 | } 223 | 224 | fn closure(&mut self) { 225 | let val = self.read_constant(); 226 | println!("{:?}", unsafe { val.as_object().unwrap().get_unchecked() }); 227 | let count = val 228 | .as_object() 229 | .and_then(|o| self.heap.get(o)) 230 | .and_then(|o| o.as_function()) 231 | .expect("closure argument to be a function") 232 | .upvalue_count(); 233 | 234 | print!("CLOSURE\t{} ", val.with_heap(self.heap)); 235 | println!(); 236 | 237 | if let Variant::Obj(cl) = val.with_heap(self.heap).item.decode() { 238 | unsafe { 239 | let closure = cl.get_unchecked().as_function().unwrap(); 240 | 241 | let dis = Disassembler::new(closure.chunk(), &self.heap); 242 | dis.disassemble() 243 | } 244 | } 245 | 246 | for _ in 0..count { 247 | let _is_local = self.read_byte() > 0; 248 | let _index = self.read_byte(); 249 | } 250 | } 251 | 252 | fn class(&mut self, idx: u8) { 253 | let val = self 254 | .chunk 255 | .get_constant(idx) 256 | .expect("invalid constant segment index"); 257 | let methods = self.read_byte(); 258 | eprint!( 259 | "CLASS\t{}\t{}\t({} method(s))", 260 | idx, 261 | val.with_heap(&self.heap), 262 | methods 263 | ); 264 | } 265 | 266 | fn get_property(&mut self) { 267 | let idx = self.read_byte(); 268 | let val = self 269 | .chunk 270 | .get_constant(idx) 271 | .expect("invalid constant segment index"); 272 | eprint!("GET_PROPERTY\t{}\t{}", idx, val.with_heap(&self.heap)); 273 | } 274 | 275 | fn set_property(&mut self) { 276 | let idx = self.read_byte(); 277 | let val = self 278 | .chunk 279 | .get_constant(idx) 280 | .expect("invalid constant segment index"); 281 | eprint!("SET_PROPERTY\t{}\t{}", idx, val.with_heap(&self.heap)); 282 | } 283 | 284 | fn read_byte(&mut self) -> u8 { 285 | self.offset += 1; 286 | self.chunk.as_ref()[self.offset - 1] 287 | } 288 | 289 | fn read_u16(&mut self) -> u16 { 290 | self.offset += 2; 291 | let lo = self.chunk.get(self.offset - 2) as u16; 292 | let hi = self.chunk.get(self.offset - 1) as u16; 293 | lo + (hi << 8) 294 | } 295 | 296 | fn read_constant(&mut self) -> Value { 297 | let idx = self.read_byte(); 298 | *self 299 | .chunk 300 | .get_constant(idx) 301 | .expect("invalid constant segment index") 302 | } 303 | } 304 | -------------------------------------------------------------------------------- /src/vm/gc/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod trace; 2 | pub mod tag; 3 | 4 | use std::{ 5 | cmp::{PartialEq, Eq}, 6 | rc::Rc, 7 | hash::{Hash, Hasher}, 8 | }; 9 | use hashbrown::{HashMap, HashSet}; 10 | use trace::*; 11 | 12 | type Generation = usize; 13 | 14 | #[derive(Clone)] 15 | pub struct Heap { 16 | last_sweep: usize, 17 | object_sweeps: HashMap, usize>, 18 | obj_counter: Generation, 19 | objects: HashSet>, 20 | rooted: HashMap, Rc<()>>, 21 | } 22 | 23 | impl Default for Heap { 24 | fn default() -> Self { 25 | Self { 26 | last_sweep: 0, 27 | object_sweeps: HashMap::default(), 28 | obj_counter: 0, 29 | objects: HashSet::default(), 30 | rooted: HashMap::default(), 31 | } 32 | } 33 | } 34 | 35 | impl> Heap { 36 | /// Create an empty heap. 37 | pub fn new() -> Self { 38 | Self::default() 39 | } 40 | 41 | fn new_generation(&mut self) -> Generation { 42 | self.obj_counter += 1; 43 | self.obj_counter 44 | } 45 | 46 | /// Adds a new object to this heap that will be cleared upon the next garbage collection, if 47 | /// not attached to the object tree. 48 | pub fn insert_temp(&mut self, object: T) -> Handle { 49 | let ptr = Box::into_raw(Box::new(object)); 50 | 51 | let gen = self.new_generation(); 52 | let handle = Handle { gen, ptr }; 53 | self.objects.insert(handle); 54 | 55 | handle 56 | } 57 | 58 | /// Adds a new object to this heap that will not be cleared by garbage collection until all 59 | /// rooted handles have been dropped. 60 | pub fn insert(&mut self, object: T) -> Rooted { 61 | let handle = self.insert_temp(object); 62 | 63 | let rc = Rc::new(()); 64 | self.rooted.insert(handle, rc.clone()); 65 | 66 | Rooted { 67 | rc, 68 | handle, 69 | } 70 | } 71 | 72 | /// Upgrade a handle (that will be cleared by the garbage collector) into a rooted handle (that 73 | /// will not). 74 | pub fn make_rooted(&mut self, handle: impl AsRef>) -> Rooted { 75 | let handle = handle.as_ref(); 76 | debug_assert!(self.contains(handle)); 77 | 78 | Rooted { 79 | rc: self.rooted 80 | .entry(*handle) 81 | .or_insert_with(|| Rc::new(())) 82 | .clone(), 83 | handle: *handle, 84 | } 85 | } 86 | 87 | /// Count the number of heap-allocated objects in this heap 88 | pub fn len(&self) -> usize { 89 | self.objects.len() 90 | } 91 | 92 | /// Return true if the heap contains the specified handle 93 | pub fn contains(&self, handle: impl AsRef>) -> bool { 94 | let handle = handle.as_ref(); 95 | self.objects.contains(&handle) 96 | } 97 | 98 | /// Get a reference to a heap object if it exists on this heap. 99 | pub fn get(&self, handle: impl AsRef>) -> Option<&T> { 100 | let handle = handle.as_ref(); 101 | if self.contains(handle) { 102 | Some(unsafe { &*handle.ptr }) 103 | } else { 104 | None 105 | } 106 | } 107 | 108 | /// Get a reference to a heap object without checking whether it is still alive or that it 109 | /// belongs to this heap. 110 | /// 111 | /// If either invariant is not upheld, calling this function results in undefined 112 | /// behaviour. 113 | pub unsafe fn get_unchecked(&self, handle: impl AsRef>) -> &T { 114 | let handle = handle.as_ref(); 115 | debug_assert!(self.contains(handle)); 116 | &*handle.ptr 117 | } 118 | 119 | /// Get a mutable reference to a heap object 120 | pub fn get_mut(&mut self, handle: impl AsRef>) -> Option<&mut T> { 121 | let handle = handle.as_ref(); 122 | if self.contains(handle) { 123 | Some(unsafe { &mut *handle.ptr }) 124 | } else { 125 | None 126 | } 127 | } 128 | 129 | /// Get a mutable reference to a heap object without first checking that it is still alive or 130 | /// that it belongs to this heap. 131 | /// 132 | /// If either invariant is not upheld, calling this function results in undefined 133 | /// behaviour. Provided they are upheld, this function provides zero-cost access. 134 | pub fn get_mut_unchecked(&mut self, handle: impl AsRef>) -> &mut T { 135 | let handle = handle.as_ref(); 136 | debug_assert!(self.contains(handle)); 137 | unsafe { &mut *handle.ptr } 138 | } 139 | 140 | pub fn clean_excluding(&mut self, excluding: impl IntoIterator>) { 141 | let new_sweep = self.last_sweep + 1; 142 | let mut tracer = Tracer { 143 | new_sweep, 144 | object_sweeps: &mut self.object_sweeps, 145 | objects: &self.objects, 146 | }; 147 | 148 | // Mark 149 | self.rooted 150 | .retain(|handle, rc| { 151 | if Rc::strong_count(rc) > 1 { 152 | tracer.mark(*handle); 153 | unsafe { (&*handle.ptr).trace(&mut tracer); } 154 | true 155 | } else { 156 | false 157 | } 158 | }); 159 | let objects = &self.objects; 160 | excluding 161 | .into_iter() 162 | .filter(|handle| objects.contains(&handle)) 163 | .for_each(|handle| { 164 | tracer.mark(handle); 165 | unsafe { (&*handle.ptr).trace(&mut tracer); } 166 | }); 167 | 168 | // Sweep 169 | let object_sweeps = &mut self.object_sweeps; 170 | self.objects 171 | .retain(|handle| { 172 | if object_sweeps 173 | .get(handle) 174 | .map(|sweep| *sweep == new_sweep) 175 | .unwrap_or(false) 176 | { 177 | true 178 | } else { 179 | object_sweeps.remove(handle); 180 | drop(unsafe { Box::from_raw(handle.ptr) }); 181 | false 182 | } 183 | }); 184 | 185 | self.last_sweep = new_sweep; 186 | } 187 | 188 | /// Clean orphaned objects from the heap. 189 | pub fn clean(&mut self) { 190 | self.clean_excluding(std::iter::empty()); 191 | } 192 | } 193 | 194 | impl Drop for Heap { 195 | fn drop(&mut self) { 196 | for handle in &self.objects { 197 | drop(unsafe { Box::from_raw(handle.ptr) }); 198 | } 199 | } 200 | } 201 | 202 | #[derive(Debug)] 203 | pub struct Handle { 204 | gen: Generation, 205 | pub ptr: *mut T, 206 | } 207 | 208 | impl Handle { 209 | pub unsafe fn get_unchecked(&self) -> &T { 210 | &*self.ptr 211 | } 212 | 213 | pub unsafe fn get_mut_unchecked(&self) -> &mut T { 214 | &mut *self.ptr 215 | } 216 | } 217 | 218 | impl Copy for Handle {} 219 | impl Clone for Handle { 220 | fn clone(&self) -> Self { 221 | Self { gen: self.gen, ptr: self.ptr } 222 | } 223 | } 224 | 225 | impl PartialEq for Handle { 226 | fn eq(&self, other: &Self) -> bool { 227 | self.gen == other.gen && self.ptr == other.ptr 228 | } 229 | } 230 | impl Eq for Handle {} 231 | 232 | impl Hash for Handle { 233 | fn hash(&self, state: &mut H) { 234 | self.gen.hash(state); 235 | self.ptr.hash(state); 236 | } 237 | } 238 | 239 | impl AsRef> for Handle { 240 | fn as_ref(&self) -> &Handle { 241 | self 242 | } 243 | } 244 | 245 | impl From> for Handle { 246 | fn from(rooted: Rooted) -> Self { 247 | rooted.handle 248 | } 249 | } 250 | 251 | #[derive(Debug)] 252 | pub struct Rooted { 253 | rc: Rc<()>, 254 | handle: Handle, 255 | } 256 | 257 | impl Clone for Rooted { 258 | fn clone(&self) -> Self { 259 | Self { 260 | rc: self.rc.clone(), 261 | handle: self.handle, 262 | } 263 | } 264 | } 265 | 266 | impl AsRef> for Rooted { 267 | fn as_ref(&self) -> &Handle { 268 | &self.handle 269 | } 270 | } 271 | 272 | impl Rooted { 273 | pub fn into_handle(self) -> Handle { 274 | self.handle 275 | } 276 | 277 | pub fn handle(&self) -> Handle { 278 | self.handle 279 | } 280 | } -------------------------------------------------------------------------------- /src/vm/gc/tag.rs: -------------------------------------------------------------------------------- 1 | use super::Handle; 2 | 3 | #[derive(Debug)] 4 | pub struct TaggedHandle { 5 | handle: Handle, 6 | } 7 | 8 | #[derive(Debug, Clone, Copy, PartialEq)] 9 | pub enum Tag { 10 | Tag(u8), 11 | Float(f64), 12 | Handle(Handle), 13 | } 14 | 15 | const QNAN: u64 = 0x7ffc000000000000; 16 | const SIGN: u64 = 1 << 63; 17 | 18 | impl TaggedHandle { 19 | pub unsafe fn from_raw(raw: u64) -> Self { 20 | TaggedHandle { 21 | handle: Handle { 22 | gen: 0, 23 | ptr: raw as *mut T 24 | }, 25 | } 26 | } 27 | 28 | pub fn to_raw(&self) -> u64 { 29 | self.handle.ptr as u64 30 | } 31 | 32 | pub fn from_handle(handle: Handle) -> Self { 33 | let u = (handle.ptr as u64) | QNAN | SIGN; 34 | TaggedHandle{ 35 | handle: Handle { 36 | gen: handle.gen, 37 | ptr: u as *mut T, 38 | } 39 | } 40 | } 41 | 42 | pub fn from_float(float: f64) -> Self { 43 | TaggedHandle { 44 | handle: Handle { 45 | gen: 0, 46 | ptr: unsafe { ::std::mem::transmute(float) }, 47 | }, 48 | } 49 | } 50 | 51 | pub fn from_tag(tag: u8) -> Self { 52 | TaggedHandle { 53 | handle: Handle { 54 | gen: 0, 55 | ptr: unsafe { ::std::mem::transmute(QNAN | (tag as u64)) }, 56 | }, 57 | } 58 | } 59 | 60 | pub fn decode(self) -> Tag { 61 | let u = self.handle.ptr as u64; 62 | if u & QNAN != QNAN { 63 | return Tag::Float(unsafe { ::std::mem::transmute(u) }); 64 | } 65 | if (u & (QNAN | SIGN)) == (QNAN | SIGN) { 66 | let ptr = u & (!(QNAN | SIGN)); // only keep lower 51 bits 67 | return Tag::Handle(Handle { 68 | gen: self.handle.gen, 69 | ptr: ptr as *mut T, 70 | }); 71 | } 72 | let tag: u8 = (u & 7) as u8; 73 | Tag::Tag(tag) 74 | } 75 | } 76 | 77 | impl Clone for TaggedHandle { 78 | fn clone(&self) -> Self { 79 | TaggedHandle { handle: self.handle } 80 | } 81 | } 82 | impl Copy for TaggedHandle {} 83 | 84 | impl PartialEq for TaggedHandle { 85 | fn eq(&self, other: &Self) -> bool { 86 | self.handle == other.handle 87 | } 88 | } 89 | impl Eq for TaggedHandle {} 90 | 91 | impl From> for TaggedHandle { 92 | fn from(handle: Handle) -> Self { 93 | Self::from_handle(handle) 94 | } 95 | } 96 | 97 | impl From for TaggedHandle { 98 | fn from(float: f64) -> Self { 99 | Self::from_float(float) 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/vm/gc/trace.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | 4 | pub trait Trace> { 5 | fn trace(&self, tracer: &mut Tracer); 6 | } 7 | 8 | pub struct Tracer<'a, T: Trace> { 9 | pub(crate) new_sweep: usize, 10 | pub(crate) object_sweeps: &'a mut HashMap, usize>, 11 | pub(crate) objects: &'a HashSet>, 12 | } 13 | 14 | impl<'a, T: Trace> Tracer<'a, T> { 15 | pub(crate) fn mark(&mut self, handle: Handle) { 16 | let sweep = self.object_sweeps 17 | .entry(handle) 18 | .or_insert(self.new_sweep - 1); 19 | if *sweep != self.new_sweep && self.objects.contains(&handle) { 20 | *sweep = self.new_sweep; 21 | unsafe { (&*handle.ptr).trace(self); } 22 | } 23 | } 24 | } 25 | 26 | impl> Trace for Handle { 27 | fn trace(&self, tracer: &mut Tracer) { 28 | tracer.mark(*self); 29 | } 30 | } 31 | 32 | impl> Trace for Rooted { 33 | fn trace(&self, tracer: &mut Tracer) { 34 | self.handle().trace(tracer); 35 | } 36 | } 37 | 38 | use std::collections::{ 39 | HashMap as StdHashMap, 40 | VecDeque, 41 | LinkedList, 42 | }; 43 | 44 | impl, T: Trace> Trace for [T] { 45 | fn trace(&self, tracer: &mut Tracer) { 46 | self.iter().for_each(|object| object.trace(tracer)); 47 | } 48 | } 49 | 50 | impl, T: Trace> Trace for VecDeque { 51 | fn trace(&self, tracer: &mut Tracer) { 52 | self.iter().for_each(|object| object.trace(tracer)); 53 | } 54 | } 55 | 56 | impl, T: Trace> Trace for LinkedList { 57 | fn trace(&self, tracer: &mut Tracer) { 58 | self.iter().for_each(|object| object.trace(tracer)); 59 | } 60 | } 61 | 62 | impl, K, V: Trace> Trace for StdHashMap { 63 | fn trace(&self, tracer: &mut Tracer) { 64 | self.values().for_each(|object| object.trace(tracer)); 65 | } 66 | } 67 | 68 | impl, T: Trace> Trace for HashSet { 69 | fn trace(&self, tracer: &mut Tracer) { 70 | self.iter().for_each(|object| object.trace(tracer)); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/vm/interop.rs: -------------------------------------------------------------------------------- 1 | use std::{sync::Mutex, rc::Rc}; 2 | 3 | use super::{Heap, Value, VM, Object, WithHeap, Handle}; 4 | 5 | pub struct CallContext<'vm> { 6 | pub vm: &'vm mut VM, 7 | frame_start: usize, 8 | } 9 | 10 | impl<'vm> CallContext<'vm> { 11 | pub fn new(vm: &'vm mut VM, frame_start: usize) -> Self { Self { vm, frame_start } } 12 | 13 | pub fn get_arg(&mut self, index: usize) -> Value { 14 | let args = &self.vm.stack[self.frame_start..]; 15 | args[index] 16 | } 17 | 18 | pub fn get_arg_with_heap(&mut self, index: usize) -> WithHeap<'_, Value> { 19 | self.get_arg(index).with_heap(&self.vm.heap) 20 | } 21 | 22 | pub fn with_heap(&mut self, value: Value) -> WithHeap<'_, Value> { 23 | value.with_heap(&self.vm.heap) 24 | } 25 | 26 | pub fn call(&mut self, function: Handle, args: Vec) -> Value { 27 | let vm = &mut self.vm; 28 | vm.internal_call(function, args) 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/vm/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod value; 2 | #[macro_use] 3 | pub mod chunk; 4 | pub mod vm; 5 | pub mod gc; 6 | pub mod disassembler; 7 | pub mod interop; 8 | 9 | use super::compiler::*; 10 | use super::ir::*; 11 | 12 | pub use self::value::*; 13 | #[macro_use] 14 | pub use self::chunk::*; 15 | pub use self::vm::*; 16 | pub use self::gc::*; 17 | pub use self::disassembler::*; 18 | pub use self::interop::*; 19 | pub use interop::CallContext; -------------------------------------------------------------------------------- /src/vm/value/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod value; 2 | pub mod object; 3 | 4 | use super::*; 5 | 6 | pub use self::value::*; 7 | pub use self::object::*; 8 | -------------------------------------------------------------------------------- /src/vm/value/object.rs: -------------------------------------------------------------------------------- 1 | use super::super::gc::{tag::*, trace::*, *}; 2 | use super::*; 3 | 4 | use std::cell::RefCell; 5 | use std::fmt::{Debug, Display}; 6 | use std::rc::Rc; 7 | 8 | use im_rc::hashmap::HashMap; 9 | 10 | // lol nice 11 | macro_rules! impl_as ( 12 | ($name:ident, $typ:ident) => { 13 | pub fn $name(&self) -> Option<&$typ> { 14 | if let Object::$typ(ref o) = *self { 15 | Some(o) 16 | } else { 17 | None 18 | } 19 | } 20 | } 21 | ); 22 | 23 | #[derive(Clone)] 24 | pub struct Tuple { 25 | pub inner: Box<[Value]>, 26 | } 27 | 28 | impl Tuple { 29 | pub fn new(data: Vec) -> Self { 30 | Self { 31 | inner: data.into_boxed_slice(), 32 | } 33 | } 34 | 35 | pub fn get(&self, index: usize) -> &Value { 36 | self.inner.get(index).unwrap() 37 | } 38 | 39 | pub fn set(&mut self, index: usize, value: Value) { 40 | self.inner[index] = value; 41 | } 42 | } 43 | 44 | impl std::fmt::Debug for Tuple { 45 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 46 | write!(f, "tuple<")?; 47 | for i in self.inner.iter() { 48 | let v = unsafe { 49 | if let Some(obj) = i.as_object() { 50 | obj.get_unchecked().fmt(f) 51 | } else { 52 | i.fmt(f) 53 | } 54 | }?; 55 | print!(","); 56 | } 57 | write!(f, ">") 58 | } 59 | } 60 | 61 | pub enum Object { 62 | String(String), 63 | Function(Function), 64 | NativeFunction(NativeFunction), 65 | Closure(Closure), 66 | List(List), 67 | Dict(Dict), 68 | Tuple(Tuple), 69 | } 70 | 71 | impl Object { 72 | impl_as!(as_string, String); 73 | impl_as!(as_closure, Closure); 74 | impl_as!(as_function, Function); 75 | impl_as!(as_list, List); 76 | impl_as!(as_dict, Dict); 77 | impl_as!(as_tuple, Tuple); 78 | 79 | pub fn native_fn(name: &str, arity: u8, function: NativeFunctionType) -> Self { 80 | Object::NativeFunction(NativeFunction { 81 | name: name.into(), 82 | arity, 83 | function, 84 | }) 85 | } 86 | 87 | pub fn as_closure_mut(&mut self) -> Option<&mut Closure> { 88 | if let Object::Closure(ref mut o) = *self { 89 | Some(o) 90 | } else { 91 | None 92 | } 93 | } 94 | } 95 | 96 | impl Trace for Object { 97 | fn trace(&self, tracer: &mut Tracer) { 98 | use self::Object::*; 99 | 100 | match self { 101 | Tuple(..) => {} 102 | String(_) => {} 103 | Function(f) => f.trace(tracer), 104 | NativeFunction(_) => {} 105 | Closure(c) => c.trace(tracer), 106 | List(l) => l.trace(tracer), 107 | Dict(d) => d.trace(tracer), 108 | } 109 | } 110 | } 111 | 112 | impl Debug for Object { 113 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 114 | use self::Object::*; 115 | 116 | match self { 117 | String(ref s) => write!(f, "{:?}", s), 118 | NativeFunction(ref na) => write!(f, "", na.name), 119 | Function(ref fun) => write!(f, "{}", display_function(fun)), 120 | Closure(ref cl) => write!(f, "", cl.function), 121 | List(ref ls) => write!(f, "", ls.content.len()), 122 | Dict(ref dict) => write!(f, "", dict.content.len()), 123 | Tuple(t) => write!(f, "{t:?}"), 124 | } 125 | } 126 | } 127 | 128 | impl<'h, 'a> Display for WithHeap<'h, &'a Object> { 129 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 130 | use self::Object::*; 131 | 132 | match self.item { 133 | String(ref s) => write!(f, "{}", s), 134 | NativeFunction(ref na) => write!(f, "", na.name), 135 | Function(ref fun) => write!(f, "{}", display_function(fun)), 136 | Closure(ref cl) => write!(f, "", cl.function.name), 137 | List(ref ls) => write!(f, "", ls.content.len()), 138 | Dict(ref ls) => write!(f, "", ls.content.len()), 139 | Tuple(t) => write!(f, "{t:?}"), 140 | } 141 | } 142 | } 143 | 144 | fn display_function(function: &Function) -> String { 145 | let chars = b"abcdefghijklmnopqrstuvwxyz"; 146 | 147 | format!( 148 | "", 149 | function.name, 150 | (0..function.arity) 151 | .map(|num| (chars[num as usize] as char).to_string()) 152 | .collect::>() 153 | .join(",") 154 | ) 155 | } 156 | 157 | #[derive(Debug)] 158 | pub struct FunctionBuilder { 159 | name: String, 160 | pub chunk: Chunk, 161 | arity: u8, 162 | upvalue_count: usize, 163 | } 164 | 165 | impl FunctionBuilder { 166 | pub fn new(name: &str, arity: u8) -> Self { 167 | let name: String = name.into(); 168 | let chunk = Chunk::new(name.clone()); 169 | FunctionBuilder { 170 | name, 171 | arity, 172 | chunk, 173 | upvalue_count: 0, 174 | } 175 | } 176 | 177 | pub fn name(&self) -> &str { 178 | &self.name 179 | } 180 | 181 | pub fn chunk_mut(&mut self) -> &mut Chunk { 182 | &mut self.chunk 183 | } 184 | 185 | pub fn set_upvalue_count(&mut self, count: usize) { 186 | self.upvalue_count = count; 187 | } 188 | 189 | pub fn build(self) -> Function { 190 | Function::new(self) 191 | } 192 | } 193 | 194 | #[derive(Debug, Clone)] 195 | pub struct Function { 196 | name: String, 197 | chunk: Chunk, 198 | arity: u8, 199 | upvalue_count: usize, 200 | } 201 | 202 | impl Function { 203 | fn new(builder: FunctionBuilder) -> Self { 204 | Function { 205 | name: builder.name, 206 | arity: builder.arity, 207 | chunk: builder.chunk, 208 | upvalue_count: builder.upvalue_count, 209 | } 210 | } 211 | 212 | pub fn name(&self) -> &str { 213 | &self.name 214 | } 215 | 216 | pub fn chunk(&self) -> &Chunk { 217 | &self.chunk 218 | } 219 | 220 | pub fn upvalue_count(&self) -> usize { 221 | self.upvalue_count 222 | } 223 | } 224 | 225 | impl Trace for Function { 226 | fn trace(&self, tracer: &mut Tracer) { 227 | self.chunk.trace(tracer); 228 | } 229 | } 230 | 231 | /// Type to represent a native function which is able to call 232 | /// a function passed to it as an argument 233 | pub type Callable<'a> = &'a mut dyn FnMut(Handle, u8, Vec); 234 | 235 | /* #[derive(Clone)] 236 | /// Whether the native function call will be able to call objects (functions) 237 | /// passed as arguments 238 | pub enum FunctionType { 239 | ParameterCall(fn(&mut Heap, &[Value], Callable) -> Value), 240 | Simple(fn(&mut Heap, &[Value]) -> Value), 241 | } 242 | */ 243 | 244 | pub type NativeFunctionType = fn(&mut CallContext) -> Value; 245 | #[derive(Clone)] 246 | pub struct NativeFunction { 247 | pub name: String, 248 | pub arity: u8, 249 | pub function: NativeFunctionType, 250 | } 251 | 252 | #[derive(Debug, Clone)] 253 | pub struct UpValue { 254 | inner: Rc>>, 255 | } 256 | 257 | impl UpValue { 258 | pub fn new(local: usize) -> Self { 259 | UpValue { 260 | inner: Rc::new(RefCell::new(Err(local))), 261 | } 262 | } 263 | 264 | pub fn close Value>(&mut self, f: F) { 265 | let mut inner = self.inner.borrow_mut(); 266 | if let Err(e) = *inner { 267 | *inner = Ok(f(e)) 268 | } 269 | } 270 | 271 | pub fn as_local(&self) -> Option { 272 | self.inner.borrow().err() 273 | } 274 | 275 | pub fn get(&self) -> Result { 276 | self.inner.borrow().clone() 277 | } 278 | 279 | pub fn set(&mut self, value: Value) -> Result<(), usize> { 280 | let mut inner = self.inner.borrow_mut(); 281 | (*inner)?; 282 | 283 | *inner = Ok(value); 284 | 285 | Ok(()) 286 | } 287 | } 288 | 289 | pub struct Dict { 290 | pub content: HashMap, 291 | } 292 | 293 | impl Dict { 294 | #[inline] 295 | pub fn new(content: HashMap) -> Self { 296 | Dict { content } 297 | } 298 | 299 | #[inline] 300 | pub fn empty() -> Self { 301 | Dict { 302 | content: HashMap::new(), 303 | } 304 | } 305 | 306 | pub fn insert(&mut self, key: HashValue, value: Value) { 307 | self.content.insert(key, value); 308 | } 309 | 310 | pub fn get(&self, key: &HashValue) -> Option<&Value> { 311 | self.content.get(key) 312 | } 313 | } 314 | 315 | impl Trace for Dict { 316 | fn trace(&self, tracer: &mut Tracer) { 317 | self.content.values().for_each(|v| v.trace(tracer)); 318 | } 319 | } 320 | 321 | #[derive(Debug)] 322 | pub struct List { 323 | pub content: Vec, 324 | } 325 | 326 | // Inline everything >:() 327 | impl List { 328 | #[inline] 329 | pub fn new(content: Vec) -> Self { 330 | List { content } 331 | } 332 | 333 | #[inline] 334 | pub fn set(&mut self, idx: usize, value: Value) { 335 | self.content[idx] = value 336 | } 337 | 338 | #[inline] 339 | pub fn push(&mut self, value: Value) { 340 | self.content.push(value) 341 | } 342 | 343 | #[inline] 344 | pub fn pop(&mut self) -> Value { 345 | self.content.pop().unwrap() 346 | } 347 | 348 | #[inline] 349 | pub fn get(&self, idx: usize) -> Value { 350 | self.content[idx].clone() // Might not have to use a clone here 351 | } 352 | } 353 | 354 | impl Trace for List { 355 | fn trace(&self, tracer: &mut Tracer) { 356 | self.content.iter().for_each(|v| v.trace(tracer)); 357 | } 358 | } 359 | 360 | #[derive(Debug, Clone)] 361 | pub struct Closure { 362 | function: Function, 363 | upvalues: Vec, 364 | } 365 | 366 | impl Closure { 367 | pub fn new(function: Function, upvalues: Vec) -> Self { 368 | Closure { function, upvalues } 369 | } 370 | 371 | pub fn name(&self) -> &str { 372 | self.function.name() 373 | } 374 | 375 | pub fn arity(&self) -> u8 { 376 | self.function.arity 377 | } 378 | 379 | pub fn chunk(&self) -> &Chunk { 380 | self.function.chunk() 381 | } 382 | 383 | pub fn upvalue_count(&self) -> usize { 384 | self.upvalues.len() 385 | } 386 | 387 | #[inline] 388 | pub fn get(&self, idx: usize) -> UpValue { 389 | self.upvalues[idx].clone() 390 | } 391 | } 392 | 393 | impl Trace for Closure { 394 | fn trace(&self, tracer: &mut Tracer) { 395 | self.function.trace(tracer); 396 | self.upvalues 397 | .iter() 398 | .flat_map(|u| u.get()) 399 | .for_each(|v| v.trace(tracer)); 400 | } 401 | } 402 | -------------------------------------------------------------------------------- /src/vm/value/value.rs: -------------------------------------------------------------------------------- 1 | use super::super::gc::{ *, tag::*, trace::* }; 2 | use super::*; 3 | 4 | use std::fmt::{Debug, Display}; 5 | use std::mem; 6 | 7 | #[derive(Clone, Copy, PartialEq, Eq)] 8 | pub struct Value { 9 | handle: TaggedHandle, 10 | } 11 | 12 | #[derive(Hash, Clone, PartialEq, Eq, Debug)] 13 | pub enum HashVariant { 14 | Bool(bool), 15 | Int(i64), 16 | Str(String), 17 | Nil, 18 | } 19 | 20 | #[derive(Hash, Clone, PartialEq, Eq, Debug)] 21 | pub struct HashValue { 22 | pub variant: HashVariant 23 | } 24 | 25 | #[derive(Debug, Clone, PartialEq)] 26 | pub enum Variant { 27 | Float(f64), 28 | True, 29 | False, 30 | Nil, 31 | Obj(Handle), 32 | } 33 | 34 | impl Variant { 35 | pub fn to_hash(&self, heap: &Heap) -> HashVariant { 36 | use self::Variant::*; 37 | 38 | match *self { 39 | Float(ref f) => { 40 | unsafe { 41 | HashVariant::Int( 42 | mem::transmute::(*f) 43 | ) 44 | } 45 | }, 46 | 47 | True => HashVariant::Bool(true), 48 | False => HashVariant::Bool(false), 49 | 50 | Obj(ref n) => unsafe { 51 | HashVariant::Str(heap.get_unchecked(n).as_string().unwrap().clone().to_string()) 52 | }, 53 | 54 | Nil => HashVariant::Nil, 55 | } 56 | } 57 | } 58 | 59 | const TAG_TRUE: u8 = 0x01; 60 | const TAG_FALSE: u8 = 0x02; 61 | const TAG_NIL: u8 = 0x03; 62 | 63 | impl Value { 64 | #[inline] 65 | pub unsafe fn from_raw(raw: u64) -> Self { 66 | Value { 67 | handle: TaggedHandle::from_raw(raw), 68 | } 69 | } 70 | 71 | pub fn to_raw(self) -> u64 { 72 | self.handle.to_raw() 73 | } 74 | 75 | #[inline] 76 | pub fn as_float(&self) -> f64 { 77 | if let Variant::Float(f) = self.decode() { 78 | return f 79 | } 80 | 81 | panic!("non-float") 82 | } 83 | 84 | #[inline] 85 | pub fn decode(&self) -> Variant { 86 | use self::Tag::*; 87 | 88 | match self.handle.clone().decode() { 89 | Float(n) => Variant::Float(n), 90 | Handle(n) => Variant::Obj(n), 91 | Tag(t) if t == TAG_TRUE => Variant::True, 92 | Tag(t) if t == TAG_FALSE => Variant::False, 93 | Tag(t) if t == TAG_NIL => Variant::Nil, 94 | Tag(t) => panic!("Unknown tag: {}", t) 95 | } 96 | } 97 | 98 | #[inline] 99 | pub fn as_object<'a>(&self) -> Option> { 100 | match self.decode() { 101 | Variant::Obj(o) => Some(o), 102 | _ => None, 103 | } 104 | } 105 | 106 | pub fn with_heap<'h>(&self, heap: &'h Heap) -> WithHeap<'h, Self> { 107 | WithHeap::new(heap, *self) 108 | } 109 | 110 | pub fn float(float: f64) -> Self { 111 | Value { 112 | handle: TaggedHandle::from_float(float), 113 | } 114 | } 115 | 116 | pub fn truelit() -> Self { 117 | Value { 118 | handle: TaggedHandle::from_tag(TAG_TRUE), 119 | } 120 | } 121 | 122 | pub fn falselit() -> Self { 123 | Value { 124 | handle: TaggedHandle::from_tag(TAG_FALSE), 125 | } 126 | } 127 | 128 | pub fn truthy(&self) -> bool { 129 | match self.decode() { 130 | Variant::False | Variant::Nil => false, 131 | _ => true, 132 | } 133 | } 134 | 135 | pub fn nil() -> Self { 136 | Value { 137 | handle: TaggedHandle::from_tag(TAG_NIL), 138 | } 139 | } 140 | 141 | pub fn object(handle: Handle) -> Self { 142 | Value { 143 | handle: TaggedHandle::from_handle(handle) 144 | } 145 | } 146 | } 147 | 148 | impl Trace for Value { 149 | fn trace(&self, tracer: &mut Tracer) { 150 | if let Variant::Obj(obj) = self.decode() { 151 | obj.trace(tracer); 152 | } 153 | } 154 | } 155 | 156 | impl From> for Value { 157 | fn from(handle: Handle) -> Self { 158 | Value::object(handle) 159 | } 160 | } 161 | 162 | impl Debug for Value { 163 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 164 | match self.decode() { 165 | Variant::Nil => write!(f, "nil"), 166 | Variant::False => write!(f, "false"), 167 | Variant::True => write!(f, "true"), 168 | Variant::Float(n) => write!(f, "{:?}", n), 169 | Variant::Obj(o) => write!(f, "{:?}", o), 170 | } 171 | } 172 | } 173 | 174 | impl Into for f64 { 175 | fn into(self) -> Value { 176 | Value::float(self) 177 | } 178 | } 179 | 180 | impl Into for bool { 181 | fn into(self) -> Value { 182 | if self { 183 | Value::truelit() 184 | } else { 185 | Value::falselit() 186 | } 187 | } 188 | } 189 | 190 | pub struct WithHeap<'h, T> { 191 | pub heap: &'h Heap, 192 | pub item: T, 193 | } 194 | 195 | impl<'h, T> WithHeap<'h, T> { 196 | pub fn new(heap: &'h Heap, item: T) -> WithHeap<'h, T> { 197 | WithHeap { heap, item } 198 | } 199 | 200 | pub fn with(&self, item: U) -> WithHeap { 201 | WithHeap { heap: self.heap, item } 202 | } 203 | } 204 | 205 | impl<'h> Display for WithHeap<'h, Value> { 206 | fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { 207 | match self.item.decode() { 208 | Variant::Nil => write!(f, "nil"), 209 | Variant::False => write!(f, "false"), 210 | Variant::True => write!(f, "true"), 211 | Variant::Float(n) => write!(f, "{}", n), 212 | Variant::Obj(o) => { 213 | let o = self.heap.get(o).ok_or(::std::fmt::Error)?; 214 | write!(f, "{}", self.with(o)) 215 | }, 216 | } 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /src/vm/vm.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::fs::File; 3 | 4 | use fnv::FnvBuildHasher; 5 | 6 | use super::*; 7 | use flame as f; 8 | use flamer::flame; 9 | 10 | use std::mem; 11 | 12 | const STACK_SIZE: usize = 4096; 13 | const HEAP_GROWTH: usize = 2; 14 | 15 | const GC_TRIGGER_COUNT: usize = 1024; 16 | 17 | pub struct CallFrame { 18 | closure: Handle, 19 | ip: usize, 20 | stack_start: usize, 21 | } 22 | 23 | impl CallFrame { 24 | pub fn new(closure: Handle, stack_start: usize) -> Self { 25 | CallFrame { 26 | closure, 27 | ip: 0, 28 | stack_start, 29 | } 30 | } 31 | 32 | pub fn read_byte(&mut self) -> u8 { 33 | let ip = self.ip; 34 | self.ip += 1; 35 | self.with_chunk(|c| c.read_byte(ip)) 36 | } 37 | 38 | pub fn read_u16(&mut self) -> u16 { 39 | let ip = self.ip; 40 | self.ip += 2; 41 | self.with_chunk(|c| c.read_u16(ip)) 42 | } 43 | 44 | pub fn read_u64(&mut self) -> u64 { 45 | let ip = self.ip; 46 | self.ip += 8; 47 | self.with_chunk(|c| c.read_u64(ip)) 48 | } 49 | 50 | pub fn read_constant_at(&mut self, idx: u8) -> Value { 51 | self.with_chunk(|c| *c.get_constant(idx).expect("invalid constant index")) 52 | } 53 | 54 | pub fn read_constant(&mut self) -> Value { 55 | let idx = self.read_byte(); 56 | self.read_constant_at(idx) 57 | } 58 | 59 | pub fn with_chunk(&self, fun: F) -> T 60 | where 61 | F: FnOnce(&Chunk) -> T, 62 | { 63 | unsafe { 64 | let closure = self 65 | .closure 66 | .get_unchecked() 67 | .as_closure() 68 | .expect("closure reference by construction"); 69 | fun(closure.chunk()) 70 | } 71 | } 72 | } 73 | 74 | macro_rules! binary_op { 75 | ($self:ident, $op:tt) => { 76 | let b = $self.pop(); 77 | let a = $self.pop(); 78 | 79 | $self.push((a == b).into()); 80 | return 81 | }; 82 | } 83 | 84 | pub struct VM { 85 | pub heap: Heap, 86 | next_gc: usize, 87 | 88 | pub globals: HashMap, 89 | pub open_upvalues: Vec, 90 | 91 | pub stack: Vec, 92 | pub frames: Vec, 93 | } 94 | 95 | impl VM { 96 | pub fn new() -> Self { 97 | VM { 98 | stack: Vec::with_capacity(STACK_SIZE), 99 | heap: Heap::default(), 100 | next_gc: GC_TRIGGER_COUNT, 101 | globals: HashMap::with_hasher(FnvBuildHasher::default()), 102 | frames: Vec::with_capacity(256), 103 | open_upvalues: Vec::with_capacity(16), 104 | } 105 | } 106 | 107 | pub fn exec_from(&mut self, atoms: &[ExprNode], locals: Vec, debug: bool) -> Vec { 108 | let mut compiler = Compiler::new(&mut self.heap); 109 | 110 | let function = compiler.compile_from(atoms, locals); 111 | let locals = compiler.locals_cache; 112 | 113 | if debug { 114 | let dis = Disassembler::new(function.chunk(), &self.heap); 115 | dis.disassemble(); 116 | } 117 | 118 | let closure = Closure::new(function, Vec::new()); 119 | let value = self.allocate(Object::Closure(closure)).into(); 120 | 121 | self.push(value); 122 | self.call(0); 123 | 124 | self.run(); 125 | 126 | if debug { 127 | f::dump_html(File::create("flamegraph.html").unwrap()).unwrap(); 128 | } 129 | 130 | locals 131 | } 132 | 133 | pub fn exec(&mut self, atoms: &[ExprNode], debug: bool) { 134 | let function = { 135 | let mut compiler = Compiler::new(&mut self.heap); 136 | compiler.compile(atoms) 137 | }; 138 | 139 | if debug { 140 | let dis = Disassembler::new(function.chunk(), &self.heap); 141 | dis.disassemble(); 142 | } 143 | 144 | let closure = Closure::new(function, Vec::new()); 145 | let value = self.allocate(Object::Closure(closure)).into(); 146 | 147 | self.push(value); 148 | self.call(0); 149 | 150 | self.run(); 151 | 152 | if debug { 153 | f::dump_html(File::create("flamegraph.html").unwrap()).unwrap(); 154 | } 155 | } 156 | 157 | pub fn add_native(&mut self, name: &str, func: NativeFunctionType, arity: u8) { 158 | let function = self.allocate(Object::native_fn(name, arity, func)); 159 | 160 | self.globals.insert(name.into(), function.into()); 161 | } 162 | 163 | fn run_and_find_value(&mut self, len: usize) -> Value { 164 | while len <= self.frames.len() { 165 | let inst = self.read_byte(); 166 | decode_op!(inst, self) 167 | } 168 | 169 | self.pop() 170 | } 171 | 172 | fn run(&mut self) { 173 | while !self.frames.is_empty() { 174 | let inst = self.read_byte(); 175 | decode_op!(inst, self) 176 | } 177 | } 178 | 179 | #[flame] 180 | pub fn internal_call(&mut self, handle: Handle, args: Vec) -> Value { 181 | for arg in &args { 182 | self.push(arg.clone()); 183 | } 184 | 185 | let last = self.stack.len(); 186 | 187 | let frame_start = if last < args.len() as usize { 188 | 0 189 | } else { 190 | last - (args.len() + 1) as usize 191 | }; 192 | 193 | let frame = CallFrame::new(handle, frame_start); 194 | 195 | self.frames.push(frame); 196 | 197 | self.run_and_find_value(self.frames.len()) 198 | } 199 | 200 | #[flame] 201 | fn call_closure(&mut self, handle: Handle, arity: u8) { 202 | let closure = self 203 | .deref(handle) 204 | .as_closure() 205 | .expect("redundant cast to succeed"); 206 | 207 | let last = self.stack.len(); 208 | let frame_start = if last < arity as usize { 209 | 0 210 | } else { 211 | last - (arity + 1) as usize 212 | }; 213 | 214 | if closure.arity() != arity { 215 | self.runtime_error(&format!( 216 | "arity mismatch: {} != {} @ {}: {:#?}", 217 | closure.arity(), 218 | arity, 219 | closure.name(), 220 | self.stack 221 | )) 222 | } 223 | 224 | let frame = CallFrame::new(handle, frame_start); 225 | self.frames.push(frame); 226 | } 227 | 228 | #[flame] 229 | fn closure(&mut self) { 230 | let value = self.frame_mut().read_constant(); 231 | let function = value 232 | .as_object() 233 | .map(|o| self.deref(o)) 234 | .and_then(|o| o.as_function()) 235 | .cloned() 236 | .expect("closure expected function argument"); 237 | 238 | let mut upvalues = Vec::new(); 239 | 240 | for _ in 0..function.upvalue_count() { 241 | let is_local = self.read_byte() > 0; 242 | let idx = self.read_byte() as usize; 243 | let upvalue = if is_local { 244 | self.capture_upvalue(idx) 245 | } else { 246 | self.current_closure().get(idx) 247 | }; 248 | 249 | upvalues.push(upvalue) 250 | } 251 | 252 | let closure = Closure::new(function, upvalues); 253 | let value = self.allocate(Object::Closure(closure)).into(); 254 | 255 | self.push(value) 256 | } 257 | 258 | #[flame] 259 | fn call(&mut self, arity: u8) { 260 | let last = self.stack.len(); 261 | 262 | let frame_start = if last < arity as usize { 263 | 0 264 | } else { 265 | last - (arity + 1) as usize 266 | }; 267 | 268 | let callee = self.stack[frame_start].decode(); 269 | 270 | if let Variant::Obj(handle) = callee { 271 | use self::Object::*; 272 | 273 | let value = { unsafe { self.heap.get_unchecked(handle) } }; 274 | 275 | if let Closure(_) = value { 276 | self.call_closure(handle, arity); 277 | } else if let NativeFunction(ref native) = value { 278 | let native = native.clone(); 279 | 280 | if native.arity != arity { 281 | self.runtime_error(&format!( 282 | "arity mismatch: {} != {} @ ({} {})", 283 | native.arity, arity, native.name, native.arity 284 | )) 285 | } 286 | 287 | let mut ctx = CallContext::new(self, frame_start); 288 | let value = (native.function)(&mut ctx); 289 | 290 | self.stack.drain(frame_start + 1..); 291 | self.stack.pop(); 292 | self.stack.push(value); 293 | } else { 294 | self.runtime_error("bad call") 295 | } 296 | } 297 | } 298 | 299 | #[flame] 300 | fn ret(&mut self) { 301 | if let Some(frame) = self.frames.pop() { 302 | let return_value = self.pop(); 303 | 304 | if frame.stack_start < self.stack.len() { 305 | self.close_upvalues(frame.stack_start) 306 | } 307 | 308 | self.stack.truncate(frame.stack_start); 309 | self.push(return_value); 310 | } else { 311 | self.runtime_error("can't return from top-level"); 312 | } 313 | } 314 | 315 | #[flame] 316 | fn capture_upvalue(&mut self, idx: usize) -> UpValue { 317 | let offset = self.frame().stack_start + idx; 318 | 319 | self.open_upvalues 320 | .iter() 321 | .rev() 322 | .find(|&up| up.as_local().map(|i| i == offset).unwrap_or(false)) 323 | .cloned() 324 | .unwrap_or_else(|| { 325 | let up = UpValue::new(offset); 326 | self.open_upvalues.push(up.clone()); 327 | up 328 | }) 329 | } 330 | 331 | fn current_closure(&mut self) -> &mut Closure { 332 | let handle = self.frame_mut().closure; 333 | self.deref_mut(handle) 334 | .as_closure_mut() 335 | .expect("valid closure") 336 | } 337 | 338 | #[flame] 339 | fn set_upvalue(&mut self) { 340 | let value = self.peek(); 341 | let idx = self.frame_mut().read_byte(); 342 | let closure = self.current_closure(); 343 | let res = closure.get(idx as usize).set(value); 344 | 345 | if let Err(i) = res { 346 | self.stack[i] = value 347 | } 348 | } 349 | 350 | #[flame] 351 | fn get_upvalue(&mut self) { 352 | let idx = self.frame_mut().read_byte(); 353 | let value = self 354 | .current_closure() 355 | .get(idx as usize) 356 | .get() 357 | .unwrap_or_else(|i| self.stack[i]); 358 | 359 | self.push(value) 360 | } 361 | 362 | #[flame] 363 | fn close_upvalue(&mut self) { 364 | let end = self.stack.len() - 1; 365 | 366 | self.close_upvalues(end); 367 | self.pop(); 368 | } 369 | 370 | #[flame] 371 | fn close_upvalues(&mut self, stack_end: usize) { 372 | let mut open_upvalues = Vec::new(); 373 | 374 | mem::swap(&mut self.open_upvalues, &mut open_upvalues); 375 | 376 | for mut up in open_upvalues { 377 | if up.get().map_err(|i| i >= stack_end).is_err() { 378 | up.close(|i| self.stack[i]); 379 | 380 | self.open_upvalues.push(up) 381 | } 382 | } 383 | } 384 | 385 | #[flame] 386 | fn allocate(&mut self, object: Object) -> Handle { 387 | let handle = self.heap.insert(object).into_handle(); 388 | 389 | if self.heap.len() * mem::size_of::() >= self.next_gc { 390 | self.next_gc *= HEAP_GROWTH; 391 | 392 | let upvalue_iter = self 393 | .open_upvalues 394 | .iter() 395 | .flat_map(|u| u.get().ok()) 396 | .flat_map(|v| v.as_object()); 397 | 398 | let globals_iter = self.globals.values().flat_map(Value::as_object); 399 | let stack_iter = self.stack.iter().flat_map(Value::as_object); 400 | 401 | let exclude = stack_iter 402 | .chain(Some(handle)) 403 | .chain(globals_iter) 404 | .chain(upvalue_iter); 405 | 406 | self.heap.clean_excluding(exclude); 407 | } 408 | 409 | handle 410 | } 411 | 412 | fn constant(&mut self, idx: u8) { 413 | let val = self.frame_mut().read_constant_at(idx); 414 | self.push(val) 415 | } 416 | 417 | #[flame] 418 | fn print(&mut self) { 419 | let value = self.pop(); 420 | println!("{}", value.with_heap(&self.heap)) 421 | } 422 | 423 | #[flame] 424 | fn add(&mut self) { 425 | let b = self.pop(); 426 | let a = self.pop(); 427 | 428 | use self::Variant::*; 429 | 430 | match (a.decode(), b.decode()) { 431 | (Float(a), Float(b)) => return self.push((a + b).into()), 432 | (Obj(a), Obj(b)) => { 433 | let a = self.deref(a).as_string().unwrap(); 434 | let b = self.deref(b).as_string().unwrap(); 435 | 436 | let new = self.allocate(Object::String(format!("{}{}", a, b))); 437 | 438 | return self.push(new.into()); 439 | } 440 | (Obj(a), Float(b)) => { 441 | let a = self.deref(a).as_string().unwrap(); 442 | 443 | let new = self.allocate(Object::String(format!("{}{}", a, b))); 444 | 445 | return self.push(new.into()); 446 | } 447 | (Float(a), Obj(b)) => { 448 | let b = self.deref(b).as_string().unwrap(); 449 | 450 | let new = self.allocate(Object::String(format!("{}{}", a, b))); 451 | 452 | return self.push(new.into()); 453 | } 454 | _ => {} 455 | } 456 | } 457 | 458 | #[flame] 459 | fn get_global(&mut self) { 460 | let global = self 461 | .frame_mut() 462 | .read_constant() 463 | .as_object() 464 | .map(|o| self.deref(o)) 465 | .and_then(|o| o.as_string()) 466 | .expect("`GetGlobal` requires a string identifier"); 467 | 468 | if let Some(value) = self.globals.get(global).cloned() { 469 | self.push(value) 470 | } else { 471 | self.runtime_error(&format!("undefined global variable: `{}`", global.clone())) 472 | } 473 | } 474 | 475 | #[flame] 476 | fn define_global(&mut self) { 477 | let var = self 478 | .frame_mut() 479 | .read_constant() 480 | .as_object() 481 | .map(|o| self.deref(o)) 482 | .and_then(|o| o.as_string()) 483 | .cloned() 484 | .expect("expected constant to be a string value"); 485 | 486 | let lhs = self.stack.pop().unwrap(); 487 | 488 | self.globals.insert(var, lhs); 489 | // TODO: Temporary bugfix for function definitions (might be inefficient) 490 | self.push(lhs); 491 | } 492 | 493 | #[flame] 494 | fn set_global(&mut self) { 495 | let handle = self 496 | .frame_mut() 497 | .read_constant() 498 | .as_object() 499 | .filter(|&o| self.deref(o).as_string().is_some()) 500 | .expect("expected constant to be a string value"); 501 | 502 | let var = unsafe { handle.get_mut_unchecked().as_string().unwrap() }; 503 | 504 | let value = *self.stack.last().unwrap(); 505 | 506 | if let Some(slot) = self.globals.get_mut(var) { 507 | *slot = value 508 | } else { 509 | self.globals.insert(var.clone(), value); 510 | } 511 | } 512 | 513 | #[flame] 514 | fn dict(&mut self) { 515 | use im_rc::hashmap::HashMap; 516 | 517 | let element_count = self.read_byte(); 518 | 519 | let mut content = HashMap::new(); 520 | 521 | for _ in 0..element_count { 522 | let value = self.pop(); 523 | let key = HashValue { 524 | variant: self.pop().decode().to_hash(&self.heap), 525 | }; 526 | 527 | content.insert(key, value); 528 | } 529 | 530 | let val = self.allocate(Object::Dict(Dict::new(content))).into(); 531 | self.push(val) 532 | } 533 | 534 | #[flame] 535 | fn set_dict_element(&mut self) { 536 | // corn 537 | let dict = self.pop(); 538 | let key = HashValue { 539 | variant: self.pop().decode().to_hash(&self.heap), 540 | }; 541 | 542 | let value = self.pop(); 543 | 544 | let dict_object = dict.as_object().map(|o| self.heap.get_mut_unchecked(o)); 545 | 546 | if let Some(Object::Dict(ref mut dict)) = dict_object { 547 | dict.insert(key, value) 548 | } 549 | } 550 | 551 | #[flame] 552 | fn get_dict_element(&mut self) { 553 | // corn 554 | let dict = self.pop(); 555 | let key = HashValue { 556 | variant: self.pop().decode().to_hash(&self.heap), 557 | }; 558 | 559 | let dict_handle = dict.as_object().unwrap(); 560 | 561 | let dict = self.deref(dict_handle); 562 | 563 | if let Some(value) = dict.as_dict().unwrap().get(&key) { 564 | self.push(*value) 565 | } else { 566 | panic!("no such field `{:?}` on dict", key) 567 | } 568 | } 569 | 570 | #[flame] 571 | fn tuple(&mut self) { 572 | let element_count = self.read_byte(); 573 | let mut elements = Vec::new(); 574 | 575 | for _ in 0..element_count { 576 | elements.push(self.pop()) 577 | } 578 | 579 | let value = self.allocate(Object::Tuple(Tuple::new(elements))); 580 | 581 | self.push(value.into()) 582 | } 583 | 584 | #[flame] 585 | fn list(&mut self) { 586 | let element_count = self.read_byte(); 587 | 588 | let mut content = Vec::new(); 589 | 590 | for _ in 0..element_count { 591 | content.push(self.pop()) 592 | } 593 | 594 | let val = self.allocate(Object::List(List::new(content))).into(); 595 | self.push(val) 596 | } 597 | 598 | #[flame] 599 | fn set_list_element(&mut self) { 600 | let list = self.pop(); 601 | let idx = if let Variant::Float(ref index) = self.pop().decode() { 602 | *index as usize 603 | } else { 604 | panic!("Can't index list with non-number") 605 | }; 606 | 607 | let value = self.pop(); 608 | 609 | let list_object = list.as_object().map(|o| self.heap.get_mut_unchecked(o)); 610 | 611 | if let Some(Object::List(ref mut list)) = list_object { 612 | list.set(idx as usize, value) 613 | } 614 | } 615 | 616 | #[flame] 617 | fn set_element(&mut self) { 618 | let list = self.pop(); 619 | let index = self.pop(); 620 | let value = self.pop(); 621 | 622 | let variant = match index.decode() { 623 | Variant::Float(n) => HashVariant::Int(n as i64), 624 | c @ Variant::True | c @ Variant::False => HashVariant::Bool(c == Variant::True), 625 | Variant::Obj(ref handle) => { 626 | HashVariant::Str(self.deref(*handle).as_string().unwrap().to_owned()) 627 | } 628 | Nil => HashVariant::Nil, 629 | }; 630 | 631 | let list_object = self.deref_mut(list.as_object().unwrap()); 632 | 633 | if let Object::List(list) = list_object { 634 | let idx = if let Variant::Float(ref index) = index.decode() { 635 | *index as usize 636 | } else { 637 | panic!("Can't index list with non-number") 638 | }; 639 | 640 | list.set(idx as usize, value); 641 | 642 | return; 643 | } 644 | 645 | if let Object::Tuple(members) = list_object { 646 | let idx = if let Variant::Float(ref index) = index.decode() { 647 | *index as usize 648 | } else { 649 | panic!("Can't index list with non-number") 650 | }; 651 | 652 | members.set(idx, value); 653 | return; 654 | } 655 | 656 | if let Object::Dict(dict) = list_object { 657 | let key = HashValue { variant }; 658 | 659 | dict.insert(key, value); 660 | } 661 | } 662 | 663 | #[flame] 664 | fn get_element(&mut self) { 665 | let list = self.pop(); 666 | let index = self.pop(); 667 | 668 | let list_handle = list.as_object().unwrap(); 669 | 670 | let list = self.deref(list_handle); 671 | 672 | if let Some(tuple) = list.as_tuple().clone() { 673 | let idx = if let Variant::Float(ref index) = index.decode() { 674 | *index as usize 675 | } else { 676 | panic!("Can't index tuple with non-number") 677 | }; 678 | 679 | println!("{tuple:?}"); 680 | let member = tuple.get(idx); 681 | 682 | self.push(*member); 683 | 684 | return; 685 | } 686 | 687 | if let Some(list) = list.as_list() { 688 | let idx = if let Variant::Float(ref index) = index.decode() { 689 | *index as usize 690 | } else { 691 | panic!("Can't index list with non-number") 692 | }; 693 | 694 | let element = list.get(idx as usize); 695 | 696 | self.push(element); 697 | 698 | return; 699 | } 700 | 701 | if let Some(dict) = list.as_dict() { 702 | let key = HashValue { 703 | variant: index.decode().to_hash(&self.heap), 704 | }; 705 | 706 | if let Some(value) = dict.get(&key) { 707 | self.push(*value) 708 | } else { 709 | panic!("no such field `{:?}` on dict with {:#?}", key, dict.content) 710 | } 711 | } 712 | } 713 | 714 | fn runtime_error(&self, err: &str) { 715 | eprintln!("[error]: {}.", err); 716 | for frame in self.frames.iter().rev() { 717 | let ip = frame.ip; 718 | frame.with_chunk(|chunk| { 719 | let name = chunk.name(); 720 | let line = chunk.line(ip); 721 | eprintln!(" at [line {}] in {}", line, name); 722 | }); 723 | } 724 | ::std::process::exit(1); 725 | } 726 | 727 | fn on_loop(&mut self) { 728 | self.frame_mut().ip -= self.read_u16() as usize 729 | } 730 | 731 | fn get_local(&mut self) { 732 | let start = self.frame().stack_start; 733 | let idx = self.read_byte() as usize; 734 | let val = self.stack[start + idx]; 735 | 736 | self.push(val) 737 | } 738 | 739 | fn set_local(&mut self) { 740 | let val = self.peek(); 741 | let start = self.frame().stack_start; 742 | let idx = self.read_byte() as usize; 743 | 744 | self.stack[start + idx] = val 745 | } 746 | 747 | fn immediate(&mut self) { 748 | let raw = self.frame_mut().read_u64(); 749 | let val = unsafe { Value::from_raw(raw) }; 750 | 751 | self.push(val) 752 | } 753 | 754 | fn imm_nil(&mut self) { 755 | self.push(Value::nil()); 756 | } 757 | 758 | fn imm_true(&mut self) { 759 | self.push(Value::truelit()); 760 | } 761 | 762 | fn imm_false(&mut self) { 763 | self.push(Value::falselit()); 764 | } 765 | 766 | #[flame] 767 | fn sub(&mut self) { 768 | binary_op!(self, -); 769 | } 770 | 771 | #[flame] 772 | fn mul(&mut self) { 773 | binary_op!(self, *); 774 | } 775 | 776 | #[flame] 777 | fn rem(&mut self) { 778 | binary_op!(self, %); 779 | } 780 | 781 | #[flame] 782 | fn pow(&mut self) { 783 | let b = self.pop(); 784 | let a = self.pop(); 785 | 786 | if let (Variant::Float(a), Variant::Float(b)) = (a.decode(), b.decode()) { 787 | let c = a.powf(b); 788 | 789 | self.push(c.into()); 790 | } 791 | } 792 | 793 | #[flame] 794 | fn div(&mut self) { 795 | binary_op!(self, /); 796 | } 797 | 798 | #[flame] 799 | fn neg(&mut self) { 800 | if let Variant::Float(a) = self.pop().decode() { 801 | self.push((-a).into()); 802 | } 803 | } 804 | 805 | #[flame] 806 | fn not(&mut self) { 807 | let a = self.pop(); 808 | 809 | self.push(if a.truthy() { 810 | Value::falselit() 811 | } else { 812 | Value::truelit() 813 | }) 814 | } 815 | 816 | #[flame] 817 | fn eq(&mut self) { 818 | binary_op!(self, ==); 819 | } 820 | 821 | #[flame] 822 | fn gt(&mut self) { 823 | binary_op!(self, >); 824 | } 825 | 826 | #[flame] 827 | fn lt(&mut self) { 828 | binary_op!(self, <); 829 | } 830 | 831 | #[flame] 832 | fn jmp(&mut self) { 833 | self.frame_mut().ip = self.read_u16() as usize 834 | } 835 | 836 | #[flame] 837 | fn jze(&mut self) { 838 | let ip = self.read_u16(); 839 | if !self.peek().truthy() { 840 | self.frame_mut().ip = ip as usize 841 | } 842 | } 843 | 844 | #[flame] 845 | fn op_loop(&mut self) { 846 | self.frame_mut().ip -= self.read_u16() as usize 847 | } 848 | 849 | fn frame(&self) -> &CallFrame { 850 | self.frames.last().expect("frames to be nonempty") 851 | } 852 | 853 | fn frame_mut(&mut self) -> &mut CallFrame { 854 | self.frames.last_mut().expect("frames to be nonempty") 855 | } 856 | 857 | fn read_byte(&mut self) -> u8 { 858 | self.frame_mut().read_byte() 859 | } 860 | 861 | fn read_u16(&mut self) -> u16 { 862 | self.frame_mut().read_u16() 863 | } 864 | 865 | fn push(&mut self, value: Value) { 866 | if self.stack.len() == STACK_SIZE { 867 | panic!("STACK OVERFLOW >:( @ {:#?}", &self.stack[STACK_SIZE - 50..]); 868 | } 869 | 870 | self.stack.push(value); 871 | } 872 | 873 | #[flame] 874 | fn pop(&mut self) -> Value { 875 | self.stack.pop().expect("stack to be nonempty") 876 | } 877 | 878 | #[flame] 879 | fn peek(&mut self) -> Value { 880 | *self.stack.last().expect("stack to be nonempty") 881 | } 882 | 883 | #[flame] 884 | fn deref(&self, o: Handle) -> &Object { 885 | unsafe { self.heap.get_unchecked(o) } 886 | } 887 | 888 | #[flame] 889 | fn deref_mut(&mut self, o: Handle) -> &mut Object { 890 | self.heap.get_mut_unchecked(o) 891 | } 892 | } 893 | --------------------------------------------------------------------------------