From b0dbb88641583b755dfcb74b53bfcd764769b5f6 Mon Sep 17 00:00:00 2001 From: Andy C Date: Mon, 30 Sep 2024 00:24:38 -0400 Subject: [PATCH] [builtin/use] Implement use --extern Add spec tests Start documenting the 'use' command --- builtin/func_reflect.py | 1 + builtin/meta_oils.py | 8 +++- builtin/pure_ysh.py | 6 +-- doc/ref/chap-builtin-cmd.md | 23 +++++++--- doc/ref/toc-ysh.md | 7 +++- frontend/args.py | 5 +++ spec/ysh-builtin-module.test.sh | 74 ++++++++++++++++++++------------- 7 files changed, 82 insertions(+), 42 deletions(-) diff --git a/builtin/func_reflect.py b/builtin/func_reflect.py index b7339fdf3..af8fddc82 100644 --- a/builtin/func_reflect.py +++ b/builtin/func_reflect.py @@ -40,6 +40,7 @@ class Id(vm._Callable): I guess only mutable objects can have IDs then """ + def __init__(self): # type: () -> None vm._Callable.__init__(self) diff --git a/builtin/meta_oils.py b/builtin/meta_oils.py index 1c30f412b..c27ccdedc 100644 --- a/builtin/meta_oils.py +++ b/builtin/meta_oils.py @@ -368,7 +368,13 @@ def _Use(self, cmd_val): import $LIB_YSH/stdlib """ - _, arg_r = flag_util.ParseCmdVal('use', cmd_val) + attrs, arg_r = flag_util.ParseCmdVal('use', cmd_val) + arg = arg_types.use(attrs.attrs) + + # Accepts any args + if arg.extern_: # use --extern grep # no-op for static analysis + return 0 + path_arg, path_loc = arg_r.ReadRequired2('requires a module path') # TODO on usage: # - typed arg is value.Place diff --git a/builtin/pure_ysh.py b/builtin/pure_ysh.py index 810ed19c9..4e2bcccf7 100644 --- a/builtin/pure_ysh.py +++ b/builtin/pure_ysh.py @@ -206,9 +206,9 @@ def Run(self, cmd_val): # type: (cmd_value.Argv) -> int # This means we ignore -- , which is consistent - arg, arg_r = flag_util.ParseCmdVal('append', - cmd_val, - accept_typed_args=True) + _, arg_r = flag_util.ParseCmdVal('append', + cmd_val, + accept_typed_args=True) rd = typed_args.ReaderForProc(cmd_val) val = rd.PosValue() diff --git a/doc/ref/chap-builtin-cmd.md b/doc/ref/chap-builtin-cmd.md index 3e9a2bc3f..fa0915c1a 100644 --- a/doc/ref/chap-builtin-cmd.md +++ b/doc/ref/chap-builtin-cmd.md @@ -353,13 +353,22 @@ Use it like this: ### use -TODO +Import code from other files, creating an `Obj` that acts like a namespace. -Reuse code from other files, respecting namespaces. + use my-dir/my-module.ysh - use lib/foo.ysh # foo myproc, $[foo.attr] - # implicit $_this_dir aka relative import + echo $[my_module.my_integer] # the module Obj has attributes + my_module myproc # the module Obj is invokable +The evaluation of such files is cached, so it won't be re-evaluated if `use` is called again. + + + + -Also a declaration +The `--extern` flag make the invocation do nothing. It can be used be tools to +analyze what names are in the file. - use --extern grep sed + use --extern grep sed awk ## I/O diff --git a/doc/ref/toc-ysh.md b/doc/ref/toc-ysh.md index 0402f992a..cdb800305 100644 --- a/doc/ref/toc-ysh.md +++ b/doc/ref/toc-ysh.md @@ -116,10 +116,13 @@ X [Wok] _field() shvar Temporary modify global settings ctx Share and update a temporary "context" push-registers Save registers like $?, PIPESTATUS - [Modules] runproc Run a proc; use as main entry point + [Introspection] runproc Run a proc; use as main entry point + X extern Run an external command, with an ENV + X invoke Control which "invokables" are run + [Modules] source-guard guard against duplicate 'source' is-main false when sourcing a file - X use use names, + use create a module Obj from a source file [I/O] ysh-read flags --all, -0 ysh-echo no -e -n with simple_echo write Like echo, with --, --sep, --end diff --git a/frontend/args.py b/frontend/args.py index 35d277420..8cad83240 100644 --- a/frontend/args.py +++ b/frontend/args.py @@ -105,6 +105,11 @@ def Set(self, name, val): # debug-completion -> debug_completion name = name.replace('-', '_') + + # similar hack to avoid C++ keyword in frontend/flag_gen.py + if name == 'extern': + name = 'extern_' + self.attrs[name] = val if 0: diff --git a/spec/ysh-builtin-module.test.sh b/spec/ysh-builtin-module.test.sh index aead44118..5a41b6109 100644 --- a/spec/ysh-builtin-module.test.sh +++ b/spec/ysh-builtin-module.test.sh @@ -38,6 +38,50 @@ stdin status=0 ## END +#### use builtin usage + +use +echo no-arg=$? + +use foo +echo one-arg=$? + +use --extern foo +echo extern=$? + +use --bad-flag +echo bad-flag=$? + +use too many +echo too-many=$? + +use ///no-builtin +echo no-builtin=$? + + +## STDOUT: +no-arg=2 +one-arg=1 +extern=0 +bad-flag=2 +too-many=2 +no-builtin=1 +## END + + +#### use --extern is a no-op, for static analysis + +use --extern grep sed awk +echo status=$? + +use --extern zzz +echo status=$? + +## STDOUT: +status=0 +status=0 +## END + #### use foo.ysh creates a value.Obj, and it's cached on later invocations shopt --set ysh:upgrade @@ -97,33 +141,3 @@ util die 'hello' ## STDOUT: ## END -#### use builtin usage - -use -echo no-arg=$? - -use foo -echo one-arg=$? - -use --extern foo -echo extern=$? - -use --bad-flag -echo bad-flag=$? - -use too many -echo too-many=$? - -use ///no-builtin -echo no-builtin=$? - - -## STDOUT: -no-arg=2 -one-arg=1 -extern=1 -bad-flag=2 -too-many=2 -no-builtin=1 -## END -