Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #16

Merged
merged 6 commits into from
Oct 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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