Skip to content

Commit

Permalink
feat: implement frocref instruction
Browse files Browse the repository at this point in the history
  • Loading branch information
Fumuran committed Oct 24, 2023
1 parent ef9a121 commit d9c4eb5
Show file tree
Hide file tree
Showing 9 changed files with 169 additions and 2 deletions.
10 changes: 10 additions & 0 deletions assembly/src/assembler/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ impl AssemblyContext {
}
}

/// Returns the [Procedure] by its index from the vector of compiled procedures.
pub fn get_compiled_procedure(&self, idx: u16) -> Result<&Procedure, AssemblyError> {
let module_context = self.module_stack.last().expect("no modules");
module_context
.compiled_procs
.get(idx as usize)
.map(|named_proc| named_proc.inner())
.ok_or_else(|| AssemblyError::local_proc_not_found(idx, &module_context.path))
}

// STATE MUTATORS
// --------------------------------------------------------------------------------------------

Expand Down
2 changes: 2 additions & 0 deletions assembly/src/assembler/instruction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ impl Assembler {
Instruction::SysCall(id) => self.syscall(id, ctx),
Instruction::DynExec => self.dynexec(),
Instruction::DynCall => self.dyncall(),
Instruction::ProcRefLocal(idx) => self.procref_local(*idx, ctx, span),
Instruction::ProcRefImported(id) => self.procref_imported(id, ctx, span),

// ----- debug decorators -------------------------------------------------------------
Instruction::Breakpoint => {
Expand Down
38 changes: 37 additions & 1 deletion assembly/src/assembler/instruction/procedures.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use super::{Assembler, AssemblyContext, AssemblyError, CodeBlock, ProcedureId, RpoDigest};
use super::{
super::Vec, Assembler, AssemblyContext, AssemblyError, CodeBlock, Operation, ProcedureId,
RpoDigest, SpanBuilder,
};

// PROCEDURE INVOCATIONS
// ================================================================================================
Expand Down Expand Up @@ -133,4 +136,37 @@ impl Assembler {
// create a new CALL block whose target is DYN
Ok(Some(CodeBlock::new_dyncall()))
}

pub(super) fn procref_local(
&self,
proc_idx: u16,
context: &mut AssemblyContext,
span: &mut SpanBuilder,
) -> Result<Option<CodeBlock>, AssemblyError> {
// get root of the compiled local procedure
let proc_root = context.get_compiled_procedure(proc_idx)?.mast_root();
// create an array with `Push` operations containing root elements
let ops: Vec<Operation> = proc_root.iter().map(|elem| Operation::Push(*elem)).collect();
span.add_ops(ops)
}

pub(super) fn procref_imported(
&self,
proc_id: &ProcedureId,
context: &mut AssemblyContext,
span: &mut SpanBuilder,
) -> Result<Option<CodeBlock>, AssemblyError> {
// make sure the procedure is in procedure cache
self.ensure_procedure_is_in_cache(proc_id, context)?;

// get the procedure from the assembler
let proc_cache = self.proc_cache.borrow();
let proc = proc_cache.get_by_id(proc_id).expect("procedure not in cache");

// get root of the cimported procedure
let proc_root = proc.mast_root();
// create an array with `Push` operations containing root elements
let ops: Vec<Operation> = proc_root.iter().map(|elem| Operation::Push(*elem)).collect();
span.add_ops(ops)
}
}
4 changes: 4 additions & 0 deletions assembly/src/ast/nodes/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ pub enum Instruction {
SysCall(ProcedureId),
DynExec,
DynCall,
ProcRefLocal(u16),
ProcRefImported(ProcedureId),

// ----- debug decorators ---------------------------------------------------------------------
Breakpoint,
Expand Down Expand Up @@ -598,6 +600,8 @@ impl fmt::Display for Instruction {
Self::SysCall(proc_id) => write!(f, "syscall.{proc_id}"),
Self::DynExec => write!(f, "dynexec"),
Self::DynCall => write!(f, "dyncall"),
Self::ProcRefLocal(index) => write!(f, "procref.{index}"),
Self::ProcRefImported(proc_id) => write!(f, "procref.{proc_id}"),

// ----- debug decorators -------------------------------------------------------------
Self::Breakpoint => write!(f, "breakpoint"),
Expand Down
4 changes: 4 additions & 0 deletions assembly/src/ast/nodes/serde/deserialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,10 @@ impl Deserializable for Instruction {
OpCode::SysCall => Ok(Instruction::SysCall(ProcedureId::read_from(source)?)),
OpCode::DynExec => Ok(Instruction::DynExec),
OpCode::DynCall => Ok(Instruction::DynCall),
OpCode::ProcRefLocal => Ok(Instruction::ProcRefLocal(source.read_u16()?)),
OpCode::ProcRefImported => {
Ok(Instruction::ProcRefImported(ProcedureId::read_from(source)?))
}

// ----- debugging --------------------------------------------------------------------
OpCode::Debug => {
Expand Down
4 changes: 3 additions & 1 deletion assembly/src/ast/nodes/serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,9 +282,11 @@ pub enum OpCode {
SysCall = 246,
DynExec = 247,
DynCall = 248,
ProcRefLocal = 249,
ProcRefImported = 250,

// ----- debugging ----------------------------------------------------------------------------
Debug = 249,
Debug = 251,

// ----- emit --------------------------------------------------------------------------------
Emit = 250,
Expand Down
8 changes: 8 additions & 0 deletions assembly/src/ast/nodes/serde/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,14 @@ impl Serializable for Instruction {
}
Self::DynExec => OpCode::DynExec.write_into(target),
Self::DynCall => OpCode::DynCall.write_into(target),
Self::ProcRefLocal(v) => {
OpCode::ProcRefLocal.write_into(target);
target.write_u16(*v)
}
Self::ProcRefImported(imported) => {
OpCode::ProcRefImported.write_into(target);
imported.write_into(target)
}

// ----- debug decorators -------------------------------------------------------------
Self::Breakpoint => {
Expand Down
25 changes: 25 additions & 0 deletions assembly/src/ast/parsers/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,30 @@ impl ParserContext<'_> {
}
}

// PROCREF PARSERS
// --------------------------------------------------------------------------------------------

/// Parse a `procref` token into an instruction node.
pub fn parse_procref(&self, token: &Token) -> Result<Node, ParsingError> {
match token.parse_invocation(token.parts()[0])? {
InvocationTarget::ProcedureName(proc_name) => {
let index = self.get_local_proc_index(proc_name, token)?;
let inner = Instruction::ProcRefLocal(index);
Ok(Node::Instruction(inner))
}
InvocationTarget::ProcedurePath { name, module } => {
let module_path = self
.import_info
.get_module_path(module)
.ok_or_else(|| ParsingError::procedure_module_not_imported(token, module))?;
let proc_id = ProcedureId::from_name(name.as_ref(), module_path);
let inner = Instruction::ProcRefImported(proc_id);
Ok(Node::Instruction(inner))
}
_ => Err(ParsingError::invalid_param(token, 1)),
}
}

// PROCEDURE PARSERS
// --------------------------------------------------------------------------------------------

Expand Down Expand Up @@ -622,6 +646,7 @@ impl ParserContext<'_> {
"syscall" => self.parse_syscall(op),
"dynexec" => simple_instruction(op, DynExec),
"dyncall" => simple_instruction(op, DynCall),
"procref" => self.parse_procref(op),

// ----- constant statements ----------------------------------------------------------
"const" => Err(ParsingError::const_invalid_scope(op)),
Expand Down
76 changes: 76 additions & 0 deletions assembly/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,82 @@ fn call_without_path() {
.unwrap();
}

// PROGRAM WITH PROCREF
// ================================================================================================

#[test]
fn test() {
// instantiate assembler
let assembler = Assembler::default();

// compile first module
let module_path1 = LibraryPath::new("module::path::one").unwrap();
let module_source1 = ModuleAst::parse(
"
export.aaa
push.7.8
end
export.foo
push.1.2
end",
)
.unwrap();

let _roots1 = assembler
.compile_module(
&module_source1,
Some(&module_path1),
&mut AssemblyContext::for_module(false),
)
.unwrap();

// compile second module
let module_path2 = LibraryPath::new("module::path::two").unwrap();
let module_source2 = ModuleAst::parse(
"
use.module::path::one
export.one::foo
export.bar
procref.one::aaa
end",
)
.unwrap();

let _roots2 = assembler
.compile_module(
&module_source2,
Some(&module_path2),
&mut AssemblyContext::for_module(false),
)
.unwrap();

// compile program with procref calls
let program_source = ProgramAst::parse(
"
use.module::path::two
proc.baz.4
push.3.4
end
begin
procref.two::bar
procref.two::foo
procref.baz
end",
)
.unwrap();

let _compiled_program = assembler
.compile_in_context(
&program_source,
&mut AssemblyContext::for_program(Some(&program_source)),
)
.unwrap();
}

// CONSTANTS
// ================================================================================================

Expand Down

0 comments on commit d9c4eb5

Please sign in to comment.