mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FEATURE: Give modules a reference to self.
This commit is contained in:
parent
f12d264778
commit
439ebf74f3
@ -604,29 +604,23 @@ let embedded_default_params = top_mod_out_expr{};
|
|||||||
embedded_default_params.value == "None";
|
embedded_default_params.value == "None";
|
||||||
```
|
```
|
||||||
|
|
||||||
### Recursive Modules
|
### Module builtin bindings
|
||||||
|
|
||||||
One consequence of a module being able to import the same file they are located in
|
One consequence of a module being able to import the same file they are located in
|
||||||
is that modules can be called recursively. They are the only expression that is
|
is that modules can be called recursively. They are the only expression that is
|
||||||
capable of recursion in UCG. Recursion can be done by importing the module's file
|
capable of recursion in UCG. Recursion can be done by importing the module's file
|
||||||
inside the module's definition and using it as normal.
|
inside the module's definition and using it as normal.
|
||||||
|
|
||||||
There is a convenience function `mod.pkg` in the mod binding for a module. That imports the
|
Modules have ia recursive reference to the current module `mod.this` that can
|
||||||
package/file that the module was declared in. This binding is only present if the module
|
be used for recursive modules.
|
||||||
was declared in a file. Modules created as part of an eval will not have it.
|
|
||||||
|
|
||||||
```
|
```
|
||||||
let recursive = module {
|
let recursive = module {
|
||||||
counter=1,
|
counter=1,
|
||||||
stop=10,
|
stop=10,
|
||||||
} => (result) {
|
} => (result) {
|
||||||
// import our enclosing file again. Careful since calling this function
|
|
||||||
// means that if you instantiate this module in the same file it is
|
|
||||||
// declared in you will trigger an import cycle error.
|
|
||||||
let pkg = mod.pkg();
|
|
||||||
|
|
||||||
let result = select mod.counter != mod.stop, {
|
let result = select mod.counter != mod.stop, {
|
||||||
true = [mod.start] + pkg.recursive{counter=mod.counter+1},
|
true = [mod.start] + mod.this{counter=mod.counter+1},
|
||||||
false = [mod.start],
|
false = [mod.start],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -634,6 +628,24 @@ let recursive = module {
|
|||||||
recursive{} == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
recursive{} == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
```
|
```
|
||||||
|
|
||||||
|
There is also a convenience function `mod.pkg` in the mod binding for a module.
|
||||||
|
That imports the package/file the module was declared in. This binding is only
|
||||||
|
present if the module was declared in a file. Modules created as part of an
|
||||||
|
eval will not have it.
|
||||||
|
|
||||||
|
```
|
||||||
|
let self_importer = module {
|
||||||
|
item=NULL,
|
||||||
|
} => () {
|
||||||
|
let pkg = mod.pkg();
|
||||||
|
|
||||||
|
let result = pkg.recursive{};
|
||||||
|
};
|
||||||
|
|
||||||
|
self_importer{} == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
Fail Expression
|
Fail Expression
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
|
@ -109,4 +109,16 @@ assert t.ok{
|
|||||||
assert t.equal{
|
assert t.equal{
|
||||||
left = export_module_tuple{foo="bar"},
|
left = export_module_tuple{foo="bar"},
|
||||||
right = {quux = "bar"},
|
right = {quux = "bar"},
|
||||||
|
};
|
||||||
|
|
||||||
|
let recursive_module = module {start=1, end=10} => (result) {
|
||||||
|
let this = mod.this;
|
||||||
|
let result = select mod.start != mod.end, mod.start, {
|
||||||
|
true = this{start=mod.start + 1, end=mod.end},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
assert t.equal{
|
||||||
|
left = recursive_module{},
|
||||||
|
right = 10,
|
||||||
};
|
};
|
@ -1159,7 +1159,7 @@ impl<'a> FileBuilder<'a> {
|
|||||||
mod_def: &ModuleDef,
|
mod_def: &ModuleDef,
|
||||||
scope: &Scope,
|
scope: &Scope,
|
||||||
) -> Result<Rc<Val>, Box<dyn Error>> {
|
) -> Result<Rc<Val>, Box<dyn Error>> {
|
||||||
let maybe_tpl = mod_def.clone().arg_tuple.unwrap().clone();
|
let maybe_tpl = mod_def.arg_tuple.as_ref().unwrap().clone();
|
||||||
if let &Val::Tuple(ref src_fields) = maybe_tpl.as_ref() {
|
if let &Val::Tuple(ref src_fields) = maybe_tpl.as_ref() {
|
||||||
// 1. First we create a builder.
|
// 1. First we create a builder.
|
||||||
let mut b = self.clone_builder();
|
let mut b = self.clone_builder();
|
||||||
@ -1188,6 +1188,10 @@ impl<'a> FileBuilder<'a> {
|
|||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
overrides.push((
|
||||||
|
Token::new("this", TokenType::BAREWORD, def.pos.clone()),
|
||||||
|
Expression::Module(mod_def.clone()),
|
||||||
|
));
|
||||||
overrides.extend(def.fields.iter().cloned());
|
overrides.extend(def.fields.iter().cloned());
|
||||||
let mod_args = self.copy_fields_from_base(src_fields, &overrides, &child_scope)?;
|
let mod_args = self.copy_fields_from_base(src_fields, &overrides, &child_scope)?;
|
||||||
// put our copied parameters tuple in our builder under the mod key.
|
// put our copied parameters tuple in our builder under the mod key.
|
||||||
@ -1327,7 +1331,12 @@ impl<'a> FileBuilder<'a> {
|
|||||||
// First we rewrite the imports to be absolute paths.
|
// First we rewrite the imports to be absolute paths.
|
||||||
def.imports_to_absolute(root);
|
def.imports_to_absolute(root);
|
||||||
// Then we create our tuple default.
|
// Then we create our tuple default.
|
||||||
def.arg_tuple = Some(self.eval_tuple(&def.arg_set, scope)?);
|
if def.arg_tuple.is_none() {
|
||||||
|
// NOTE: This is an ugly hack to enable recursive references to work
|
||||||
|
// in eval_module_copy. We should really fix out DataModel to properly
|
||||||
|
// handle this but for now this should work.
|
||||||
|
def.arg_tuple = Some(self.eval_tuple(&def.arg_set, scope)?);
|
||||||
|
}
|
||||||
// Then we construct a new Val::Module
|
// Then we construct a new Val::Module
|
||||||
Ok(Rc::new(Val::Module(def)))
|
Ok(Rc::new(Val::Module(def)))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user