Skip to content

Commit

Permalink
Remove VM Session
Browse files Browse the repository at this point in the history
  • Loading branch information
95th committed Apr 25, 2020
1 parent cba6727 commit 78ea44d
Show file tree
Hide file tree
Showing 7 changed files with 111 additions and 38 deletions.
2 changes: 2 additions & 0 deletions sample.lox
@@ -0,0 +1,2 @@
var a = "hello world";
print a;
8 changes: 8 additions & 0 deletions src/chunk.rs
Expand Up @@ -9,6 +9,8 @@ pub enum OpCode {
True,
False,
Pop,
GetGlobal,
DefineGlobal,
Equal,
Greater,
Less,
Expand Down Expand Up @@ -48,4 +50,10 @@ impl Chunk {
self.values.push(value);
len
}

pub fn clear(&mut self) {
self.code.clear();
self.values.clear();
self.lines.clear();
}
}
50 changes: 48 additions & 2 deletions src/compile.rs
Expand Up @@ -35,13 +35,48 @@ impl<'a> Compiler<'a> {
}

fn declaration(&mut self) {
self.statement();
if self.matches(TokenKind::Var) {
self.var_decl();
} else {
self.statement();
}

if self.parser.panic_mode {
self.synchronize();
}
}

fn var_decl(&mut self) {
let global = self.parse_var("Expect variable name");
if self.matches(TokenKind::Equal) {
self.expression();
} else {
self.emit_op(OpCode::Nil);
}

self.consume(
TokenKind::Semicolon,
"Expect ';' after variable declaration",
);

self.define_var(global);
}

fn define_var(&mut self, global: u8) {
self.emit_op(OpCode::DefineGlobal);
self.emit_byte(global);
}

fn parse_var(&mut self, msg: &str) -> u8 {
self.consume(TokenKind::Identifier, msg);
self.identifier_constant(self.parser.previous.lexeme_str())
}

fn identifier_constant(&mut self, s: &str) -> u8 {
let s = self.strings.intern(s);
self.make_constant(s.into())
}

