mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
FEATURE: Add a function to the mod binding that imports the containing package.
This commit is contained in:
parent
4afac26497
commit
0e41a40ab3
@ -576,9 +576,9 @@ let embedded_with_params = top_mod{deep_value = "Some"};
|
||||
embedded_with_params.embedded.value == "Some";
|
||||
```
|
||||
|
||||
### Out Expressions
|
||||
### Return Expressions
|
||||
|
||||
If there is an out expression then the module will only export the result of
|
||||
If there is a return expression then the module will only export the result of
|
||||
that expression. The out expression is computed after the last statement in the
|
||||
module has been evaluated.
|
||||
|
||||
@ -611,6 +611,29 @@ 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
|
||||
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
|
||||
package/file that 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 recursive = module {
|
||||
counter=1,
|
||||
stop=10,
|
||||
} => (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, {
|
||||
true = [mod.start] + pkg.recursive{counter=mod.counter+1},
|
||||
false = [mod.start],
|
||||
};
|
||||
};
|
||||
|
||||
recursive{} == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
|
||||
```
|
||||
|
||||
Fail Expression
|
||||
---------------
|
||||
|
||||
|
@ -1071,7 +1071,7 @@ impl<'a> FileBuilder<'a> {
|
||||
Rc::new(Val::Tuple(fields))
|
||||
}
|
||||
|
||||
fn copy_from_base(
|
||||
fn copy_fields_from_base(
|
||||
&self,
|
||||
src_fields: &Vec<(String, Rc<Val>)>,
|
||||
overrides: &Vec<(Token, Expression)>,
|
||||
@ -1166,9 +1166,29 @@ impl<'a> FileBuilder<'a> {
|
||||
// Push our base tuple on the stack so the copy can use
|
||||
// self to reference it.
|
||||
let child_scope = scope.spawn_child().set_curr_val(maybe_tpl.clone());
|
||||
let mod_args = self.copy_from_base(src_fields, &def.fields, &child_scope)?;
|
||||
let mut overrides = Vec::new();
|
||||
if let Some(ref path) = mod_def.pos.file {
|
||||
overrides.push((
|
||||
Token::new("pkg", TokenType::BAREWORD, def.pos.clone()),
|
||||
Expression::Func(FuncDef {
|
||||
scope: None,
|
||||
argdefs: Vec::new(),
|
||||
fields: Box::new(Expression::Import(ImportDef {
|
||||
pos: def.pos.clone(),
|
||||
path: Token::new(
|
||||
path.to_string_lossy().to_string(),
|
||||
TokenType::QUOTED,
|
||||
def.pos.clone(),
|
||||
),
|
||||
})),
|
||||
pos: def.pos.clone(),
|
||||
}),
|
||||
));
|
||||
}
|
||||
overrides.extend(def.fields.iter().cloned());
|
||||
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.
|
||||
let mod_key = PositionedItem::new_with_pos(String::from("mod"), Position::new(0, 0, 0));
|
||||
let mod_key = PositionedItem::new_with_pos(String::from("mod"), def.pos.clone());
|
||||
match b.scope.build_output.entry(mod_key) {
|
||||
Entry::Occupied(e) => {
|
||||
return Err(error::BuildError::with_pos(
|
||||
@ -1215,7 +1235,7 @@ impl<'a> FileBuilder<'a> {
|
||||
let v = self.eval_value(&def.selector, scope)?;
|
||||
if let &Val::Tuple(ref src_fields) = v.as_ref() {
|
||||
let child_scope = scope.spawn_child().set_curr_val(v.clone());
|
||||
return self.copy_from_base(&src_fields, &def.fields, &child_scope);
|
||||
return self.copy_fields_from_base(&src_fields, &def.fields, &child_scope);
|
||||
}
|
||||
if let &Val::Module(ref mod_def) = v.as_ref() {
|
||||
return self.eval_module_copy(def, mod_def, scope);
|
||||
|
@ -16,7 +16,7 @@
|
||||
let maybe = module{
|
||||
val = NULL,
|
||||
} => ({do=do, is_null=is_null, or=or, unwrap=unwrap, expect=expect}) {
|
||||
let maybe = import "std/functional.ucg".maybe;
|
||||
let maybe = mod.pkg().maybe;
|
||||
|
||||
let do = func (op) => select (mod.val != NULL), maybe{val=NULL}, {
|
||||
true = maybe{val=op(mod.val)},
|
||||
|
@ -77,7 +77,7 @@ let slice = module {
|
||||
end = NULL,
|
||||
list = NULL,
|
||||
} => (result) {
|
||||
let list = import "std/lists.ucg";
|
||||
let list = mod.pkg();
|
||||
|
||||
let list_len = list.len(mod.list);
|
||||
|
||||
@ -111,7 +111,7 @@ let zip = module{
|
||||
list1 = NULL,
|
||||
list2 = NULL,
|
||||
} => (result) {
|
||||
let len = import "std/lists.ucg".len;
|
||||
let len = mod.pkg().len;
|
||||
|
||||
// Compute the length of each list.
|
||||
let len1 = len(mod.list1);
|
||||
@ -169,7 +169,7 @@ let ops = module{
|
||||
reverse=reverse,
|
||||
list=list,
|
||||
}) {
|
||||
let super = import "std/lists.ucg";
|
||||
let super = mod.pkg();
|
||||
let list = mod.list;
|
||||
let len = super.len(mod.list);
|
||||
let str_join = func(sep) => super.str_join{list=mod.list, sep=sep};
|
||||
|
@ -32,7 +32,7 @@ let any = module {
|
||||
// The set of allowed type shapes it can be.
|
||||
types=[],
|
||||
} => (result) {
|
||||
let schema = import "std/schema.ucg";
|
||||
let schema = mod.pkg();
|
||||
|
||||
let reducer = func (acc, t) => acc{
|
||||
ok = acc.ok || (schema.shaped{val=acc.val, shape=t}),
|
||||
@ -66,7 +66,7 @@ let shaped = module {
|
||||
// shape it is compared with.
|
||||
partial = true,
|
||||
} => (result) {
|
||||
let schema = import "std/schema.ucg";
|
||||
let schema = mod.pkg();
|
||||
|
||||
let simple_handler = func (val, shape) => val is schema.base_type_of(shape);
|
||||
|
||||
|
@ -65,7 +65,7 @@ let ops = module {
|
||||
start = 0,
|
||||
end = len,
|
||||
} => (result) {
|
||||
let filepkg = import "std/strings.ucg";
|
||||
let filepkg = mod.pkg();
|
||||
let reducer = func(acc, char) => acc{
|
||||
counter = acc.counter + 1,
|
||||
str = select ((acc.counter >= mod.start) && (acc.counter <= mod.end)), acc.str, {
|
||||
|
@ -48,7 +48,7 @@ let ops = module{
|
||||
} => ({fields=fields, values=values, iter=iter}) {
|
||||
(mod.tpl != NULL) || fail "tpl must not be null";
|
||||
|
||||
let super = import "std/tuples.ucg";
|
||||
let super = mod.pkg();
|
||||
|
||||
let fields = func() => super.fields{tpl=mod.tpl};
|
||||
let values = func() => super.values{tpl=mod.tpl};
|
||||
@ -71,7 +71,7 @@ let has_fields = module{
|
||||
tpl = NULL,
|
||||
fields = [],
|
||||
} => (result) {
|
||||
let lib = import "std/tuples.ucg";
|
||||
let lib = mod.pkg();
|
||||
// First we check that mod.tpl is a tuple.
|
||||
lib.assert_tuple(mod.tpl);
|
||||
|
||||
@ -86,7 +86,7 @@ let field_type = module{
|
||||
field = NULL,
|
||||
type = NULL,
|
||||
} => (result) {
|
||||
let lib = import "std/tuples.ucg";
|
||||
let lib = mod.pkg();
|
||||
// First we check that mod.tpl is a tuple.
|
||||
lib.assert_tuple(mod.tpl);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user