murarth / ketos

Lisp dialect scripting and extension language for Rust programs
Apache License 2.0
751 stars 45 forks source link

Default module in scope #15

Closed hauleth closed 8 years ago

hauleth commented 8 years ago

How to add additional "core" methods? That I do not need to add (use core :all) at the beginning of each file?

murarth commented 8 years ago

The set of core system functions cannot be modified at runtime. However, you could call interpreter.run_code("(use core :all)") after creating the interpreter.

hauleth commented 8 years ago

Will it provide methods from core for all (including dependencies) files or only for directly executed ones?

Łukasz Jan Niemier

Dnia 27 lut 2016 o godz. 00:17 Murarth notifications@github.com napisał(a):

The set of core system functions cannot be modified at runtime. However, you could call interpreter.run_code("(use core :all)") after creating the interpreter.

— Reply to this email directly or view it on GitHub.

murarth commented 8 years ago

No, that would affect only the "main" scope created by the interpreter.

A custom ModuleLoader could modify a newly created scope before initializing the module. But this wouldn't work well with existing ModuleLoader implementations (such as the built-in file loader), which create their own scopes immediately before module initialization.

I think a more flexible module loader API may be a good solution to this issue (and other yet unforeseen issues).

murarth commented 8 years ago

Okay, I've made a minor change to the ModuleLoader trait and some changes to implementations (all listed in the commit message: 5e52a53baea2f4dd01d992c3400c9200cef035a4) which should allow you to implement a simple loader that modifies a Scope (using e.g. run_code_in_scope) and passes the scope on to another loader (e.g. FileModuleLoader) which will be the base for the new module, before its code is run.

It's a small change, but I think I've freed things up to allow more complicated schemes without a lot of trouble and while being able to reuse ModuleLoaders provided by ketos. Through chaining and wrapper implementations, one could do something like this:

struct PreludeWrapper<T>(T);

impl<T> ModuleLoader for PreludeWrapper<T> { ... }

let loader = Box::new(
    // Built-in modules first
    BuiltinModuleLoader
    // Then user-supplied files; with prelude
    .chain(PreludeWrapper(FileModuleLoader::new()))
    // Then standard library files; no prelude
    .chain(FileModuleLoader::with_search_paths(vec![PathBuf::from("lib")]))
);

let interp = Interpreter::with_loader(loader);