Skip to content

Instantly share code, notes, and snippets.

@jFransham
Last active March 24, 2016 23:11
Show Gist options
  • Save jFransham/6a66072516075ceb7a0c to your computer and use it in GitHub Desktop.
Save jFransham/6a66072516075ceb7a0c to your computer and use it in GitHub Desktop.
extern crate ketos;
use ketos::{Interpreter, FromValue};
macro_rules! ketos_mod {
(
mod $name:ident {
$( $inner:tt )*
}
) => {
mod $name {
use ketos::{
self,
Arity,
Error,
BuiltinModuleLoader, Module, ModuleBuilder, ModuleLoader,
Name,
GlobalScope, Scope,
FromValueRef, Value
};
#[derive(Debug)]
pub struct Loader;
ketos_mod!{ @fun $( $inner )* }
impl ModuleLoader for Loader {
fn load_module(&self, name: Name, scope: &Scope) -> Result<Module, Error> {
if scope.with_name(
name, |name| name == stringify!($name)
) {
let scope = GlobalScope::new_using(scope);
let module = ketos_mod!(@matchfns scope, $name { $( $inner )* });
Ok(module)
} else {
BuiltinModuleLoader.load_module(name, scope)
}
}
}
}
};
(@fun use $p:path; $( $rest:tt )*) => {
use $p;
ketos_mod!(@fun $( $rest )*);
};
(@fun fn $fn_name:ident($( $arg:ident : $t:ty ),*) $body:block $( $rest:tt )*) => {
fn $fn_name(
_: &Scope, _args: &mut [Value]
) -> Result<Value, Error> {
let mut _i = 0;
$(
let $arg: $t = FromValueRef::from_value_ref(&_args[_i])
.unwrap();
_i = _i + 1;
)*
let cls = |$($arg: $t ),*| $body;
Ok(cls($( $arg ),*).into())
}
ketos_mod!(@fun $( $rest )*);
};
(@fun #[raw] fn $fn_name:ident($arg:ident : $t0:ty, $v:ident: $t1:ty) $body:block $( $rest:tt )*) => {
fn $fn_name($arg: &Scope, $v: &mut [Value]) -> Result<ketos::value::Value, ketos::error::Error> $body
ketos_mod!(@fun $( $rest )*);
};
(@fun) => {};
(@matchfns
$scope:expr, $name:ident {
$(
$(#[$raw:tt])* fn $fn_name:ident($( $arg:tt )*) $body:block
)*
}
) => {
{
let mut m = ModuleBuilder::new(stringify!($name), $scope);
$(
m = ketos_mod!(@matchfn $scope, $name {
$(#[$raw])* fn $fn_name($($arg)*) $body
})(m);
)*
m.finish()
}
};
(@matchfn
$scope:expr, $name:ident {
fn $fn_name:ident($( $arg:ident : $t:ty ),*) $b:block
}
) => {
|m: ModuleBuilder| m.add_function(
stringify!($fn_name),
$fn_name,
Arity::Exact(
{
let arg_names: &[&str] = &[
$( stringify!($arg) ),*
];
arg_names.len()
} as u32
)
)
};
(@matchfn
$scope:expr, $name:ident {
#[raw] fn $fn_name:ident($arg:ident : $t:ty, $v:ident: &mut [Value]) $b:block
}
) => {
ketos_mod! {
@matchfn $scope, $name {
#[raw] fn $fn_name($arg : $t, $v: &mut [Value; 0..]) $b
}
}
};
(@matchfn
$scope:expr, $name:ident {
#[raw] fn $fn_name:ident($arg:ident : $t:ty, $v:ident: &mut [Value; $a:tt]) $b:block
}
) => {
|m: ModuleBuilder| m.add_function(
stringify!($fn_name),
$fn_name,
ketos_mod!(@range_to_arity $a)
)
};
(@matchfn
$scope:expr, $name:ident {
#[raw] fn $fn_name:ident($arg:ident : $t:ty, $v:ident: &mut [Value; $a:tt..$b:tt]) $body:block
}
) => {
|m: ModuleBuilder| m.add_function(
stringify!($fn_name),
$fn_name,
ketos_mod!(@range_to_arity $a..$b)
)
};
(@matchfn
$scope:expr, $name:ident {
#[raw] fn $fn_name:ident($arg:ident : $t:ty, $v:ident: &mut [Value; $a:tt..]) $b:block
}
) => {
|m: ModuleBuilder| m.add_function(
stringify!($fn_name),
$fn_name,
ketos_mod!(@range_to_arity $a..)
)
};
(@range_to_arity $i:tt..) => {
ketos::function::Arity::Min(ketos_mod!(@capture $i))
};
(@range_to_arity $a:tt..$b:tt) => {
ketos::function::Arity::Range(
ketos_mod!(@capture $a),
ketos_mod!(@capture $b)
)
};
(@range_to_arity $i:tt) => {
ketos::function::Arity::Min(ketos_mod!(@capture $i))
};
(@capture $i:expr) => { $i }
}
ketos_mod! {
mod hello {
fn do_something(first: &str, second: &str) {
first.len() + second.len()
}
fn meaning_of_life() {
return "Fourty-two";
}
fn interpret(inp: &str) {
use ketos::Interpreter;
let interp = Interpreter::new();
interp.run_code(inp, None).unwrap()
}
#[raw]
fn set(s: &Scope, args: &mut [Value; 2..10]) {
Ok(().into())
}
}
}
fn main() {
let interp = Interpreter::with_loader(Box::new(hello::Loader));
// Import our custom module and run the imported function
let v = interp.run_code(r#"
(use hello (interpret))
(interpret "(+ 1 2)")
"#, None).unwrap();
println!("{:?}", v);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment