{"id":19838990,"url":"https://github.com/objectionary/eo2py","last_synced_at":"2025-05-01T18:31:46.944Z","repository":{"id":48904525,"uuid":"373900298","full_name":"objectionary/eo2py","owner":"objectionary","description":"Translates EOLANG to Python","archived":true,"fork":false,"pushed_at":"2025-04-02T20:04:30.000Z","size":227,"stargazers_count":9,"open_issues_count":22,"forks_count":2,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-15T07:19:32.418Z","etag":null,"topics":["compiler","eolang","python"],"latest_commit_sha":null,"homepage":"","language":"XSLT","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/objectionary.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-06-04T16:26:12.000Z","updated_at":"2025-04-12T02:37:03.000Z","dependencies_parsed_at":"2023-01-21T06:02:17.761Z","dependency_job_id":"a80426d3-c7ce-4b43-b591-f5aeef25ff33","html_url":"https://github.com/objectionary/eo2py","commit_stats":{"total_commits":232,"total_committers":4,"mean_commits":58.0,"dds":"0.18534482758620685","last_synced_commit":"dab4fb1cf426e50be49c65c66de88b08a171ad6a"},"previous_names":["polystat/eo2py"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/objectionary%2Feo2py","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/objectionary%2Feo2py/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/objectionary%2Feo2py/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/objectionary%2Feo2py/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/objectionary","download_url":"https://codeload.github.com/objectionary/eo2py/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251924801,"owners_count":21666039,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["compiler","eolang","python"],"created_at":"2024-11-12T12:19:50.654Z","updated_at":"2025-05-01T18:31:46.050Z","avatar_url":"https://github.com/objectionary.png","language":"XSLT","funding_links":[],"categories":[],"sub_categories":[],"readme":"# eo2py\n\n![build](https://github.com/polystat/eo2py/actions/workflows/maven.yml/badge.svg) [![codecov](https://codecov.io/gh/nikololiahim/eo-python/branch/main/graph/badge.svg?token=CuHSiScipH)](https://codecov.io/gh/nikololiahim/eo-python)\n\nA Python implementation of [EO](https://github.com/cqfn/eo).\n\n## This repository contains:\n* Transcompiler\n    * Maven plugin that transforms `.eo` programs into `.py` programs using XSLT.\n* Python runtime environment\n    * Implementation of atoms and data objects as a [pip package](https://pypi.org/project/eo2py/).\n* Examples of translated programs in [`eo-python-runtime/tests/example_programs`](https://github.com/polystat/eo2py/tree/main/eo-python-runtime/tests/example_programs) as `pytest` unit tests.\n* [Sandbox](https://github.com/polystat/eo2py/tree/main/sandbox) to compile and execute your own EO programs! \n## How to use\nCheck out `README.md` in [`sandbox`](https://github.com/polystat/eo2py/tree/main/sandbox) directory.\n\n\n## Supported features:\n* Abstraction\n* Positional application\n* Decoration (nested decoration, free decoratees)\n* Dataization\n* Inner objects, both closed and abstract\n* Varargs\n* Arrays\n\n\n## Unsupported features:\n* Metas\n* Dataize Once (`!`)\n* `memory` atom\n* Regexes\n* Arbitrary partial application, argument labels\n* `@` with free attributes\n* Anonymous abstract objects (as arguments to copying)\n* Maybe some more (whenever you experience a bug, feel free to submit an issue)\n\n\n\n\n\n## Code mappings\n\n### Abstraction\n\nAt the time of declaration, abstract and closed objects map to classes. In `__init__()` method, special (`@`, `$`, and `^`) attributes are created, and free attributes are initialized to `DataizationError()` ([more about this](#DataizationError)). Bound attributes become methods decorated with `@property`.\nProjections of object and attribute names get prefixes `EO` and `attr_` correspondingly to avoid name collisions between user-defined and inner entities.\n\n```=\n[isbn] \u003e book\n  \"Object Thinking\" \u003e title\n```\n\n```python\nclass EObook(ApplicationMixin, Object):\n    \n    def __init__(self):\n        # corresponds to `$`\n        self.attr__self = self \n        \n        # corresponds to `^`\n        self.attr__parent = DataizationError()\n        \n        # corresponds to `@`\n        self.attr__phi = DataizationError()\n        \n        # corresponds to `isbn`\n        self.attr_isbn = DataizationError()\n        \n        self.attributes = [\"isbn\", ]\n    \n    # corresponds to `title` bound attribute\n    @property\n    def attr_title(self):\n        return (String(\"Object Thinking\"))\n```\n\n#### Inner Objects \nAttribute might be tied to an abstract object. Our translation model utilizes classes and `partial()` method defined in `functools` (Python standard library package) to specify `^` a.k.a. `attr__parent` object:\n```\n[x y] \u003e point\n  [to] \u003e distance\n    length. \u003e @\n      vector\n        to.x.sub (^.x)\n        to.y.sub (^.y)\n```\n\n\n```python\nclass EOpoint(ApplicationMixin, Object):\n\n    def __init__(self):\n        # omitted for brevity \n        self.attributes = [\"x\", \"y\", ]\n\n    @property\n    def attr_distance(self):\n        return partial(EOpointEOdistance, self)\n        \n\nclass EOpointEOdistance(ApplicationMixin, Object):\n\n    def __init__(self, attr__parent):\n        # omitted for brevity\n        self.attributes = [\"to\", ]\n\n    @property\n    def attr__phi(self):\n        return (Attribute(\n                   (EOvector()\n                       (Attribute((Attribute((self.attr_to), \"x\")), \"sub\")\n                            (Attribute((self.attr__parent), \"x\")))\n                       (Attribute((Attribute((self.attr_to), \"y\")), \"sub\")\n                            (Attribute((self.attr__parent), \"y\")))),\n                \"length\"))\n\n```\n\n### Decoration\nFunctionality of decoration is achieved via `attr__phi` attribute combined with class-wrapper `Attribute`.\nWhenever specific attribute is needed, `dataize()` in `Attribute` searches for the attribute in object itself; upon failure recursively searches for it in object bound to `attr__phi`.\n\n```=\n[] \u003e a\n  \"nothing else matters\" \u003e a_message\n\n[] \u003e b\n  a \u003e @\n  \n[] \u003e c\n  b.a_message \u003e c_message\n```\n\n```python\nclass EOa(ApplicationMixin, Object):\n    \n    def __init__(self):\n        # special \u0026 free attributes handling\n    \n    @property\n    def attr_a_message(self):\n        return (String(\"nothing else matters\"))\n    \n\nclass EOb(ApplicationMixin, Object):\n    \n    def __init__(self):\n        # special \u0026 free attributes handling\n        \n    @property\n    def attr__phi(self):\n        return (EOa())\n        \n\n\nclass EOc(ApplicationMixin, Object):\n    \n    def __init__(self):\n        # special \u0026 free attributes handling\n    \n    @property\n    def attr_c_message(self):\n        return (Attribute((EOb()), \"a_message\"))\n```\n\n\n\n\n### Application\n\nBeing a copy of objects in EO with some arguments, application is class instantiation in Python. Current implementation supports only full positional application (in absence of free attributes in decoratee) as overwritten `__call__()` methods. In order to apply some argument to an object you need to `__call__()` an object with this argument. `__call__()` return an object itself, which means that these 'applications' can be chained as follows:\n\n```=\nobj(arg1)(arg2)(arg3)...\n```\n\nThe particular implementation of `__call__()` is injected into each `Object` with the `ApplicationMixin` class defined in [atoms.py](https://github.com/polystat/eo2py/blob/main/eo-python-runtime/src/eo2py/atoms.py), whom all classes inherit from:\n\n```=\n[truth_value] \u003e answer\n  truth_value.if \"yes\" \"no\" \u003e @\n```\n\n```python\nclass EOanswer(ApplicationMixin, Object):\n    \n    def __init__(self):\n        # special attributes\n        \n        self.attributes = [\"truth_value\", ]\n    \n    @property\n    def attr__phi(self):\n        return (Attribute((self.attr_truth_value), \"if\")\n                   (String(\"yes\"))\n                   (String(\"no\")))\n```\n\n#### Varargs\nAs per [EO paper](https://github.com/cqfn/eo/tree/master/paper), all the varargs are packaged into an `Array` atom and can be accessed by index using `get` attribute:\n\n```=\n[arg1, arg2, varargs...] \u003e obj\n  stdout \u003e @\n    sprintf\n      \"%d %d %d\"\n      get.\n        varargs\n        3\n      arg1\n      arg2\n```\n\n```python\nclass EOobj(ApplicationMixin, Object):\n    def __init__(self):\n        # Free attributes\n        self.attr__parent = DataizationError()\n        self.attr__self = self\n\n        self.attributes = [\"arg1\", \"arg2\", \"varargs\"]\n        self.attr_arg1 = DataizationError()\n        self.attr_arg2 = DataizationError()\n        self.attr_varargs = Array()\n        self.varargs = True\n\n    @property\n    def attr__phi(self):\n        return Stdout()(\n                   Sprintf()\n                       (String(\"%d %d %d\"))\n                       (Attribute(self.attr_varargs, \"get\")\n                           ((Number(3)))\n                       (self.attr_arg1)\n                       (self.attr_arg2)\n        )\n\n```\n\n\n### Dataization\nAll classes (think, abstract objects), both auto-generated and atomic, implement an `Object` interface with only one method - `dataize()`. This method is responsible for reducing a complex object to some `Atom` object. The `Atom` object, in turn, can not be dataized any further and will simply return itself whenever it receives a dataization request. \n\n```python\nclass Atom(Object):\n\n    def dataize(self):\n        return self\n        \n    @abstractmethod\n    def data(self):\n        raise NotImplementedError()\n```\n\nYou can query the actual data associated with the `Atom` object by calling its `data()` method. This method will return the actual Python data (`str`, `int`, `object` or `None`), whereas `dataize()` only returns an `Atom` object.\n\nThe dataization process can be summed up as follows:\n* If an auto-generated `Object` is dataized, it returns `self.attr__phi.dataize()`\n* If an atomic `Object` (e.g. `Attrubute`) is dataized, it returns some `Atom` based on its internal implementation, potentially with some side effects (`Stdout`).\n* If an `Atom` is dataized, it returns itself.\n\nIf for some reason an object does not define `attr__phi` attribute, then its dataization would result in an `AttributeError`.\n\n#### `DataizationError`\nAll the uninitialized free attributes are initialized as a special `DataizationError` object. As its name suggests, an attempt to `dataize()` it would yield a runtime exception in Python, resulting in immediate termination of the program. Attributes initialized with `DataizationError` are intended to be assigned some value at runtime.\n\n\n\u003c!-- ## Justification of design decisions --\u003e\n\u003c!-- мне эта секция кажется немного лишней если честно, мне кажется что примеры говорят сами за себя\n**bruh**\nхм, ну ок, можно написать что у нас был итеративный дизайн, TDD и все такое, и что мы пришли к этим идеям путем проб и ошибок (как и было на самом деле)\nда, там просто вот:\n- Описать подход к реализации проекций, а также обоснование сделанных проектных решений - тоже краткий документ.\nНУ КОНЕЧНО МОЖНО УБРАТЬ\nесли ему интересна мотивация, пусть предыдущий док читает\n\n\nокей да.\nкстати, когда будет с ним встреча????\nз****? надо спросить\nможно скинуть ридми и он призовется\nлан, все, убираем эту секцию к \nе****? дададад, сегодня допишем и скинем сразу же\nв polystat тоже можно скинуть, пусть посмотрят\nда!\nтупо пасхалка\nахаха\nшизаа--\u003e\n\u003c!-- The mapping abstract objects -\u003e Python classes, closed objects -\u003e Python objects seemed natural at first.\nМБ убрать это вообще?\n\nFree attributes - not in init, see application\n\nBound attributes decorated with @property to simulate declarative behavior (in particular, to avoid compile time recursion in creation of fibonacci objects)\n\nInner Objects -\u003e existing parser\n\ndataize() everywhere to account for \"every object has a special $\\delta$ attribute\"\nIf obj does not have it, maybe \n --\u003e\n\u003c!--`Attribute` object exists for multiple reasons:\n* It encapsulates attribute lookup logic, deferring the Python's default lookup mechanism. \n* \n\nApplication as `__call__` methods — to ease translation in XSLT sheets\n\nSpecial $\\varphi$ attribute instead of inheritance mainly because of impossibility of dynamic inheritance in the latter approach\n--\u003e\n\n\n## Further considerations\n\nWe are yet to come up with examples of:\n* Partial application\n* Application of abstract object\n* Accessing the free attributes of decoratees (O_o)\n\nIf you have an example of programs using such constructs of EO, feel free to submit an issue, then we'll see what we can do about it. \n\n### A note on partial application\nWe are thinking of a different way to achieve functionality of the partial application other than object instantiation. The reason is that instantiation in Python makes an object out of class, which is  structurally different, whilst objects in EO, as a set, 'are closed' under operation of application.\nSo idea is to either work with objects or classes ([proof of concept drafts](https://gist.github.com/eyihluyc/c5f7c481ad6c97c5b8d131addba710ec) for classes)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fobjectionary%2Feo2py","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fobjectionary%2Feo2py","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fobjectionary%2Feo2py/lists"}