Skip to content

Commit

Permalink
Merge pull request #16 from ZakFarmer/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
ZakFarmer authored Oct 27, 2023
2 parents 52f0da0 + 8c1b1e7 commit 53e6b0e
Show file tree
Hide file tree
Showing 10 changed files with 532 additions and 122 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

200 changes: 163 additions & 37 deletions compiler/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::rc::Rc;

use anyhow::Error;
use opcode::Opcode;
use opcode::{Opcode, Instructions};
use parser::ast::{
BlockStatement, BooleanLiteral, Expression, IntegerLiteral, Literal, Node, Statement, StringLiteral,
};
Expand Down Expand Up @@ -29,97 +29,155 @@ impl std::fmt::Debug for Bytecode {
}
}

#[derive(Debug, Clone)]
struct EmittedInstruction {
opcode: opcode::Opcode,
position: usize,
#[derive(Clone, Debug)]
pub struct CompilationScope {
pub instructions: opcode::Instructions,
pub last_instruction: EmittedInstruction,
pub previous_instruction: EmittedInstruction,
}

pub struct Compiler {
instructions: opcode::Instructions,
pub constants: Vec<Rc<object::Object>>,

pub symbol_table: SymbolTable,

last_instruction: Option<EmittedInstruction>,
previous_instruction: Option<EmittedInstruction>,
scopes: Vec<CompilationScope>,
scope_index: usize,
}

impl Compiler {
pub fn new() -> Self {
Self {
let main_scope = CompilationScope {
instructions: opcode::Instructions::default(),
last_instruction: EmittedInstruction {
opcode: opcode::Opcode::OpNull,
position: 0,
},
previous_instruction: EmittedInstruction {
opcode: opcode::Opcode::OpNull,
position: 0,
},
};

Self {
constants: Vec::new(),
last_instruction: None,
previous_instruction: None,
symbol_table: SymbolTable::new(),
scopes: vec![main_scope],
scope_index: 0,
}
}

pub fn new_with_state(constants: Vec<Rc<object::Object>>, symbol_table: SymbolTable) -> Self {
let compiler = Self::new();

Self {
instructions: opcode::Instructions::default(),
constants,
last_instruction: None,
previous_instruction: None,
symbol_table,
..compiler
}
}

pub fn enter_scope(&mut self) {
let scope = CompilationScope {
instructions: opcode::Instructions::default(),
last_instruction: EmittedInstruction {
opcode: Opcode::OpNull,
position: 0,
},
previous_instruction: EmittedInstruction {
opcode: Opcode::OpNull,
position: 0,
},
};

self.scopes.push(scope);
self.scope_index += 1;
}

pub fn exit_scope(&mut self) -> opcode::Instructions {
let instructions = self.current_instructions().clone();

self.scopes.pop();
self.scope_index -= 1;

instructions
}

pub fn scopes(&self) -> &Vec<CompilationScope> {
&self.scopes
}

pub fn scope_index(&self) -> usize {
self.scope_index
}

fn add_constant(&mut self, obj: object::Object) -> usize {
self.constants.push(obj.into());

return (self.constants.len() - 1) as usize;
}

fn change_operand(&mut self, position: usize, operand: usize) {
let op = Opcode::from(self.instructions.0[position]);
let op = Opcode::from(self.current_instructions().0[position]);

let new_instruction = opcode::make(op, &vec![operand]);

self.replace_instruction(position, new_instruction);
}

fn add_instructions(&mut self, instructions: opcode::Instructions) -> usize {
let position = self.instructions.0.len();
pub fn add_instructions(&mut self, ins: &Instructions) -> usize {
let position = self.current_instructions().0.len();

self.instructions.0.extend(instructions.0);
let new_instruction = self.scopes[self.scope_index]
.instructions
.merge_instructions(ins);

self.scopes[self.scope_index].instructions = new_instruction;
return position;
}

fn current_instructions(&self) -> &opcode::Instructions {
return &self.instructions;
pub fn current_instructions(&self) -> &opcode::Instructions {
return &self.scopes[self.scope_index].instructions;
}

fn replace_instruction(&mut self, position: usize, new_instruction: opcode::Instructions) {
let instructions = &mut self.scopes[self.scope_index].instructions;

for (i, instruction) in new_instruction.0.iter().enumerate() {
self.instructions.0[position + i] = *instruction;
instructions.0[position + i] = *instruction;
}
}

fn set_last_instruction(&mut self, op: opcode::Opcode, position: usize) {
let previous = self.last_instruction.clone();

self.previous_instruction = previous;

self.last_instruction = Some(EmittedInstruction {
fn set_last_instruction(&mut self, op: opcode::Opcode, position: usize) -> Result<(), Error> {
let previous = self.scopes[self.scope_index].last_instruction.clone();
let last = EmittedInstruction {
opcode: op,
position,
});
};

self.scopes[self.scope_index].last_instruction = last;
self.scopes[self.scope_index].previous_instruction = previous;

Ok(())
}

fn replace_last_pop_with_return(&mut self) {
let last_position = self.scopes[self.scope_index].last_instruction.position;
self.replace_instruction(last_position, opcode::make(Opcode::OpReturn, &vec![]));

self.scopes[self.scope_index].last_instruction.opcode = Opcode::OpReturn;
}

pub fn bytecode(&self) -> Bytecode {
Bytecode {
instructions: self.instructions.clone(),
instructions: self.current_instructions().clone(),
constants: self.constants.clone(),
}
}

fn emit(&mut self, op: opcode::Opcode, operands: Vec<usize>) -> usize {
pub fn emit(&mut self, op: opcode::Opcode, operands: Vec<usize>) -> usize {
let instructions = opcode::make(op, &operands);

let index = self.add_instructions(instructions);
let index = self.add_instructions(&instructions);

self.set_last_instruction(op, index);

Expand Down Expand Up @@ -166,6 +224,8 @@ impl Compiler {
Statement::Return(r) => {
self.compile_expression(&r.return_value)?;

self.emit(opcode::Opcode::OpReturnValue, vec![]);

Ok(())
}
Statement::Expr(e) => {
Expand Down Expand Up @@ -219,6 +279,42 @@ impl Compiler {

Ok(())
}
Expression::Function(function_literal) => {
self.enter_scope();

self.compile_block_statement(&function_literal.body)?;

if self.last_instruction_is(Opcode::OpPop) {
self.replace_last_pop_with_return();
}

if ! self.last_instruction_is(Opcode::OpReturnValue) {
self.emit(Opcode::OpReturn, vec![]);
}

let instructions = self.exit_scope();

let compiled_function = Rc::from(
object::CompiledFunction::new(
instructions,
),
);

let operands = vec![self.add_constant(
object::Object::CompiledFunction(compiled_function)
)];

self.emit(Opcode::OpConst, operands);

Ok(())
}
Expression::Call(call_expression) => {
self.compile_expression(&call_expression.function)?;

self.emit(Opcode::OpCall, vec![call_expression.arguments.len()]);

Ok(())
}
Expression::If(if_expression) => {
self.compile_expression(&if_expression.condition)?;

Expand Down Expand Up @@ -250,6 +346,14 @@ impl Compiler {

Ok(())
}
Expression::Index(index_expression) => {
self.compile_expression(&index_expression.left)?;
self.compile_expression(&index_expression.index)?;

self.emit(opcode::Opcode::OpIndex, vec![]);

Ok(())
}
Expression::Infix(infix_expression) => {
self.compile_operands(
&infix_expression.left,
Expand Down Expand Up @@ -282,6 +386,15 @@ impl Compiler {
Ok(())
}
Expression::Literal(literal_expression) => match literal_expression {
Literal::Array(array) => {
for element in array.elements.iter() {
self.compile_expression(element)?;
}

self.emit(opcode::Opcode::OpArray, vec![array.elements.len()]);

Ok(())
}
Literal::Boolean(boolean) => match boolean {
BooleanLiteral { value: true, .. } => {
self.emit(opcode::Opcode::OpTrue, vec![]);
Expand Down Expand Up @@ -323,14 +436,27 @@ impl Compiler {
}

fn last_instruction_is(&self, op: Opcode) -> bool {
match &self.last_instruction {
Some(instruction) => instruction.opcode == op,
None => false,
if self.current_instructions().0.is_empty() {
return false;
}

&self.scopes[self.scope_index].last_instruction.opcode == &op
}

fn remove_last_pop(&mut self) {
self.instructions.0.pop();
self.last_instruction = self.previous_instruction.clone();
let last = self.scopes[self.scope_index].last_instruction.clone();
let previous = self.scopes[self.scope_index].previous_instruction.clone();

let old_instructions = self.current_instructions().0.clone();
let new_instructions = old_instructions[..last.position].to_vec();

self.scopes[self.scope_index].instructions.0 = new_instructions;
self.scopes[self.scope_index].last_instruction = previous;
}
}

#[derive(Clone, Copy, Debug)]
pub struct EmittedInstruction {
pub opcode: opcode::Opcode,
pub position: usize,
}
Loading

0 comments on commit 53e6b0e

Please sign in to comment.