From 179f3821ba0014810f00374237dcdcf3e5719cb1 Mon Sep 17 00:00:00 2001 From: marsninja Date: Sun, 25 Feb 2024 16:00:22 -0500 Subject: [PATCH 1/2] feat(cli): creating option to not cache bytecode in cli --- jaclang/cli/cli.py | 9 +++------ jaclang/cli/cmdreg.py | 42 ++++++++++++++++++++++++++++------------ jaclang/core/importer.py | 5 +++-- 3 files changed, 36 insertions(+), 20 deletions(-) diff --git a/jaclang/cli/cli.py b/jaclang/cli/cli.py index e8f459afb..f1278304d 100644 --- a/jaclang/cli/cli.py +++ b/jaclang/cli/cli.py @@ -60,12 +60,8 @@ def format_file(filename: str) -> None: @cmd_registry.register -def run(filename: str, main: bool = True) -> None: - """Run the specified .jac file. - - :param filename: The path to the .jac file. - :param main: If True, use '__main__' as the module name, else use the actual module name. - """ +def run(filename: str, main: bool = True, cache: bool = True) -> None: + """Run the specified .jac file.""" base, mod = os.path.split(filename) base = base if base else "./" mod = mod[:-4] @@ -79,6 +75,7 @@ def run(filename: str, main: bool = True) -> None: jac_import( target=mod, base_path=base, + cachable=cache, override_name="__main__" if main else None, mod_bundle=ir, ) diff --git a/jaclang/cli/cmdreg.py b/jaclang/cli/cmdreg.py index f766d34af..d5db81b3a 100644 --- a/jaclang/cli/cmdreg.py +++ b/jaclang/cli/cmdreg.py @@ -42,7 +42,9 @@ def register(self, func: Callable) -> Callable: name = func.__name__ cmd = Command(func) self.registry[name] = cmd - cmd_parser = self.sub_parsers.add_parser(name, description=func.__doc__) + cmd_parser: argparse.ArgumentParser = self.sub_parsers.add_parser( + name, description=func.__doc__ + ) first = True for param_name, param in cmd.sig.parameters.items(): arg_msg = f"type: {param.annotation.__name__}" @@ -83,17 +85,33 @@ def register(self, func: Callable) -> Callable: ) else: arg_msg += f", default: {param.default}" - cmd_parser.add_argument( - f"-{param_name[:1]}", - f"--{param_name}", - default=param.default, - help=arg_msg, - type=( - eval(param.annotation) - if isinstance(param.annotation, str) - else param.annotation - ), - ) + if param.annotation == bool: + cmd_parser.add_argument( + f"-{param_name[:1]}", + f"--{param_name}", + default=param.default, + action="store_true", + help=arg_msg, + ) + cmd_parser.add_argument( + f"-n{param_name[:1]}", + f"--no-{param_name}", + dest=param_name, + action="store_false", + help=f"Compliment of {arg_msg}", + ) + else: + cmd_parser.add_argument( + f"-{param_name[:1]}", + f"--{param_name}", + default=param.default, + help=arg_msg, + type=( + eval(param.annotation) + if isinstance(param.annotation, str) + else param.annotation + ), + ) return func def get(self, name: str) -> Optional[Command]: diff --git a/jaclang/core/importer.py b/jaclang/core/importer.py index 6b8328fa3..00997c404 100644 --- a/jaclang/core/importer.py +++ b/jaclang/core/importer.py @@ -62,8 +62,9 @@ def jac_importer( print(e) logging.error(e) return None - with open(pyc_file_path, "rb") as f: - codeobj = marshal.load(f) + if cachable: + with open(pyc_file_path, "rb") as f: + codeobj = marshal.load(f) module_name = override_name if override_name else module_name module = types.ModuleType(module_name) From 7b894e3360515ee9374f842fdca945206c992e62 Mon Sep 17 00:00:00 2001 From: marsninja Date: Sun, 25 Feb 2024 20:35:21 -0500 Subject: [PATCH 2/2] feat(cli): CLI work complete --- jaclang/cli/cli.py | 5 ++- jaclang/compiler/compile.py | 9 +++--- jaclang/compiler/passes/main/pyout_pass.py | 4 +-- jaclang/core/importer.py | 20 ++++++------ jaclang/tests/fixtures/hello_nc.jac | 5 +++ jaclang/tests/test_cli.py | 36 +++++++++++++++++++++- 6 files changed, 59 insertions(+), 20 deletions(-) create mode 100644 jaclang/tests/fixtures/hello_nc.jac diff --git a/jaclang/cli/cli.py b/jaclang/cli/cli.py index f1278304d..a951d7b1a 100644 --- a/jaclang/cli/cli.py +++ b/jaclang/cli/cli.py @@ -67,7 +67,10 @@ def run(filename: str, main: bool = True, cache: bool = True) -> None: mod = mod[:-4] if filename.endswith(".jac"): jac_import( - target=mod, base_path=base, override_name="__main__" if main else None + target=mod, + base_path=base, + cachable=cache, + override_name="__main__" if main else None, ) elif filename.endswith(".jir"): with open(filename, "rb") as f: diff --git a/jaclang/compiler/compile.py b/jaclang/compiler/compile.py index e4f02c449..2cfb0ad2e 100644 --- a/jaclang/compiler/compile.py +++ b/jaclang/compiler/compile.py @@ -8,20 +8,19 @@ from jaclang.compiler.passes.main import PyOutPass, pass_schedule from jaclang.compiler.passes.tool import JacFormatPass from jaclang.compiler.passes.tool.schedules import format_pass -from jaclang.compiler.passes.transform import Alert -def compile_jac(file_path: str) -> list[Alert]: +def compile_jac(file_path: str, cache_result: bool = False) -> Pass: """Start Compile for Jac file and return python code as string.""" code = jac_file_to_pass( file_path=file_path, schedule=pass_schedule, ) - if isinstance(code.ir, ast.Module) and not code.errors_had: + if cache_result and isinstance(code.ir, ast.Module) and not code.errors_had: print_pass = PyOutPass(input_ir=code.ir, prior=code) + return print_pass else: - return code.errors_had - return print_pass.errors_had + return code def jac_file_to_pass( diff --git a/jaclang/compiler/passes/main/pyout_pass.py b/jaclang/compiler/passes/main/pyout_pass.py index 867ce95a0..22e0ea61d 100644 --- a/jaclang/compiler/passes/main/pyout_pass.py +++ b/jaclang/compiler/passes/main/pyout_pass.py @@ -39,8 +39,8 @@ def enter_module(self, node: ast.Module) -> None: mods = [node] + self.get_all_sub_nodes(node, ast.Module) for mod in mods: mod_path, out_path_py, out_path_pyc = self.get_output_targets(mod) - if os.path.exists(out_path_py) and os.path.getmtime( - out_path_py + if os.path.exists(out_path_pyc) and os.path.getmtime( + out_path_pyc ) > os.path.getmtime(mod_path): continue self.gen_python(mod, out_path=out_path_py) diff --git a/jaclang/core/importer.py b/jaclang/core/importer.py index 00997c404..ac325a6df 100644 --- a/jaclang/core/importer.py +++ b/jaclang/core/importer.py @@ -46,25 +46,23 @@ def jac_importer( codeobj = marshal.loads(codeobj) else: gen_dir = path.join(caller_dir, Con.JAC_GEN_DIR) - py_file_path = path.join(gen_dir, module_name + ".py") pyc_file_path = path.join(gen_dir, module_name + ".jbc") if ( cachable - and path.exists(py_file_path) - and path.getmtime(py_file_path) > path.getmtime(full_target) + and path.exists(pyc_file_path) + and path.getmtime(pyc_file_path) > path.getmtime(full_target) ): with open(pyc_file_path, "rb") as f: codeobj = marshal.load(f) else: - if error := compile_jac(full_target): - if error: - for e in error: - print(e) - logging.error(e) + result = compile_jac(full_target, cache_result=cachable) + if result.errors_had or not result.ir.gen.py_bytecode: + for e in result.errors_had: + print(e) + logging.error(e) return None - if cachable: - with open(pyc_file_path, "rb") as f: - codeobj = marshal.load(f) + else: + codeobj = marshal.loads(result.ir.gen.py_bytecode) module_name = override_name if override_name else module_name module = types.ModuleType(module_name) diff --git a/jaclang/tests/fixtures/hello_nc.jac b/jaclang/tests/fixtures/hello_nc.jac new file mode 100644 index 000000000..07b905410 --- /dev/null +++ b/jaclang/tests/fixtures/hello_nc.jac @@ -0,0 +1,5 @@ +"""Hello World!""" + +with entry { + "Hello World!" |> print; +} \ No newline at end of file diff --git a/jaclang/tests/test_cli.py b/jaclang/tests/test_cli.py index 97eaef052..544355e43 100644 --- a/jaclang/tests/test_cli.py +++ b/jaclang/tests/test_cli.py @@ -23,7 +23,7 @@ def test_jac_cli_run(self) -> None: sys.stdout = captured_output # Execute the function - cli.run(self.fixture_abs_path("hello.jac")) # type: ignore + cli.run(self.fixture_abs_path("hello.jac")) sys.stdout = sys.__stdout__ stdout_value = captured_output.getvalue() @@ -116,3 +116,37 @@ def test_build_and_run(self) -> None: stdout_value = captured_output.getvalue() self.assertIn("Errors: 0, Warnings: 0", stdout_value) self.assertIn(" None: + """Basic test for pass.""" + process = subprocess.Popen( + ["jac", "run", f"{self.fixture_abs_path('hello_nc.jac')}", "-nc"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + stdout, _ = process.communicate() + self.assertFalse( + os.path.exists( + f"{self.fixture_abs_path(os.path.join('__jac_gen__', 'hello_nc.jbc'))}" + ) + ) + self.assertIn("Hello World!", stdout) + process = subprocess.Popen( + ["jac", "run", f"{self.fixture_abs_path('hello_nc.jac')}", "-c"], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + stdout, _ = process.communicate() + self.assertIn("Hello World!", stdout) + self.assertTrue( + os.path.exists( + f"{self.fixture_abs_path(os.path.join('__jac_gen__', 'hello_nc.jbc'))}" + ) + ) + os.remove( + f"{self.fixture_abs_path(os.path.join('__jac_gen__', 'hello_nc.jbc'))}" + )