Skip to content

Commit

Permalink
Merge pull request #287 from CohenArthur/add-link-with-builtin
Browse files Browse the repository at this point in the history
Add ffi module and link_with() function
  • Loading branch information
CohenArthur authored Oct 14, 2021
2 parents 80f1807 + 399aec1 commit b15fc3d
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 38 deletions.
24 changes: 22 additions & 2 deletions src/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,18 @@ fn string_display_err(ctx: &mut Context, args: Args) -> Option<ObjectInstance> {
None
}

/// Link with a given library at runtime
fn ffi_link_with(ctx: &mut Context, args: Args) -> Option<ObjectInstance> {
let lib_path = JkString::from_instance(&args[0].execute(ctx).unwrap()).0;

match unsafe { libloading::Library::new(lib_path) } {
Ok(lib) => ctx.add_lib(lib),
Err(e) => ctx.error(e.into()),
}

None
}

impl Builtins {
fn add(&mut self, name: &'static str, builtin_fn: BuiltinFn) {
self.functions.insert(String::from(name), builtin_fn);
Expand All @@ -62,6 +74,7 @@ impl Builtins {
builtins.add("__builtin_string_concat", string_concat);
builtins.add("__builtin_string_display", string_display);
builtins.add("__builtin_string_display_err", string_display_err);
builtins.add("__builtin_ffi_link_with", ffi_link_with);

builtins
}
Expand All @@ -86,12 +99,19 @@ mod tests {
use crate::jinko;

#[test]
fn t_all_builtins_are_valid() {
fn t_string_builtins_are_valid() {
jinko! {
__builtin_string_len("jk");
__builtin_string_concat("file", ".jk");
__builtin_string_display("to display");
__builtin_string_display_err("to display on err"):
__builtin_string_display_err("to display on err");
};
}

#[test]
fn t_ffi_builtins_are_valid() {
jinko! {
__builtin_ffi_link_with("tests/fixtures/clib/lib.so");
};
}
}
42 changes: 14 additions & 28 deletions src/instruction/function_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,22 +120,18 @@ impl FunctionCall {
fn execute_external_function(
&self,
ctx: &mut Context,
builtin_name: &str,
dec: &FunctionDec,
) -> Option<ObjectInstance> {
if ctx.is_builtin(builtin_name) {
match ctx.call_builtin(builtin_name, self.args.clone()) {
if ctx.is_builtin(dec.name()) {
match ctx.call_builtin(dec.name(), self.args.clone()) {
Ok(value) => value,
Err(e) => {
ctx.error(e);
None
}
}
} else {
ctx.error(Error::new(ErrKind::Context).with_msg(format!(
"error executing external function `{}`",
builtin_name
)));
None
crate::ffi::execute(dec, self, ctx)
}
}
}
Expand Down Expand Up @@ -173,7 +169,7 @@ impl Instruction for FunctionCall {
};

if function.fn_kind() == FunctionKind::Ext {
return self.execute_external_function(ctx, function.name());
return self.execute_external_function(ctx, &function);
}

ctx.scope_enter();
Expand All @@ -182,7 +178,7 @@ impl Instruction for FunctionCall {

self.map_args(&function, ctx);

let ret_val = function.run(self, ctx);
let ret_val = function.run(ctx);

ctx.scope_exit();

Expand Down Expand Up @@ -246,7 +242,6 @@ impl TypeCheck for FunctionCall {
#[cfg(test)]
mod tests {
use super::*;
use crate::instruction::TypeId;
use crate::{jinko, jinko_fail};

#[test]
Expand All @@ -260,35 +255,26 @@ mod tests {

#[test]
fn t_invalid_args_number() {
use super::super::{DecArg, FunctionDec};
use crate::instruction::FunctionKind;
use crate::value::JkInt;

let mut ctx = Context::new();

// Create a new function with two integers arguments
let mut f = FunctionDec::new("func0".to_owned(), None);
f.set_kind(FunctionKind::Func);

f.set_args(vec![
DecArg::new("a".to_owned(), TypeId::from("int")),
DecArg::new("b".to_owned(), TypeId::from("int")),
]);

ctx.add_function(f).unwrap();
let mut ctx = jinko! {
func func0(a: int, b: int);
};

let mut f_call = FunctionCall::new("func0".to_string());
let mut type_ctx = TypeCtx::new(&mut ctx);

assert!(f_call.execute(&mut ctx).is_none());
assert_eq!(f_call.resolve_type(&mut type_ctx), CheckedType::Unknown);
assert!(
ctx.error_handler.has_errors(),
type_ctx.context.error_handler.has_errors(),
"Given 0 arguments to 2 arguments function"
);
ctx.clear_errors();
type_ctx.context.clear_errors();

f_call.add_arg(Box::new(JkInt::from(12)));

assert!(f_call.execute(&mut ctx).is_none());
assert_eq!(f_call.resolve_type(&mut type_ctx), CheckedType::Unknown);
assert!(
ctx.error_handler.has_errors(),
"Given 1 arguments to 2 arguments function"
Expand Down
11 changes: 3 additions & 8 deletions src/instruction/function_declaration.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Function Declarations are used when adding a new function to the source. They contain
//! a name, a list of required arguments as well as an associated code block
use crate::instruction::{Block, DecArg, FunctionCall, InstrKind, Instruction, TypeId};
use crate::instruction::{Block, DecArg, InstrKind, Instruction, TypeId};
use crate::typechecker::{CheckedType, TypeCtx};
use crate::{Context, ErrKind, Error, ObjectInstance, TypeCheck};

Expand Down Expand Up @@ -107,13 +107,8 @@ impl FunctionDec {

/// Run through the function as if it was called. This is useful for setting
/// an entry point into the interpreter and executing it
pub fn run(&self, call: &FunctionCall, ctx: &mut Context) -> Option<ObjectInstance> {
let block = match self.block() {
Some(b) => b,
None => return crate::ffi::execute(self, call, ctx),
};

block.execute(ctx)
pub fn run(&self, ctx: &mut Context) -> Option<ObjectInstance> {
self.block().unwrap().execute(ctx)
}
}

Expand Down
5 changes: 5 additions & 0 deletions stdlib/ffi.jk
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
ext func __builtin_ffi_link_with(path: string);

func link_with(lib: string) {
lib.__builtin_ffi_link_with()
}
1 change: 1 addition & 0 deletions stdlib/lib.jk
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
incl pair
incl string
incl maybe
incl ffi
5 changes: 5 additions & 0 deletions tests/ft/stdlib/ffi.jk
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
link_with("tests/fixtures/clib/lib.so");

ext func print_something();

print_something();
5 changes: 5 additions & 0 deletions tests/ft/stdlib/stdlib.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ tests:
binary: "target/debug/jinko"
args:
- "tests/ft/stdlib/maybe.jk"
- name: "Test FFI module"
binary: "target/debug/jinko"
args:
- "tests/ft/stdlib/ffi.jk"
stdout: "jinko called\n"

0 comments on commit b15fc3d

Please sign in to comment.