From ccbdcee8e067210e07920a44cf87f553602d672c Mon Sep 17 00:00:00 2001 From: marsninja Date: Sat, 16 Sep 2023 10:31:13 -0400 Subject: [PATCH] Better Jac cli --- README.md | 2 +- jaclang/cli/cmds.jac | 4 +-- jaclang/cli/impl/cli_impl.jac | 29 +++++++++++++++++----- jaclang/cli/impl/cmds_impl.jac | 6 ++--- jaclang/cli/tests/test_cli.py | 6 ++--- jaclang/jac/importer.py | 28 ++++++++++++++++----- jaclang/jac/passes/blue/blue_pygen_pass.py | 6 ++++- jaclang/jac/transform.py | 2 +- 8 files changed, 60 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index afafdd505..f14e2d008 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Getting Started with JacLang +# Getting Started with the Jac Programming Language Welcome to JacLang, a unique and powerful programming language that runs on top of Python. To get you started, this guide will walk you through the process of installation, running Jac files, and importing Jac into existing Python modules. diff --git a/jaclang/cli/cmds.jac b/jaclang/cli/cmds.jac index 659532443..b272f52e4 100644 --- a/jaclang/cli/cmds.jac +++ b/jaclang/cli/cmds.jac @@ -8,10 +8,10 @@ import:jac from cli, cmd_registry as cmd_reg; include:jac impl.cmds_impl; @cmd_reg.register -can load(filename: str); +can run(filename: str); @cmd_reg.register -can run(filename: str, entrypoint: str, args: list); +can enter(filename: str, entrypoint: str, args: list); @cmd_reg.register can ast_tool(tool: str); diff --git a/jaclang/cli/impl/cli_impl.jac b/jaclang/cli/impl/cli_impl.jac index 3a1332cf7..41907d131 100644 --- a/jaclang/cli/impl/cli_impl.jac +++ b/jaclang/cli/impl/cli_impl.jac @@ -21,20 +21,37 @@ cmd = func |> Command; .registry[name] = cmd; cmd_parser = name |> .sub_parsers.add_parser; + param_items = cmd.sig.parameters.items; + first = True; for param_name, param in |> cmd.sig.parameters.items { if param_name == "args" { ('args', nargs=argparse.REMAINDER) |> cmd_parser.add_argument; } elif param.default is param.empty { - (f"-{param_name[:1]}", f"--{param_name}", - required=True, type=param.annotation|>eval) - |> cmd_parser.add_argument; + if first { + first = False; + (f"{param_name}", type=param.annotation|>eval) + |> cmd_parser.add_argument; + } + else { + (f"-{param_name[:1]}", f"--{param_name}", + required=True, type=param.annotation|>eval) + |> cmd_parser.add_argument; + } + } else { - (f"-{param_name[:1]}", f"--{param_name}", - default=param.default, type=param.annotation|>eval) - |> cmd_parser.add_argument; + if first { + first = False; + (f"{param_name}", default=param.default, type=param.annotation|>eval) + |> cmd_parser.add_argument; + } + else { + (f"-{param_name[:1]}", f"--{param_name}", + default=param.default, type=param.annotation|>eval) + |> cmd_parser.add_argument; + } } } return func; diff --git a/jaclang/cli/impl/cmds_impl.jac b/jaclang/cli/impl/cmds_impl.jac index c5b8b4019..4feaca902 100644 --- a/jaclang/cli/impl/cmds_impl.jac +++ b/jaclang/cli/impl/cmds_impl.jac @@ -3,20 +3,20 @@ import:py os; import:py shutil; """Load a .jac file and return the entrypoint function.""" -:a:load +:a:run (filename: str) { if filename.endswith(".jac"){ [base, mod] = os.path.split(filename); base = './' if not base else base; mod=mod[:-4]; - __jac_import__(target=mod, base_path=base); + __jac_import__(target=mod, base_path=base, override_name="__main__"); } else { "Not a .jac file." :> print; } } """Run the entrypoint of the given .jac file.""" -:a:run +:a:enter (filename: str, entrypoint: str, args: list) { if filename.endswith(".jac") { [base, mod] = os.path.split(filename); diff --git a/jaclang/cli/tests/test_cli.py b/jaclang/cli/tests/test_cli.py index ba5371a45..c17854bb2 100644 --- a/jaclang/cli/tests/test_cli.py +++ b/jaclang/cli/tests/test_cli.py @@ -19,7 +19,7 @@ def test_jac_cli_load(self) -> None: sys.stdout = captured_output # Execute the function - cmds.load(self.fixture_abs_path("hello.jac")) # type: ignore + cmds.run(self.fixture_abs_path("hello.jac")) # type: ignore sys.stdout = sys.__stdout__ stdout_value = captured_output.getvalue() @@ -35,7 +35,7 @@ def test_jac_cli_err_output(self) -> None: # Execute the function try: - cmds.run(self.fixture_abs_path("err.jac"), entrypoint="speak", args=[]) # type: ignore + cmds.enter(self.fixture_abs_path("err.jac"), entrypoint="speak", args=[]) # type: ignore except Exception as e: print(f"Error: {e}") @@ -55,7 +55,7 @@ def test_jac_cli_alert_based_err(self) -> None: # Execute the function try: - cmds.run(self.fixture_abs_path("err2.jac"), entrypoint="speak", args=[]) # type: ignore + cmds.enter(self.fixture_abs_path("err2.jac"), entrypoint="speak", args=[]) # type: ignore except Exception as e: print(f"Error: {e}") diff --git a/jaclang/jac/importer.py b/jaclang/jac/importer.py index 38fa24539..95ea1144c 100644 --- a/jaclang/jac/importer.py +++ b/jaclang/jac/importer.py @@ -17,6 +17,7 @@ def import_jac_module( target: str, base_path: Optional[str] = None, cachable: bool = True, + override_name: Optional[str] = None, ) -> Optional[types.ModuleType]: """Core Import Process.""" target = path.join(*(target.split("."))) + ".jac" @@ -54,7 +55,7 @@ def import_jac_module( module = types.ModuleType(module_name) module.__file__ = full_target - module.__name__ = module_name + module.__name__ = override_name if override_name else module_name module.__dict__["_jac_pycodestring_"] = code_string if ( @@ -65,7 +66,12 @@ def import_jac_module( with open(py_file_path + "c", "rb") as f: codeobj = marshal.load(f) else: - codeobj = compile(code_string, f"_jac_py_gen ({module.__file__})", "exec") + try: + codeobj = compile(code_string, f"_jac_py_gen ({module.__file__})", "exec") + except Exception as e: + tb = traceback.extract_tb(e.__traceback__) + err = handle_jac_error(code_string, e, tb) + raise type(e)(str(e) + "\n" + err) with open(py_file_path + "c", "wb") as f: marshal.dump(codeobj, f) @@ -118,14 +124,24 @@ def handle_jac_error(code_string: str, e: Exception, tb: traceback.StackSummary) def jac_blue_import( - target: str, base_path: Optional[str] = None, cachable: bool = True + target: str, + base_path: Optional[str] = None, + cachable: bool = True, + override_name: Optional[str] = None, ) -> Optional[types.ModuleType]: """Jac Blue Imports.""" - return import_jac_module(transpile_jac_blue, target, base_path, cachable) + return import_jac_module( + transpile_jac_blue, target, base_path, cachable, override_name + ) def jac_purple_import( - target: str, base_path: Optional[str] = None, cachable: bool = True + target: str, + base_path: Optional[str] = None, + cachable: bool = True, + override_name: Optional[str] = None, ) -> Optional[types.ModuleType]: """Jac Purple Imports.""" - return import_jac_module(transpile_jac_purple, target, base_path, cachable) + return import_jac_module( + transpile_jac_purple, target, base_path, cachable, override_name + ) diff --git a/jaclang/jac/passes/blue/blue_pygen_pass.py b/jaclang/jac/passes/blue/blue_pygen_pass.py index 26cc77cbd..e4954eb9d 100644 --- a/jaclang/jac/passes/blue/blue_pygen_pass.py +++ b/jaclang/jac/passes/blue/blue_pygen_pass.py @@ -371,6 +371,10 @@ def exit_ability(self, node: ast.Ability) -> None: self.emit(node, node.body.meta["py_code"]) self.indent_level -= 1 self.emit_jac_error_handler(node) + elif node.is_abstract: + self.indent_level += 1 + self.emit_ln(node, "pass") + self.indent_level -= 1 else: self.decl_def_missing(ability_name) self.indent_level -= 1 @@ -611,7 +615,7 @@ def exit_enum_block(self, node: ast.EnumBlock) -> None: if isinstance(i, ast.Name): self.emit_ln(node, i.meta["py_code"] + " = __jac_auto__()") else: - self.emit(node, i.meta["py_code"]) + self.emit_ln(node, i.meta["py_code"]) def exit_code_block(self, node: ast.CodeBlock) -> None: """Sub objects. diff --git a/jaclang/jac/transform.py b/jaclang/jac/transform.py index 7ebc33977..3d508f8d5 100644 --- a/jaclang/jac/transform.py +++ b/jaclang/jac/transform.py @@ -24,7 +24,7 @@ def __init__(self, msg: str, mod: str, line: int) -> None: def __str__(self) -> str: """Return string representation of alert.""" - return f"{self.mod}: Line {self.line}, {self.msg}" + return f"{self.mod}, line {self.line}: {self.msg}" class TransformError(Exception):