{"id":19032755,"url":"https://github.com/joutvhu/expansy","last_synced_at":"2026-06-18T06:31:39.867Z","repository":{"id":142269786,"uuid":"598522463","full_name":"joutvhu/expansy","owner":"joutvhu","description":"An expression analyzer that allows you to define expression elements of your design.","archived":false,"fork":false,"pushed_at":"2023-07-28T07:00:52.000Z","size":404,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-21T20:36:46.987Z","etag":null,"topics":["analysis","engine","expression","expression-parser","parser"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/joutvhu.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2023-02-07T09:34:16.000Z","updated_at":"2023-08-30T09:30:35.000Z","dependencies_parsed_at":"2023-08-18T02:21:32.061Z","dependency_job_id":null,"html_url":"https://github.com/joutvhu/expansy","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/joutvhu/expansy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joutvhu%2Fexpansy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joutvhu%2Fexpansy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joutvhu%2Fexpansy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joutvhu%2Fexpansy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/joutvhu","download_url":"https://codeload.github.com/joutvhu/expansy/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/joutvhu%2Fexpansy/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34479552,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["analysis","engine","expression","expression-parser","parser"],"created_at":"2024-11-08T21:30:57.861Z","updated_at":"2026-06-18T06:31:39.849Z","avatar_url":"https://github.com/joutvhu.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Expansy\n\nExpansy is an expression analyzer that allows you to declare expression elements of your design.\n\n## Installation\n\n- If you are using Gradle just add the following dependency to your `build.gradle`.\n\n```groovy\nimplementation \"com.github.joutvhu:expansy:1.0.2\"\n```\n\n- Or add the following dependency to your `pom.xml` if you are using Maven.\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.github.joutvhu\u003c/groupId\u003e\n    \u003cartifactId\u003eexpansy\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.2\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n## How to use?\n\nFirst you need to define the elements of your design.\nThe elements need to implement the interface `com.joutvhu.expansy.element.Element`.\n\n```java\npublic class NumberElement implements Element\u003cBigDecimal\u003e {\n    @Override\n    public String name() {\n        return \"Number\";\n    }\n\n    @Override\n    public void define(Definer\u003cBigDecimal\u003e definer) {\n        definer\n                .name(\"value\")\n                .numeric();\n    }\n\n    @Override\n    public BigDecimal render(Node\u003cBigDecimal\u003e node) {\n        String value = node.getString(\"value\");\n        return new BigDecimal(value);\n    }\n}\n```\n\nEach element need to implement `define` and `render` methods.\n- The `define` method is used to declare the structure of the element. Use the [match functions](#match-functions) below to define the structure.\n- The `render` method is used to create the result object based on the analyzed node.\n- Also, you can override the `name` method to name the element (_optional_). If you don't overwrite the default is the name of the element class.\n\nAfter you have created the elements, register them and use.\n```java\nExpansy\u003cBigDecimal\u003e expansy = Expansy\n        .instance()\n        ... // register other elements\n        .register(new NumberElement());\n\nBigDecimal result = expansy.useAll().parseSingle(\"5 + 5 * 3\");\n```\n\n## Match functions\n\n### `size`\n\nUsed to match a string of characters of the specified length.\n\n- `size(int length)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.size(5);\n}\n```\n\n### `character`\n\nUsed to match specified characters.\n\n- `character(char... characters)` match one character contained in the `characters` array.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.character('a', 'b');\n}\n```\n\n- `characters(char... characters)` match multiple characters contained in the `characters` array.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.characters('1', '2', '3');\n}\n```\n\n- `characters(char[] characters, int length)` match `{length}` characters, each of which must be contained in the `characters` array.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.characters(new char[]{'1', '2', '3'), 10);\n}\n```\n\n- `characters(char[] characters, Integer minLength, Integer maxLength)` match a minimum of `{minLength}` characters and a maximum of `{maxLength}` characters, each of which must be contained in the `characters` array.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.characters(new char[]{'1', '2', '3'), 10, 20);\n}\n```\n\n### `space`\n\nUsed to match space character.\n\n- `space()` match one space character.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.space();\n}\n```\n\n- `spaces()` match multiple space characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.spaces();\n}\n```\n\n- `spaces(int length)` match `{length}` space characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.spaces(10);\n}\n```\n\n- `spaces(Integer minLength, Integer maxLength)` match a minimum of `{minLength}` space characters and a maximum of `{maxLength}` space characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.spaces(10, 20);\n}\n```\n\n### `whitespace`\n\nUsed to match any whitespace character (spaces, tabs, line breaks).\n\n- `whitespace()` match one whitespace character.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.whitespace();\n}\n```\n\n- `whitespaces()` match multiple whitespace characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.whitespaces();\n}\n```\n\n- `whitespaces(int length)` match `{length}` whitespace characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.whitespaces(10);\n}\n```\n\n- `whitespaces(Integer minLength, Integer maxLength)` match a minimum of `{minLength}` whitespace characters and a maximum of `{maxLength}` whitespace characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.whitespaces(10, 20);\n}\n```\n\n### `digit`\n\nUsed to match any digit character (0-9).\n\n- `digit()` match one digit character.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.digit();\n}\n```\n\n- `digits()` match multiple digit characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.digits();\n}\n```\n\n- `digits(int length)` match `{length}` digit characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.digits(10);\n}\n```\n\n- `digits(Integer minLength, Integer maxLength)` match a minimum of `{minLength}` digit characters and a maximum of `{maxLength}` digit characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.digits(10, 20);\n}\n```\n\n### `lowercase`\n\nUsed to match any lowercase character.\n\n- `lowercase()` match one lowercase character.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.lowercase();\n}\n```\n\n- `lowercases()` match multiple lowercase characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.lowercases();\n}\n```\n\n- `lowercases(int length)` match `{length}` lowercase characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.lowercases(10);\n}\n```\n\n- `lowercases(Integer minLength, Integer maxLength)` match a minimum of `{minLength}` lowercase characters and a maximum of `{maxLength}` lowercase characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.lowercases(10, 20);\n}\n```\n\n### `uppercase`\n\nUsed to match any uppercase character.\n\n- `uppercase()` match one uppercase character.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.uppercase();\n}\n```\n\n- `uppercases()` match multiple uppercase characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.uppercases();\n}\n```\n\n- `uppercases(int length)` match `{length}` uppercase characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.uppercases(10);\n}\n```\n\n- `uppercases(Integer minLength, Integer maxLength)` match a minimum of `{minLength}` uppercase characters and a maximum of `{maxLength}` uppercase characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.uppercases(10, 20);\n}\n```\n\n### `alphabet`\n\nUsed to match any alphabet character.\n\n- `alphabet()` match one alphabet character.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.alphabet();\n}\n```\n\n- `alphabets()` match multiple alphabet characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.alphabets();\n}\n```\n\n- `alphabets(int length)` match `{length}` alphabet characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.alphabets(10);\n}\n```\n\n- `alphabets(Integer minLength, Integer maxLength)` match a minimum of `{minLength}` alphabet characters and a maximum of `{maxLength}` alphabet characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.alphabets(10, 20);\n}\n```\n\n### `alphanumeric`\n\nUsed to match any alphanumeric character.\n\n- `alphanumeric()` match one alphanumeric character.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.alphanumeric();\n}\n```\n\n- `alphanumerics()` match multiple alphanumeric characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.alphanumerics();\n}\n```\n\n- `alphanumerics(int length)` match `{length}` alphanumeric characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.alphanumerics(10);\n}\n```\n\n- `alphanumerics(Integer minLength, Integer maxLength)` match a minimum of `{minLength}` alphanumeric characters and a maximum of `{maxLength}` alphanumeric characters.\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.alphanumerics(10, 20);\n}\n```\n\n### `numeric`\n\nUsed to match a numeric.\n\n- `numeric()`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.numeric();\n}\n```\n\n### `word`\n\nUsed to match a word (any alphanumeric or underscore).\n\n- `word()`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.word();\n}\n```\n\n### `quote`\n\nUsed to match a quote.\n\n- `quote()`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.quote();\n}\n```\n\n- `quote(char... types)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.quote('\"');\n}\n```\n\n### `equalsWith`\n\nUsed to match the specified strings.\n\n- `equalsWith(String value)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.equalsWith(\"abc\");\n}\n```\n\n- `equalsWith(String... values)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.equalsWith(\"abc\", \"123\");\n}\n```\n\n- `equalsWith(List\u003cString\u003e values)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.equalsWith(Arrays.asList(\"abc\", \"123\"));\n}\n```\n\n### `equalsIgnoreCase`\n\nUsed to match the specified strings but ignore case.\n\n- `equalsIgnoreCase(String value)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.equalsIgnoreCase(\"abc\");\n}\n```\n\n- `equalsIgnoreCase(String... values)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.equalsIgnoreCase(\"abc\", \"123\");\n}\n```\n\n- `equalsIgnoreCase(List\u003cString\u003e values)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.equalsIgnoreCase(Arrays.asList(\"abc\", \"123\"));\n}\n```\n\n### `pattern`\n\nUsed to match a specified pattern.\n\n- `pattern(String regex)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.pattern(\"^-?[0-9]+(\\\\.[0-9]+)?$\");\n}\n```\n\n- `pattern(String regex, int length)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.pattern(\"^-?[0-9]+(\\\\.[0-9]+)?$\", 16);\n}\n```\n\n- `pattern(String regex, Integer minLength, Integer maxLength)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.pattern(\"^-?[0-9]+(\\\\.[0-9]+)?$\", 12, 32);\n}\n```\n\n- `pattern(Pattern pattern)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.pattern(Pattern.compile(\"^-?[0-9]+(\\\\.[0-9]+)?$\", 0));\n}\n```\n\n- `pattern(Pattern pattern, int length)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.pattern(Pattern.compile(\"^-?[0-9]+(\\\\.[0-9]+)?$\", 0), 16);\n}\n```\n\n- `pattern(Pattern pattern, Integer minLength, Integer maxLength)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.pattern(Pattern.compile(\"^-?[0-9]+(\\\\.[0-9]+)?$\", 0), 12, 32);\n}\n```\n\n### `match`\n\nUse a matcher to match.\n\n- `match(MatchFunction\u003cE\u003e matcher)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.match(new ArrayMatcher());\n}\n```\n\n### `check`\n\nUse a method to match.\n\n- `check(Function\u003cString, Boolean\u003e checker)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.check(value -\u003e {\n        if (value == null || value.length() \u003e 3)\n            return false;\n        if (\"abc\".equalsWith(value))\n            return true;\n        return null;\n    });\n}\n```\n\n- `check(Function\u003cString, Boolean\u003e checker, int length)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.check(value -\u003e {\n        return \"abc\".equalsWith(value);\n    }, 3);\n}\n```\n\n- `check(Function\u003cString, Boolean\u003e checker, Integer minLength, Integer maxLength)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.check((String value) -\u003e {\n        if (value != null \u0026\u0026 value.startsWith(\"{\")) {\n            if (value.endsWith(\"}\"))\n                return true;\n            return null;\n        }\n        return false;\n    }, 3, 5);\n}\n```\n\n### `element`\n\nUsed to match the provided elements.\n\n- `element(Element\u003cE\u003e element)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.element(new NumberElement());\n}\n```\n\n- `element(Element\u003cE\u003e... elements)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.element(new MultiplyElement(), new DivisionElement());\n}\n```\n\n- `element(List\u003cElement\u003cE\u003e\u003e elements)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.element(Arrays.asList(new MultiplyElement(), new DivisionElement()));\n}\n```\n\n### `elements`\n\nUsed to match all registered elements.\n\n- `elements()`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.elements();\n}\n```\n\n### `include`\n\nUsed to match the listed elements.\n\n- `include(String element)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.include(\"Number\");\n}\n```\n\n- `include(String... elements)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.include(\"Add\", \"Subtract\");\n}\n```\n\n- `include(List\u003cString\u003e elements)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.include(Arrays.asList(\"Add\", \"Subtract\"));\n}\n```\n\n### `exclude`\n\nUsed to match registered elements except those listed.\n\n- `exclude(String element)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.exclude(\"Number\");\n}\n```\n\n- `exclude(String... elements)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.exclude(\"Add\", \"Subtract\");\n}\n```\n\n- `exclude(List\u003cString\u003e elements)`\n```java\npublic void define(Definer\u003cObject\u003e definer) {\n    definer.exclude(Arrays.asList(\"Add\", \"Subtract\"));\n}\n```\n\n### `maybe`\n\nUsed to define a matcher group that may or may not appear.\n\nSyntax:\n```\ndefiner\n    .maybe()\n    ... // content may or may not be appear\n    .end()\n```\n\n### `options`\n\nCould match with a group in the matcher groups.\n\nSyntax:\n```\ndefiner\n    .options()\n    ... // case 1\n    .or()\n    ... // case 2\n    .or()\n    ... // case 3\n    .end()\n```\n\nYou can declare as many cases as you want.\nThe cases at the top will take precedence.\n\n```java\npublic class GroupMultiply implements Element\u003cBigDecimal\u003e {\n    @Override\n    public void define(Definer\u003cBigDecimal\u003e definer) {\n        definer\n            .options()\n                .name(\"first\")\n                .include(\"Group\")\n                .name(\"second\")\n                .include(\"Number\")\n            .or()\n                .name(\"first\")\n                .include(\"Number\")\n                .name(\"second\")\n                .include(\"Group\")\n            .or()\n                .name(\"first\")\n                .include(\"Group\")\n                .name(\"second\")\n                .include(\"Group\")\n            .end();\n    }\n    ...\n}\n```\n\n### `loop`\n\nUsed to define a matcher group it is repeatable.\n\nSyntax:\n```\ndefiner\n    .loop()\n    ... // repeatable content\n    .end()\n```\n\nThe following are variations of the `loop()` function:\n- `loop()` the minimum number of repetitions is 0 and unlimited number of repetitions.\n- `loop(int repetitions)` used to indicate the exact number of repetitions.\n- `loop(int minRepetitions, Integer maxRepetitions)` used to indicate the minimum and maximum number of repetitions.\n\n```java\npublic class VariableElement implements Element\u003cObject\u003e {\n    @Override\n    public void define(Definer\u003cObject\u003e definer) {\n        definer\n            .equalsWith(\"$\")\n            .name(\"name\")\n            .word()\n            .loop()\n                .options()\n                    .character('.')\n                    .name(\"child\")\n                    .word()\n                .or()\n                    .equalsWith(\"[\")\n                    .name(\"child\")\n                    .quote('\\'')\n                    .equalsWith(\"]\")\n                .end()\n            .end();\n    }\n    ...\n}\n```\n\n### `between`\n\nUsed to define a matcher group it can repeat and be interspersed by another matcher group.\n\nSyntax:\n```\ndefiner\n    .between()\n    ... // content to separate\n    .is()\n    ... // define separator here\n    .end()\n```\n\nThe following are variations of the `between()` function:\n- `between()` the minimum number of repetitions is 0 and unlimited number of repetitions.\n- `between(int repetitions)` used to indicate the exact number of repetitions.\n- `between(int minRepetitions, Integer maxRepetitions)` used to indicate the minimum and maximum number of repetitions.\n\nThe following example uses `between` to define function parameters separated by commas.\n```java\npublic class FunctionElement implements Element\u003cBigDecimal\u003e {\n    @Override\n    public void define(Definer\u003cBigDecimal\u003e definer) {\n        definer\n            .equalsWith(\"#\")\n            .name(\"name\")\n            .word()        // Function name\n            .equalsWith(\"(\")\n            .between()\n                .spaces()\n                .name(\"param\")\n                .elements()    // The parameter can be any element\n                .spaces()\n            .is()\n                .equalsWith(\",\")   // There is a comma between the parameters\n            .end()\n            .equalsWith(\")\");\n    }\n    ...\n}\n```\n\n## Render\n\nThe `render` method is used to generate the result of the expression. The `render` method will receive a `Node`.\n\nThe `Node` is the result of the expression string after being analysed, you can use it to get parts of expression.\nThe `Node` represents only part of an expression, not the entire input expression.\n\nUse the `name(String name)` function to name parts of an expression and then get it in `render` method.\n\n```java\npublic class Add implements Element\u003cBigDecimal\u003e {\n    @Override\n    public void define(Definer\u003cBigDecimal\u003e definer) {\n        definer\n                .name(\"first\")\n                .elements()\n                .spaces()\n                .equalsWith(\"+\")\n                .spaces()\n                .name(\"second\")\n                .exclude(\"Add\", \"Subtract\");\n    }\n\n    @Override\n    public BigDecimal render(Node\u003cBigDecimal\u003e node) {\n        BigDecimal first = node.getNode(\"first\").render();\n        BigDecimal second = node.getNode(\"second\").render();\n        return first.add(second);\n    }\n}\n```\n\nThe structure of `Node` is similar to a tree, it can contain child Nodes.\nA node's children can be another node or a string.\n\n```java\npublic class MultiplyOrDivision implements Element\u003cBigDecimal\u003e {\n    @Override\n    public void define(Definer\u003cBigDecimal\u003e definer) {\n        definer\n                .name(\"first\")\n                .exclude(\"AddOrSubtract\")\n                .spaces()\n                .name(\"operator\")\n                .equalsWith(\"/\", \"*\")\n                .spaces()\n                .name(\"second\")\n                .exclude(\"AddOrSubtract\", \"MultiplyOrDivision\");\n    }\n\n    @Override\n    public BigDecimal render(Node\u003cBigDecimal\u003e node) {\n        BigDecimal first = node.getNode(\"first\").render();\n        BigDecimal second = node.getNode(\"second\").render();\n        String operator = node.getString(\"operator\");\n        if (\"*\".equalsWith(operator))\n            return first.multiply(second);\n        else\n            return first.divide(second);\n    }\n}\n```\n\n# Branch\n\nA `Branch` represents a way of arranging the elements to match the input expression.\nA `Branch` can contain one or more Nodes.\n\nThe expression analyzing can return multiple branches.\n`BranchSelector` is used to select a branch when you call`parse` or `parseSingle`.\n\n```java\nList\u003cBranch\u003cBigDecimal\u003e\u003e branchs = expansy.useAll().analysis(\"8 - 3 + 3\");\n```\n\nIf you define addition like this\n```java\npublic void define(Definer\u003cBigDecimal\u003e definer) {\n    definer\n        .name(\"first\")\n        .elements()\n        .spaces()\n        .name(\"operator\")\n        .equalsWith(\"+\")\n        .spaces()\n        .name(\"second\")\n        .elements();\n}\n```\nAnd use it to analysis the expression `1 + 2 + 3`, you can get 2 branches:\n```\nBranch1:\n- Node:+\n  - Node:+\n    - Node:1\n    - Node:2\n  - Node:3\n\nBranch2:\n- Node:+\n  - Node:1\n  - Node:+\n    - Node:2\n    - Node:3\n```\n\nTo apply the precedence of the operation you can use `exclude()` instead of `elements()` to exclude some elements at `first` or `second`.\nSee examples in the [Render](#render) section.\nUse the following rule:\n- The `first` will exclude operations with lower precedence than the current operation.\n- The `second` will exclude operations with lower or equal (because the priority is left-to-right) precedence than the current operation.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoutvhu%2Fexpansy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjoutvhu%2Fexpansy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjoutvhu%2Fexpansy/lists"}