{"id":15540236,"url":"https://github.com/rm-hull/infix","last_synced_at":"2025-04-06T12:09:22.592Z","repository":{"id":27661205,"uuid":"31146889","full_name":"rm-hull/infix","owner":"rm-hull","description":"A Clojure library for expressing LISP expressions as infix rather than prefix notation","archived":false,"fork":false,"pushed_at":"2024-01-31T14:28:25.000Z","size":190,"stargazers_count":106,"open_issues_count":7,"forks_count":12,"subscribers_count":5,"default_branch":"main","last_synced_at":"2024-10-03T12:17:31.187Z","etag":null,"topics":["clojure","infix-expression","infix-notation"],"latest_commit_sha":null,"homepage":"https://www.destructuring-bind.org/infix/","language":"Clojure","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/rm-hull.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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":"2015-02-22T00:26:47.000Z","updated_at":"2024-08-20T20:12:59.000Z","dependencies_parsed_at":"2024-11-03T20:15:30.695Z","dependency_job_id":null,"html_url":"https://github.com/rm-hull/infix","commit_stats":{"total_commits":129,"total_committers":5,"mean_commits":25.8,"dds":0.03100775193798455,"last_synced_commit":"e36e8aa5537014b2d34a99408b10fecb47eae24c"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rm-hull%2Finfix","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rm-hull%2Finfix/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rm-hull%2Finfix/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rm-hull%2Finfix/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rm-hull","download_url":"https://codeload.github.com/rm-hull/infix/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247478323,"owners_count":20945266,"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":["clojure","infix-expression","infix-notation"],"created_at":"2024-10-02T12:13:19.431Z","updated_at":"2025-04-06T12:09:22.561Z","avatar_url":"https://github.com/rm-hull.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Infix\n\n[![Build Status](https://github.com/rm-hull/infix/actions/workflows/clojure.yml/badge.svg)](https://github.com/rm-hull/infix/actions/workflows/clojure.yml)\n[![Coverage Status](https://coveralls.io/repos/rm-hull/infix/badge.svg?branch=main)](https://coveralls.io/r/rm-hull/infix?branch=main)\n[![Downloads](https://versions.deps.co/rm-hull/infix/downloads.svg)](https://versions.deps.co/rm-hull/infix)\n[![Clojars Project](https://img.shields.io/clojars/v/rm-hull/infix.svg)](https://clojars.org/rm-hull/infix)\n[![Maintenance](https://img.shields.io/maintenance/yes/2025.svg?maxAge=2592000)]()\n\nA small Clojure library for representing LISP expressions in infix\nrather than prefix notation... sometimes it's easier to rely on operator precedence,\ninstead of LISP's insistence on parentheses – this is especially true when dealing\nwith mathematical equations.\n\nAn infix expression is rewritten as a prefix expression using a macro. The operator\nprecedence rules were taken from [Wikipedia](https://en.wikipedia.org/wiki/Order_of_operations#Programming_languages).\nAny function calls should _generally_ have parens around the arguments and not the function name. Aliased unary operators\n(as outlined below) do not need parens however.\n\n### Pre-requisites\n\nYou will need [Leiningen](https://github.com/technomancy/leiningen) 2.6.1 or above installed.\n\n### Building\n\nTo build and install the library locally, run:\n\n    $ cd infix\n    $ lein test\n    $ lein install\n\n### Including in your project\n\nThere is a version hosted at [Clojars](https://clojars.org/rm-hull/infix).\nFor leiningen include a dependency:\n\n```clojure\n[rm-hull/infix \"0.4.4\"]\n```\n\nFor maven-based projects, add the following to your `pom.xml`:\n\n```xml\n\u003cdependency\u003e\n  \u003cgroupId\u003erm-hull\u003c/groupId\u003e\n  \u003cartifactId\u003einfix\u003c/artifactId\u003e\n  \u003cversion\u003e0.4.4\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## API Documentation\n\nSee [www.destructuring-bind.org/infix](http://www.destructuring-bind.org/infix/) for API details.\n\n## Basic Usage\n\n```clojure\n(use 'infix.macros)\n; =\u003e nil\n\n(infix 3 + 5 * 8)\n; =\u003e 43\n\n(infix (3 + 5) * 8)\n; =\u003e 64\n```\n\nYou can also use `$=` as a short alias for `infix`, like this for example:\n\n```clojure\n(refer 'infix.macros :only '[$=])\n; =\u003e nil\n\n($= 3 + 5 * 8)\n; =\u003e 43\n```\n\nAll of the examples below should work if you replace `infix` by `$=`.\n\nSome `Math` functions have been aliased (see [below](#aliased-operators--functions)\nfor full list), so nullary and unary-argument functions can be used as follows:\n\n```clojure\n(infix √(5 * 5))\n; =\u003e 5.0\n\n(infix √ 121)\n; =\u003e 11.0\n\n(infix 2 ** 6)\n; =\u003e 64.0\n\n(def t 0.324)\n; =\u003e #'user/t\n\n(infix sin(2 * t) + 3 * cos(4 * t))\n; =\u003e 1.4176457261295824\n\n(infix rand() * 3)\n; =\u003e 0.5544039436207262\n```\n\n#### Debugging\n\nIt may be the case that you encounter some esoteric errors emitted from the\nlibrary trying to rephrase expressions from infix to prefix. Use\n`macroexpand-1` to show how the expression would be rewritten, and if necessary\nfile an [issue](https://github.com/rm-hull/infix/issues/new).\n\n```clojure\n(macroexpand-1 '(infix sin(2 * t) + 3 * cos(4 * t))\n; =\u003e (+ (Math/sin (* 2 t)) (* 3 (Math/cos (* 4 t))))\n```\n\n### Usage in ClojureScript projects\n\nThe `infix` macro may be used to expand infix expressions in ClojureScript code\nby adding the require-macros directive to a namespace, for example:\n\n```clojure\n(ns my.clojurescript.project\n  (:require-macros [infix.macros :refer [infix]]))\n```\n\n### Evaluating infix expressions dynamically from a string\n\nA function can created at runtime from an expression held in a string as\nfollows. When building from a string, a number of binding arguments should be\nsupplied, corresponding to any variable that may be used in the string\nexpression, for example:\n\n```clojure\n(def hypot\n  (from-string [x y]\n    \"sqrt(x**2 + y**2)\"))\n; =\u003e #'user/hypot\n\n(hypot 3 4)\n; =\u003e 5\n\n(meta hypot)\n; =\u003e {:params [:x :y], :doc \"sqrt(x**2 + y**2)\"}\n```\n\n`from-string` is deliberately designed to _look_ like an anonymous function\ndefinition, mainly because that is more-or-less what it is. In effect, this is\nequivalent to creating the following function:\n\n```clojure\n(def hypot\n  (fn [x y]\n    (infix sqrt(x ** 2 + y ** 2))))\n```\n\nHowever, it does so without recourse to `eval` and `read-string` - instead it is\nbuilt using our [old friend](https://github.com/rm-hull/jasentaa), the monadic\nparser-combinator, with an EBNF grammar (implementing the infix notation) and a\nrestricted base environment of math functions, as outlined in the next section.\n\nThe `base-env` may be extended with any number of key/value pairs (where keys\nare keywords) and values may either be values or functions, to provide\nthe required extensions. When referenced in the string it is **not** necessary\nto prefix the name with a colon.\n\n```clojure\n(def extended-env\n  (merge\n    base-env\n    {:rad (fn [deg] (infix deg * π / 180))\n     :hypot hypot}))\n; =\u003e user/extended-env\n\n(def rhs-triangle-height\n  (from-string [base angle]\n    extended-env\n    \"tan(rad(angle)) * base\"))\n; =\u003e user/rhs-triangle-height\n\n(rhs-triangle-height 10 45)\n; =\u003e 9.9999999999998\n```\n\nObviously, a function that was previously created from a string can also\nreferenced in a subsequent function definition:\n\n```clojure\n(def hypot2\n  (from-string [x y]\n    extended-env\n    \"hypot(x, y) ** 2\"))\n; =\u003e user/hypot2\n\n(hypot2 5 12)\n; =\u003e 169.0\n```\n\n### Aliased Operators \u0026 Functions\n\n| Alias   | Operator                |   | Alias  | Operator     |   | Alias | Operator     |\n|---------|-------------------------|---|--------|--------------|---|-------|--------------|\n| \u0026\u0026      | and                     |   | abs    | Math/abs     |   | sin   | Math/sin     |\n| \\|\\|    | or                      |   | signum | Math/signum  |   | cos   | Math/cos     |\n| ==      | =                       |   | \\*\\*   | Math/pow     |   | tan   | Math/tan     |\n| \u003e       | \u003e                       |   | \u003c      | \u003c            |   |       |              |\n| \u003e=      | \u003e=                      |   | \u003c=     | \u003c=           |   |       |              |\n| !=      | not=                    |   | exp    | Math/exp     |   | asin  | Math/asin    |\n| %       | mod                     |   | log    | Math/log     |   | acos  | Math/acos    |\n| \u003c\u003c      | bit-shift-left          |   | e      | Math/E       |   | atan  | Math/atan    |\n| \u003e\u003e      | bit-shift-right         |   | π      | Math/PI      |   | sinh  | Math/sinh    |\n| !       | not                     |   | sqrt   | Math/sqrt    |   | cosh  | Math/cosh    |\n| \u0026       | bit-and                 |   | √      | Math/sqrt    |   | tanh  | Math/tanh    |\n| \\|      | bit-or                  |   | root   | b √ a        |   | sec   | Secant       |\n|         |                         |   | φ      | Golden ratio |   | csc   | Cosecant     |\n| gcd     | Greatest common divisor |   | fact   | Factorial    |   | cot   | Cotangent    |\n| lcm     | Least common multiple   |   | ∑      | Sum          |   | asec  | Arcsecant    |\n| rand    | Random number generator |   | ∏      | Product      |   | acsc  | Arccosecant  |\n| randInt | Random int between 0..n |   |        |              |   | acot  | Arccotangent |\n\n## EBNF Grammar Rules\n\nThe `from-string` macro parses infix expressions based on the EBNF\n[grammar rules](https://github.com/rm-hull/infix/blob/main/src/infix/grammar.clj)\nas follows:\n\n- _**\u0026lt;expression\u0026gt;** ::= term { addop term }._\n\n- _**\u0026lt;term\u0026gt;** ::= factor { mulop factor }._\n\n- _**\u0026lt;factor\u0026gt;** ::= base { expop base }._\n\n- _**\u0026lt;base\u0026gt;** ::= \"(\" expression \")\" | boolean | number | var | function._\n\n- _**\u0026lt;addop\u0026gt;** ::= \"+\" | \"-\" | \"|\" | \"\u0026\" | \"||\" | \"\u0026\u0026\"._\n\n- _**\u0026lt;mulop\u0026gt;** ::= \"\\*\" | \"/\" | \"÷\" | \"%\" | \"\u003e\u003e\" | \"\u003e\u003e\u003e\" | \"\u003c\u003c\"._\n\n- _**\u0026lt;expop\u0026gt;** ::= \"\\*\\*\" ._\n\n- _**\u0026lt;function\u0026gt;** ::= envref expression | envref \"(\" \u0026lt;empty\u0026gt; | expression { \",\" expression } \")\"._\n\n- _**\u0026lt;ternary\u0026gt;** ::= \"(\" expression \")\" \"?\" expression \":\" expression._\n\n- _**\u0026lt;envref\u0026gt;** ::= letter | \"_\" { letter | digit | \"_\"  | \".\" }.\\_\n\n- _**\u0026lt;var\u0026gt;** ::= envref._\n\n- _**\u0026lt;boolean\u0026gt;** ::= \"true\" | \"false\"_\n\n- _**\u0026lt;number\u0026gt;** ::= integer | decimal | rational | binary | hex_\n\n- _**\u0026lt;binary\u0026gt;** :: = [ \"-\" ] \"0b\" { \"0\" | \"1\" }._\n\n- _**\u0026lt;hex\u0026gt;** :: = [ \"-\" ] \"0x\" | \"#\" { \"0\" | ... | \"9\" | \"A\" | ... | \"F\" | \"a\" | ... | \"f\" }._\n\n- _**\u0026lt;integer\u0026gt;** :: = [ \"-\" ] digits._\n\n- _**\u0026lt;decimal\u0026gt;** :: = [ \"-\" ] digits \".\" digits._\n\n- _**\u0026lt;rational\u0026gt;** :: = integer \"/\" digits._\n\n- _**\u0026lt;letter\u0026gt;** ::= \"A\" | \"B\" | ... | \"Z\" | \"a\" | \"b\" | ... | \"z\"._\n\n- _**\u0026lt;digit\u0026gt;** ::= \"0\" | \"1\" | ... | \"8\" | \"9\"._\n\n- _**\u0026lt;digits\u0026gt;** ::= digit { digit }._\n\n## References\n\n- https://en.wikipedia.org/wiki/Order_of_operations#Programming_languages\n\n## License\n\nThe MIT License (MIT)\n\nCopyright (c) 2016 Richard Hull\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of\nthis software and associated documentation files (the \"Software\"), to deal in\nthe Software without restriction, including without limitation the rights to\nuse, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of\nthe Software, and to permit persons to whom the Software is furnished to do so,\nsubject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS\nFOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR\nCOPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER\nIN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\nCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frm-hull%2Finfix","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frm-hull%2Finfix","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frm-hull%2Finfix/lists"}