{"id":13414130,"url":"https://github.com/nullne/evaluator","last_synced_at":"2025-12-15T09:43:42.970Z","repository":{"id":45788376,"uuid":"89628525","full_name":"nullne/evaluator","owner":"nullne","description":null,"archived":false,"fork":false,"pushed_at":"2023-04-14T11:05:55.000Z","size":53,"stargazers_count":42,"open_issues_count":0,"forks_count":8,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-08-14T01:52:51.245Z","etag":null,"topics":["evaluation","evaluator","expression","golang","s-expressions"],"latest_commit_sha":null,"homepage":null,"language":"Go","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/nullne.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":"2017-04-27T18:31:46.000Z","updated_at":"2025-03-17T09:40:33.000Z","dependencies_parsed_at":"2024-06-19T00:07:07.440Z","dependency_job_id":"8d0267b6-fabd-44ae-8097-99800d737aad","html_url":"https://github.com/nullne/evaluator","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/nullne/evaluator","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nullne%2Fevaluator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nullne%2Fevaluator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nullne%2Fevaluator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nullne%2Fevaluator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nullne","download_url":"https://codeload.github.com/nullne/evaluator/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nullne%2Fevaluator/sbom","scorecard":{"id":698407,"data":{"date":"2025-08-11","repo":{"name":"github.com/nullne/evaluator","commit":"bae92dd254176378140491cffed712facb595155"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.5,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":0,"reason":"Found 2/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 2 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-22T04:25:50.849Z","repository_id":45788376,"created_at":"2025-08-22T04:25:50.849Z","updated_at":"2025-08-22T04:25:50.849Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":27748754,"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","status":"online","status_checked_at":"2025-12-15T02:00:09.782Z","response_time":96,"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":["evaluation","evaluator","expression","golang","s-expressions"],"created_at":"2024-07-30T20:01:58.532Z","updated_at":"2025-12-15T09:43:42.909Z","avatar_url":"https://github.com/nullne.png","language":"Go","readme":"[![Build Status](https://travis-ci.org/nullne/evaluator.svg?branch=master)](https://travis-ci.org/nullne/evaluator.svg?branch=master)\n[![Coverage Status](https://coveralls.io/repos/github/nullne/evaluator/badge.svg)](https://coveralls.io/github/nullne/evaluator)\n[![GoDoc](https://godoc.org/github.com/nullne/evaluator?status.svg)](http://godoc.org/github.com/nullne/evaluator)\n[![Go Report Card](https://goreportcard.com/badge/github.com/nullne/evaluator)](https://goreportcard.com/report/github.com/nullne/evaluator)\n\nIt's very common to evaluate an expression dynamicly, so that's why we are here.  \n#### S-expression\nWe use s-epxression syntax to parse and evaluate.\n\u003e In computing, s-expressions, sexprs or sexps (for \"symbolic expression\") are a notation for nested list (tree-structured) data, invented for and popularized by the programming language Lisp, which uses them for source code as well as data. \n\nFor example, for expression in common way:\n​\t\n\t(\n\t\t\t(gender = \"female\")\n\t and  \n\t \t\t((age % 2) != 0)\n\t )\nit's coresponding format in s-expression is:\n​\t\n\t(and\n\t\t(= gender \"female\")\n\t\t(!= \n\t\t\t(% age 2)\n\t\t\t0\n\t\t)\n\t)\n\n#### Element types within expression\n- number  \n  For convenience, we treat float64, int64 and so on as type of number. For example, float `100.0` is equal to int `100`, but not euqal to string `\"100\"`\n\n- string  \n   character string quoted with `` ` ``, `'`, or `\"` are treated as type of `string`. You can convert type `string` to any other defined type you like by type convert functions which are mentioned later\n\n- function or variable  \n    character string without quotes are regarded as type of `function` or `variable` which depends on whether this function exists. For example in expression `(age birthdate)`, both `age` and `birthdate` is unquoted. `age` is type of function because we have registered a function named `age`, while `birthdate` is type of variable for not found. The program will come to errors if there is neither parameter nor function named `birthdate` when evaluating\n\n\n#### How to\nYou can evaluate directly:\n\n    params := evaluator.MapParams{\n        \"gender\": \"female\",\n    }\n    res, err := evaluator.EvalBool(`(in gender (\"female\" \"male\"))`, params)\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Println(res)\n    # true\t\n\nor you can reuse the `Expression` to evaluate multiple times:\n\n    params := evaluator.MapParams{\n        \"gender\": \"female\",\n    }\n    exp, err := evaluator.New(`(in gender (\"female\" \"male\"))`)\n    if err != nil {\n        log.Fatal(err)\n    }\n    res, err := exp.EvalBool(params)\n    if err != nil {\n        log.Fatal(err)\n    }\n    fmt.Println(res)\n    # true\n\n##### And you can write expressions like this\n- `(in gender (\"male\", \"female\"))`\n- `(between now (td_time \"2017-01-02 12:00:00\") (td_time \"2017-12-02 12:00:00\"))`\n- `(ne (mod (age birthdate) 7) 5)`\n- or multiple-line for clarity\n\n  ```\n  (and\n  \t(ne os \"ios\")\n  \t(eq gender \"male\")\n  \t(beteen version (t_version \"2.7.1\") (t_version \"2.9.1\"))\n  )\n  ```\n\n\n#### Functions\n##### Implemented functions\n\n\n| operand | function  | example | description \n| ------- | --------- | ---------- | ----\n| -       | `in`      | `(in 1 (1 2))` | also suport array like `(in (1) ((1)))`\n| -       | `between` | `(between age 18 20)` \n| -       | `overlap` | `(overlap region (3142 1860))` \n| `\u0026`     | `and`     | `(and (eq gender \"femal\") (between age 18 20))`\n| `|`     | `or`      |\n| `!`     | `not`     |\n| `=`     | `eq`      | | equal\n| `!=`    | `ne`      | | not equal\n| `\u003e`     | `gt`      | | greater than\n| `\u003c`     | `lt`      | | less than\n| `\u003e=`    | `ge`      | | greater than or equal to\n| `\u003c=`    | `le`      | | less than or equal to\n| `%`     | `mod`     |\n| `+`     | -         | | plus \n| `-`     | -         | | minus\n| `*`     | -         | | multiply\n| `/`     | -         | | divide\n| -       | `t_version` ||  convert type to version\n| -       | `t_time`    |`(t_time \"2006-01-02 15:04\" \"2017-09-09 12:00\")`| convert type to time, first param must be the layout for the time\n| -       | `td_time` |`(td_time \"2017:09:09 12:00:00)`| convert type to time of default layout format `2006-01-02 15:04:05`\n| _       | `td_date`    |`(in (td_date now) (td_date (\"2017-01-02\" \"2017-02-01\")) )`| convert type to time  of default layout format `2006-01-02`\n\np.s. either operand or function can be used in expression\n##### How to use self-defined functions\nYes, you can write your own function by following thses steps:\n\n1. implement your function\n2. regist to functions\n3. enjoy it\n\nhere is an example:\n\n```go\npackage main\n\n\nimport (\n\t\"errors\"\n\t\"log\"\n\t\"time\"\n\n\t\"github.com/nullne/evaluator\"\n\t\"github.com/nullne/evaluator/function\"\n)\n\n// define your own function and don't forget to register\nfunc age(params ...interface{}) (interface{}, error) {\n\tif len(params) != 1 {\n\t\treturn nil, errors.New(\"only one params accepted\")\n\t}\n\tbirth, ok := params[0].(string)\n\tif !ok {\n\t\treturn nil, errors.New(\"birth format need to be string\")\n\t}\n\tr, err := time.Parse(\"2006-01-02\", birth)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tnow := time.Now()\n\ta := r.Year() - now.Year()\n\tif r.Month() \u003c now.Month() {\n\t\ta--\n\t} else if r.Month() == now.Month() {\n\t\tif r.Day() \u003c now.Day() {\n\t\t\ta--\n\t\t}\n\t}\n\treturn a, nil\n}\n\nfunc main() {\n\tif err := function.Regist(\"age\", age); err != nil {\n\t\tlog.Print(err)\n\t}\n\n\texp := `(not (between (age birthdate) 18 20))`\n\tvvf := evaluator.MapParams{\n\t\t\"birthdate\": \"1980-02-01\",\n\t}\n\te, err := evaluator.New(exp)\n\tif err != nil {\n\t\tlog.Print(err)\n\t}\n\tr, err := e.Eval(vvf)\n\tif err != nil {\n\t\tlog.Print(err)\n\t}\n\tlog.Printf(\"expression: `%s`, wanna: %+v, got: %+v\\r\", exp, true, r)\n}\n```\n\n\n#### Params\n- `Params` interface, which has a method named `Get` to get all params needed\n- `MapParams` a simple implemented `Params` in `map`\n\n#### Bench\n    BenchmarkEqualString-8   \t 3000000\t       473 ns/op\n    BenchmarkInString-8      \t 2000000\t       916 ns/op\n    BenchmarkBetweenInt-8    \t 3000000\t       467 ns/op\n    BenchmarkBetweenTime-8   \t 1000000\t      2089 ns/op\n    BenchmarkOverlapInt-8    \t  500000\t      2966 ns/op\n    BenchmarkTypeTime-8      \t 2000000\t       638 ns/op\n    BenchmarkTypeVersion-8   \t 3000000\t       539 ns/op\n\np.s. on MacBook Pro (Retina, 15-inch, Mid 2015), Memory: 16 GB 1600 MHz DDR3, Processor: 2.2 GHz Intel Core i7\n","funding_links":[],"categories":["Utilities","公用事业公司","工具库","工具库`可以提升效率的通用代码库和工具`","Utility","实用工具"],"sub_categories":["Utility/Miscellaneous","Fail injection","实用程序/Miscellaneous","HTTP Clients","查询语","Advanced Console UIs","交流","\u003cspan id=\"高级控制台用户界面-advanced-console-uis\"\u003e高级控制台用户界面 Advanced Console UIs\u003c/span\u003e"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnullne%2Fevaluator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnullne%2Fevaluator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnullne%2Fevaluator/lists"}