fn statement(&mut self) {
if self.matches(TokenKind::Print) {
self.print_statement();
Expand Down Expand Up @@ -151,7 +186,7 @@ impl<'a> Compiler<'a> {
GreaterEqual => p!(None, Some binary, Comparison),
Less => p!(None, Some binary, Comparison),
LessEqual => p!(None, Some binary, Comparison),
Identifier => p!(),
Identifier => p!(Some variable, None, None),
String => p!(Some string, None, None),
Number => p!(Some number, None, None),
And => p!(),
Expand All @@ -175,6 +210,16 @@ impl<'a> Compiler<'a> {
}
}

fn variable(&mut self) {
self.named_variable(self.parser.previous.lexeme_str());
}

fn named_variable(&mut self, name: &str) {
let arg = self.identifier_constant(name);
self.emit_op(OpCode::GetGlobal);
self.emit_byte(arg);
}

fn string(&mut self) {
let s = self.parser.previous.lexeme_str();
let s = self.strings.intern(&s[1..s.len() - 1]);
Expand Down Expand Up @@ -618,6 +663,7 @@ fn is_digit(c: u8) -> bool {
matches!(c, b'0'..=b'9')
}

#[derive(Clone)]
pub struct Token<'a> {
kind: TokenKind,
lexeme: &'a [u8],
Expand Down
4 changes: 3 additions & 1 deletion src/debug.rs
Expand Up @@ -35,7 +35,9 @@ impl Chunk {
match opcode {
Return | Negate | Add | Subtract | Multiply | Divide | Nil | True | False | Not
| Equal | Greater | Less | Print | Pop => self.simple_instr(opcode, offset, buf),
Constant => self.constant_instr(opcode, offset, buf, strings),
Constant | GetGlobal | DefineGlobal => {
self.constant_instr(opcode, offset, buf, strings)
}
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/intern.rs
Expand Up @@ -42,6 +42,13 @@ impl StringPool {
self.vec[id as usize].get()
}

pub fn clear(&mut self) {
self.map.clear();
self.vec.clear();
self.curr_buf.clear();
self.full.clear();
}

fn alloc(&mut self, name: &str) -> Ptr<str> {
let cap = self.curr_buf.capacity();
if cap < self.curr_buf.len() + name.len() {
Expand Down
4 changes: 3 additions & 1 deletion src/main.rs
Expand Up @@ -41,9 +41,11 @@ fn repl() {
break;
}
match vm.interpret(&line) {
Ok(()) => {}
Ok(()) => continue,
Err(Error::Compile) => println!("Unable to compile: {}", line),
Err(Error::Runtime) => println!("Runtime error"),
}

vm.clear();
}
}
74 changes: 40 additions & 34 deletions src/vm.rs
Expand Up @@ -5,25 +5,31 @@ use crate::value::Value;
use crate::Error;
use log::Level;
use num_traits::FromPrimitive;
use std::collections::HashMap;

pub struct Vm {
stack: Vec<Value>,
chunk: Chunk,
strings: StringPool,
globals: HashMap<u32, Value>,
ip: usize,
}

impl Vm {
pub fn new() -> Self {
const STACK_SIZE: usize = 256;
Self {
stack: Vec::with_capacity(STACK_SIZE),
chunk: Chunk::new(),
strings: StringPool::new(),
globals: HashMap::new(),
ip: 0,
}
}

pub fn interpret(&mut self, source: &str) -> crate::Result<()> {
let mut chunk = Chunk::new();
let mut strings = StringPool::new();
Compiler::new(source, &mut chunk, &mut strings).compile()?;
let mut session = VmSession::new(self, &chunk, &mut strings);
session.run()
Compiler::new(source, &mut self.chunk, &mut self.strings).compile()?;
self.run()
}

fn print_stack(&self, strings: &StringPool) {
Expand All @@ -36,24 +42,25 @@ impl Vm {

trace!("{}", buf);
}
}

struct VmSession<'a> {
vm: &'a mut Vm,
chunk: &'a Chunk,
strings: &'a mut StringPool,
ip: usize,
pub fn clear(&mut self) {
self.stack.clear();
self.chunk.clear();
self.globals.clear();
self.strings.clear();
self.ip = 0;
}
}

macro_rules! push {
($me: expr, $value: expr) => {
$me.vm.stack.push($value);
$me.stack.push($value);
};
}

macro_rules! pop {
($me: expr) => {
$me.vm.stack.pop().unwrap()
$me.stack.pop().unwrap()
};
}

Expand All @@ -73,34 +80,23 @@ macro_rules! binary_op {

macro_rules! runtime_error {
($self: expr, $fmt: literal $(, $($args: tt)* )?) => {
println!($fmt, $($args)*);
println!($fmt $(, $($args)* )? );
let i = $self.ip - 1;
let line = $self.chunk.lines[i];
println!("[line: {}] in script", line);
$self.reset_stack();
$self.stack.clear();
return Err(Error::Runtime);
}
}

impl<'a> VmSession<'a> {
fn new(vm: &'a mut Vm, chunk: &'a Chunk, strings: &'a mut StringPool) -> Self {
Self {
vm,
chunk,
ip: 0,
strings,
}
}

impl Vm {
fn run(&mut self) -> crate::Result<()> {
use OpCode::*;

self.vm.stack.clear();

while let Some(instr) = self.read_instr() {
if log_enabled!(Level::Trace) {
self.vm.print_stack(self.strings);
self.chunk.disassemble_instr(self.ip - 1, self.strings);
self.print_stack(&self.strings);
self.chunk.disassemble_instr(self.ip - 1, &self.strings);
}

match instr {
Expand All @@ -114,6 +110,20 @@ impl<'a> VmSession<'a> {
Pop => {
pop!(self);
}
GetGlobal => {
let name = self.read_constant();
let name = name.as_string().unwrap();
if let Some(value) = self.globals.get(&name) {
push!(self, value.clone());
} else {
runtime_error!(self, "Undefined variable {}", self.strings.lookup(name));
}
}
DefineGlobal => {
let name = self.read_constant();
let name = name.as_string().unwrap();
self.globals.insert(name, pop!(self));
}
Equal => {
let b = pop!(self);
let a = pop!(self);
Expand Down Expand Up @@ -156,7 +166,7 @@ impl<'a> VmSession<'a> {
}
Print => {
let mut s = String::new();
pop!(self).write(&mut s, self.strings).unwrap();
pop!(self).write(&mut s, &self.strings).unwrap();
println!("{}", s);
}
Return => return Ok(()),
Expand All @@ -180,10 +190,6 @@ impl<'a> VmSession<'a> {
let idx = self.read_byte().unwrap() as usize;
self.chunk.values[idx].clone()
}

fn reset_stack(&mut self) {
self.vm.stack.clear();
}
}

fn is_falsey(value: Value) -> bool {
Expand Down

0 comments on commit 78ea44d

Please sign in to comment.