diff --git a/builtin/meta_oils.py b/builtin/meta_oils.py index 944e0d225..fe93399d2 100644 --- a/builtin/meta_oils.py +++ b/builtin/meta_oils.py @@ -95,7 +95,12 @@ def Run(self, cmd_val): cmd_flags=cmd_eval.RaiseControlFlow) -class Source(vm._Builtin): +class ShellFile(vm._Builtin): + """ + These share code: + - 'source' builtin for OSH + - 'use' builtin for YSH + """ def __init__( self, @@ -106,6 +111,7 @@ def __init__( tracer, # type: dev.Tracer errfmt, # type: ui.ErrorFormatter loader, # type: pyutil._ResourceLoader + ysh_use=False, # type: bool ): # type: (...) -> None self.parse_ctx = parse_ctx @@ -116,10 +122,92 @@ def __init__( self.tracer = tracer self.errfmt = errfmt self.loader = loader + self.ysh_use = ysh_use self.mem = cmd_ev.mem def Run(self, cmd_val): + # type: (cmd_value.Argv) -> int + """ + Use is like Source + """ + if self.ysh_use: + return self._Use(cmd_val) + else: + return self._Source(cmd_val) + + def _Use(self, cmd_val): + # type: (cmd_value.Argv) -> int + """ + Module system with all the power of Python, but still a proc + + use util.ysh # util is a value.Obj + + # Importing a bunch of words + use dialect-ninja.ysh { all } # requires 'provide' in dialect-ninja + use dialect-github.ysh { all } + + # This declares some names + use --extern grep sed + + # Renaming + use util.ysh (&myutil) + + # Ignore + use util.ysh (&_) + + # Picking specifics + use util.ysh { + pick log die + pick foo (&myfoo) + } + + # A long way to write this is: + + use util.ysh + const log = util.log + const die = util.die + const myfoo = util.foo + + Another way is: + for name in log die { + call setVar(name, util[name]) + + # value.Obj may not support [] though + # get(propView(util), name, null) is a long way of writing it + } + + Other considerations: + + - Statically parseable subset? For fine-grained static tree-shaking + - We're doing coarse dynamic tree-shaking first though + + - if TYPE_CHECKING is an issue + - that can create circular dependencies, especially with gradual typing, + when you go dynamic to static (like Oils did) + - I guess you can have + - use --static parse_lib.ysh { pick ParseContext } + """ + _, arg_r = flag_util.ParseCmdVal('use', cmd_val) + + mod_path, _ = arg_r.ReadRequired2('requires a module path') + + log('m %s', mod_path) + + arg_r.Done() + + # TODO on usage: + # - typed arg is value.Place + # - block arg binds 'pick' and 'all' + + # TODO: + # with ctx_Module + # and then do something very similar to 'source' + + return 0 + return 0 + + def _Source(self, cmd_val): # type: (cmd_value.Argv) -> int attrs, arg_r = flag_util.ParseCmdVal('source', cmd_val) arg = arg_types.source(attrs.attrs) diff --git a/builtin/module_ysh.py b/builtin/module_ysh.py index 1c25fe960..c5d601fa2 100644 --- a/builtin/module_ysh.py +++ b/builtin/module_ysh.py @@ -54,81 +54,3 @@ def Run(self, cmd_val): return 1 self.guards[name] = True return 0 - - -class Use(vm._Builtin): - """ - Module system with all the power of Python, but still a proc - - use util.ysh # util is a value.Obj - - # Importing a bunch of words - use dialect-ninja.ysh { all } # requires 'provide' in dialect-ninja - use dialect-github.ysh { all } - - # This declares some names - use --extern grep sed - - # Renaming - use util.ysh (&myutil) - - # Ignore - use util.ysh (&_) - - # Picking specifics - use util.ysh { - pick log die - pick foo (&myfoo) - } - - # A long way to write this is: - - use util.ysh - const log = util.log - const die = util.die - const myfoo = util.foo - - Another way is: - for name in log die { - call setVar(name, util[name]) - - # value.Obj may not support [] though - # get(propView(util), name, null) is a long way of writing it - } - - Other considerations: - - - Statically parseable subset? For fine-grained static tree-shaking - - We're doing coarse dynamic tree-shaking first though - - - if TYPE_CHECKING is an issue - - that can create circular dependencies, especially with gradual typing, - when you go dynamic to static (like Oils did) - - I guess you can have - - use --static parse_lib.ysh { pick ParseContext } - """ - - def __init__(self, mem, errfmt): - # type: (state.Mem, ui.ErrorFormatter) -> None - self.mem = mem - self.errfmt = errfmt - - def Run(self, cmd_val): - # type: (cmd_value.Argv) -> int - _, arg_r = flag_util.ParseCmdVal('use', cmd_val) - - mod_path, _ = arg_r.ReadRequired2('requires a module path') - - log('m %s', mod_path) - - arg_r.Done() - - # TODO on usage: - # - typed arg is value.Place - # - block arg binds 'pick' and 'all' - - # TODO: - # with ctx_Module - # and then do something very similar to 'source' - - return 0 diff --git a/core/shell.py b/core/shell.py index f4907321d..abd4577fd 100644 --- a/core/shell.py +++ b/core/shell.py @@ -632,8 +632,16 @@ def Main( b[builtin_i.extern_] = meta_oils.Extern(shell_ex, procs, errfmt) # Meta builtins - source_builtin = meta_oils.Source(parse_ctx, search_path, cmd_ev, fd_state, - tracer, errfmt, loader) + b[builtin_i.use] = meta_oils.ShellFile(parse_ctx, + search_path, + cmd_ev, + fd_state, + tracer, + errfmt, + loader, + ysh_use=True) + source_builtin = meta_oils.ShellFile(parse_ctx, search_path, cmd_ev, + fd_state, tracer, errfmt, loader) b[builtin_i.source] = source_builtin b[builtin_i.dot] = source_builtin b[builtin_i.eval] = meta_oils.Eval(parse_ctx, exec_opts, cmd_ev, tracer, @@ -644,7 +652,6 @@ def Main( b[builtin_i.source_guard] = module_ysh.SourceGuard(guards, exec_opts, errfmt) b[builtin_i.is_main] = module_ysh.IsMain(mem) - b[builtin_i.use] = module_ysh.Use(mem, errfmt) # Errors b[builtin_i.error] = error_ysh.Error()