Skip to content

Commit

Permalink
Function calls
Browse files Browse the repository at this point in the history
  • Loading branch information
juanvillacortac committed Dec 9, 2022
1 parent 388443e commit e0f664f
Show file tree
Hide file tree
Showing 15 changed files with 240 additions and 333 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
on:
release:
types: [created]

jobs:
release:
name: release ${{ matrix.target }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- target: x86_64-pc-windows-gnu
archive: zip
- target: x86_64-unknown-linux-musl
archive: tar.gz tar.xz tar.zst
- target: x86_64-apple-darwin
archive: zip
steps:
- uses: actions/checkout@master
- name: Compile and release
uses: rust-build/rust-build.action@v1.4.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
RUSTTARGET: ${{ matrix.target }}
ARCHIVE_TYPES: ${{ matrix.archive }}
213 changes: 44 additions & 169 deletions core/compiler/src/code.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
use crate::CompiledInstructions;
use bytecoding::{Bytecode, DecodeError};

pub const BYTE_ENDIAN: &'static str = "big";
pub enum ByteEndianness {
Big,
Little,
}
pub type CompiledInstructions = Vec<u8>;

#[repr(u8)]
#[derive(Eq, PartialEq, Debug, Clone)]
#[derive(Eq, PartialEq, Debug, Clone, Bytecode)]
#[bytecode(type = u8)]
pub enum Instruction {
Illegal,
Call,

Call(u16),

Return,
ReturnValue,

Const,
Const(u16),
Pop,

SetGlobal,
GetGlobal,
SetLocal,
GetLocal,
SetGlobal(u16),
GetGlobal(u16),
SetLocal(u16),
GetLocal(u16),

Array,
Hash,
Array(u16),
Hash(u16),
Index,

Jump,
JumpNot,
Jump(u16),
JumpNot(u16),

Add,
Mul,
Expand All @@ -36,8 +34,7 @@ pub enum Instruction {
Mod,
Pow,

True,
False,
Bool(#[bytecode(flatten_all = [true, false])] bool),

Nil,

Expand All @@ -52,93 +49,15 @@ pub enum Instruction {

Negative,
Not,
ShellCommand,
}

impl Instruction {
pub fn from_u8(byte: u8) -> Self {
unsafe { ::std::mem::transmute(byte) }
}
}

pub type Operand = usize;
pub type Operands = Vec<usize>;

pub struct InstructionPacker(pub ByteEndianness);

impl InstructionPacker {
fn unpack_16(&self, operand: u16) -> (u8, u8) {
let x1 = ((operand >> 8) & 0x00FF) as u8;
let x2 = (operand & 0x00FF) as u8;

let InstructionPacker(endian) = self;
match endian {
ByteEndianness::Big => (x1, x2),
ByteEndianness::Little => (x2, x1),
}
}

fn pack_u16(&self, x1: u8, x2: u8) -> u16 {
let InstructionPacker(endian) = self;
match endian {
ByteEndianness::Big => (((x1 as u16) & 0x00FF) << 8) | ((x2 as u16) & 0x00FF),
ByteEndianness::Little => (((x2 as u16) & 0x00FF) << 8) | ((x1 as u16) & 0x00FF),
}
}

pub fn encode_instruction(&self, instruction: Instruction, operands: &Operands) -> Vec<u8> {
let operand_sizes = instruction.get_encoding_width();
let mut statement = Vec::new();

statement.push(instruction as u8);
for idx in 0..operands.len() {
let operand = operands[idx];
let width = operand_sizes[idx];

if width == 2 {
let (x1, x2) = self.unpack_16(operand as u16);
statement.push(x1);
statement.push(x2);
} else {
statement.push(operand as u8);
}
}

return statement;
}

pub fn decode_instruction(
&self,
instruction: &Instruction,
packed_ops: &[u8],
) -> (Vec<usize>, usize) {
let operand_widths = instruction.get_encoding_width();
let mut unpacked_stmt = vec![];
let mut offset = 0;

for width in operand_widths {
if width == 2 {
let operand_bytes = &packed_ops[offset..offset + 2];
let packed_value = self.pack_u16(operand_bytes[0], operand_bytes[1]);
unpacked_stmt.push(packed_value as usize);
offset += 2;
} else {
unpacked_stmt.push(packed_ops[offset] as usize);
offset += 1;
}
}

return (unpacked_stmt, offset);
}
}

impl Instruction {
#[allow(dead_code)]
pub fn as_string(&self) -> String {
match self {
Self::Const => "OpConst".to_string(),
Self::Const(op) => format!("OpConst {op}"),
Self::Pop => "OpPop".to_string(),
Self::Call => "OpCall".to_string(),
Self::Call(op) => format!("OpCall {op}"),
Self::Return => "OpReturn".to_string(),
Self::ReturnValue => "OpReturnValue".to_string(),
Self::Add => "OpAdd".to_string(),
Expand All @@ -147,8 +66,7 @@ impl Instruction {
Self::Div => "OpDiv".to_string(),
Self::Pow => "OpPow".to_string(),
Self::Mod => "OpMod".to_string(),
Self::True => "OpTrue".to_string(),
Self::False => "OpFalse".to_string(),
Self::Bool(op) => format!("OpBool {op}"),
Self::Gt => "OpGt".to_string(),
Self::Lt => "OpLt".to_string(),
Self::Eq => "OpEq".to_string(),
Expand All @@ -159,85 +77,42 @@ impl Instruction {
Self::Or => "OpOr".to_string(),
Self::Negative => "OpNegative".to_string(),
Self::Not => "OpNot".to_string(),
Self::Jump => "OpJump".to_string(),
Self::JumpNot => "OpJumpNot".to_string(),
Self::Jump(op) => format!("OpJump {op}"),
Self::JumpNot(op) => format!("OpJumpNot {op}"),
Self::Nil => "OpNil".to_string(),
Self::GetGlobal => "OpGetGlobal".to_string(),
Self::SetGlobal => "OpSetGlobal".to_string(),
Self::GetLocal => "OpGetLocal".to_string(),
Self::SetLocal => "OpSetLocal".to_string(),
Self::Array => "OpArray".to_string(),
Self::Hash => "OpHash".to_string(),
Self::SetGlobal(op) => format!("OpSetGlobal {op}"),
Self::GetGlobal(op) => format!("OpGetGlobal {op}"),
Self::SetLocal(op) => format!("OpSetLocal {op}"),
Self::GetLocal(op) => format!("OpGetLocal {op}"),
Self::Array(op) => format!("OpArr {op}"),
Self::Hash(op) => format!("OpHash {op}"),
Self::Index => "OpIndex".to_string(),
Self::ShellCommand => "OpCmd".to_string(),
Self::Illegal => "ILLEGAL_OP".to_string(),
}
}

#[allow(dead_code)]
pub fn get_encoding_width(&self) -> Vec<u8> {
match self {
Self::Const
| Self::Jump
| Self::JumpNot
| Self::SetGlobal
| Self::GetGlobal
| Self::Array
| Self::Hash => vec![2],
Self::Call | Self::SetLocal | Self::GetLocal => vec![1],
Self::Pop
| Self::Add
| Self::Sub
| Self::Return
| Self::ReturnValue
| Self::Mul
| Self::Div
| Self::Mod
| Self::Pow
| Self::True
| Self::False
| Self::Lt
| Self::Gt
| Self::Lte
| Self::Gte
| Self::Eq
| Self::Neq
| Self::And
| Self::Or
| Self::Not
| Self::Negative
| Self::ShellCommand
| Self::Nil
| Self::Index
| Self::Illegal => vec![],
}
pub fn compile(&self) -> CompiledInstructions {
let mut buf = Vec::new();
self.encode(&mut buf);
buf
}

#[allow(dead_code)]
pub fn disasm_instruction(&self, operands: &Operands) -> String {
let op_strings: Vec<String> = operands.into_iter().map(|op| format!("{:x}", op)).collect();
let op_formatted = op_strings.join(", ");
let opcode = self.as_string();

return format!("{} {}", opcode, op_formatted);
pub fn compile_instructions(instructions: Vec<Instruction>) -> Vec<u8> {
let mut encoded = Vec::new();
for ins in instructions {
ins.encode(&mut encoded);
}
encoded
}

pub fn decompile_instructions(
endian: ByteEndianness,
instructions: &CompiledInstructions,
) -> Vec<(Instruction, Vec<usize>)> {
let packer = InstructionPacker(endian);
let mut ip = 0 as usize;
let mut ins = vec![];
while ip < instructions.len() {
let op: Instruction = Instruction::from_u8(instructions[ip]);

let (operands, next_offset) = packer.decode_instruction(&op, &instructions[ip + 1..]);

ins.push((op, operands));

ip += next_offset + 1;
) -> Result<Vec<Instruction>, DecodeError> {
let mut buf: &[u8] = &instructions;
let mut ins = Vec::new();
while !buf.is_empty() {
ins.push(Instruction::decode(&mut buf)?);
}
ins
Ok(ins)
}
}
9 changes: 2 additions & 7 deletions core/compiler/src/objects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ use std::{
hash::{Hash, Hasher},
};

use pk_parser::ast::*;

use crate::CompiledInstructions;

pub type BuiltinFunc = fn(Vec<Object>) -> Object;
Expand All @@ -17,7 +15,6 @@ pub enum Object {
Boolean(bool),
Array(Vec<Object>),
Hash(HashMap<Object, Object>),
Func(Vec<Ident>, BlockStatement),
CompiledFunction {
instructions: CompiledInstructions,
locals: usize,
Expand Down Expand Up @@ -60,7 +57,7 @@ impl fmt::Display for Object {
.join(", ")
)
}
Object::Func(..) | Object::CompiledFunction { .. } => {
Object::CompiledFunction { .. } => {
write!(f, "[Function]")
}
Object::Builtin(..) => {
Expand All @@ -87,9 +84,7 @@ impl Object {
Object::Boolean(_) => "boolean".to_string(),
Object::Array(_) => "array".to_string(),
Object::Hash(_) => "hash".to_string(),
Object::Func(..) | Object::Builtin(..) | Object::CompiledFunction { .. } => {
"fn".to_string()
}
Object::Builtin(..) | Object::CompiledFunction { .. } => "fn".to_string(),
Object::ReturnValue(_) => "return".to_string(),
Object::Error(_) => "error".to_string(),
Object::Nil => "nil".to_string(),
Expand Down
2 changes: 1 addition & 1 deletion core/compiler/src/symbols_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,10 @@ impl SymbolTable {
scope,
name: name.to_string(),
};
self.store.insert(name.to_string(), symbol.clone());
if !self.store.contains_key(&name.to_string()) {
self.num_defs += 1;
}
self.store.insert(name.to_string(), symbol.clone());
symbol
}

Expand Down
2 changes: 0 additions & 2 deletions core/lexer/src/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,6 @@ pub enum RawToken {
Minus,
#[token("!")]
Bang,
#[token("$")]
Dollar,
#[token("*")]
Asterisk,
#[token("/")]
Expand Down
1 change: 0 additions & 1 deletion core/parser/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ pub enum Prefix {
Plus,
Minus,
Not,
Dollar,
}

#[derive(PartialEq, Clone, Debug)]
Expand Down
11 changes: 2 additions & 9 deletions core/parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,7 @@ impl Parser {
RawToken::String(_) => self.parse_string_expr(),
RawToken::Nil => self.parse_nil_expr(),
RawToken::True | RawToken::False => self.parse_boolean_expr(),
RawToken::Plus | RawToken::Bang | RawToken::Minus | RawToken::Dollar => {
self.parse_prefix_expr()
}
RawToken::Plus | RawToken::Bang | RawToken::Minus => self.parse_prefix_expr(),
RawToken::ParenL => self.parse_grouped_expr(),
RawToken::BracketL => self.parse_array_expr(),
RawToken::BraceL => self.parse_hash_expr(),
Expand Down Expand Up @@ -449,17 +447,12 @@ impl Parser {
RawToken::Bang => Prefix::Not,
RawToken::Minus => Prefix::Minus,
RawToken::Plus => Prefix::Plus,
RawToken::Dollar => Prefix::Dollar,
_ => return None,
};

self.step();

match self.parse_expression(if current == RawToken::Dollar {
Precedence::Highest
} else {
Precedence::Prefix
}) {
match self.parse_expression(Precedence::Prefix) {
Some(expr) => Some(Expression::Prefix(prefix, Box::new(expr))),
None => None,
}
Expand Down
Loading

0 comments on commit e0f664f

Please sign in to comment.