diff --git a/examples/manual_code/circle.jac b/examples/manual_code/circle.jac index f0ba9b9ea..ef0421731 100644 --- a/examples/manual_code/circle.jac +++ b/examples/manual_code/circle.jac @@ -5,7 +5,7 @@ This module demonstrates a simple circle class and a function to calculate the a import:py math; # Module-level global -global RADIUS = 5; +global RAD = 5; """Function to calculate the area of a circle.""" can calculate_area(radius: float) -> float { @@ -50,29 +50,17 @@ object Circle:Shape { } } -with entry {c = Circle(RADIUS);} # Global also works here +with entry {c = Circle(RAD);} # Global also works here with entry:__main__ { # TODO: add name == option abstract feature # To run the program functionality - print(f"Area of a circle with radius 5: {calculate_area(RADIUS)}"); + print(f"Area of a circle with radius 5: {calculate_area(RAD)}"); print(f"Area of a {c.shape_type.value} with radius 5: {c.area()}"); } -test calculate_area -"Tests for the calculate_area function." { - expected_area = 78.53981633974483; - assertAlmostEqual(calculate_area(RADIUS), expected_area); -} -test circle_area -"Tests for the area method of the Circle class." { - c = Circle(RADIUS); - expected_area = 78.53981633974483; - assertAlmostEqual(c.area(), expected_area); -} +global expected_area = 78.53981633974483; -test circle_type -"Tests for the shape_type attribute of the Circle class." { - c = Circle(RADIUS); - assertEqual(c.shape_type, ShapeType.CIRCLE); -} \ No newline at end of file +test calculate_area { check.AlmostEqual(calculate_area(RAD), expected_area); } +test circle_area { c = Circle(RAD); check.AlmostEqual(c.area(), expected_area); } +test circle_type { c = Circle(RAD); check.Equal(c.shape_type, ShapeType.CIRCLE); } \ No newline at end of file diff --git a/examples/manual_code/circle.py b/examples/manual_code/circle.py index 2ce8d4250..9558123bb 100644 --- a/examples/manual_code/circle.py +++ b/examples/manual_code/circle.py @@ -7,7 +7,7 @@ import unittest # Module-level global -RADIUS = 5 +RAD = 5 def calculate_area(radius: float) -> float: @@ -51,16 +51,12 @@ def area(self) -> float: return math.pi * self.radius * self.radius -c = Circle(RADIUS) +c = Circle(RAD) if __name__ == "__main__": # To run the program functionality - print( - f"Area of a circle with radius {RADIUS} using function: {calculate_area(RADIUS)}" - ) - print( - f"Area of a {c.shape_type.value} with radius {RADIUS} using class: {c.area()}" - ) + print(f"Area of a circle with radius {RAD} using function: {calculate_area(RAD)}") + print(f"Area of a {c.shape_type.value} with radius {RAD} using class: {c.area()}") # Uncomment the next line if you want to run the unit tests # run_tests() @@ -70,13 +66,13 @@ def area(self) -> float: class TestShapesFunctions(unittest.TestCase): def test_calculate_area(self): expected_area = 78.53981633974483 - self.assertAlmostEqual(calculate_area(RADIUS), expected_area) + self.assertAlmostEqual(calculate_area(RAD), expected_area) def test_circle_area(self): - c = Circle(RADIUS) + c = Circle(RAD) expected_area = 78.53981633974483 self.assertAlmostEqual(c.area(), expected_area) def test_circle_type(self): - c = Circle(RADIUS) + c = Circle(RAD) self.assertEqual(c.shape_type, ShapeType.CIRCLE) diff --git a/examples/micro/module_structure.jac b/examples/micro/module_structure.jac index d59cae85a..8f8cb20ec 100644 --- a/examples/micro/module_structure.jac +++ b/examples/micro/module_structure.jac @@ -45,7 +45,7 @@ with entry { # module level freestyle code } -test mytest -"A test of my functionality" { +"""A test of my functionality""" +test mytest { # test code here } \ No newline at end of file diff --git a/jaclang/jac/absyntree.py b/jaclang/jac/absyntree.py index 614c2fe1a..1421470f0 100644 --- a/jaclang/jac/absyntree.py +++ b/jaclang/jac/absyntree.py @@ -150,9 +150,8 @@ class Test(AstNode): def __init__( self, - name: Name, + name: Optional[Name], doc: Optional[Token], - description: Token, body: CodeBlock, parent: Optional[AstNode], mod_link: Optional[Module], @@ -163,7 +162,6 @@ def __init__( """Initialize test node.""" self.doc = doc self.name = name - self.description = description self.body = body super().__init__( parent=parent, mod_link=mod_link, kid=kid, line=line, sym_tab=sym_tab diff --git a/jaclang/jac/parser.py b/jaclang/jac/parser.py index 173c38513..a50160a83 100644 --- a/jaclang/jac/parser.py +++ b/jaclang/jac/parser.py @@ -93,7 +93,10 @@ def access_tag(self, p: YaccProduction) -> YaccProduction: """Permission tag rule.""" return p - @_("doc_tag KW_TEST NAME multistring code_block") + @_( + "doc_tag KW_TEST NAME code_block", + "doc_tag KW_TEST code_block", + ) def test(self, p: YaccProduction) -> YaccProduction: """Test rule.""" return p diff --git a/jaclang/jac/passes/blue/ast_build_pass.py b/jaclang/jac/passes/blue/ast_build_pass.py index 3ca696aca..1d6855c28 100644 --- a/jaclang/jac/passes/blue/ast_build_pass.py +++ b/jaclang/jac/passes/blue/ast_build_pass.py @@ -121,22 +121,36 @@ def exit_access_tag(self, node: ast.AstNode) -> None: def exit_test(self, node: ast.AstNode) -> None: """Grammar rule. - test -> doc_tag KW_TEST NAME multistring code_block + test -> doc_tag KW_TEST code_block + test -> doc_tag KW_TEST NAME code_block """ del node.kid[1] - replace_node( - node, - ast.Test( - doc=node.kid[0], - name=node.kid[1], - description=node.kid[2], - body=node.kid[3], - parent=node.parent, - mod_link=self.mod_link, - kid=node.kid, - line=node.line, - ), - ) + if len(node.kid) == 3: + replace_node( + node, + ast.Test( + doc=node.kid[0], + name=node.kid[1], + body=node.kid[2], + parent=node.parent, + mod_link=self.mod_link, + kid=node.kid, + line=node.line, + ), + ) + else: + replace_node( + node, + ast.Test( + doc=node.kid[0], + name=None, + body=node.kid[1], + parent=node.parent, + mod_link=self.mod_link, + kid=node.kid, + line=node.line, + ), + ) def exit_mod_code(self, node: ast.AstNode) -> None: """Grammar rule. diff --git a/jaclang/jac/passes/blue/blue_pygen_pass.py b/jaclang/jac/passes/blue/blue_pygen_pass.py index 9e81c088d..ce79cdfaa 100644 --- a/jaclang/jac/passes/blue/blue_pygen_pass.py +++ b/jaclang/jac/passes/blue/blue_pygen_pass.py @@ -8,6 +8,8 @@ class BluePygenPass(Pass): """Jac blue transpilation to python pass.""" + TEST_COUNT = 0 + def before_pass(self) -> None: """Initialize pass.""" self.indent_size = 4 @@ -179,16 +181,36 @@ def exit_global_vars(self, node: ast.GlobalVars) -> None: self.emit_ln(node, node.doc.value) self.emit(node, node.assignments.meta["py_code"]) - # NOTE: Incomplete for Jac Purple and Red def exit_test(self, node: ast.Test) -> None: """Sub objects. - name: Token, - doc: Optional["Token"], - description: Token, - body: "CodeBlock", + name: Optional[Name], + doc: Optional[Token], + body: CodeBlock, """ - self.warning("Test feature not supported in bootstrap Jac.") + if node.name: + test_name = node.name.value + else: + test_name = f"_jac_t{self.TEST_COUNT}" + self.TEST_COUNT += 1 + test_code = "import unittest as __jac_unittest__\n" + test_code += "__jac_tc__ = __jac_unittest__.TestCase()\n" + test_code += "__jac_suite__ = __jac_unittest__.TestSuite()\n" + test_code += "class __jac_check:\n" + test_code += " def __getattr__(self, name):\n" + test_code += " return getattr(__jac_tc__, 'assert'+name)" + self.emit_ln_unique(self.preamble, test_code) + self.emit_ln(node, f"def test_{test_name}():") + self.indent_level += 1 + if node.doc: + self.emit_ln(node, node.doc.value) + self.emit_ln(node, "check = __jac_check()") + self.emit_ln(node, node.body.meta["py_code"]) + self.indent_level -= 1 + self.emit_ln( + node, + f"__jac_suite__.addTest(__jac_unittest__.FunctionTestCase(test_{test_name}))", + ) def exit_module_code(self, node: ast.ModuleCode) -> None: """Sub objects.