From 31d982a0f2a5839218da9f96b3bd9df757c62aa9 Mon Sep 17 00:00:00 2001 From: Zehen-249 <1hasanmehendi123@gmail.com> Date: Tue, 11 Mar 2025 15:06:19 +0530 Subject: [PATCH 1/5] add generatorExpr flow --- src/astx/base.py | 1 + src/astx/flows.py | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/src/astx/base.py b/src/astx/base.py index 84d4b5b9..0e55931f 100644 --- a/src/astx/base.py +++ b/src/astx/base.py @@ -127,6 +127,7 @@ class ASTKind(Enum): SwitchStmtKind = -509 GotoStmtKind = -511 WithStmtKind = -512 + GeneratorExprKind = -513 # data types NullDTKind = -600 diff --git a/src/astx/flows.py b/src/astx/flows.py index 79f3196c..139f8537 100644 --- a/src/astx/flows.py +++ b/src/astx/flows.py @@ -562,3 +562,46 @@ def get_struct(self, simplified: bool = False) -> ReprStruct: key = f"GOTO-STMT[{self.label.value}]" value: DictDataTypesStruct = {} return self._prepare_struct(key, value, simplified) + +@public +@typechecked +class GeneratorExpr(Expr): + """AST class for generator expressions.""" + + element: Expr + iterable: Expr + condition: Optional[Expr] + + def __init__( + self, + element: Expr, + iterable: Expr, + condition: Optional[Expr] = None, + loc: SourceLocation = NO_SOURCE_LOCATION, + parent: Optional[ASTNodes] = None, + ) -> None: + """Initialize the GeneratorExpr instance.""" + super().__init__(loc=loc, parent=parent) + self.element = element + self.iterable = iterable + self.condition = condition + self.kind = ASTKind.GeneratorExprKind + + def __str__(self) -> str: + """Return a string representation of the object.""" + if self.condition: + return f"GeneratorExpr[{self.element} for {self.iterable} if {self.condition}]" + else: + return f"GeneratorExpr[{self.element} for {self.iterable}]" + + def get_struct(self, simplified: bool = False) -> ReprStruct: + """Return the AST structure of the object.""" + key = "GENERATOR-EXPR" + value: ReprStruct = { + "element": self.element.get_struct(simplified), + "iterable": self.iterable.get_struct(simplified), + } + if self.condition: + value["condition"] = self.condition.get_struct(simplified) + + return self._prepare_struct(key, value, simplified) \ No newline at end of file From b52aacf689afc5e98dbde64c221f1e5b328ff34c Mon Sep 17 00:00:00 2001 From: Zehen-249 <1hasanmehendi123@gmail.com> Date: Tue, 11 Mar 2025 23:34:48 +0530 Subject: [PATCH 2/5] fix iterator in generatorExp --- docs/tutorials/context.ipynb | 4 +- docs/tutorials/generatorExp.ipynb | 211 ++++++++++++++++++++++++++++++ src/astx/flows.py | 49 ++++--- src/astx/literals/collections.py | 1 - 4 files changed, 243 insertions(+), 22 deletions(-) create mode 100644 docs/tutorials/generatorExp.ipynb diff --git a/docs/tutorials/context.ipynb b/docs/tutorials/context.ipynb index d2cc6e07..a6fdd58d 100644 --- a/docs/tutorials/context.ipynb +++ b/docs/tutorials/context.ipynb @@ -229,7 +229,7 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3 (ipykernel)", + "display_name": "ast", "language": "python", "name": "python3" }, @@ -243,7 +243,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.7" + "version": "3.13.2" } }, "nbformat": 4, diff --git a/docs/tutorials/generatorExp.ipynb b/docs/tutorials/generatorExp.ipynb new file mode 100644 index 00000000..bc18bb8b --- /dev/null +++ b/docs/tutorials/generatorExp.ipynb @@ -0,0 +1,211 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "c:\\Users\\1hasa\\astx\\src\n" + ] + } + ], + "source": [ + "\n", + "import os, sys\n", + "print(os.path.abspath(os.path.join(os.getcwd(), \"../../\", \"src\")))\n", + "sys.path.insert(0, os.path.abspath(os.path.join(os.getcwd(), \"../../\", \"src\")))" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "from astx.flows import GeneratorExpr,GotoStmt\n", + "import astx" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "from astx.base import (\n", + " NO_SOURCE_LOCATION,\n", + " ASTKind,\n", + " ASTNodes,\n", + " DictDataTypesStruct,\n", + " Expr,\n", + " Identifier,\n", + " ReprStruct,\n", + " SourceLocation,\n", + " StatementType,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "got = GotoStmt(astx.Identifier('x'))\n", + "it = astx.LiteralFloat32(1)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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YlKRQQiNE9AU1/r27YspU6agqKhIdilEYSsqKkJVVRX27t0ruxT6zUIuyhMRkS4YKEREpAsGChER6YKBQkREumCgEBGRLhgoRESkCwYKERHpgoFCRES6YKAQEZEuGChERKQLBgoREemCgUJERLpgoBARkS4YKEREpAsGChER6SJVdgEUPXv27EFVVZXsMojCtmfPHtklkA8MlCTy6quv4tVXX5VdBpEu+vTpI7sEaoFTXkli7969EELExc3hcOD666+HwWDA4sWLpdcTzC0vLw95eXlB9amqqkJKSgrq6uqk1x9PN35bY+xhoFDMOHnyJMrKytC/f3/s378f69atw/333y+7rIibPHkyBg8ejEceeUR2KURhYaBQTNi9ezeuvPJKzJkzB/fccw92796NnJwc2WVFhcFgwOOPP44333wT7733nuxyiELGQCGpjh49iqKiIgwbNgwpKSnYtWsXnnjiCXTo0EF2aVE1btw4jBkzBg899BCEELLLIQoJA4Wk2bhxIwYOHIglS5ZgyZIl2Lx5M/r16ye7LGkWLVqEDz/8EDabTXYpRCFhoFDUHT16FPPmzUNOTg769OmDvXv34p577kFKSnL/dxw+fDgmTZqERx55BCdOnJBdDlHQkvsvmKJu9+7dGDVqFCoqKrB06VKsWrUK559/vuyyYsbjjz+O/fv34+WXX5ZdClHQGCgUFSdOnMCTTz6JYcOGoWPHjti5cyfuuusu2WXFnJ49e+K2227DggUL8PPPP8suhygoDBSKuC+++AI5OTkoKirCo48+is2bN6NHjx6yy4pZCxcuxOHDh7F06VLZpRAFhYFCEfXSSy9h4MCB+Pbbb7Ft2zb88Y9/TPq1kracd955mDNnDh577DF89913sssh0ox/2RQRX3/9NSZOnIg77rgD9913H3bs2IHMzEzZZcWNhx9+GCdPnkRpaansUog0Y6CQ7rZu3YohQ4Zgz5492Lx5M0pKSpCWlia7rLjSpUsXPPDAA1i8eDGcTqfscog0YaCQboQQePrpp3HNNddg4MCB2LlzJ0aNGiW7rLh13333oUuXLnjsscdkl0KkCQOFdPHdd99h6tSpmDdvHh5++GFUV1eja9eussuKa6effjrMZjOWLVuGf/zjH7LLIWoTA4XCtmvXLgwZMgQbN27E6tWrUVRUxIV3ncycOROXXHIJioqKZJdC1Cb+1VNYXnrpJVx55ZW48MILUVdXh7Fjx8ouKaGkpqZi4cKFsFqt2Ldvn+xyiAJioFBIfvrpJ8yYMQO33347HnzwQaxbtw7/9m//JrushDRlyhT069cPjz76qOxSiAJioFDQDh48iKuvvhqrV6/GO++8g6KiIrRr1052WQkrJSUFhYWFqKqqwscffyy7HCK/GCgUlF27dmHUqFFwu93YsmULxo0bJ7ukpHDzzTdj4MCBKC4ull0KkV8MFNLMarUiKysL/fv3x/bt29G7d2/ZJSUNg8GABQsW4LXXXoPdbpddDpFPDBTS5IknnsCMGTMwe/Zs2Gw2GI1G2SUlnRtvvBHDhg3DwoULZZdC5BMDhQI6ceIE5syZgz/96U948sknsXjxYq6XSPTnP/8Zf//737F9+3bZpRC1wkAhv3788UdMmjQJ//u//4vXXnsNDzzwgOySkt7111+PESNG8IovikkMFPLpu+++w3XXXYctW7Zg3bp1uOmmm2SXRL8qKirCm2++iQ8++EB2KUTNMFColW+//Rbjxo3Dp59+ig0bNiArK0t2SeTluuuuw1VXXcV3z1PMYaBQM4cOHUJ2djYOHTqEzZs3Y8CAAbJLIh/+/Oc/Y/Xq1di8ebPsUog8GCjk8eWXX+LKK6/E8ePHsWXLFlx22WWySyI/xo4di+zsbK6lUExhoBAAoLGxETk5OTAajdi4cSPOP/982SVRG0pKSrBu3Tps3LhRdilEABgoBODAgQPIyclB586dsXbtWnTr1k1z36amJlRWViI3NzeCFZIvo0ePRk5ODsxms+xSiAAwUJKe0+nEuHHjkJaWhjVr1uCcc84Jqv+CBQuQn58Pm80WoQojw+12w2AwyC4jbMXFxXj//fexfv162aUQMVCSmdPpRHZ2NgwGAzZu3BjSpwUvXbo0ApVF3qZNm2SXoIusrCyMGzcOhYWFskshYqAkK5fLhWuvvRZCCNTU1CA9PV12SVHjdrtRXl4uuwzdPPbYY6itrcXatWtll0JJjoGShH766Sfk5ubi66+/xpo1azSdmTQ1NaG0tBQGgwG5ubmaplj89Wm57mKz2WAwGDB79mw0NjYCACorK1ttC2fs3NxczzgWi8UzRWcwGOJ+6mvYsGEYP348P+OL5BOUVH755RcxceJEcc4554g9e/Zo6uN0OoWiKMJqtQohhKipqREAhN1uF0IIAUC0/K8UqI+iKJ4+6hi1tbUCgDCZTKK2tlYIIYTD4fBsC2XsQOP4qlkPeXl5Ii8vT/dx27Jt2zYBQKxfvz7q+yb6VREDJYmcOHFC5Ofni86dO4sPP/xQcz+r1drqyReAMJvNnn+3vD+UPlq36TF2ogWKEEKMGTNGjBkzRsq+iYQQRZzySiIPPfQQXnvtNbzxxhsYPny45n4rVqwA8Nv0kDpFVFJSomufSNaTDB555BHU1NRgy5YtskuhJGUQQgjZRVDklZWVwWQy4a9//St+//vfB9VXfcL291/F1/169YnU2G2NEaopU6YAAKqqqnQdV6urrroKRqMRb775ppT9U1JbyDOUJPD222/j3nvvRXFxcdBh4q2hoSEqfWJh7Hj18MMP46233sJHH30kuxRKQgyUBLdjxw5MnToVt956Kx555JGQxigrKwMALF++HG63G8BvV1np2SeS9SSLCRMmYNiwYXjiiSdkl0LJSM7aDUXDwYMHxbnnniuuvfZacezYsZDHcTqdnkVs75vD4Wh2n9PpDLqPy+Vq1V4dR6+xXS5Xq3HUq8GcTqewWCwhPzYtyVyUV7322mvCYDCI3bt3S62Dkg6v8kpUP/30kxgxYoTo1auX+Pbbb8Mez+FwCLPZ7Ln81uFwCCFEqyf1UPto3abX2Ha73XNlmHdYhSsWAuXkyZNiwIAB4pZbbpFaByWdIi7KJ6hZs2ahqqoK27ZtQ9++fWWXkzRkL8qrVqxYgd///vdoaGjApZdeKrUWShpclE9EixcvxgsvvIAVK1YwTJLU1KlTcckll8BiscguhZIIAyXBrFu3Dn/84x+xaNEiXH/99bLLIUnatWuH+++/Hy+88AIOHTokuxxKEgyUBPLll18iPz8fN954Ix544AHZ5ZBkd9xxB7p06YJnn31WdimUJBgoCeL//u//oCgKLrjgArz44otx/4GHFL4OHTrg3nvvxXPPPYfvv/9edjmUBBgoCUAIgTvuuAOHDx9GdXU1OnbsKLskihH33nsvjh8/nlAf10+xi4GSABYuXIhVq1bhlVdewYUXXii7HIohZ511FmbNmoXFixfjl19+kV0OJTgGSpxbu3YtiouL8dRTT+Gqq66SXQ7FoD/84Q84fPiw50M1iSKFgRLHnE4nbr31VkyePBmzZ8+WXQ7FqAsuuAD5+fl48skncfLkSdnlUAJjoMSpkydPYsaMGejUqRPnx6lNDz74IOrr6/kpxBRRDJQ4VVRUhPfffx9VVVU488wzZZdDMa5v376YMGEClixZIrsUSmAMlBh27Ngxn9s3bNiAxx9/HE899RQGDx4c5aooXt1///147733sH37dtmlUIJioMQoIQSGDRuGVatWNdvudDoxY8YMTJo0CSaTSVJ1FI/GjBmDzMxMPPPMM7JLoQTFQIlRu3fvxscff4wbb7wRt912G7777jucPHkSBQUFOOOMM7huQiG57777UFlZiQMHDsguhRIQAyVGrVmzBmlpaQBOfXJs7969cccdd2DTpk1YuXIljEaj5AopHk2fPh1nn302li1bJrsUSkAMlBj1zjvv4MSJEwBOraU0NTXhxRdfxLBhw9C7d2/J1VG8Ou2002AymbB06VL88MMPssuhBMNAiUFHjx7Fli1bmr1nQA2XDz74AAMHDuR3hlPI7rnnHvz44494+eWXZZdCCYaBEoM2b97s92Myjh8/DofDgZEjR+LRRx/F8ePHo1wdxbtu3bph+vTpWLx4Md/oSLpioMSgtWvXon379n7vP378OE6ePIny8nLU19dHsTJKFHPnzsWnn36KNWvWyC6FEggDJQa9+eabAT/Iz2AwQFEU1NXVoV+/flGsjBLFgAEDkJOTw0uISVcMlBjjdDr9nnWkpqYiLS0NS5YswapVq9C1a9coV0eJ5N5778Xq1avx6aefyi6FEgQDJcasXbvW55djpaam4uKLL8ZHH32E++67T0JllGhyc3ORkZGBsrIy2aVQgmCgxJi1a9eiXbt2np/VcJk6dSrsdjsGDhwoqzRKMO3atcOsWbPw/PPP48cff5RdDiUABkoMEUJg9erVns/wSktLQ8eOHbFixQq8/PLLOOOMMyRXSInm7rvvxo8//oiqqirZpVACYKDEkN27d+Prr78GcOrV46BBg/DJJ58gPz9fcmWUqLp164ZJkybhv//7v2WXQgmAgRJD1q5dC+DUNNe9996LLVu24OKLL5ZbFCW8e+65B7t27cKHH34ouxSKcwyUGPLuu++iW7duePfdd/H00097PsuLKJJGjx6NIUOG4LnnnpNdCsW51JYbDhw4gK1bt8qoJakdO3YMR44cQUlJCY4cOZLUc9pZWVm44IILZJeRVO6++27853/+J/7rv/4L3bp1k10OxalWgbJ161ZM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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 20, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# gen = GeneratorExpr(\n", + "# Identifier('x*x'),\n", + "# Identifier('x'),\n", + "# astx.literals.LiteralSet(\n", + "# elements={\n", + "# astx.LiteralInt32(1),\n", + "# astx.LiteralInt32(2),\n", + "# astx.LiteralInt32(3)\n", + "# }\n", + "# )\n", + "\n", + "# )\n", + "\n", + "gen = GeneratorExpr(\n", + " Identifier('x*x'),\n", + " Identifier('x'),\n", + " astx.Identifier(\"list\")\n", + "\n", + ")\n", + "gen" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(x*x for x in {3, 1, 2})\n" + ] + }, + { + "data": { + "image/png": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "\n", + "print(gen)\n", + "gen" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import astx.operators\n", + "from typing import Optional, cast, Iterable\n", + "from astx.types.collections import List\n", + "# iterable = astx.TupleType([\n", + "# astx.LiteralInt32(2),\n", + "# astx.LiteralInt32(3),\n", + "# astx.LiteralInt32(1)]\n", + "# )\n", + "iterable = astx.literals.LiteralList(\n", + " elements=[\n", + " astx.LiteralInt32(1),\n", + " astx.LiteralInt32(2),\n", + " astx.LiteralInt32(3)\n", + " ]\n", + ")\n", + "for i in iterable.elements:\n", + " print(i)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# print(gen)\n", + "print(iterable)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ast", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/src/astx/flows.py b/src/astx/flows.py index 139f8537..83bb7aea 100644 --- a/src/astx/flows.py +++ b/src/astx/flows.py @@ -2,7 +2,8 @@ from __future__ import annotations -from typing import Optional, cast +from typing import Optional, cast, Union + from public import public @@ -20,7 +21,7 @@ from astx.blocks import Block from astx.tools.typing import typechecked from astx.variables import InlineVariableDeclaration - +from astx.literals import LiteralString, LiteralList, LiteralTuple, LiteralSet @public @typechecked @@ -562,46 +563,56 @@ def get_struct(self, simplified: bool = False) -> ReprStruct: key = f"GOTO-STMT[{self.label.value}]" value: DictDataTypesStruct = {} return self._prepare_struct(key, value, simplified) - @public @typechecked class GeneratorExpr(Expr): """AST class for generator expressions.""" - element: Expr - iterable: Expr - condition: Optional[Expr] - + element: Identifier + target: Identifier + iterator: Union[LiteralList, LiteralTuple, LiteralSet, LiteralString, Identifier] def __init__( self, - element: Expr, - iterable: Expr, - condition: Optional[Expr] = None, + element: Identifier, + target: Identifier, + iterator: Union[LiteralList, LiteralTuple, LiteralSet, LiteralString, Identifier], loc: SourceLocation = NO_SOURCE_LOCATION, parent: Optional[ASTNodes] = None, ) -> None: """Initialize the GeneratorExpr instance.""" super().__init__(loc=loc, parent=parent) self.element = element - self.iterable = iterable - self.condition = condition + self.target = target + self.iterator = iterator self.kind = ASTKind.GeneratorExprKind def __str__(self) -> str: """Return a string representation of the object.""" - if self.condition: - return f"GeneratorExpr[{self.element} for {self.iterable} if {self.condition}]" + if isinstance(self.iterator, LiteralList): + return f"({self.element.value} for {self.target.value} in [{", ".join(str(e.value) for e in self.iterator.elements)}])" + elif isinstance(self.iterator, LiteralTuple): + return f"({self.element.value} for {self.target.value} in ({", ".join(str(e.value) for e in self.iterator.elements)}))" + elif isinstance(self.iterator, LiteralSet): + return f"({self.element.value} for {self.target.value} in {{{", ".join(str(e.value) for e in self.iterator.elements)}}})" + elif isinstance(self.iterator, Identifier): + return f"({self.element.value} for {self.target.value} in {self.iterator.value})" else: - return f"GeneratorExpr[{self.element} for {self.iterable}]" - + return f"({self.element.value} for {self.target.value} in {self.iterator})" + def get_struct(self, simplified: bool = False) -> ReprStruct: """Return the AST structure of the object.""" key = "GENERATOR-EXPR" value: ReprStruct = { "element": self.element.get_struct(simplified), - "iterable": self.iterable.get_struct(simplified), + "target": self.target.get_struct(simplified), + # "iterator": self.iterator.get_struct(simplified) } - if self.condition: - value["condition"] = self.condition.get_struct(simplified) + if isinstance(self.iterator, (LiteralList, LiteralTuple, LiteralSet)): + value["iterator"] = { + "type": self.iterator.__class__.__name__, + "elements": [e.get_struct(simplified) for e in self.iterator.elements] + } + else: + value["iterator"] = self.iterator.get_struct(simplified) return self._prepare_struct(key, value, simplified) \ No newline at end of file diff --git a/src/astx/literals/collections.py b/src/astx/literals/collections.py index 2b05ee39..3025a292 100644 --- a/src/astx/literals/collections.py +++ b/src/astx/literals/collections.py @@ -69,7 +69,6 @@ def __init__( ) self.loc = loc - @public @typechecked class LiteralDict(Literal): From 5c95889da8ffb7ad180f8498190966fd471cec69 Mon Sep 17 00:00:00 2001 From: Zehen-249 <1hasanmehendi123@gmail.com> Date: Sat, 15 Mar 2025 19:37:47 +0530 Subject: [PATCH 3/5] feat(generatorExp): - Change ASRKind code for GeneratorExp - Add support for `YieldFromExpr` (#206) - Add support for `AsyncFor` (#211) change ASRKind code for GeneratorExp feat: Add support for `YieldFromExpr` (#206) feat: Add support for `AsyncFor` (#211) --- src/astx/__init__.py | 6 ++ src/astx/base.py | 5 +- src/astx/callables.py | 29 ++++++ src/astx/flows.py | 125 +++++++++++++++++++++++++ src/astx/tools/transpilers/python.py | 31 ++++++ tests/test_callables.py | 11 +++ tests/test_flows.py | 42 +++++++++ tests/tools/transpilers/test_python.py | 50 ++++++++++ 8 files changed, 298 insertions(+), 1 deletion(-) diff --git a/src/astx/__init__.py b/src/astx/__init__.py index 0ffa1e51..f50c6ac6 100644 --- a/src/astx/__init__.py +++ b/src/astx/__init__.py @@ -43,6 +43,7 @@ FunctionReturn, LambdaExpr, YieldExpr, + YieldFromExpr, ) from astx.classes import ( ClassDeclStmt, @@ -58,6 +59,8 @@ ThrowStmt, ) from astx.flows import ( + AsyncForRangeLoopExpr, + AsyncForRangeLoopStmt, CaseStmt, ForCountLoopExpr, ForCountLoopStmt, @@ -199,6 +202,8 @@ def get_version() -> str: "Argument", "Arguments", "AssignmentExpr", + "AsyncForRangeLoopExpr", + "AsyncForRangeLoopStmt", "AwaitExpr", "BinaryOp", "Block", @@ -330,6 +335,7 @@ def get_version() -> str: "XnorOp", "XorOp", "YieldExpr", + "YieldFromExpr", "base", "blocks", "callables", diff --git a/src/astx/base.py b/src/astx/base.py index 0e55931f..17ccc2ca 100644 --- a/src/astx/base.py +++ b/src/astx/base.py @@ -113,6 +113,7 @@ class ASTKind(Enum): FunctionAsyncDefKind = -405 AwaitExprKind = -406 YieldExprKind = -510 + YieldFromExprKind = -407 # control flow IfStmtKind = -500 @@ -127,7 +128,9 @@ class ASTKind(Enum): SwitchStmtKind = -509 GotoStmtKind = -511 WithStmtKind = -512 - GeneratorExprKind = -513 + GeneratorExprKind = -516 + AsyncRangeLoopStmtKind = -513 + AsyncRangeLoopExprKind = -514 # data types NullDTKind = -600 diff --git a/src/astx/callables.py b/src/astx/callables.py index 7d9cae1f..2cecaa8f 100644 --- a/src/astx/callables.py +++ b/src/astx/callables.py @@ -386,3 +386,32 @@ def get_struct(self, simplified: bool = False) -> ReprStruct: key = "YIELD-EXPR" value = {} if self.value is None else self.value.get_struct(simplified) return self._prepare_struct(key, value, simplified) + + +@public +@typechecked +class YieldFromExpr(Expr): + """AST class for YieldFromExpr.""" + + value: Expr + + def __init__( + self, + value: Expr, + loc: SourceLocation = NO_SOURCE_LOCATION, + parent: Optional[ASTNodes] = None, + ) -> None: + """Initialize the YieldFromExpr instance.""" + super().__init__(loc=loc, parent=parent) + self.value = value + self.kind = ASTKind.YieldFromExprKind + + def __str__(self) -> str: + """Return a string representation of the object.""" + return f"YieldFromExpr[{self.value}]" + + def get_struct(self, simplified: bool = False) -> ReprStruct: + """Return the AST structure of the object.""" + key = "YIELDFROM-EXPR" + value = self.value.get_struct(simplified) + return self._prepare_struct(key, value, simplified) diff --git a/src/astx/flows.py b/src/astx/flows.py index 83bb7aea..42aa8c1d 100644 --- a/src/astx/flows.py +++ b/src/astx/flows.py @@ -344,6 +344,131 @@ def get_struct(self, simplified: bool = False) -> ReprStruct: return self._prepare_struct(key, value, simplified) +@public +@typechecked +class AsyncForRangeLoopStmt(StatementType): + """AST class for asynchronous `For` Range Statement.""" + + variable: InlineVariableDeclaration + start: Optional[Expr] + end: Expr + step: Optional[Expr] + body: Block + + def __init__( + self, + variable: InlineVariableDeclaration, + start: Optional[Expr], + end: Expr, + step: Optional[Expr], + body: Block, + loc: SourceLocation = NO_SOURCE_LOCATION, + parent: Optional[ASTNodes] = None, + ) -> None: + """Initialize the AsyncForRangeLoopStmt instance.""" + super().__init__(loc=loc, parent=parent) + self.variable = variable + self.start = start + self.end = end + self.step = step + self.body = body + self.kind = ASTKind.AsyncRangeLoopStmtKind + + def __str__(self) -> str: + """Return a string that represents the object.""" + start = self.start + end = self.end + step = self.step + var_name = self.variable.name + return f"AsyncForRangeLoopStmt({var_name}=[{start}:{end}:{step}])" + + def get_struct(self, simplified: bool = False) -> ReprStruct: + """Return the AST structure of the object.""" + for_start = { + "start": {} + if self.start is None + else self.start.get_struct(simplified) + } + for_end = {"end": self.end.get_struct(simplified)} + for_step = { + "step": {} + if self.step is None + else self.step.get_struct(simplified) + } + for_body = self.body.get_struct(simplified) + + key = "ASYNC-FOR-RANGE-LOOP-STMT" + value: ReprStruct = { + **cast(DictDataTypesStruct, for_start), + **cast(DictDataTypesStruct, for_end), + **cast(DictDataTypesStruct, for_step), + **cast(DictDataTypesStruct, for_body), + } + return self._prepare_struct(key, value, simplified) + + +@public +@typechecked +class AsyncForRangeLoopExpr(Expr): + """AST class for asynchronous `For` Range Expression.""" + + variable: InlineVariableDeclaration + start: Optional[Expr] + end: Expr + step: Optional[Expr] + body: Block + + def __init__( + self, + variable: InlineVariableDeclaration, + start: Optional[Expr], + end: Expr, + step: Optional[Expr], + body: Block, + loc: SourceLocation = NO_SOURCE_LOCATION, + parent: Optional[ASTNodes] = None, + ) -> None: + """Initialize the AsyncForRangeLoopExpr instance.""" + super().__init__(loc=loc, parent=parent) + self.variable = variable + self.start = start + self.end = end + self.step = step + self.body = body + self.kind = ASTKind.AsyncRangeLoopExprKind + + def __str__(self) -> str: + """Return a string that represents the object.""" + var_name = self.variable.name + return f"AsyncForRangeLoopExpr[{var_name}]" + + def get_struct(self, simplified: bool = False) -> ReprStruct: + """Return the AST structure of the object.""" + for_var = {"var": self.variable.get_struct(simplified)} + for_start = { + "start": {} + if self.start is None + else self.start.get_struct(simplified) + } + for_end = {"end": self.end.get_struct(simplified)} + for_step = { + "step": {} + if self.step is None + else self.step.get_struct(simplified) + } + for_body = self.body.get_struct(simplified) + + key = "ASYNC-FOR-RANGE-LOOP-EXPR" + value: ReprStruct = { + **cast(DictDataTypesStruct, for_var), + **cast(DictDataTypesStruct, for_start), + **cast(DictDataTypesStruct, for_end), + **cast(DictDataTypesStruct, for_step), + **cast(DictDataTypesStruct, for_body), + } + return self._prepare_struct(key, value, simplified) + + @public @typechecked class WhileStmt(StatementType): diff --git a/src/astx/tools/transpilers/python.py b/src/astx/tools/transpilers/python.py index 6383bff1..a15246cd 100644 --- a/src/astx/tools/transpilers/python.py +++ b/src/astx/tools/transpilers/python.py @@ -66,6 +66,31 @@ def visit(self, node: astx.AssignmentExpr) -> str: target_str = " = ".join(self.visit(target) for target in node.targets) return f"{target_str} = {self.visit(node.value)}" + @dispatch # type: ignore[no-redef] + def visit(self, node: astx.AsyncForRangeLoopExpr) -> str: + """Handle AsyncForRangeLoopExpr nodes.""" + if len(node.body) > 1: + raise ValueError( + "AsyncForRangeLoopExpr in Python just accept 1 node in the " + "body attribute." + ) + start = ( + self.visit(node.start) + if getattr(node, "start", None) is not None + else "0" + ) + end = self.visit(node.end) + step = ( + self.visit(node.step) + if getattr(node, "step", None) is not None + else "1" + ) + + return ( + f"result = [{self.visit(node.body).strip()} async for " + f"{node.variable.name} in range({start}, {end}, {step})]" + ) + @dispatch # type: ignore[no-redef] def visit(self, node: astx.AwaitExpr) -> str: """Handle AwaitExpr nodes.""" @@ -520,6 +545,12 @@ def visit(self, node: astx.YieldExpr) -> str: value = self.visit(node.value) if node.value else "" return f"yield {value}".strip() + @dispatch # type: ignore[no-redef] + def visit(self, node: astx.YieldFromExpr) -> str: + """Handle YieldFromExpr nodes.""" + value = self.visit(node.value) + return f"yield from {value}".strip() + @dispatch # type: ignore[no-redef] def visit(self, node: astx.Date) -> str: """Handle Date nodes.""" diff --git a/tests/test_callables.py b/tests/test_callables.py index 70478a25..4672c83c 100644 --- a/tests/test_callables.py +++ b/tests/test_callables.py @@ -14,6 +14,7 @@ FunctionReturn, LambdaExpr, YieldExpr, + YieldFromExpr, ) from astx.literals.numeric import LiteralInt32 from astx.modifiers import ScopeKind, VisibilityKind @@ -163,3 +164,13 @@ def test_yield_expr() -> None: assert yield_expr.get_struct() assert yield_expr.get_struct(simplified=True) visualize(yield_expr.get_struct()) + + +def test_yieldfrom_expr() -> None: + """Test `YieldFromExpr` class.""" + yieldfrom_expr = YieldFromExpr(value=LiteralInt32(1)) + + assert str(yieldfrom_expr) + assert yieldfrom_expr.get_struct() + assert yieldfrom_expr.get_struct(simplified=True) + visualize(yieldfrom_expr.get_struct()) diff --git a/tests/test_flows.py b/tests/test_flows.py index 69068d57..83837cd6 100644 --- a/tests/test_flows.py +++ b/tests/test_flows.py @@ -6,6 +6,8 @@ from astx.base import SourceLocation from astx.blocks import Block from astx.flows import ( + AsyncForRangeLoopExpr, + AsyncForRangeLoopStmt, CaseStmt, ForCountLoopExpr, ForCountLoopStmt, @@ -155,6 +157,46 @@ def test_for_count_loop_expr() -> None: visualize(for_expr.get_struct()) +def test_async_for_range_loop_expr() -> None: + """Test `Async For Range Loop` expression`.""" + decl_a = InlineVariableDeclaration( + "a", type_=Int32(), value=LiteralInt32(-1) + ) + start = LiteralInt32(1) + end = LiteralInt32(10) + step = LiteralInt32(1) + body = Block() + body.append(LiteralInt32(2)) + for_expr = AsyncForRangeLoopExpr( + variable=decl_a, start=start, end=end, step=step, body=body + ) + + assert str(for_expr) + assert for_expr.get_struct() + assert for_expr.get_struct(simplified=True) + visualize(for_expr.get_struct()) + + +def test_async_for_range_loop_stmt() -> None: + """Test `Async For Range Loop` statement.""" + decl_a = InlineVariableDeclaration( + "a", type_=Int32(), value=LiteralInt32(-1) + ) + start = LiteralInt32(1) + end = LiteralInt32(10) + step = LiteralInt32(1) + body = Block() + body.append(LiteralInt32(2)) + for_stmt = AsyncForRangeLoopStmt( + variable=decl_a, start=start, end=end, step=step, body=body + ) + + assert str(for_stmt) + assert for_stmt.get_struct() + assert for_stmt.get_struct(simplified=True) + visualize(for_stmt.get_struct()) + + def test_while_expr() -> None: """Test `WhileExpr` class.""" # Define a condition: x < 5 diff --git a/tests/tools/transpilers/test_python.py b/tests/tools/transpilers/test_python.py index 4ce136d6..41fe58f3 100644 --- a/tests/tools/transpilers/test_python.py +++ b/tests/tools/transpilers/test_python.py @@ -434,6 +434,29 @@ def test_transpiler_for_range_loop_expr() -> None: ) +def test_transpiler_async_for_range_loop_expr() -> None: + """Test `Async For Range Loop` expression`.""" + decl_a = astx.InlineVariableDeclaration( + "a", type_=astx.Int32(), value=astx.LiteralInt32(-1) + ) + start = astx.LiteralInt32(0) + end = astx.LiteralInt32(10) + step = astx.LiteralInt32(1) + body = astx.Block() + body.append(astx.LiteralInt32(2)) + + for_expr = astx.AsyncForRangeLoopExpr( + variable=decl_a, start=start, end=end, step=step, body=body + ) + + generated_code = translate(for_expr) + expected_code = "result = [2 async for a in range(0, 10, 1)]" + + assert generated_code == expected_code, ( + f"Expected '{expected_code}', but got '{generated_code}'" + ) + + def test_transpiler_binary_op() -> None: """Test astx.BinaryOp for addition operation.""" # Create a BinaryOp node for the expression "x + y" @@ -1047,6 +1070,33 @@ def test_transpiler_yieldexpr_whilestmt() -> None: ) +def test_transpiler_yieldfromexpr_whilestmt() -> None: + """Test astx.YieldFromExpr (using WhileStmt).""" + # Create the `while True` loop + while_cond = astx.LiteralBoolean(True) + while_body = astx.Block() + + # Create the `yieldfrom` expression + yieldfrom_expr = astx.YieldFromExpr(value=astx.Variable("x")) + + # Assign the result of `yieldfrom` back to `value` + assign_value = astx.VariableAssignment(name="value", value=yieldfrom_expr) + + # Add the assignment to the loop body + while_body.append(assign_value) + + # Define the `while` loop and add it to the function body + while_stmt = astx.WhileStmt(condition=while_cond, body=while_body) + + # Generate Python code + generated_code = translate(while_stmt) + expected_code = "while True:\n value = yield from x" + + assert generated_code == expected_code, ( + f"Expected '{expected_code}', but got '{generated_code}'" + ) + + def test_transpiler_assignmentexpr() -> None: """Test astx.AssignmentExpr.""" var_a = astx.Variable(name="a") From 1bf4478f2099304576bbe64d191e83565357bebf Mon Sep 17 00:00:00 2001 From: Zehen-249 <1hasanmehendi123@gmail.com> Date: Sat, 15 Mar 2025 21:56:00 +0530 Subject: [PATCH 4/5] add test for generatorExp --- docs/tutorials/generatorExp.ipynb | 41 +++++++++++++++---------------- src/astx/flows.py | 4 +-- tests/test_flows.py | 21 ++++++++++++++++ 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/docs/tutorials/generatorExp.ipynb b/docs/tutorials/generatorExp.ipynb index bc18bb8b..247a8a63 100644 --- a/docs/tutorials/generatorExp.ipynb +++ b/docs/tutorials/generatorExp.ipynb @@ -22,7 +22,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ @@ -32,7 +32,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -69,7 +69,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -86,49 +86,48 @@ "data": { "text/plain": [] }, - "execution_count": 20, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "# gen = GeneratorExpr(\n", - "# Identifier('x*x'),\n", - "# Identifier('x'),\n", - "# astx.literals.LiteralSet(\n", - "# elements={\n", - "# astx.LiteralInt32(1),\n", - "# astx.LiteralInt32(2),\n", - "# astx.LiteralInt32(3)\n", - "# }\n", - "# )\n", + "gen = GeneratorExpr(\n", + " Identifier('x*x'),\n", + " Identifier('x'),\n", + " astx.literals.LiteralSet(\n", + " elements={\n", + " astx.LiteralInt32(1),\n", + " astx.LiteralInt32(2),\n", + " astx.LiteralInt32(3)\n", + " }\n", + " )\n", "\n", - "# )\n", + ")\n", "\n", "gen = GeneratorExpr(\n", " Identifier('x*x'),\n", " Identifier('x'),\n", " astx.Identifier(\"list\")\n", - "\n", ")\n", "gen" ] }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ - "(x*x for x in {3, 1, 2})\n" + "(x*x for x in list)\n" ] }, { "data": { - "image/png": "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", + "image/png": "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YlKRQQiNE9AU1/r27YspU6agqKhIdilEYSsqKkJVVRX27t0ruxT6zUIuyhMRkS4YKEREpAsGChER6YKBQkREumCgEBGRLhgoRESkCwYKERHpgoFCRES6YKAQEZEuGChERKQLBgoREemCgUJERLpgoBARkS4YKEREpAsGChER6SJVdgEUPXv27EFVVZXsMojCtmfPHtklkA8MlCTy6quv4tVXX5VdBpEu+vTpI7sEaoFTXkli7969EELExc3hcOD666+HwWDA4sWLpdcTzC0vLw95eXlB9amqqkJKSgrq6uqk1x9PN35bY+xhoFDMOHnyJMrKytC/f3/s378f69atw/333y+7rIibPHkyBg8ejEceeUR2KURhYaBQTNi9ezeuvPJKzJkzB/fccw92796NnJwc2WVFhcFgwOOPP44333wT7733nuxyiELGQCGpjh49iqKiIgwbNgwpKSnYtWsXnnjiCXTo0EF2aVE1btw4jBkzBg899BCEELLLIQoJA4Wk2bhxIwYOHIglS5ZgyZIl2Lx5M/r16ye7LGkWLVqEDz/8EDabTXYpRCFhoFDUHT16FPPmzUNOTg769OmDvXv34p577kFKSnL/dxw+fDgmTZqERx55BCdOnJBdDlHQkvsvmKJu9+7dGDVqFCoqKrB06VKsWrUK559/vuyyYsbjjz+O/fv34+WXX5ZdClHQGCgUFSdOnMCTTz6JYcOGoWPHjti5cyfuuusu2WXFnJ49e+K2227DggUL8PPPP8suhygoDBSKuC+++AI5OTkoKirCo48+is2bN6NHjx6yy4pZCxcuxOHDh7F06VLZpRAFhYFCEfXSSy9h4MCB+Pbbb7Ft2zb88Y9/TPq1kracd955mDNnDh577DF89913sssh0ox/2RQRX3/9NSZOnIg77rgD9913H3bs2IHMzEzZZcWNhx9+GCdPnkRpaansUog0Y6CQ7rZu3YohQ4Zgz5492Lx5M0pKSpCWlia7rLjSpUsXPPDAA1i8eDGcTqfscog0YaCQboQQePrpp3HNNddg4MCB2LlzJ0aNGiW7rLh13333oUuXLnjsscdkl0KkCQOFdPHdd99h6tSpmDdvHh5++GFUV1eja9eussuKa6effjrMZjOWLVuGf/zjH7LLIWoTA4XCtmvXLgwZMgQbN27E6tWrUVRUxIV3ncycOROXXHIJioqKZJdC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oMSpkydPYsaMGejUqRPnx6lNDz74IOrr6/kpxBRRDJQ4VVRUhPfffx9VVVU488wzZZdDMa5v376YMGEClixZIrsUSmAMlBh27Ngxn9s3bNiAxx9/HE899RQGDx4c5aooXt1///147733sH37dtmlUIJioMQoIQSGDRuGVatWNdvudDoxY8YMTJo0CSaTSVJ1FI/GjBmDzMxMPPPMM7JLoQTFQIlRu3fvxscff4wbb7wRt912G7777jucPHkSBQUFOOOMM7huQiG57777UFlZiQMHDsguhRIQAyVGrVmzBmlpaQBOfXJs7969cccdd2DTpk1YuXIljEaj5AopHk2fPh1nn302li1bJrsUSkAMlBj1zjvv4MSJEwBOraU0NTXhxRdfxLBhw9C7d2/J1VG8Ou2002AymbB06VL88MMPssuhBMNAiUFHjx7Fli1bmr1nQA2XDz74AAMHDuR3hlPI7rnnHvz44494+eWXZZdCCYaBEoM2b97s92Myjh8/DofDgZEjR+LRRx/F8ePHo1wdxbtu3bph+vTpWLx4Md/oSLpioMSgtWvXon379n7vP378OE6ePIny8nLU19dHsTJKFHPnzsWnn36KNWvWyC6FEggDJQa9+eabAT/Iz2AwQFEU1NXVoV+/flGsjBLFgAEDkJOTw0uISVcMlBjjdDr9nnWkpqYiLS0NS5YswapVq9C1a9coV0eJ5N5778Xq1avx6aefyi6FEgQDJcasXbvW55djpaam4uKLL8ZHH32E++67T0JllGhyc3ORkZGBsrIy2aVQgmCgxJi1a9eiXbt2np/VcJk6dSrsdjsGDhwoqzRKMO3atcOsWbPw/PPP48cff5RdDiUABkoMEUJg9erVns/wSktLQ8eOHbFixQq8/PLLOOOMMyRXSInm7rvvxo8//oiqqirZpVACYKDEkN27d+Prr78GcOrV46BBg/DJJ58gPz9fcmWUqLp164ZJkybhv//7v2WXQgmAgRJD1q5dC+DUNNe9996LLVu24OKLL5ZbFCW8e+65B7t27cKHH34ouxSKcwyUGPLuu++iW7duePfdd/H00097PsuLKJJGjx6NIUOG4LnnnpNdCsW51JYbDhw4gK1bt8qoJakdO3YMR44cQUlJCY4cOZLUc9pZWVm44IILZJeRVO6++27853/+J/7rv/4L3bp1k10OxalWgbJ161ZMnTpVRi2EU3/YyW7lypWYMmWK7DKSyowZM/Dggw9i+fLl+MMf/iC7HIpTrQJFJYSIZh1EAODzPTgUeWeccQamTZuG8vJyBgqFjGsoRAQAmDlzJvbv349t27bJLoXiFAOFiAAAw4cPR2ZmJp5//nnZpVCcYqAQkcftt9+OyspKfP/997JLoTjEQCEij1tuuQXHjh3Dq6++KrsUikMMFCLyOPvss3HDDTdw2otCwkAhomZmzpyJLVu2YO/evbJLoTjDQCGiZsaOHYuLLroIL7zwguxSKM4wUIiomZSUFNx+++146aWXPJ98TaQFA4WIWpk5cyaOHDmCN998U3YpFEcYKETUygUXXIAxY8ZwcZ6CwkAhIp9mzpyJ1atX46uvvpJdCsUJBgoR+XTDDTegS5cu+Nvf/ia7FIoTDBQi8um0007DlClTsHz5ctmlUJxgoBCRXwUFBdi7dy927doluxSKAwwUIvJr1KhR6NmzJ89SSBMGChEFlJ+fj7/97W84fvy47FIoxjFQEozBYGh2C4Xb7UZubi7cbre0Gih2FBQU4PDhw1i3bp3sUijGhR0oLZ88tNxKS0ths9laPWFp7b9+/XrPvwsLC3WrK5ZugY4hNzcXpaWlaGho8Pt7EUKE/K2bbrfb5+9Hq3D2nSjcbndMhWk49fTo0QMjR47Eyy+/rHNVlGjCDhQhBFwul+dnl8vleUJxOp0+t48dOxbl5eUoKChAU1OT37HU9uqtvr4eAJCTkwOXywWr1YqSkhKfoeK9f6fT6XmCs1qtzcb0tS+r1eqp2Vf9gWqsqalp83HRcowtj8G7bUVFBVwuF3r16oW6ujo/v5ngqUFlNBoBAB06dEBlZSVyc3N120ey2LRpk+wSmgm3noKCArzxxhv8nhQKTLSwcuVK4WNzmwD47Odvu9PpFIqiCEVRhMvl0tRHvc9XW6vV2mZ7rfW5XC7PtmCPy9c+w+nfVo0mk0nzuG1xOp2ipqZG1NTUCADCbrcLh8MhnE5nSOOFUgsAsXLlypD2Fwvy8vLEjTfeKBRFCfn3oDeXyxV2PUeOHBGnnXaaePHFF3WsjBJMkbQ1lPT0dMydOxc2m03Tqyf1dF34mEqxWCzIz89HZWVlwDEcDoem2oxGo+a2WmvUu796FrFs2TJN47Y1nebPZ599hqNHj4Y9TjKpr6+HzWYDgGaPi9vtRnl5ebPpWvUMvampCTabzbN2NXv27GZn3uvXr0dubq5nytj7zF7V1NSE0tJSz7To+vXrAZz6+/BVTzC6du2K8ePH82ovCqxlxETrDEUI7a+yHQ5Hm6/mzWaz51W1r/uDrbut+7XWGG5/f2Oo7S0Wi6b9lZWVCQCesw31DNH78VIURVitVs/vxel0CqvVKhRFCWqctmoJBAlwhpKXl+fz2E0mk+exU39/6v999QwCgKitrRV2u91zX3V1tWe7EEJYrVZPW3Uf6u9BPVP3PssUIrwzV9Wrr74qUlJSxFdffRXWOJSwiqQGir/7vf9YWv7h+OovRPPT+vr6+lb3B1u31uNqq8Zw+/saw263e6YLW05HBRrH+wnNYrH4ncpSn+wcDkdY4zBQmh+72Wxu9uKpZRv1Zy1TwC1fTKgh07KN2Wz2O0awfv75Z3H22WeLv/zlL2GNQwkrtgNFpeUMRYhTr9IANHuiTaQzFO9bTU1N0Mfj/fh4h25Laji3fGILdhwGiu9jdzgcwmKx+A2UltQA99ayrfcZjq8XKXoEihBC3HXXXaJfv35hj0MJSd4aCgDPZalmszlgu4yMDE3jpaenw263w2azYdasWSFf9hoKrTWG01/8epWXoijYsGFD0PtIT0+H1WqFzWbDN99847ed0WhEdXW1Z50m1HGotfLycsyZMweKomjuYzKZAMCzRqhe2WexWDxt1DUS9f+I901PBQUF2LNnDz7++GNdx6XEIDVQduzYAQC45ppr2myr9Q8jMzMT1dXVsNlszf7goiHcP16t/SsqKlBXV+f3PTj+NDU14eDBg7BYLBg1apTPhd1ojpNsKisrcdddd+HZZ59Fz549NfdT/08fPHjQs5hvtVoxb968Vm0DvTdJD1deeSUuuugirFy5MqL7oTjV8pxFxmXDWvsIcWq6QJ0XVtv64r1wGUrdbd2vZexQ+/s6xpZt1cfPu11b46pz7uqUVsuLIbTSOo7Wx6hln0Sd8mq5ra2fVdXV1X6nH1XqxRJms9nTVl3jCjR2KObPny8uvfRScfLkSV3Go4ShzxqKelUQWiwo+tseaFHZu09LDodDmEwmz9Uu6ly+v0Vh9covf9T+/sYI9rhC6a/1GH3VaLfbBQBRVlbWbM2o5bgul6vZE413DS0DKZBgx0nmQFHXNLyf1NVtDodD1NfXN/u9ev+eW1K3t7yZTKZmV9v5aqNeWOGrnlBt375dABDbt28PaxxKOOEHir//7IFuFovF84QZyljeT8jeN198nQEF2leox6XH46LlGFvuSw0V9XH11UbL8WkR7DjJHCjq78VsNnue9FtuU6/6Ui/IUG8t/8+qL8D8hYpKPbNVt3tfpeernnBcdtllYv78+WGPQwmlyCBE84n7qqoqTJ06VffFPIqOcN9cqadQajEYDFi5ciWmTJkSqbIiSq27qqpKtzEbGhrQoUOHVhduNDQ0oFevXlJ+13/605/w8ssvw+Fw8A2tpFrITxsmimGVlZXo2bOnz6sAu3fv7vncuWibOnUqvvrqK9TW1krZP8UmBgpRDFuxYgXKy8vR2NjYbHtDQwOqqqowbdo0KXVlZmaib9++vNqLmmGgJCiZn63Fz/XSz/Lly9G5c2csWrSo2WeAHThwAHfeeafU2vLy8lBVVYUTJ05IrYNiBwMlwYgIvqktnmpIFEajEdOmTcPSpUs9j2dxcTFycnJkl4Zp06bh0KFDeP/992WXQjGCgUJEIenduzcGDhzIaS/yYKAQUcimTp2KV155hd83TwAYKEQUhmnTpuHIkSMhfbYcJR4GChGF7NJLL8XQoUM57UUAGChEFKa8vDz8/e9/57QXMVCIKDx5eXk4cuQINm7cKLsUkoyBQkRhueSSSzBw4EC8/vrrskshyRgoRBS2SZMm4fXXX8fJkydll0ISMVCIKGw333wzDh06hG3btskuhSRioBBR2Pr3749evXpx2ivJMVCISBc33XQTXnvtNX7cThJL9XeHnt/nQESJb9KkSXjiiSdgt9sxePBg2eWQBH4DZerUqdGsg4ji3LBhw5CRkYHXX3+dgZKkWn1jIxGFLhLf2BhP5s6di9WrV2P//v2yS6Ho4zc2EpF+Jk2ahPr6euzbt092KSQBA4WIdDN69Gice+65vNorSTFQiEg3KSkpyM3NZaAkKQYKEenqpptuws6dO/Hll1/KLoWijIFCRLrKyclBly5dYLPZZJdCUcZAISJdpaWlYdy4cQyUJMRAISLdKYqC9957Dy6XS3YpFEUMFCLS3YQJEyCEwJo1a2SXQlHEQCEi3XXt2hWjR4/mtFeSYaAQUUQoioK33noLx44dk10KRQkDhYgi4oYbboDL5cL7778vuxSKEgYKEUVEjx490KdPH057JREGChFFTG5uLlatWiW7DIoSBgoRRYyiKPj888+xZ88e2aVQFDBQiChiRo0ahe7du3PaK0kwUIgoYlJSUjBhwgQGSpJgoBBRRCmKgm3btuHQoUOyS6EIY6AQUUT9+7//O9LS0rB69WrZpVCEMVCIKKI6deqE7OxsvPPOO7JLoQhjoBBRxI0fPx5r1qzhu+YTHAOFiCJOURS43W5s3bpVdikUQQwUIoq4HoRJ5msAABdFSURBVD164PLLL+e0V4JjoBBRVEyYMAFvv/227DIoghgoRBQV48ePx+7du+FwOGSXQhHCQCGiqPjd736HTp068fLhBMZAIaKoOO2005CTk8N1lATGQCGiqBk/fjzWrVuHn3/+WXYpFAEMFCKKmokTJ+KHH37Apk2bWt1XWFiIwsJCCVWRXhgoRBQ1F154Ifr376/5ai+32w2DwRDhqqK/r0SVKrsAIkouEydOxBtvvIElS5Y0215cXNyqra8zmUiJ5r4SFc9QiCiqJkyYgIaGBnz22WcB27ndbpSXl0elpmjuK5ExUIgoqrKysmA0GrFmzRrPtqamJlRWViI3N9ezzWKxeL5HxWAwNJuOampqQmlpKQwGA3Jzc7F+/XrPdpvNhtzcXLjdbsyePduzLqOGhjpWYWEhmpqa2tyX2+1GZWWlZ3t5ebmnX6D9JSVBRLrJy8sTeXl5ssuIeTfeeKPIzc31/KwoigAgWj4l+drmdDqFoijCarUKIYSoqakRAITdbm82Tm1trbDb7cJkMgkhhDCZTAKAcDqdwuFwCACe+/ztS62trKys2b4VRREulyvg/pJQEQOFSEcMFG2ee+450blzZ/Hzzz97tmkNFKvV6rOd2Wxu1sflcjVrYzabAwaIr32pYeV0Oj3bamtrBQBPoPnbXxIq4pQXEUXdddddh++//x61tbVB912xYgWA36am1OmpkpKSZu2MRmOzn4uLi7F06VI0NjaitLRU075eeeUVAEB6erpnW58+fZrV4W9/yYiBQkRRd8kll6BHjx549913g+6rrnUIIVrd2lJeXo45c+ZAURRN+1q2bFmrbWpwqHXQbxgoRCTFtdde22xhPlgNDQ1Bta+srMRdd92FZ599Fj179tTURw0edRHem8lkCmr/yYCBQkRSjBs3Djt37sThw4eD6ldWVgYAWL58OdxuN4DfrvoKJD8/HwCQkZGheV/Tp08HAHz++eeebeo+8/LytBedJBgoRCRFTk4O2rVrh5qammZnAN7/9j5DUAPjhhtuAHBqzaRLly4wGAzo3r078vLyfJ5JtByrsbGx2dmN2sfXvsaPHw9FUfD444972r3zzjswmUzIyckJuL9kxEAhIik6d+6MkSNHYu3atejevbtnu/e/1XfPP/PMMygoKABwaoHc4XDAbDYDODX15HA4kJGR0ayv93tavMcqLy9Hly5dYDabYTKZcPToUb/7MhqNqKiogKIo6N69u+cCgCeeeKJVrS33l4wMQstKFhFpMmXKFABAVVWV5EriQ0lJCZ577jkcPHiQn6MV/xbyDIWIpBk3bhz+9a9/Yc+ePbJLIR0wUIhImmHDhqFbt25Yu3at7FJIBwwUIpImJSUFOTk5DJQEwUAhIqnGjRuHTZs2eRbHKX4xUIhIqrFjx+Knn37C1q1bZZdCYWKgEJFUGRkZuPzyy1FTUyO7FAoTA4WIpBszZgzWrVsnuwwKEwOFiKQbM2YMduzYgW+//VZ2KRQGBgoRSZeTkwMhBDZu3Ci7FAoDA4WIpOvatSsGDRrEdZQ4lyq7AKJ49fXXX+O7775rtu2HH34A0PzTaQHgzDPPxDnnnBO12uLR2LFj+R0jcY6f5UUUor/+9a+4/fbbNbV94YUXcNttt0W2oDi3du1aXHvttfjqq69wwQUXyC6HgsfP8iIK1U033YS0tLQ226WlpeGmm26KQkXxbfTo0TjttNOwYcMG2aVQiBgoRCEyGo2YMGECUlP9zxynpqZi4sSJ/L5xDTp27IhRo0ZxHSWOMVCIwnDLLbfgxIkTfu8/ceIEbrnllihWFN/GjBkT0vfMU2xgoBCF4frrr0fHjh393n/66adjwoQJUawovo0dOxb//Oc/UV9fL7sUCgEDhSgMHTp0wM033+xzLSUtLQ2TJ0/G6aefLqGy+DRs2DAYjUa+az5OMVCIwjR9+nQcO3as1fZjx45hxowZEiqKX6mpqbj66qvx3nvvyS6FQsBAIQrT2LFj0bVr11bbu3TpgpycHAkVxberr74aGzduBN/REH8YKERhateuHaZPn4727dt7trVv3x4FBQUBrwAj37Kzs3H48GHs379fdikUJAYKkQ7y8/Pxyy+/eH7+5ZdfkJ+fL7Gi+DV48GCceeaZ/FyvOMRAIdLBqFGjmr27+7zzzsPIkSMlVhS/UlNTkZWVxUCJQwwUIh0YDAYUFBQgLS0N7du3x6233gqDwSC7rLiVnZ3NQIlDDBQineTn5+PYsWP45ZdfMH36dNnlxLXs7Gz861//wqeffiq7FAoCVwyJdDJgwAD07NkTANC/f3/J1cS34cOHo1OnTti4cSMuv/xy2eWQRjxDIdLRrbfeyk8V1kFqaipGjhzJaa84wzMUCtqBAwewdetW2WXEpM6dOwMAqqqqJFcSm7KysjR/NH12djb+53/+J8IVkZ4YKBS0rVu3YurUqbLLoDi0cuVKTJkyRVPb7OxsFBYW4osvvsAll1wS4cpIDwwUChnfyUzBCPaqtxEjRqBjx47YuHEjAyVOcA2FiGJS+/btMWLECK6jxBEGChHFLL4fJb4wUIgoZmVnZ+OLL76Aw+GQXQppwEAhopg1cuRIdOjQAZs2bZJdCmnAQCGimNWhQwcMHz6c015xgoFCRDGN6yjxg4FCRDEtOzsbn332GQ4ePCi7FGoDA4WIYlpWVhbat2/PdZQ4wEAhopjWsWNHDB06lNNecYCBQkQxj+so8YGBQkQxLzs7G/X19XA6nbJLoQAYKEQU80aPHo127dpxHSXGMVCIKOZ16tQJgwcP5rRXjGOgEFFc4DpK7GOgEFFcuOqqq7Bnzx58++23skshPxgoRBQXsrKyAAC1tbWSKyF/GChEScZgMDS7RatvuM455xxcfvnlDJQYxkChiGv5JKTlVlpaCpvNBrfbHdJY69ev9/y7sLBQt7pi6RboGHJzc1FaWoqGhga/vxchRNDfuhlKHz1lZWVh69at0vZPgTFQKOKEEHC5XJ6fXS6X54nJ+30F3tvHjh2L8vJyFBQUoKmpye9Yanv1Vl9fDwDIycmBy+WC1WpFSUmJz1Dx3r/T6fQ8UVqt1mZj+tqX1Wr11Oyr/kA11tTUtPm4aDnGlsfg3baiogIulwu9evVCXV2dn99M/MnKysIHH3yA48ePyy6FfBFEQVq5cqUI5b8OAJ/9/G13Op1CURShKIpwuVya+qj3+WprtVrbbK+1PpfL5dkW7HH52mc4/duq0WQyaR5Xq1DGACBWrlwZ1n4/+eQTAUB89NFHYY1DEVHEMxSKWenp6Zg7dy5sNpumN7Sp00DCx5SMxWJBfn4+KisrA46h9ZsBjUZjSN8iGKhGvfsbjUYAwLJlyzSN29Z0Wizo27cvunbtymmvGMVAoZg2dOhQAMDbb78dsF1jY2PA++fNmwez2Yz8/PyAU0AZGRmaawumLdB2jXr3V9tbLJY22wohUFZWBgDNpgEVRYHdbpe6buLNYDBgxIgRXJiPUamyCyAKxPtV9tKlS1vdH8wr5/nz56Ourg6DBg1CfX09evbsqVudgYT76j6U/nV1dSgsLISiKCgoKNDU584778TOnTvRvXt3OJ1OLF++HBUVFUhPTw96/5E0atQoPP/887LLIB94hkJxTfy6CK1l+sloNKKiogLAqXDxXuyPpGBqDLe/Oj01aNAgzJ07F9XV1UEFwsKFCwEAs2bNgqIoMRcmwKmFeYfDgQMHDsguhVpgoFBMUy8bNpvNAdtpnX5KT0+H3W6HzWbDrFmzWl2WHEnBTpGF0l8NH0VRsGHDhqD3kZ6eDqvVCpvNhm+++SaUMiNu5MiRSE1N5bRXDGKgUEzbsWMHAOCaa65ps63Wef7MzExUV1fDZrNpWl/QU7hrEVr7V1RUeKa9gtHU1ISDBw/CYrFg1KhRUTuLC8YZZ5yBAQMGMFBiEAOFYlZTUxOeeuopKIqCnJwczf0aGxvbfCJVFMXzHpV41NYxpqenhxQqy5cvx7x58zxTXgsWLNCjXN1lZWVhy5YtssugFhgoFBXeU0ta/l1XV4dZs2YBgGfdw1e7lhobG7Fo0SJMnDgRADyvsH290p42bVqbU2ne/XyNEexxhdK/JX/H2PLf6enpKC4uRklJCcrLywOebbjdbhQWFnoec6PRiOXLl2PZsmVBn+VEQ1ZWFnbt2oUff/xRdinkLfrvfaF4F+wbG/Hrm+CCuVksFlFbWxvyWOqb+lrefFEUJai6Qz0uPR4XLcfYcl92u73Z4+qrjZbj89U+GNDhjY2qL774QgAQGzdu1GU80kURLxumiBM6vochmLG0tq2urg6pf7jHpcfjomWMzMzMZu3mz5+vaRw9f296u/jii3H++edj69atuPrqq2WXQ7/ilBcRxaVRo0ZxYT7GMFCIKC6NGjUKW7dujekzqWTDQCFKUuF8H0osyMrKwtdff41PP/1Udin0KwYKUZIRLT4OP1p99TZ06FCcfvrp/KDIGMJAIaK4lJaWhqFDhzJQYggDhYjiFr/BMbYwUIgobmVlZWHv3r0x+7ljyYaBQkRx68orrwQAfPDBB5IrIYCBQkRx7JxzzkGPHj34fpQYwUAhorg2YsQIbN++XXYZBAYKEcW54cOH48MPP5R+GTMxUIgozl1xxRX45ptv8I9//EN2KUmPgUJEcW3w4MFo3749PvzwQ9mlJD0GChHFtQ4dOmDAgAFcR4kBDBQiintXXHEFz1BiAL8PhUJWVVUluwQiAKcW5l944QUcO3YMaWlpsstJWgwUCtnUqVNll0AE4NQZytGjR/HJJ59g8ODBsstJWgbBa+2IKM6dPHkSZ511Fv7yl7/g7rvvll1OslrINRQiinspKSkYMmQIF+YlY6AQUULgwrx8DBQiSgjDhw/Hnj178P3338suJWkxUIgoIVxxxRU4efIkdu7cKbuUpMVAIaKEkJGRgXPPPZfrKBIxUIgoYQwfPpyBIhEDhYgShvrJwyQHA4WIEsYVV1yBL7/8Ek6nU3YpSYmBQkQJ44orroDBYOC0lyQMFCJKGF26dMFll13GQJGEgUJECYVvcJSHgUJECYVfCSwPA4WIEor6lcCff/657FKSDgOFiBLK4MGDkZaWhh07dsguJekwUIgooXTo0AG9e/fmR7BIwEAhooQzZMgQBooEDBQiSjgMFDkYKESUcIYMGYIjR47A4XDILiWpMFCIKOEMGjQIKSkpPEuJMgYKESWcTp06oWfPngyUKGOgEFFC4jpK9DFQiCghDRkyhO9FiTIGChElpCFDhsDpdOKf//yn7FKSBgOFiBLSkCFDYDAYeJYSRQwUIkpIRqMRl156KddRooiBQkQJiwvz0cVAIaKExUCJLgYKESWsIUOG4MCBA/yO+ShhoBBRwho6dCgAYNeuXZIrSQ4MFCJKWGeffTYyMjI47RUlqbILICKKJO91FIfDgbq6Onz88cdIT0/HXXfdJbm6xMJAIaKE8/PPP2PPnj2oq6uD0+nErl27cOaZZ+L777/3tFm4cKHEChMTA4WIEkZjYyMmTJiA/fv348SJE2jXrh1SUlJw7NgxHD161NPOYDCgd+/eEitNTFxDIaKEkZGRgcsuuwxCCADAiRMncOzYsVbthBAMlAgwCPWRJyJKAJ9//jl69+7tM0hUBoMBP/zwA04//fQoVpbwFvIMhYgSyqWXXor7778fqan+Z/TPO+88hkkEMFCIKOGYzWZ06dIFBoPB5/39+vWLckXJgYFCRAmnc+fOePzxx30GSvv27RkoEcJAIaKENHPmTPTv37/V1NfJkyfRq1cvSVUlNgYKESWklJQUPP300zh+/Hiz7cePH+cVXhHCQCGihPW73/0ON9xwA9LS0ppt5xlKZPCyYSJKaC0vI+7UqVOzd8yTbnjZMBEltpaXEffs2VNyRYmLgUJECe+RRx6B0WgEAAwYMEByNYmLgUJECe/MM8/EokWLAHD9JJIYKESUFO644w4MGjSIV3hFED9tmIiSQrt27bBkyRJ0795ddikJi4FClCD69u2Lffv2yS6DkkCfPn2wd+/eVtsZKEQJZPLkycjLy5NdBiWwV155BXv27PF5HwOFKIH069cPU6ZMkV0GJbC9e/f6DRQuyhMRkS4YKEREpAsGChER6YKBQkREumCgEBGRLhgoRESkCwYKERHpgoFCRES6YKAQEZEuGChERKQLBgoREemCgUJERLpgoBARkS4YKEREpAsGChER6YKBQkQkmcFgaHYDgKamJlRWViI3N7dZ28LCQhQWFuq+Pz0wUIiSUMsnFC230tJS2Gw2uN3ukMZav36959/+nhBDqSuWboGOITc3F6WlpWhoaPD7exFCQAgBAFiwYAHy8/Nhs9nC+l273e5WoeG9Hz0xUIiSkBACLpfL87PL5fI8yTidTp/bx44di/LychQUFKCpqcnvWGp79VZfXw8AyMnJgcvlgtVqRUlJic9Q8d6/0+n0POlZrdZmY/ral9Vq9dTsq/5ANdbU1LT5uGg5xpbH4N22oqICLpcLvXr1Ql1dnZ/fzG+WLl3qc3txcTGKi4vb7K/atGmT5rZhE0SUEPr06SMWLFgQVB8AwtfTgL/tTqdTKIoiFEURLpdLUx/1Pl9trVZrm+211udyuTzbgj0uX/sMp39bNZpMJk3jBtqfFi6XSyiKErDmYMdfsGCB6NOnj6+7iniGQkSapaenY+7cubDZbJpe+apTLcLH9IrFYkF+fj4qKysDjuFwODTVZjQaNbfVWqPe/Y1GIwBg2bJlIe3L37oKAJSWlsJgMKC8vBxNTU0wGAywWCyeKTO910t8YaAQUVCGDh0KAHj77bcDtmtsbAx4/7x582A2m5Gfnx9wCigjI0NzbcG0BdquUe/+anuLxRLS/mbNmuVzXaW0tBR5eXkQQmDKlCl45plnAKDZ1JiI0LqJNwYKEQWlrVfZ6ivhiy66qM2x5s+fD0VRMGjQoICL1XoLpka9+tfV1WHOnDlQFAUFBQUh7be6utrn9vnz56NDhw4ATv1+/uM//iOk8cPFQCEiXamvhLVMPxmNRlRUVAA49aTovdgfScHUGG5/NXwGDRqEuXPnorq6Gunp6SHt1x+TyYTu3bujsrISbrcb6enpET8b8YWBQkRBUS8bNpvNAdtpnX5KT0+H3W6HzWbDrFmzWl2WHEnBTpGF0l8NH0VRsGHDhrD258/9998PRVGQn5+PLl26oLS0NCL7aQsDhYiCsmPHDgDANddc02Zbra+SMzMzUV1dDZvNFvL6QqjCfSWvtX9FRQXq6urCflOiLz179kR1dTXsdjtMJhPmz58vJVQYKESkWVNTE5566ikoioKcnBzN/RobG9t8IlUUxfMelXjU1jGmp6dHLFQMBgPcbjcyMzOxdOlS2O12zJ8/X9d9aMFAIUpS3lNLWv5dV1eHWbNmAYBn3cNXu5YaGxuxaNEiTJw4EQA86yS+1kumTZvW5lSadz9fYwR7XKH0b8nfMbb8d3p6OoqLi1FSUuK5vNcfX2MEOnaLxeK5iuyss87ynOkpiuJpH/GzlqDe0UJEMSuYNzbi1ze0BXOzWCyitrY25LHUN/W1vPmiKEpQdYd6XHo8LlqOseW+7HZ7s8fVVxtf/QMdt9Pp9IxlsVha7ctsNgun0+lzH8EI9MbG1KDSh4gSgtDxCqBgxtLa1t/lsW31D/e49HhctIyRmZnZrJ2v6Slf4/gbW90+b948zJs3L+C+IolTXkREpAsGChER6YJTXkREMSLczxULdj96Y6AQEUkWrTWOSO+PU15ERKQLBgoREemCgUJERLpgoBARkS4YKEREpAsGChER6YKBQkREumCgEBGRLhgoRESkCwYKERHpgoFCRES6YKAQEZEuDCLan0pGRBHRt29f7Nu3T3YZlAT69OmDvXv3tty8kJ82TJQglixZEvB7z4n0YjQafW7nGQoREelhIddQiIhIFwwUIiLSBQOFiIh08f99GjjbYZVGbQAAAABJRU5ErkJggg==", "text/plain": [ "" ] @@ -140,14 +139,14 @@ "data": { "text/plain": [] }, - "execution_count": 12, + "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\n", - "print(gen)\n", + "print((gen))\n", "gen" ] }, diff --git a/src/astx/flows.py b/src/astx/flows.py index 42aa8c1d..dad44e21 100644 --- a/src/astx/flows.py +++ b/src/astx/flows.py @@ -718,7 +718,7 @@ def __str__(self) -> str: elif isinstance(self.iterator, LiteralTuple): return f"({self.element.value} for {self.target.value} in ({", ".join(str(e.value) for e in self.iterator.elements)}))" elif isinstance(self.iterator, LiteralSet): - return f"({self.element.value} for {self.target.value} in {{{", ".join(str(e.value) for e in self.iterator.elements)}}})" + return f"({self.element.value} for {self.target.value} in {{{", ".join(str(e.value) for e in self.iterator.elements)}}})" elif isinstance(self.iterator, Identifier): return f"({self.element.value} for {self.target.value} in {self.iterator.value})" else: @@ -740,4 +740,4 @@ def get_struct(self, simplified: bool = False) -> ReprStruct: else: value["iterator"] = self.iterator.get_struct(simplified) - return self._prepare_struct(key, value, simplified) \ No newline at end of file + return self._prepare_struct(key, value, simplified) diff --git a/tests/test_flows.py b/tests/test_flows.py index 83837cd6..9900702e 100644 --- a/tests/test_flows.py +++ b/tests/test_flows.py @@ -1,8 +1,14 @@ """Tests for control flow statements.""" +import os,sys +# print(os.path.abspath(os.path.join(os.getcwd(),".", "src"))) +sys.path.insert(0, os.path.abspath(os.path.join(os.getcwd(), ".", "src"))) + import astx import pytest + + from astx.base import SourceLocation from astx.blocks import Block from astx.flows import ( @@ -18,6 +24,7 @@ SwitchStmt, WhileExpr, WhileStmt, + GeneratorExpr, ) from astx.literals import LiteralInt32, LiteralString from astx.literals.numeric import LiteralInt32 @@ -323,3 +330,17 @@ def test_goto_stmt() -> None: assert goto_stmt.get_struct() assert goto_stmt.get_struct(simplified=True) visualize(goto_stmt.get_struct()) + +def test_generator_exp() -> None: + """Test `GeneratorEx` class.""" + gen1 = GeneratorExpr( + astx.Identifier('x*x'), + astx.Identifier('x'), + astx.Identifier("list") + + ) + + assert str(gen1) == '(x*x for x in list)' + assert gen1.get_struct() + assert gen1.get_struct(simplified=True) + visualize(gen1.get_struct()) From 163d50f4a1aa9f078c039dc07d50b4acb9093e99 Mon Sep 17 00:00:00 2001 From: Zehen-249 <1hasanmehendi123@gmail.com> Date: Sun, 16 Mar 2025 09:21:16 +0530 Subject: [PATCH 5/5] add transplier code for generatorExp --- src/astx/__init__.py | 2 ++ src/astx/flows.py | 1 - src/astx/tools/transpilers/python.py | 5 +++++ tests/test_flows.py | 4 ---- tests/tools/transpilers/test_python.py | 16 ++++++++++++++++ 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/astx/__init__.py b/src/astx/__init__.py index f50c6ac6..136955ad 100644 --- a/src/astx/__init__.py +++ b/src/astx/__init__.py @@ -67,6 +67,7 @@ ForRangeLoopExpr, ForRangeLoopStmt, GotoStmt, + GeneratorExpr, IfExpr, IfStmt, SwitchStmt, @@ -241,6 +242,7 @@ def get_version() -> str: "FunctionDef", "FunctionPrototype", "FunctionReturn", + "GeneratorExpr", "GotoStmt", "Identifier", "IfExpr", diff --git a/src/astx/flows.py b/src/astx/flows.py index dad44e21..e409a03c 100644 --- a/src/astx/flows.py +++ b/src/astx/flows.py @@ -730,7 +730,6 @@ def get_struct(self, simplified: bool = False) -> ReprStruct: value: ReprStruct = { "element": self.element.get_struct(simplified), "target": self.target.get_struct(simplified), - # "iterator": self.iterator.get_struct(simplified) } if isinstance(self.iterator, (LiteralList, LiteralTuple, LiteralSet)): value["iterator"] = { diff --git a/src/astx/tools/transpilers/python.py b/src/astx/tools/transpilers/python.py index a15246cd..af64627b 100644 --- a/src/astx/tools/transpilers/python.py +++ b/src/astx/tools/transpilers/python.py @@ -674,3 +674,8 @@ def visit(self, node: astx.LiteralDict) -> str: for key, value in node.elements.items() ) return f"{{{items_code}}}" + + @dispatch # type: ignore[no-redef] + def visit(self, node: astx.GeneratorExpr) -> str: + """Handle GeneratorExr nodes.""" + return f"({self.visit(node.element)} for {self.visit(node.target)} in {self.visit(node.iterator)})".strip() diff --git a/tests/test_flows.py b/tests/test_flows.py index 9900702e..af9a72db 100644 --- a/tests/test_flows.py +++ b/tests/test_flows.py @@ -1,9 +1,5 @@ """Tests for control flow statements.""" -import os,sys -# print(os.path.abspath(os.path.join(os.getcwd(),".", "src"))) -sys.path.insert(0, os.path.abspath(os.path.join(os.getcwd(), ".", "src"))) - import astx import pytest diff --git a/tests/tools/transpilers/test_python.py b/tests/tools/transpilers/test_python.py index 41fe58f3..c28e84bc 100644 --- a/tests/tools/transpilers/test_python.py +++ b/tests/tools/transpilers/test_python.py @@ -1397,3 +1397,19 @@ def test_transpiler_literal_dict() -> None: 1: 10, 2: 20, }, f"Expected '{expected_code}', but got '{generated_code}'" + + def test_generator_expression() -> None: + gen = astx.GeneratorExpr( + astx.Identifier('x*x'), + astx.Identifier('x'), + astx.LiteralList( + list = [ + astx.LiteralInt32(4), + astx.LiteralInt32(1), + astx.LiteralInt32(5) + ] + ) + ) + generated_code = transpiler.visit(gen) + expected_code = "(x*x for x in [4, 1, 5])" + assert generated_code == expected_code , f"expected: {expected_code} ; generated: {generated_code}"