Showing preview only (2,938K chars total). Download the full file or copy to clipboard to get everything.
Repository: expr-lang/expr
Branch: master
Commit: b90e77c64fb9
Files: 230
Total size: 2.8 MB
Directory structure:
gitextract_ewtnex4r/
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── images/
│ │ └── demo.tape
│ ├── scripts/
│ │ └── coverage.mjs
│ └── workflows/
│ ├── build.yml
│ ├── check.yml
│ ├── diff.yml
│ ├── fuzz.yml
│ └── test.yml
├── .gitignore
├── LICENSE
├── README.md
├── SECURITY.md
├── ast/
│ ├── dump.go
│ ├── find.go
│ ├── find_test.go
│ ├── node.go
│ ├── print.go
│ ├── print_test.go
│ ├── visitor.go
│ └── visitor_test.go
├── bench_test.go
├── builtin/
│ ├── builtin.go
│ ├── builtin_test.go
│ ├── function.go
│ ├── lib.go
│ ├── utils.go
│ └── validation.go
├── checker/
│ ├── checker.go
│ ├── checker_bench_test.go
│ ├── checker_test.go
│ ├── info.go
│ ├── info_test.go
│ └── nature/
│ ├── nature.go
│ └── utils.go
├── compiler/
│ ├── compiler.go
│ └── compiler_test.go
├── conf/
│ ├── config.go
│ └── env.go
├── debug/
│ ├── debugger.go
│ ├── go.mod
│ └── go.sum
├── docgen/
│ ├── README.md
│ ├── docgen.go
│ ├── docgen_test.go
│ └── markdown.go
├── docs/
│ ├── configuration.md
│ ├── environment.md
│ ├── functions.md
│ ├── getting-started.md
│ ├── language-definition.md
│ ├── patch.md
│ └── visitor.md
├── expr.go
├── expr_test.go
├── file/
│ ├── error.go
│ ├── location.go
│ ├── source.go
│ └── source_test.go
├── go.mod
├── internal/
│ ├── deref/
│ │ ├── deref.go
│ │ └── deref_test.go
│ ├── difflib/
│ │ ├── difflib.go
│ │ └── difflib_test.go
│ ├── ring/
│ │ ├── ring.go
│ │ └── ring_test.go
│ ├── spew/
│ │ ├── bypass.go
│ │ ├── bypasssafe.go
│ │ ├── common.go
│ │ ├── common_test.go
│ │ ├── config.go
│ │ ├── doc.go
│ │ ├── dump.go
│ │ ├── dump_test.go
│ │ ├── dumpcgo_test.go
│ │ ├── dumpnocgo_test.go
│ │ ├── example_test.go
│ │ ├── format.go
│ │ ├── format_test.go
│ │ ├── internal_test.go
│ │ ├── internalunsafe_test.go
│ │ ├── spew.go
│ │ ├── spew_test.go
│ │ └── testdata/
│ │ └── dumpcgo.go
│ └── testify/
│ ├── assert/
│ │ ├── assertion_compare.go
│ │ ├── assertion_compare_test.go
│ │ ├── assertion_format.go
│ │ ├── assertion_format.go.tmpl
│ │ ├── assertion_forward.go
│ │ ├── assertion_forward.go.tmpl
│ │ ├── assertion_order.go
│ │ ├── assertion_order_test.go
│ │ ├── assertions.go
│ │ ├── assertions_test.go
│ │ ├── doc.go
│ │ ├── errors.go
│ │ ├── forward_assertions.go
│ │ ├── forward_assertions_test.go
│ │ ├── http_assertions.go
│ │ ├── http_assertions_test.go
│ │ └── internal/
│ │ └── unsafetests/
│ │ ├── doc.go
│ │ └── unsafetests_test.go
│ └── require/
│ ├── doc.go
│ ├── forward_requirements.go
│ ├── forward_requirements_test.go
│ ├── require.go
│ ├── require.go.tmpl
│ ├── require_forward.go
│ ├── require_forward.go.tmpl
│ ├── requirements.go
│ └── requirements_test.go
├── optimizer/
│ ├── const_expr.go
│ ├── count_any.go
│ ├── count_any_test.go
│ ├── count_threshold.go
│ ├── count_threshold_test.go
│ ├── filter_first.go
│ ├── filter_last.go
│ ├── filter_len.go
│ ├── filter_map.go
│ ├── filter_map_test.go
│ ├── fold.go
│ ├── fold_test.go
│ ├── in_array.go
│ ├── in_range.go
│ ├── optimizer.go
│ ├── optimizer_test.go
│ ├── predicate_combination.go
│ ├── sum_array.go
│ ├── sum_array_test.go
│ ├── sum_map.go
│ ├── sum_map_test.go
│ ├── sum_range.go
│ └── sum_range_test.go
├── parser/
│ ├── bench_test.go
│ ├── lexer/
│ │ ├── lexer.go
│ │ ├── lexer_test.go
│ │ ├── state.go
│ │ ├── token.go
│ │ └── utils.go
│ ├── operator/
│ │ └── operator.go
│ ├── parser.go
│ ├── parser_test.go
│ └── utils/
│ └── utils.go
├── patcher/
│ ├── operator_override.go
│ ├── value/
│ │ ├── bench_test.go
│ │ ├── value.go
│ │ ├── value_example_test.go
│ │ └── value_test.go
│ ├── with_context.go
│ ├── with_context_test.go
│ ├── with_timezone.go
│ └── with_timezone_test.go
├── repl/
│ ├── go.mod
│ ├── go.sum
│ └── repl.go
├── test/
│ ├── bench/
│ │ └── bench_call_test.go
│ ├── coredns/
│ │ ├── coredns.go
│ │ └── coredns_test.go
│ ├── crowdsec/
│ │ ├── crowdsec.go
│ │ ├── crowdsec_test.go
│ │ └── funcs.go
│ ├── deref/
│ │ └── deref_test.go
│ ├── examples/
│ │ ├── examples_test.go
│ │ └── markdown.go
│ ├── fuzz/
│ │ ├── fuzz_corpus.sh
│ │ ├── fuzz_corpus.txt
│ │ ├── fuzz_env.go
│ │ ├── fuzz_expr.dict
│ │ └── fuzz_test.go
│ ├── gen/
│ │ ├── env.go
│ │ ├── gen.go
│ │ ├── gen_test.go
│ │ └── utils.go
│ ├── interface/
│ │ ├── interface_method_test.go
│ │ └── interface_test.go
│ ├── issues/
│ │ ├── 461/
│ │ │ └── issue_test.go
│ │ ├── 567/
│ │ │ └── issue_test.go
│ │ ├── 688/
│ │ │ └── issue_test.go
│ │ ├── 723/
│ │ │ └── issue_test.go
│ │ ├── 730/
│ │ │ └── issue_test.go
│ │ ├── 739/
│ │ │ └── issue_test.go
│ │ ├── 756/
│ │ │ └── issue_test.go
│ │ ├── 785/
│ │ │ └── issue_test.go
│ │ ├── 817/
│ │ │ └── issue_test.go
│ │ ├── 819/
│ │ │ └── issue_test.go
│ │ ├── 823/
│ │ │ └── issue_test.go
│ │ ├── 830/
│ │ │ └── issue_test.go
│ │ ├── 836/
│ │ │ └── issue_test.go
│ │ ├── 840/
│ │ │ └── issue_test.go
│ │ ├── 844/
│ │ │ └── issue_test.go
│ │ ├── 854/
│ │ │ └── issue_test.go
│ │ ├── 857/
│ │ │ └── issue_test.go
│ │ ├── 888/
│ │ │ └── issue_test.go
│ │ ├── 924/
│ │ │ └── issue_test.go
│ │ └── 934/
│ │ └── issue_test.go
│ ├── mock/
│ │ └── mock.go
│ ├── operator/
│ │ ├── issues584/
│ │ │ └── issues584_test.go
│ │ └── operator_test.go
│ ├── patch/
│ │ ├── change_ident_test.go
│ │ ├── patch_count_test.go
│ │ ├── patch_test.go
│ │ └── set_type/
│ │ └── set_type_test.go
│ ├── pipes/
│ │ └── pipes_test.go
│ ├── playground/
│ │ ├── data.go
│ │ └── env.go
│ └── time/
│ └── time_test.go
├── testdata/
│ ├── crash.txt
│ ├── crowdsec.json
│ ├── examples.md
│ └── generated.txt
├── types/
│ ├── types.go
│ └── types_test.go
└── vm/
├── debug.go
├── debug_off.go
├── debug_test.go
├── func_types/
│ └── main.go
├── func_types[generated].go
├── opcodes.go
├── program.go
├── program_test.go
├── runtime/
│ ├── helpers/
│ │ └── main.go
│ ├── helpers[generated].go
│ ├── helpers_test.go
│ ├── runtime.go
│ └── sort.go
├── utils.go
├── vm.go
├── vm_bench_test.go
└── vm_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
*\[generated\].go linguist-language=txt
================================================
FILE: .github/FUNDING.yml
================================================
github: antonmedv
================================================
FILE: .github/images/demo.tape
================================================
Set Shell zsh
Sleep 500ms
Type "repl"
Enter
Sleep 500ms
Type "1..9 | filter("
Sleep 500ms
Type "# "
Sleep 500ms
Type "% 2 == 0) | map("
Sleep 500ms
Type "# ^ 2"
Sleep 500ms
Type ")"
Enter
Sleep 1s
Type "de"
Sleep 500ms
Type "bug"
Enter
Sleep 1.5s
Enter 50
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Enter
Sleep 1.5s
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Escape
Type "OB"
Enter
Sleep 2s
Escape
Type "OB"
Escape
Type "OB"
Ctrl+C
Sleep 1s
Ctrl+D
Ctrl+D
================================================
FILE: .github/scripts/coverage.mjs
================================================
#!/usr/bin/env zx
const expected = 90
const exclude = [
'expr/test', // We do not need to test the test package.
'checker/mock', // Mocks only used for testing.
'vm/func_types', // Generated files.
'vm/runtime/helpers', // Generated files.
'internal/difflib', // Test dependency. This is vendored dependency, and ideally we also have good tests for it.
'internal/spew', // Test dependency.
'internal/testify', // Test dependency.
'patcher/value', // Contains a lot of repeating code. Ideally we should have a test for it.
'pro', // Expr Pro is not a part of the main codebase.
]
cd(path.resolve(__dirname, '..', '..'))
await spinner('Running tests', async () => {
await $`go test -coverprofile=coverage.out -coverpkg=github.com/expr-lang/expr/... ./...`
const coverage = fs.readFileSync('coverage.out').toString()
.split('\n')
.filter(line => {
for (const ex of exclude)
if (line.includes(ex)) return false
return true
})
.join('\n')
fs.writeFileSync('coverage.out', coverage)
await $`go tool cover -html=coverage.out -o coverage.html`
})
const cover = await $({verbose: true})`go tool cover -func=coverage.out`
const total = +cover.stdout.match(/total:\s+\(statements\)\s+(\d+\.\d+)%/)[1]
if (total < expected) {
echo(chalk.red(`Coverage is too low: ${total}% < ${expected}% (expected)`))
process.exit(1)
} else {
echo(`Coverage is good: ${chalk.green(total + '%')} >= ${expected}% (expected)`)
}
================================================
FILE: .github/workflows/build.yml
================================================
name: build
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
go-versions: [ '1.18', '1.22', '1.24', '1.25', '1.26' ]
go-arch: [ '386' ]
steps:
- uses: actions/checkout@v3
- name: Setup Go ${{ matrix.go-version }}
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}
- name: Build
run: GOARCH=${{ matrix.go-arch }} go build
================================================
FILE: .github/workflows/check.yml
================================================
name: check
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
coverage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Go 1.18
uses: actions/setup-go@v4
with:
go-version: 1.18
- name: Test
run: npx zx .github/scripts/coverage.mjs
================================================
FILE: .github/workflows/diff.yml
================================================
name: diff
on:
pull_request:
branches: [ master ]
jobs:
bench:
runs-on: ubuntu-latest
steps:
- name: Setup Go 1.18
uses: actions/setup-go@v4
with:
go-version: 1.18
- name: Install benchstat
# NOTE: benchstat@latest requires go 1.23 since 2025-02-14 - this is the last go 1.18 ref
# https://cs.opensource.google/go/x/perf/+/c95ad7d5b636f67d322a7e4832e83103d0fdd292
run: go install golang.org/x/perf/cmd/benchstat@884df5810d2850d775c2cb4885a7ea339128a17d
- uses: actions/checkout@v3
- name: Benchmark new code
run: go test -bench=. -benchmem -run=^$ -count=10 -timeout=30m | tee /tmp/new.txt
- name: Checkout master
uses: actions/checkout@v3
with:
ref: master
- name: Benchmark master
run: go test -bench=. -benchmem -run=^$ -count=10 -timeout=30m | tee /tmp/old.txt
- name: Diff
run: benchstat /tmp/old.txt /tmp/new.txt
================================================
FILE: .github/workflows/fuzz.yml
================================================
name: fuzz
on: [pull_request]
permissions: {}
jobs:
fuzzing:
runs-on: ubuntu-latest
permissions:
security-events: write
steps:
- name: Build Fuzzers
id: build
uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
with:
oss-fuzz-project-name: 'expr'
language: 'go'
- name: Run Fuzzers
uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
with:
oss-fuzz-project-name: 'expr'
language: 'go'
fuzz-seconds: 600
output-sarif: true
- name: Upload Crash
uses: actions/upload-artifact@v4
if: failure() && steps.build.outcome == 'success'
with:
name: artifacts
path: ./out/artifacts
- name: Upload Sarif
if: always() && steps.build.outcome == 'success'
uses: github/codeql-action/upload-sarif@v3
with:
# Path to SARIF file relative to the root of the repository
sarif_file: cifuzz-sarif/results.sarif
checkout_path: cifuzz-sarif
================================================
FILE: .github/workflows/test.yml
================================================
name: test
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
go-versions: [ '1.18', '1.19', '1.20', '1.21', '1.22', '1.23', '1.24', '1.25', '1.26' ]
steps:
- uses: actions/checkout@v3
- name: Setup Go ${{ matrix.go-version }}
uses: actions/setup-go@v4
with:
go-version: ${{ matrix.go-version }}
- name: Test
run: go test ./...
debug:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Go 1.18
uses: actions/setup-go@v4
with:
go-version: 1.18
- name: Test
run: go test -tags=expr_debug -run=TestDebugger -v ./vm
race:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Setup Go 1.21
uses: actions/setup-go@v4
with:
go-version: 1.21
- name: Test
run: go test -race .
================================================
FILE: .gitignore
================================================
*.exe
*.exe~
*.dll
*.so
*.dylib
*.test
*.out
*.html
custom_tests.json
pro/
test/avs/
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018 Anton Medvedev
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
<h1><a href="https://expr-lang.org"><img src="https://expr-lang.org/img/logo.png" alt="Zx logo" height="48"align="right"></a> Expr</h1>
[](https://github.com/expr-lang/expr/actions/workflows/test.yml)
[](https://goreportcard.com/report/github.com/expr-lang/expr)
[](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:expr)
[](https://godoc.org/github.com/expr-lang/expr)
**Expr** is a Go-centric expression language designed to deliver dynamic configurations with unparalleled accuracy, safety, and speed.
**Expr** combines simple [syntax](https://expr-lang.org/docs/language-definition) with powerful features for ease of use:
```js
// Allow only admins and moderators to moderate comments.
user.Group in ["admin", "moderator"] || user.Id == comment.UserId
```
```js
// Determine whether the request is in the permitted time window.
request.Time - resource.Age < duration("24h")
```
```js
// Ensure all tweets are less than 240 characters.
all(tweets, len(.Content) <= 240)
```
## Features
**Expr** is a safe, fast, and intuitive expression evaluator optimized for the Go language.
Here are its standout features:
### Safety and Isolation
* **Memory-Safe**: Expr is designed with a focus on safety, ensuring that programs do not access unrelated memory or introduce memory vulnerabilities.
* **Side-Effect-Free**: Expressions evaluated in Expr only compute outputs from their inputs, ensuring no side-effects that can change state or produce unintended results.
* **Always Terminating**: Expr is designed to prevent infinite loops, ensuring that every program will conclude in a reasonable amount of time.
### Go Integration
* **Seamless with Go**: Integrate Expr into your Go projects without the need to redefine types.
### Static Typing
* Ensures type correctness and prevents runtime type errors.
```go
out, err := expr.Compile(`name + age`)
// err: invalid operation + (mismatched types string and int)
// | name + age
// | .....^
```
### User-Friendly
* Provides user-friendly error messages to assist with debugging and development.
### Flexibility and Utility
* **Rich Operators**: Offers a reasonable set of basic operators for a variety of applications.
* **Built-in Functions**: Functions like `all`, `none`, `any`, `one`, `filter`, and `map` are provided out-of-the-box.
### Performance
* **Optimized for Speed**: Expr stands out in its performance, utilizing an optimizing compiler and a bytecode virtual machine. Check out these [benchmarks](https://github.com/antonmedv/golang-expression-evaluation-comparison#readme) for more details.
## Install
```
go get github.com/expr-lang/expr
```
## Documentation
* See [Getting Started](https://expr-lang.org/docs/Getting-Started) page for developer documentation.
* See [Language Definition](https://expr-lang.org/docs/language-definition) page to learn the syntax.
## Examples
[Play Online](https://go.dev/play/p/XCoNXEjm3TS)
```go
package main
import (
"fmt"
"github.com/expr-lang/expr"
)
func main() {
env := map[string]interface{}{
"greet": "Hello, %v!",
"names": []string{"world", "you"},
"sprintf": fmt.Sprintf,
}
code := `sprintf(greet, names[0])`
program, err := expr.Compile(code, expr.Env(env))
if err != nil {
panic(err)
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println(output)
}
```
[Play Online](https://go.dev/play/p/tz-ZneBfSuw)
```go
package main
import (
"fmt"
"github.com/expr-lang/expr"
)
type Tweet struct {
Len int
}
type Env struct {
Tweets []Tweet
}
func main() {
code := `all(Tweets, {.Len <= 240})`
program, err := expr.Compile(code, expr.Env(Env{}))
if err != nil {
panic(err)
}
env := Env{
Tweets: []Tweet{{42}, {98}, {69}},
}
output, err := expr.Run(program, env)
if err != nil {
panic(err)
}
fmt.Println(output)
}
```
## Who uses Expr?
* [Google](https://google.com) uses Expr as one of its expression languages on the [Google Cloud Platform](https://cloud.google.com).
* [Uber](https://uber.com) uses Expr to allow customization of its Uber Eats marketplace.
* [GoDaddy](https://godaddy.com) employs Expr for the customization of its GoDaddy Pro product.
* [ByteDance](https://bytedance.com) incorporates Expr into its internal business rule engine.
* [Aviasales](https://aviasales.ru) utilizes Expr as a business rule engine for its flight search engine.
* [Alibaba](https://alibaba.com) uses Expr in a web framework for building recommendation services.
* [Argo](https://argoproj.github.io) integrates Expr into Argo Rollouts and Argo Workflows for Kubernetes.
* [Wish.com](https://www.wish.com) employs Expr in its decision-making rule engine for the Wish Assistant.
* [OpenTelemetry](https://opentelemetry.io) integrates Expr into the OpenTelemetry Collector.
* [Philips Labs](https://github.com/philips-labs/tabia) employs Expr in Tabia, a tool designed to collect insights on their code bases.
* [CrowdSec](https://crowdsec.net) incorporates Expr into its security automation tool.
* [CoreDNS](https://coredns.io) uses Expr in CoreDNS, which is a DNS server.
* [qiniu](https://www.qiniu.com) implements Expr in its trade systems.
* [Junglee Games](https://www.jungleegames.com/) uses Expr for its in-house marketing retention tool, Project Audience.
* [Faceit](https://www.faceit.com) uses Expr to enhance customization of its eSports matchmaking algorithm.
* [Chaos Mesh](https://chaos-mesh.org) incorporates Expr into Chaos Mesh, a cloud-native Chaos Engineering platform.
* [Visually.io](https://visually.io) employs Expr as a business rule engine for its personalization targeting algorithm.
* [Akvorado](https://github.com/akvorado/akvorado) utilizes Expr to classify exporters and interfaces in network flows.
* [keda.sh](https://keda.sh) uses Expr to allow customization of its Kubernetes-based event-driven autoscaling.
* [Span Digital](https://spandigital.com/) uses Expr in its Knowledge Management products.
* [Xiaohongshu](https://www.xiaohongshu.com/) combining yaml with Expr for dynamically policies delivery.
* [Melrōse](https://melrōse.org) uses Expr to implement its music programming language.
* [Tork](https://www.tork.run/) integrates Expr into its workflow execution.
* [Critical Moments](https://criticalmoments.io) uses Expr for its mobile realtime conditional targeting system.
* [WoodpeckerCI](https://woodpecker-ci.org) uses Expr for [filtering workflows/steps](https://woodpecker-ci.org/docs/usage/workflow-syntax#evaluate).
* [FastSchema](https://github.com/fastschema/fastschema) - A BaaS leveraging Expr for its customizable and dynamic Access Control system.
* [WunderGraph Cosmo](https://github.com/wundergraph/cosmo) - GraphQL Federeration Router uses Expr to customize Middleware behaviour
* [SOLO](https://solo.one) uses Expr interally to allow dynamic code execution with custom defined functions.
* [Naoma.AI](https://www.naoma.ai) uses Expr as a part of its call scoring engine.
* [GlassFlow.dev](https://github.com/glassflow/clickhouse-etl) uses Expr to do realtime data transformation in ETL pipelines
* [Kargo](https://kargo.io/) uses Expr to evaluate and manipulate variables dynamically during [promotion steps](https://docs.kargo.io/user-guide/reference-docs/expressions/)
[Add your company too](https://github.com/expr-lang/expr/edit/master/README.md)
## License
[MIT](https://github.com/expr-lang/expr/blob/master/LICENSE)
<p align="center"><img src="https://expr-lang.org/img/gopher-small.png" width="150" /></p>
================================================
FILE: SECURITY.md
================================================
# Security Policy
## Supported Versions
Expr is generally backwards compatible with very few exceptions, so we
recommend users to always use the latest version to experience stability,
performance and security.
We generally backport security issues to a single previous minor version,
unless this is not possible or feasible with a reasonable effort.
| Version | Supported |
|---------|--------------------|
| 1.x | :white_check_mark: |
| 0.x | :x: |
## Reporting a Vulnerability
If you believe you've discovered a serious vulnerability, please contact the
Expr core team at anton+security@medv.io. We will evaluate your report and if
necessary issue a fix and an advisory. If the issue was previously undisclosed,
we'll also mention your name in the credits.
================================================
FILE: ast/dump.go
================================================
package ast
import (
"fmt"
"reflect"
"regexp"
)
func Dump(node Node) string {
return dump(reflect.ValueOf(node), "")
}
func dump(v reflect.Value, ident string) string {
if !v.IsValid() {
return "nil"
}
t := v.Type()
switch t.Kind() {
case reflect.Struct:
out := t.Name() + "{\n"
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if isPrivate(f.Name) {
continue
}
s := v.Field(i)
out += fmt.Sprintf("%v%v: %v,\n", ident+"\t", f.Name, dump(s, ident+"\t"))
}
return out + ident + "}"
case reflect.Slice:
if v.Len() == 0 {
return t.String() + "{}"
}
out := t.String() + "{\n"
for i := 0; i < v.Len(); i++ {
s := v.Index(i)
out += fmt.Sprintf("%v%v,", ident+"\t", dump(s, ident+"\t"))
if i+1 < v.Len() {
out += "\n"
}
}
return out + "\n" + ident + "}"
case reflect.Ptr:
return dump(v.Elem(), ident)
case reflect.Interface:
return dump(reflect.ValueOf(v.Interface()), ident)
case reflect.String:
return fmt.Sprintf("%q", v)
default:
return fmt.Sprintf("%v", v)
}
}
var isCapital = regexp.MustCompile("^[A-Z]")
func isPrivate(s string) bool {
return !isCapital.Match([]byte(s))
}
================================================
FILE: ast/find.go
================================================
package ast
func Find(node Node, fn func(node Node) bool) Node {
v := &finder{fn: fn}
Walk(&node, v)
return v.node
}
type finder struct {
node Node
fn func(node Node) bool
}
func (f *finder) Visit(node *Node) {
if f.fn(*node) {
f.node = *node
}
}
================================================
FILE: ast/find_test.go
================================================
package ast_test
import (
"testing"
"github.com/expr-lang/expr/internal/testify/require"
"github.com/expr-lang/expr/ast"
)
func TestFind(t *testing.T) {
left := &ast.IdentifierNode{
Value: "a",
}
var root ast.Node = &ast.BinaryNode{
Operator: "+",
Left: left,
Right: &ast.IdentifierNode{
Value: "b",
},
}
x := ast.Find(root, func(node ast.Node) bool {
if n, ok := node.(*ast.IdentifierNode); ok {
return n.Value == "a"
}
return false
})
require.Equal(t, left, x)
}
================================================
FILE: ast/node.go
================================================
package ast
import (
"reflect"
"github.com/expr-lang/expr/checker/nature"
"github.com/expr-lang/expr/file"
)
var (
anyType = reflect.TypeOf(new(any)).Elem()
)
// Node represents items of abstract syntax tree.
type Node interface {
Location() file.Location
SetLocation(file.Location)
Nature() *nature.Nature
SetNature(nature.Nature)
Type() reflect.Type
SetType(reflect.Type)
String() string
}
// Patch replaces the node with a new one.
// Location information is preserved.
// Type information is lost.
func Patch(node *Node, newNode Node) {
newNode.SetLocation((*node).Location())
*node = newNode
}
// base is a base struct for all nodes.
type base struct {
loc file.Location
nature nature.Nature
}
// Location returns the location of the node in the source code.
func (n *base) Location() file.Location {
return n.loc
}
// SetLocation sets the location of the node in the source code.
func (n *base) SetLocation(loc file.Location) {
n.loc = loc
}
// Nature returns the nature of the node.
func (n *base) Nature() *nature.Nature {
return &n.nature
}
// SetNature sets the nature of the node.
func (n *base) SetNature(nature nature.Nature) {
n.nature = nature
}
// Type returns the type of the node.
func (n *base) Type() reflect.Type {
if n.nature.Type == nil {
return anyType
}
return n.nature.Type
}
// SetType sets the type of the node.
func (n *base) SetType(t reflect.Type) {
n.nature = nature.FromType(t)
}
// NilNode represents nil.
type NilNode struct {
base
}
// IdentifierNode represents an identifier.
type IdentifierNode struct {
base
Value string // Name of the identifier. Like "foo" in "foo.bar".
}
// IntegerNode represents an integer.
type IntegerNode struct {
base
Value int // Value of the integer.
}
// FloatNode represents a float.
type FloatNode struct {
base
Value float64 // Value of the float.
}
// BoolNode represents a boolean.
type BoolNode struct {
base
Value bool // Value of the boolean.
}
// StringNode represents a string.
type StringNode struct {
base
Value string // Value of the string.
}
// BytesNode represents a byte slice.
type BytesNode struct {
base
Value []byte // Value of the byte slice.
}
// ConstantNode represents a constant.
// Constants are predefined values like nil, true, false, array, map, etc.
// The parser.Parse will never generate ConstantNode, it is only generated
// by the optimizer.
type ConstantNode struct {
base
Value any // Value of the constant.
}
// UnaryNode represents a unary operator.
type UnaryNode struct {
base
Operator string // Operator of the unary operator. Like "!" in "!foo" or "not" in "not foo".
Node Node // Node of the unary operator. Like "foo" in "!foo".
}
// BinaryNode represents a binary operator.
type BinaryNode struct {
base
Operator string // Operator of the binary operator. Like "+" in "foo + bar" or "matches" in "foo matches bar".
Left Node // Left node of the binary operator.
Right Node // Right node of the binary operator.
}
// ChainNode represents an optional chaining group.
// A few MemberNode nodes can be chained together,
// and will be wrapped in a ChainNode. Example:
//
// foo.bar?.baz?.qux
//
// The whole chain will be wrapped in a ChainNode.
type ChainNode struct {
base
Node Node // Node of the chain.
}
// MemberNode represents a member access.
// It can be a field access, a method call,
// or an array element access.
// Example:
//
// foo.bar or foo["bar"]
// foo.bar()
// array[0]
type MemberNode struct {
base
Node Node // Node of the member access. Like "foo" in "foo.bar".
Property Node // Property of the member access. For property access it is a StringNode.
Optional bool // If true then the member access is optional. Like "foo?.bar".
Method bool
}
// SliceNode represents access to a slice of an array.
// Example:
//
// array[1:4]
type SliceNode struct {
base
Node Node // Node of the slice. Like "array" in "array[1:4]".
From Node // From an index of the array. Like "1" in "array[1:4]".
To Node // To an index of the array. Like "4" in "array[1:4]".
}
// CallNode represents a function or a method call.
type CallNode struct {
base
Callee Node // Node of the call. Like "foo" in "foo()".
Arguments []Node // Arguments of the call.
}
// BuiltinNode represents a builtin function call.
type BuiltinNode struct {
base
Name string // Name of the builtin function. Like "len" in "len(foo)".
Arguments []Node // Arguments of the builtin function.
Throws bool // If true then accessing a field or array index can throw an error. Used by optimizer.
Map Node // Used by optimizer to fold filter() and map() builtins.
Threshold *int // Used by optimizer for count() early termination.
}
// PredicateNode represents a predicate.
// Example:
//
// filter(foo, .bar == 1)
//
// The predicate is ".bar == 1".
type PredicateNode struct {
base
Node Node // Node of the predicate body.
}
// PointerNode represents a pointer to a current value in predicate.
type PointerNode struct {
base
Name string // Name of the pointer. Like "index" in "#index".
}
// ConditionalNode represents a ternary operator or if/else operator.
type ConditionalNode struct {
base
Ternary bool // Is it ternary or if/else operator?
Cond Node // Condition
Exp1 Node // Expression 1
Exp2 Node // Expression 2
}
// VariableDeclaratorNode represents a variable declaration.
type VariableDeclaratorNode struct {
base
Name string // Name of the variable. Like "foo" in "let foo = 1; foo + 1".
Value Node // Value of the variable. Like "1" in "let foo = 1; foo + 1".
Expr Node // Expression of the variable. Like "foo + 1" in "let foo = 1; foo + 1".
}
// SequenceNode represents a sequence of nodes separated by semicolons.
// All nodes are executed, only the last node will be returned.
type SequenceNode struct {
base
Nodes []Node
}
// ArrayNode represents an array.
type ArrayNode struct {
base
Nodes []Node // Nodes of the array.
}
// MapNode represents a map.
type MapNode struct {
base
Pairs []Node // PairNode nodes.
}
// PairNode represents a key-value pair of a map.
type PairNode struct {
base
Key Node // Key of the pair.
Value Node // Value of the pair.
}
================================================
FILE: ast/print.go
================================================
package ast
import (
"encoding/json"
"fmt"
"strings"
"github.com/expr-lang/expr/parser/operator"
"github.com/expr-lang/expr/parser/utils"
)
func (n *NilNode) String() string {
return "nil"
}
func (n *IdentifierNode) String() string {
return n.Value
}
func (n *IntegerNode) String() string {
return fmt.Sprintf("%d", n.Value)
}
func (n *FloatNode) String() string {
return fmt.Sprintf("%v", n.Value)
}
func (n *BoolNode) String() string {
return fmt.Sprintf("%t", n.Value)
}
func (n *StringNode) String() string {
return fmt.Sprintf("%q", n.Value)
}
func (n *BytesNode) String() string {
return fmt.Sprintf("b%q", n.Value)
}
func (n *ConstantNode) String() string {
if n.Value == nil {
return "nil"
}
b, err := json.Marshal(n.Value)
if err != nil {
panic(err)
}
return string(b)
}
func (n *UnaryNode) String() string {
op := n.Operator
if n.Operator == "not" {
op = fmt.Sprintf("%s ", n.Operator)
}
wrap := false
switch b := n.Node.(type) {
case *BinaryNode:
if operator.Binary[b.Operator].Precedence <
operator.Unary[n.Operator].Precedence {
wrap = true
}
case *ConditionalNode:
wrap = true
}
if wrap {
return fmt.Sprintf("%s(%s)", op, n.Node.String())
}
return fmt.Sprintf("%s%s", op, n.Node.String())
}
func (n *BinaryNode) String() string {
if n.Operator == ".." {
return fmt.Sprintf("%s..%s", n.Left, n.Right)
}
var lhs, rhs string
var lwrap, rwrap bool
if l, ok := n.Left.(*UnaryNode); ok {
if operator.Unary[l.Operator].Precedence <
operator.Binary[n.Operator].Precedence {
lwrap = true
}
}
if lb, ok := n.Left.(*BinaryNode); ok {
if operator.Less(lb.Operator, n.Operator) {
lwrap = true
}
if operator.Binary[lb.Operator].Precedence ==
operator.Binary[n.Operator].Precedence &&
operator.Binary[n.Operator].Associativity == operator.Right {
lwrap = true
}
if lb.Operator == "??" {
lwrap = true
}
if operator.IsBoolean(lb.Operator) && n.Operator != lb.Operator {
lwrap = true
}
}
if rb, ok := n.Right.(*BinaryNode); ok {
if operator.Less(rb.Operator, n.Operator) {
rwrap = true
}
if operator.Binary[rb.Operator].Precedence ==
operator.Binary[n.Operator].Precedence &&
operator.Binary[n.Operator].Associativity == operator.Left {
rwrap = true
}
if operator.IsBoolean(rb.Operator) && n.Operator != rb.Operator {
rwrap = true
}
}
if _, ok := n.Left.(*ConditionalNode); ok {
lwrap = true
}
if _, ok := n.Right.(*ConditionalNode); ok {
rwrap = true
}
if lwrap {
lhs = fmt.Sprintf("(%s)", n.Left.String())
} else {
lhs = n.Left.String()
}
if rwrap {
rhs = fmt.Sprintf("(%s)", n.Right.String())
} else {
rhs = n.Right.String()
}
return fmt.Sprintf("%s %s %s", lhs, n.Operator, rhs)
}
func (n *ChainNode) String() string {
return n.Node.String()
}
func (n *MemberNode) String() string {
node := n.Node.String()
if _, ok := n.Node.(*BinaryNode); ok {
node = fmt.Sprintf("(%s)", node)
}
if n.Optional {
if str, ok := n.Property.(*StringNode); ok && utils.IsValidIdentifier(str.Value) {
return fmt.Sprintf("%s?.%s", node, str.Value)
} else {
return fmt.Sprintf("%s?.[%s]", node, n.Property.String())
}
}
if str, ok := n.Property.(*StringNode); ok && utils.IsValidIdentifier(str.Value) {
if _, ok := n.Node.(*PointerNode); ok {
return fmt.Sprintf(".%s", str.Value)
}
return fmt.Sprintf("%s.%s", node, str.Value)
}
return fmt.Sprintf("%s[%s]", node, n.Property.String())
}
func (n *SliceNode) String() string {
if n.From == nil && n.To == nil {
return fmt.Sprintf("%s[:]", n.Node.String())
}
if n.From == nil {
return fmt.Sprintf("%s[:%s]", n.Node.String(), n.To.String())
}
if n.To == nil {
return fmt.Sprintf("%s[%s:]", n.Node.String(), n.From.String())
}
return fmt.Sprintf("%s[%s:%s]", n.Node.String(), n.From.String(), n.To.String())
}
func (n *CallNode) String() string {
arguments := make([]string, len(n.Arguments))
for i, arg := range n.Arguments {
arguments[i] = arg.String()
}
return fmt.Sprintf("%s(%s)", n.Callee.String(), strings.Join(arguments, ", "))
}
func (n *BuiltinNode) String() string {
arguments := make([]string, len(n.Arguments))
for i, arg := range n.Arguments {
arguments[i] = arg.String()
}
return fmt.Sprintf("%s(%s)", n.Name, strings.Join(arguments, ", "))
}
func (n *PredicateNode) String() string {
return n.Node.String()
}
func (n *PointerNode) String() string {
return fmt.Sprintf("#%s", n.Name)
}
func (n *VariableDeclaratorNode) String() string {
return fmt.Sprintf("let %s = %s; %s", n.Name, n.Value.String(), n.Expr.String())
}
func (n *SequenceNode) String() string {
nodes := make([]string, len(n.Nodes))
for i, node := range n.Nodes {
nodes[i] = node.String()
}
return strings.Join(nodes, "; ")
}
func (n *ConditionalNode) String() string {
if !n.Ternary {
cond := n.Cond.String()
exp1 := n.Exp1.String()
if c2, ok := n.Exp2.(*ConditionalNode); ok && !c2.Ternary {
return fmt.Sprintf("if %s { %s } else %s", cond, exp1, c2.String())
}
exp2 := n.Exp2.String()
return fmt.Sprintf("if %s { %s } else { %s }", cond, exp1, exp2)
}
var cond, exp1, exp2 string
if _, ok := n.Cond.(*ConditionalNode); ok {
cond = fmt.Sprintf("(%s)", n.Cond.String())
} else {
cond = n.Cond.String()
}
if _, ok := n.Exp1.(*ConditionalNode); ok {
exp1 = fmt.Sprintf("(%s)", n.Exp1.String())
} else {
exp1 = n.Exp1.String()
}
if _, ok := n.Exp2.(*ConditionalNode); ok {
exp2 = fmt.Sprintf("(%s)", n.Exp2.String())
} else {
exp2 = n.Exp2.String()
}
return fmt.Sprintf("%s ? %s : %s", cond, exp1, exp2)
}
func (n *ArrayNode) String() string {
nodes := make([]string, len(n.Nodes))
for i, node := range n.Nodes {
nodes[i] = node.String()
}
return fmt.Sprintf("[%s]", strings.Join(nodes, ", "))
}
func (n *MapNode) String() string {
pairs := make([]string, len(n.Pairs))
for i, pair := range n.Pairs {
pairs[i] = pair.String()
}
return fmt.Sprintf("{%s}", strings.Join(pairs, ", "))
}
func (n *PairNode) String() string {
if str, ok := n.Key.(*StringNode); ok {
if utils.IsValidIdentifier(str.Value) {
return fmt.Sprintf("%s: %s", str.Value, n.Value.String())
}
return fmt.Sprintf("%s: %s", str.String(), n.Value.String())
}
return fmt.Sprintf("(%s): %s", n.Key.String(), n.Value.String())
}
================================================
FILE: ast/print_test.go
================================================
package ast_test
import (
"testing"
"github.com/expr-lang/expr/internal/testify/assert"
"github.com/expr-lang/expr/internal/testify/require"
"github.com/expr-lang/expr/ast"
"github.com/expr-lang/expr/parser"
)
func TestPrint(t *testing.T) {
tests := []struct {
input string
want string
}{
{`nil`, `nil`},
{`true`, `true`},
{`false`, `false`},
{`1`, `1`},
{`1.1`, `1.1`},
{`"a"`, `"a"`},
{`'a'`, `"a"`},
{`a`, `a`},
{`a.b`, `a.b`},
{`a[0]`, `a[0]`},
{`a["the b"]`, `a["the b"]`},
{`a.b[0]`, `a.b[0]`},
{`a?.b`, `a?.b`},
{`x[0][1]`, `x[0][1]`},
{`x?.[0]?.[1]`, `x?.[0]?.[1]`},
{`-a`, `-a`},
{`!a`, `!a`},
{`not a`, `not a`},
{`a + b`, `a + b`},
{`a + b * c`, `a + b * c`},
{`(a + b) * c`, `(a + b) * c`},
{`a * (b + c)`, `a * (b + c)`},
{`-(a + b) * c`, `-(a + b) * c`},
{`a == b`, `a == b`},
{`a matches b`, `a matches b`},
{`a in b`, `a in b`},
{`a not in b`, `not (a in b)`},
{`a and b`, `a and b`},
{`a or b`, `a or b`},
{`a or b and c`, `a or (b and c)`},
{`a or (b and c)`, `a or (b and c)`},
{`(a or b) and c`, `(a or b) and c`},
{`a ? b : c`, `a ? b : c`},
{`a ? b : c ? d : e`, `a ? b : (c ? d : e)`},
{`(a ? b : c) ? d : e`, `(a ? b : c) ? d : e`},
{`a ? (b ? c : d) : e`, `a ? (b ? c : d) : e`},
{`func()`, `func()`},
{`func(a)`, `func(a)`},
{`func(a, b)`, `func(a, b)`},
{`{}`, `{}`},
{`{a: b}`, `{a: b}`},
{`{a: b, c: d}`, `{a: b, c: d}`},
{`{"a": b, 'c': d}`, `{a: b, c: d}`},
{`{"a": b, c: d}`, `{a: b, c: d}`},
{`{"a": b, 8: 8}`, `{a: b, "8": 8}`},
{`{"9": 9, '8': 8, "foo": d}`, `{"9": 9, "8": 8, foo: d}`},
{`[]`, `[]`},
{`[a]`, `[a]`},
{`[a, b]`, `[a, b]`},
{`len(a)`, `len(a)`},
{`map(a, # > 0)`, `map(a, # > 0)`},
{`map(a, {# > 0})`, `map(a, # > 0)`},
{`map(a, .b)`, `map(a, .b)`},
{`a.b()`, `a.b()`},
{`a.b(c)`, `a.b(c)`},
{`a[1:-1]`, `a[1:-1]`},
{`a[1:]`, `a[1:]`},
{`a[1:]`, `a[1:]`},
{`a[:]`, `a[:]`},
{`(nil ?? 1) > 0`, `(nil ?? 1) > 0`},
{`{("a" + "b"): 42}`, `{("a" + "b"): 42}`},
{`(One == 1 ? true : false) && Two == 2`, `(One == 1 ? true : false) && Two == 2`},
{`not (a == 1 ? b > 1 : b < 2)`, `not (a == 1 ? b > 1 : b < 2)`},
{`(-(1+1)) ** 2`, `(-(1 + 1)) ** 2`},
{`2 ** (-(1+1))`, `2 ** -(1 + 1)`},
{`(2 ** 2) ** 3`, `(2 ** 2) ** 3`},
{`(3 + 5) / (5 % 3)`, `(3 + 5) / (5 % 3)`},
{`(-(1+1)) == 2`, `-(1 + 1) == 2`},
{`if true { 1 } else { 2 }`, `if true { 1 } else { 2 }`},
{`if true { 1 } else if false { 2 } else { 3 }`, `if true { 1 } else if false { 2 } else { 3 }`},
}
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
tree, err := parser.Parse(tt.input)
require.NoError(t, err)
assert.Equal(t, tt.want, tree.Node.String())
})
}
}
func TestPrint_MemberNode(t *testing.T) {
node := &ast.MemberNode{
Node: &ast.IdentifierNode{
Value: "a",
},
Property: &ast.StringNode{Value: "b c"},
Optional: true,
}
require.Equal(t, `a?.["b c"]`, node.String())
}
func TestPrint_ConstantNode(t *testing.T) {
tests := []struct {
input any
want string
}{
{nil, `nil`},
{true, `true`},
{false, `false`},
{1, `1`},
{1.1, `1.1`},
{"a", `"a"`},
{[]int{1, 2, 3}, `[1,2,3]`},
{map[string]int{"a": 1}, `{"a":1}`},
}
for _, tt := range tests {
t.Run(tt.want, func(t *testing.T) {
node := &ast.ConstantNode{
Value: tt.input,
}
require.Equal(t, tt.want, node.String())
})
}
}
================================================
FILE: ast/visitor.go
================================================
package ast
import "fmt"
type Visitor interface {
Visit(node *Node)
}
func Walk(node *Node, v Visitor) {
if *node == nil {
return
}
switch n := (*node).(type) {
case *NilNode:
case *IdentifierNode:
case *IntegerNode:
case *FloatNode:
case *BoolNode:
case *StringNode:
case *BytesNode:
case *ConstantNode:
case *UnaryNode:
Walk(&n.Node, v)
case *BinaryNode:
Walk(&n.Left, v)
Walk(&n.Right, v)
case *ChainNode:
Walk(&n.Node, v)
case *MemberNode:
Walk(&n.Node, v)
Walk(&n.Property, v)
case *SliceNode:
Walk(&n.Node, v)
if n.From != nil {
Walk(&n.From, v)
}
if n.To != nil {
Walk(&n.To, v)
}
case *CallNode:
Walk(&n.Callee, v)
for i := range n.Arguments {
Walk(&n.Arguments[i], v)
}
case *BuiltinNode:
for i := range n.Arguments {
Walk(&n.Arguments[i], v)
}
case *PredicateNode:
Walk(&n.Node, v)
case *PointerNode:
case *VariableDeclaratorNode:
Walk(&n.Value, v)
Walk(&n.Expr, v)
case *SequenceNode:
for i := range n.Nodes {
Walk(&n.Nodes[i], v)
}
case *ConditionalNode:
Walk(&n.Cond, v)
Walk(&n.Exp1, v)
Walk(&n.Exp2, v)
case *ArrayNode:
for i := range n.Nodes {
Walk(&n.Nodes[i], v)
}
case *MapNode:
for i := range n.Pairs {
Walk(&n.Pairs[i], v)
}
case *PairNode:
Walk(&n.Key, v)
Walk(&n.Value, v)
default:
panic(fmt.Sprintf("undefined node type (%T)", node))
}
v.Visit(node)
}
================================================
FILE: ast/visitor_test.go
================================================
package ast_test
import (
"testing"
"github.com/expr-lang/expr/internal/testify/assert"
"github.com/expr-lang/expr/ast"
)
type visitor struct {
identifiers []string
}
func (v *visitor) Visit(node *ast.Node) {
if n, ok := (*node).(*ast.IdentifierNode); ok {
v.identifiers = append(v.identifiers, n.Value)
}
}
func TestWalk(t *testing.T) {
var node ast.Node
node = &ast.BinaryNode{
Operator: "+",
Left: &ast.IdentifierNode{Value: "foo"},
Right: &ast.IdentifierNode{Value: "bar"},
}
visitor := &visitor{}
ast.Walk(&node, visitor)
assert.Equal(t, []string{"foo", "bar"}, visitor.identifiers)
}
type patcher struct{}
func (p *patcher) Visit(node *ast.Node) {
if _, ok := (*node).(*ast.IdentifierNode); ok {
*node = &ast.NilNode{}
}
}
func TestWalk_patch(t *testing.T) {
var node ast.Node
node = &ast.BinaryNode{
Operator: "+",
Left: &ast.IdentifierNode{Value: "foo"},
Right: &ast.IdentifierNode{Value: "bar"},
}
patcher := &patcher{}
ast.Walk(&node, patcher)
assert.IsType(t, &ast.NilNode{}, node.(*ast.BinaryNode).Left)
assert.IsType(t, &ast.NilNode{}, node.(*ast.BinaryNode).Right)
}
================================================
FILE: bench_test.go
================================================
package expr_test
import (
"testing"
"github.com/expr-lang/expr/internal/testify/require"
"github.com/expr-lang/expr"
"github.com/expr-lang/expr/vm"
)
func Benchmark_expr(b *testing.B) {
params := make(map[string]any)
params["Origin"] = "MOW"
params["Country"] = "RU"
params["Adults"] = 1
params["Value"] = 100
program, err := expr.Compile(`(Origin == "MOW" || Country == "RU") && (Value >= 100 || Adults == 1)`, expr.Env(params))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, params)
}
b.StopTimer()
require.NoError(b, err)
require.True(b, out.(bool))
}
func Benchmark_expr_eval(b *testing.B) {
params := make(map[string]any)
params["Origin"] = "MOW"
params["Country"] = "RU"
params["Adults"] = 1
params["Value"] = 100
var out any
var err error
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = expr.Eval(`(Origin == "MOW" || Country == "RU") && (Value >= 100 || Adults == 1)`, params)
}
b.StopTimer()
require.NoError(b, err)
require.True(b, out.(bool))
}
func Benchmark_expr_reuseVm(b *testing.B) {
params := make(map[string]any)
params["Origin"] = "MOW"
params["Country"] = "RU"
params["Adults"] = 1
params["Value"] = 100
program, err := expr.Compile(`(Origin == "MOW" || Country == "RU") && (Value >= 100 || Adults == 1)`, expr.Env(params))
require.NoError(b, err)
var out any
v := vm.VM{}
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = v.Run(program, params)
}
b.StopTimer()
require.NoError(b, err)
require.True(b, out.(bool))
}
func Benchmark_len(b *testing.B) {
env := map[string]any{
"arr": make([]int, 100),
}
program, err := expr.Compile(`len(arr)`, expr.Env(env))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.Equal(b, 100, out)
}
func Benchmark_filter(b *testing.B) {
type Env struct {
Ints []int
}
env := Env{
Ints: make([]int, 1000),
}
for i := 1; i <= len(env.Ints); i++ {
env.Ints[i-1] = i
}
program, err := expr.Compile(`filter(Ints, # % 7 == 0)`, expr.Env(Env{}))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.Len(b, out.([]any), 142)
}
func Benchmark_filterLen(b *testing.B) {
type Env struct {
Ints []int
}
env := Env{
Ints: make([]int, 1000),
}
for i := 1; i <= len(env.Ints); i++ {
env.Ints[i-1] = i
}
program, err := expr.Compile(`len(filter(Ints, # % 7 == 0))`, expr.Env(Env{}))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.Equal(b, 142, out)
}
func Benchmark_filterFirst(b *testing.B) {
type Env struct {
Ints []int
}
env := Env{
Ints: make([]int, 1000),
}
for i := 1; i <= len(env.Ints); i++ {
env.Ints[i-1] = i
}
program, err := expr.Compile(`filter(Ints, # % 7 == 0)[0]`, expr.Env(Env{}))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.Equal(b, 7, out)
}
func Benchmark_filterLast(b *testing.B) {
type Env struct {
Ints []int
}
env := Env{
Ints: make([]int, 1000),
}
for i := 1; i <= len(env.Ints); i++ {
env.Ints[i-1] = i
}
program, err := expr.Compile(`filter(Ints, # % 7 == 0)[-1]`, expr.Env(Env{}))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.Equal(b, 994, out)
}
func Benchmark_filterMap(b *testing.B) {
type Env struct {
Ints []int
}
env := Env{
Ints: make([]int, 100),
}
for i := 1; i <= len(env.Ints); i++ {
env.Ints[i-1] = i
}
program, err := expr.Compile(`map(filter(Ints, # % 7 == 0), # * 2)`, expr.Env(Env{}))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.Len(b, out.([]any), 14)
require.Equal(b, 14, out.([]any)[0])
}
func Benchmark_arrayIndex(b *testing.B) {
env := map[string]any{
"arr": make([]int, 100),
}
for i := 0; i < 100; i++ {
env["arr"].([]int)[i] = i
}
program, err := expr.Compile(`arr[50]`, expr.Env(env))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.Equal(b, 50, out)
}
func Benchmark_envStruct(b *testing.B) {
type Price struct {
Value int
}
type Env struct {
Price Price
}
program, err := expr.Compile(`Price.Value > 0`, expr.Env(Env{}))
require.NoError(b, err)
env := Env{Price: Price{Value: 1}}
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.True(b, out.(bool))
}
func Benchmark_envStruct_noEnv(b *testing.B) {
type Price struct {
Value int
}
type Env struct {
Price Price
}
program, err := expr.Compile(`Price.Value > 0`)
require.NoError(b, err)
env := Env{Price: Price{Value: 1}}
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.True(b, out.(bool))
}
func Benchmark_envMap(b *testing.B) {
type Price struct {
Value int
}
env := map[string]any{
"price": Price{Value: 1},
}
program, err := expr.Compile(`price.Value > 0`, expr.Env(env))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.True(b, out.(bool))
}
type CallEnv struct {
A int
B int
C int
Fn func() bool
FnFast func(...any) any
Foo CallFoo
}
func (CallEnv) Func() string {
return "func"
}
type CallFoo struct {
D int
E int
F int
}
func (CallFoo) Method() string {
return "method"
}
func Benchmark_callFunc(b *testing.B) {
program, err := expr.Compile(`Func()`, expr.Env(CallEnv{}))
require.NoError(b, err)
env := CallEnv{}
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.Equal(b, "func", out)
}
func Benchmark_callMethod(b *testing.B) {
program, err := expr.Compile(`Foo.Method()`, expr.Env(CallEnv{}))
require.NoError(b, err)
env := CallEnv{}
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.Equal(b, "method", out)
}
func Benchmark_callField(b *testing.B) {
program, err := expr.Compile(`Fn()`, expr.Env(CallEnv{}))
require.NoError(b, err)
env := CallEnv{
Fn: func() bool {
return true
},
}
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.True(b, out.(bool))
}
func Benchmark_callFast(b *testing.B) {
program, err := expr.Compile(`FnFast()`, expr.Env(CallEnv{}))
if err != nil {
b.Fatal(err)
}
env := CallEnv{
FnFast: func(s ...any) any {
return "fn_fast"
},
}
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.Equal(b, "fn_fast", out)
}
func Benchmark_callConstExpr(b *testing.B) {
program, err := expr.Compile(`Func()`, expr.Env(CallEnv{}), expr.ConstExpr("Func"))
require.NoError(b, err)
env := CallEnv{}
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, env)
}
b.StopTimer()
require.NoError(b, err)
require.Equal(b, "func", out)
}
func Benchmark_largeStructAccess(b *testing.B) {
type Env struct {
Data [1024 * 1024 * 10]byte
Field int
}
program, err := expr.Compile(`Field > 0 && Field > 1 && Field < 99`, expr.Env(Env{}))
require.NoError(b, err)
env := Env{Field: 21}
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, &env)
}
b.StopTimer()
require.NoError(b, err)
require.True(b, out.(bool))
}
func Benchmark_largeNestedStructAccess(b *testing.B) {
type Env struct {
Inner struct {
Data [1024 * 1024 * 10]byte
Field int
}
}
program, err := expr.Compile(`Inner.Field > 0 && Inner.Field > 1 && Inner.Field < 99`, expr.Env(Env{}))
require.NoError(b, err)
env := Env{}
env.Inner.Field = 21
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, &env)
}
b.StopTimer()
require.NoError(b, err)
require.True(b, out.(bool))
}
func Benchmark_largeNestedArrayAccess(b *testing.B) {
type Env struct {
Data [1][1024 * 1024 * 10]byte
}
program, err := expr.Compile(`Data[0][0] > 0`, expr.Env(Env{}))
require.NoError(b, err)
env := Env{}
env.Data[0][0] = 1
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, err = vm.Run(program, &env)
}
b.StopTimer()
require.NoError(b, err)
require.True(b, out.(bool))
}
func Benchmark_sort(b *testing.B) {
env := map[string]any{
"arr": []any{55, 58, 42, 61, 75, 52, 64, 62, 16, 79, 40, 14, 50, 76, 23, 2, 5, 80, 89, 51, 21, 96, 91, 13, 71, 82, 65, 63, 11, 17, 94, 81, 74, 4, 97, 1, 39, 3, 28, 8, 84, 90, 47, 85, 7, 56, 49, 93, 33, 12, 19, 60, 86, 100, 44, 45, 36, 72, 95, 77, 34, 92, 24, 73, 18, 38, 43, 26, 41, 69, 67, 57, 9, 27, 66, 87, 46, 35, 59, 70, 10, 20, 53, 15, 32, 98, 68, 31, 54, 25, 83, 88, 22, 48, 29, 37, 6, 78, 99, 30},
}
program, err := expr.Compile(`sort(arr)`, expr.Env(env))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, _ = vm.Run(program, env)
}
b.StopTimer()
require.Equal(b, 1, out.([]any)[0])
require.Equal(b, 100, out.([]any)[99])
}
func Benchmark_sortBy(b *testing.B) {
type Foo struct {
Value int
}
arr := []any{55, 58, 42, 61, 75, 52, 64, 62, 16, 79, 40, 14, 50, 76, 23, 2, 5, 80, 89, 51, 21, 96, 91, 13, 71, 82, 65, 63, 11, 17, 94, 81, 74, 4, 97, 1, 39, 3, 28, 8, 84, 90, 47, 85, 7, 56, 49, 93, 33, 12, 19, 60, 86, 100, 44, 45, 36, 72, 95, 77, 34, 92, 24, 73, 18, 38, 43, 26, 41, 69, 67, 57, 9, 27, 66, 87, 46, 35, 59, 70, 10, 20, 53, 15, 32, 98, 68, 31, 54, 25, 83, 88, 22, 48, 29, 37, 6, 78, 99, 30}
env := map[string]any{
"arr": make([]Foo, len(arr)),
}
for i, v := range arr {
env["arr"].([]Foo)[i] = Foo{Value: v.(int)}
}
program, err := expr.Compile(`sortBy(arr, .Value)`, expr.Env(env))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, _ = vm.Run(program, env)
}
b.StopTimer()
require.Equal(b, 1, out.([]any)[0].(Foo).Value)
require.Equal(b, 100, out.([]any)[99].(Foo).Value)
}
func Benchmark_groupBy(b *testing.B) {
program, err := expr.Compile(`groupBy(1..100, # % 7)[6]`)
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, _ = vm.Run(program, nil)
}
b.StopTimer()
require.Equal(b, 6, out.([]any)[0])
}
func Benchmark_reduce(b *testing.B) {
program, err := expr.Compile(`reduce(1..100, # + #acc)`)
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, _ = vm.Run(program, nil)
}
b.StopTimer()
require.Equal(b, 5050, out.(int))
}
func Benchmark_min(b *testing.B) {
arr := []any{55, 58, 42, 61, 75, 52, 64, 62, 16, 79, 40, 14, 50, 76, 23, 2, 5, 80, 89, 51, 21, 96, 91, 13, 71, 82, 65, 63, 11, 17, 94, 81, 74, 4, 97, 1, 39, 3, 28, 8, 84, 90, 47, 85, 7, 56, 49, 93, 33, 12, 19, 60, 86, 100, 44, 45, 36, 72, 95, 77, 34, 92, 24, 73, 18, 38, 43, 26, 41, 69, 67, 57, 9, 27, 66, 87, 46, 35, 59, 70, 10, 20, 53, 15, 32, 98, 68, 31, 54, 25, 83, 88, 22, 48, 29, 37, 6, 78, 99, 30}
env := map[string]any{"arr": arr}
program, err := expr.Compile(`min(arr)`, expr.Env(env))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, _ = vm.Run(program, env)
}
b.StopTimer()
require.Equal(b, 1, out)
}
func Benchmark_max(b *testing.B) {
arr := []any{55, 58, 42, 61, 75, 52, 64, 62, 16, 79, 40, 14, 50, 76, 23, 2, 5, 80, 89, 51, 21, 96, 91, 13, 71, 82, 65, 63, 11, 17, 94, 81, 74, 4, 97, 1, 39, 3, 28, 8, 84, 90, 47, 85, 7, 56, 49, 93, 33, 12, 19, 60, 86, 100, 44, 45, 36, 72, 95, 77, 34, 92, 24, 73, 18, 38, 43, 26, 41, 69, 67, 57, 9, 27, 66, 87, 46, 35, 59, 70, 10, 20, 53, 15, 32, 98, 68, 31, 54, 25, 83, 88, 22, 48, 29, 37, 6, 78, 99, 30}
env := map[string]any{"arr": arr}
program, err := expr.Compile(`max(arr)`, expr.Env(env))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, _ = vm.Run(program, env)
}
b.StopTimer()
require.Equal(b, 100, out)
}
func Benchmark_mean(b *testing.B) {
arr := []any{55, 58, 42, 61, 75, 52, 64, 62, 16, 79, 40, 14, 50, 76, 23, 2, 5, 80, 89, 51, 21, 96, 91, 13, 71, 82, 65, 63, 11, 17, 94, 81, 74, 4, 97, 1, 39, 3, 28, 8, 84, 90, 47, 85, 7, 56, 49, 93, 33, 12, 19, 60, 86, 100, 44, 45, 36, 72, 95, 77, 34, 92, 24, 73, 18, 38, 43, 26, 41, 69, 67, 57, 9, 27, 66, 87, 46, 35, 59, 70, 10, 20, 53, 15, 32, 98, 68, 31, 54, 25, 83, 88, 22, 48, 29, 37, 6, 78, 99, 30}
env := map[string]any{"arr": arr}
program, err := expr.Compile(`mean(arr)`, expr.Env(env))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, _ = vm.Run(program, env)
}
b.StopTimer()
require.Equal(b, 50.5, out)
}
func Benchmark_median(b *testing.B) {
arr := []any{55, 58, 42, 61, 75, 52, 64, 62, 16, 79, 40, 14, 50, 76, 23, 2, 5, 80, 89, 51, 21, 96, 91, 13, 71, 82, 65, 63, 11, 17, 94, 81, 74, 4, 97, 1, 39, 3, 28, 8, 84, 90, 47, 85, 7, 56, 49, 93, 33, 12, 19, 60, 86, 100, 44, 45, 36, 72, 95, 77, 34, 92, 24, 73, 18, 38, 43, 26, 41, 69, 67, 57, 9, 27, 66, 87, 46, 35, 59, 70, 10, 20, 53, 15, 32, 98, 68, 31, 54, 25, 83, 88, 22, 48, 29, 37, 6, 78, 99, 30}
env := map[string]any{"arr": arr}
program, err := expr.Compile(`median(arr)`, expr.Env(env))
require.NoError(b, err)
var out any
b.ResetTimer()
for n := 0; n < b.N; n++ {
out, _ = vm.Run(program, env)
}
b.StopTimer()
require.Equal(b, 50.5, out)
}
================================================
FILE: builtin/builtin.go
================================================
package builtin
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"reflect"
"sort"
"strings"
"time"
"github.com/expr-lang/expr/internal/deref"
"github.com/expr-lang/expr/vm/runtime"
)
var (
Index map[string]int
Names []string
// MaxDepth limits the recursion depth for nested structures.
MaxDepth = 10000
ErrorMaxDepth = errors.New("recursion depth exceeded")
)
func init() {
Index = make(map[string]int)
Names = make([]string, len(Builtins))
for i, fn := range Builtins {
Index[fn.Name] = i
Names[i] = fn.Name
}
}
var Builtins = []*Function{
{
Name: "all",
Predicate: true,
Types: types(new(func([]any, func(any) bool) bool)),
},
{
Name: "none",
Predicate: true,
Types: types(new(func([]any, func(any) bool) bool)),
},
{
Name: "any",
Predicate: true,
Types: types(new(func([]any, func(any) bool) bool)),
},
{
Name: "one",
Predicate: true,
Types: types(new(func([]any, func(any) bool) bool)),
},
{
Name: "filter",
Predicate: true,
Types: types(new(func([]any, func(any) bool) []any)),
},
{
Name: "map",
Predicate: true,
Types: types(new(func([]any, func(any) any) []any)),
},
{
Name: "find",
Predicate: true,
Types: types(new(func([]any, func(any) bool) any)),
},
{
Name: "findIndex",
Predicate: true,
Types: types(new(func([]any, func(any) bool) int)),
},
{
Name: "findLast",
Predicate: true,
Types: types(new(func([]any, func(any) bool) any)),
},
{
Name: "findLastIndex",
Predicate: true,
Types: types(new(func([]any, func(any) bool) int)),
},
{
Name: "count",
Predicate: true,
Types: types(new(func([]any, func(any) bool) int)),
},
{
Name: "sum",
Predicate: true,
Types: types(new(func([]any, func(any) bool) int)),
},
{
Name: "groupBy",
Predicate: true,
Types: types(new(func([]any, func(any) any) map[any][]any)),
},
{
Name: "sortBy",
Predicate: true,
Types: types(new(func([]any, func(any) bool, string) []any)),
},
{
Name: "reduce",
Predicate: true,
Types: types(new(func([]any, func(any, any) any, any) any)),
},
{
Name: "len",
Fast: Len,
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Array, reflect.Map, reflect.Slice, reflect.String, reflect.Interface:
return integerType, nil
}
return anyType, fmt.Errorf("invalid argument for len (type %s)", args[0])
},
},
{
Name: "type",
Fast: Type,
Types: types(new(func(any) string)),
},
{
Name: "abs",
Fast: Abs,
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Interface:
return args[0], nil
}
return anyType, fmt.Errorf("invalid argument for abs (type %s)", args[0])
},
},
{
Name: "ceil",
Fast: Ceil,
Validate: func(args []reflect.Type) (reflect.Type, error) {
return validateRoundFunc("ceil", args)
},
},
{
Name: "floor",
Fast: Floor,
Validate: func(args []reflect.Type) (reflect.Type, error) {
return validateRoundFunc("floor", args)
},
},
{
Name: "round",
Fast: Round,
Validate: func(args []reflect.Type) (reflect.Type, error) {
return validateRoundFunc("round", args)
},
},
{
Name: "int",
Fast: Int,
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Interface:
return integerType, nil
case reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return integerType, nil
case reflect.String:
return integerType, nil
}
return anyType, fmt.Errorf("invalid argument for int (type %s)", args[0])
},
},
{
Name: "float",
Fast: Float,
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Interface:
return floatType, nil
case reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return floatType, nil
case reflect.String:
return floatType, nil
}
return anyType, fmt.Errorf("invalid argument for float (type %s)", args[0])
},
},
{
Name: "string",
Fast: String,
Types: types(new(func(any any) string)),
},
{
Name: "trim",
Func: func(args ...any) (any, error) {
if len(args) == 1 {
return strings.TrimSpace(args[0].(string)), nil
} else if len(args) == 2 {
return strings.Trim(args[0].(string), args[1].(string)), nil
} else {
return nil, fmt.Errorf("invalid number of arguments for trim (expected 1 or 2, got %d)", len(args))
}
},
Types: types(
strings.TrimSpace,
strings.Trim,
),
},
{
Name: "trimPrefix",
Func: func(args ...any) (any, error) {
s := " "
if len(args) == 2 {
s = args[1].(string)
}
return strings.TrimPrefix(args[0].(string), s), nil
},
Types: types(
strings.TrimPrefix,
new(func(string) string),
),
},
{
Name: "trimSuffix",
Func: func(args ...any) (any, error) {
s := " "
if len(args) == 2 {
s = args[1].(string)
}
return strings.TrimSuffix(args[0].(string), s), nil
},
Types: types(
strings.TrimSuffix,
new(func(string) string),
),
},
{
Name: "upper",
Fast: func(arg any) any {
return strings.ToUpper(arg.(string))
},
Types: types(strings.ToUpper),
},
{
Name: "lower",
Fast: func(arg any) any {
return strings.ToLower(arg.(string))
},
Types: types(strings.ToLower),
},
{
Name: "split",
Func: func(args ...any) (any, error) {
if len(args) == 2 {
return strings.Split(args[0].(string), args[1].(string)), nil
} else if len(args) == 3 {
return strings.SplitN(args[0].(string), args[1].(string), runtime.ToInt(args[2])), nil
} else {
return nil, fmt.Errorf("invalid number of arguments for split (expected 2 or 3, got %d)", len(args))
}
},
Types: types(
strings.Split,
strings.SplitN,
),
},
{
Name: "splitAfter",
Func: func(args ...any) (any, error) {
if len(args) == 2 {
return strings.SplitAfter(args[0].(string), args[1].(string)), nil
} else if len(args) == 3 {
return strings.SplitAfterN(args[0].(string), args[1].(string), runtime.ToInt(args[2])), nil
} else {
return nil, fmt.Errorf("invalid number of arguments for splitAfter (expected 2 or 3, got %d)", len(args))
}
},
Types: types(
strings.SplitAfter,
strings.SplitAfterN,
),
},
{
Name: "replace",
Func: func(args ...any) (any, error) {
if len(args) == 4 {
return strings.Replace(args[0].(string), args[1].(string), args[2].(string), runtime.ToInt(args[3])), nil
} else if len(args) == 3 {
return strings.ReplaceAll(args[0].(string), args[1].(string), args[2].(string)), nil
} else {
return nil, fmt.Errorf("invalid number of arguments for replace (expected 3 or 4, got %d)", len(args))
}
},
Types: types(
strings.Replace,
strings.ReplaceAll,
),
},
{
Name: "repeat",
Safe: func(args ...any) (any, uint, error) {
s := args[0].(string)
n := runtime.ToInt(args[1])
if n < 0 {
return nil, 0, fmt.Errorf("invalid argument for repeat (expected positive integer, got %d)", n)
}
if n > 1e6 {
return nil, 0, fmt.Errorf("memory budget exceeded")
}
return strings.Repeat(s, n), uint(len(s) * n), nil
},
Types: types(strings.Repeat),
},
{
Name: "join",
Func: func(args ...any) (any, error) {
glue := ""
if len(args) == 2 {
glue = args[1].(string)
}
switch args[0].(type) {
case []string:
return strings.Join(args[0].([]string), glue), nil
case []any:
var s []string
for _, arg := range args[0].([]any) {
s = append(s, arg.(string))
}
return strings.Join(s, glue), nil
}
return nil, fmt.Errorf("invalid argument for join (type %s)", reflect.TypeOf(args[0]))
},
Types: types(
strings.Join,
new(func([]any, string) string),
new(func([]any) string),
new(func([]string, string) string),
new(func([]string) string),
),
},
{
Name: "indexOf",
Func: func(args ...any) (any, error) {
return strings.Index(args[0].(string), args[1].(string)), nil
},
Types: types(strings.Index),
},
{
Name: "lastIndexOf",
Func: func(args ...any) (any, error) {
return strings.LastIndex(args[0].(string), args[1].(string)), nil
},
Types: types(strings.LastIndex),
},
{
Name: "hasPrefix",
Func: func(args ...any) (any, error) {
return strings.HasPrefix(args[0].(string), args[1].(string)), nil
},
Types: types(strings.HasPrefix),
},
{
Name: "hasSuffix",
Func: func(args ...any) (any, error) {
return strings.HasSuffix(args[0].(string), args[1].(string)), nil
},
Types: types(strings.HasSuffix),
},
{
Name: "max",
Func: func(args ...any) (any, error) {
return minMax("max", runtime.Less, 0, args...)
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
return validateAggregateFunc("max", args)
},
},
{
Name: "min",
Func: func(args ...any) (any, error) {
return minMax("min", runtime.More, 0, args...)
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
return validateAggregateFunc("min", args)
},
},
{
Name: "mean",
Func: func(args ...any) (any, error) {
count, sum, err := mean(0, args...)
if err != nil {
return nil, err
}
if count == 0 {
return 0.0, nil
}
return sum / float64(count), nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
return validateAggregateFunc("mean", args)
},
},
{
Name: "median",
Func: func(args ...any) (any, error) {
values, err := median(0, args...)
if err != nil {
return nil, err
}
if n := len(values); n > 0 {
sort.Float64s(values)
if n%2 == 1 {
return values[n/2], nil
}
return (values[n/2-1] + values[n/2]) / 2, nil
}
return 0.0, nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
return validateAggregateFunc("median", args)
},
},
{
Name: "toJSON",
Func: func(args ...any) (any, error) {
b, err := json.MarshalIndent(args[0], "", " ")
if err != nil {
return nil, err
}
return string(b), nil
},
Types: types(new(func(any) string)),
},
{
Name: "fromJSON",
Func: func(args ...any) (any, error) {
var v any
err := json.Unmarshal([]byte(args[0].(string)), &v)
if err != nil {
return nil, err
}
return v, nil
},
Types: types(new(func(string) any)),
},
{
Name: "toBase64",
Func: func(args ...any) (any, error) {
return base64.StdEncoding.EncodeToString([]byte(args[0].(string))), nil
},
Types: types(new(func(string) string)),
},
{
Name: "fromBase64",
Func: func(args ...any) (any, error) {
b, err := base64.StdEncoding.DecodeString(args[0].(string))
if err != nil {
return nil, err
}
return string(b), nil
},
Types: types(new(func(string) string)),
},
{
Name: "now",
Func: func(args ...any) (any, error) {
if len(args) == 0 {
return time.Now(), nil
}
if len(args) == 1 {
if tz, ok := args[0].(*time.Location); ok {
return time.Now().In(tz), nil
}
}
return nil, fmt.Errorf("invalid number of arguments (expected 0, got %d)", len(args))
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) == 0 {
return timeType, nil
}
if len(args) == 1 {
if args[0] != nil && args[0].AssignableTo(locationType) {
return timeType, nil
}
}
return anyType, fmt.Errorf("invalid number of arguments (expected 0, got %d)", len(args))
},
Deref: func(i int, arg reflect.Type) bool {
return false
},
},
{
Name: "duration",
Func: func(args ...any) (any, error) {
return time.ParseDuration(args[0].(string))
},
Types: types(time.ParseDuration),
},
{
Name: "date",
Func: func(args ...any) (any, error) {
tz, ok := args[0].(*time.Location)
if ok {
args = args[1:]
}
date := args[0].(string)
if len(args) == 2 {
layout := args[1].(string)
if tz != nil {
return time.ParseInLocation(layout, date, tz)
}
return time.Parse(layout, date)
}
if len(args) == 3 {
layout := args[1].(string)
timeZone := args[2].(string)
tz, err := time.LoadLocation(timeZone)
if err != nil {
return nil, fmt.Errorf("unknown time zone %s", timeZone)
}
t, err := time.ParseInLocation(layout, date, tz)
if err != nil {
return nil, err
}
return t, nil
}
layouts := []string{
"2006-01-02",
"15:04:05",
"2006-01-02 15:04:05",
time.RFC3339,
time.RFC822,
time.RFC850,
time.RFC1123,
}
for _, layout := range layouts {
if tz == nil {
t, err := time.Parse(layout, date)
if err == nil {
return t, nil
}
} else {
t, err := time.ParseInLocation(layout, date, tz)
if err == nil {
return t, nil
}
}
}
return nil, fmt.Errorf("invalid date %s", date)
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) < 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected at least 1, got %d)", len(args))
}
if args[0] != nil && args[0].AssignableTo(locationType) {
args = args[1:]
}
if len(args) > 3 {
return anyType, fmt.Errorf("invalid number of arguments (expected at most 3, got %d)", len(args))
}
return timeType, nil
},
Deref: func(i int, arg reflect.Type) bool {
if arg.AssignableTo(locationType) {
return false
}
return true
},
},
{
Name: "timezone",
Func: func(args ...any) (any, error) {
tz, err := time.LoadLocation(args[0].(string))
if err != nil {
return nil, err
}
return tz, nil
},
Types: types(time.LoadLocation),
},
{
Name: "first",
Func: func(args ...any) (any, error) {
defer func() {
if r := recover(); r != nil {
return
}
}()
return runtime.Fetch(args[0], 0), nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Interface:
return anyType, nil
case reflect.Slice, reflect.Array:
return args[0].Elem(), nil
}
return anyType, fmt.Errorf("cannot get first element from %s", args[0])
},
},
{
Name: "last",
Func: func(args ...any) (any, error) {
defer func() {
if r := recover(); r != nil {
return
}
}()
return runtime.Fetch(args[0], -1), nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Interface:
return anyType, nil
case reflect.Slice, reflect.Array:
return args[0].Elem(), nil
}
return anyType, fmt.Errorf("cannot get last element from %s", args[0])
},
},
{
Name: "get",
Func: get,
},
{
Name: "take",
Func: func(args ...any) (any, error) {
if len(args) != 2 {
return nil, fmt.Errorf("invalid number of arguments (expected 2, got %d)", len(args))
}
v := reflect.ValueOf(args[0])
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
return nil, fmt.Errorf("cannot take from %s", v.Kind())
}
n := reflect.ValueOf(args[1])
if !n.CanInt() {
return nil, fmt.Errorf("cannot take %s elements", n.Kind())
}
to := 0
if n.Int() > int64(v.Len()) {
to = v.Len()
} else {
to = int(n.Int())
}
return v.Slice(0, to).Interface(), nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 2 {
return anyType, fmt.Errorf("invalid number of arguments (expected 2, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Interface, reflect.Slice, reflect.Array:
default:
return anyType, fmt.Errorf("cannot take from %s", args[0])
}
switch kind(args[1]) {
case reflect.Interface, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
default:
return anyType, fmt.Errorf("cannot take %s elements", args[1])
}
return args[0], nil
},
},
{
Name: "keys",
Func: func(args ...any) (any, error) {
if len(args) != 1 {
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
v := reflect.ValueOf(args[0])
if v.Kind() != reflect.Map {
return nil, fmt.Errorf("cannot get keys from %s", v.Kind())
}
keys := v.MapKeys()
out := make([]any, len(keys))
for i, key := range keys {
out[i] = key.Interface()
}
return out, nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Interface:
return arrayType, nil
case reflect.Map:
return arrayType, nil
}
return anyType, fmt.Errorf("cannot get keys from %s", args[0])
},
},
{
Name: "values",
Func: func(args ...any) (any, error) {
if len(args) != 1 {
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
v := reflect.ValueOf(args[0])
if v.Kind() != reflect.Map {
return nil, fmt.Errorf("cannot get values from %s", v.Kind())
}
keys := v.MapKeys()
out := make([]any, len(keys))
for i, key := range keys {
out[i] = v.MapIndex(key).Interface()
}
return out, nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Interface:
return arrayType, nil
case reflect.Map:
return arrayType, nil
}
return anyType, fmt.Errorf("cannot get values from %s", args[0])
},
},
{
Name: "toPairs",
Func: func(args ...any) (any, error) {
if len(args) != 1 {
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
v := reflect.ValueOf(args[0])
if v.Kind() != reflect.Map {
return nil, fmt.Errorf("cannot transform %s to pairs", v.Kind())
}
keys := v.MapKeys()
out := make([][2]any, len(keys))
for i, key := range keys {
out[i] = [2]any{key.Interface(), v.MapIndex(key).Interface()}
}
return out, nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Interface, reflect.Map:
return arrayType, nil
}
return anyType, fmt.Errorf("cannot transform %s to pairs", args[0])
},
},
{
Name: "fromPairs",
Func: func(args ...any) (any, error) {
if len(args) != 1 {
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
v := reflect.ValueOf(args[0])
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
return nil, fmt.Errorf("cannot transform %s from pairs", v)
}
out := reflect.MakeMap(mapType)
for i := 0; i < v.Len(); i++ {
pair := deref.Value(v.Index(i))
if pair.Kind() != reflect.Array && pair.Kind() != reflect.Slice {
return nil, fmt.Errorf("invalid pair %v", pair)
}
if pair.Len() != 2 {
return nil, fmt.Errorf("invalid pair length %v", pair)
}
key := pair.Index(0)
value := pair.Index(1)
out.SetMapIndex(key, value)
}
return out.Interface(), nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Interface, reflect.Slice, reflect.Array:
return mapType, nil
}
return anyType, fmt.Errorf("cannot transform %s from pairs", args[0])
},
},
{
Name: "reverse",
Safe: func(args ...any) (any, uint, error) {
if len(args) != 1 {
return nil, 0, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
v := reflect.ValueOf(args[0])
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
return nil, 0, fmt.Errorf("cannot reverse %s", v.Kind())
}
size := v.Len()
arr := make([]any, size)
for i := 0; i < size; i++ {
arr[i] = v.Index(size - i - 1).Interface()
}
return arr, uint(size), nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Interface, reflect.Slice, reflect.Array:
return arrayType, nil
default:
return anyType, fmt.Errorf("cannot reverse %s", args[0])
}
},
},
{
Name: "uniq",
Func: func(args ...any) (any, error) {
if len(args) != 1 {
return nil, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
v := reflect.ValueOf(args[0])
if v.Kind() != reflect.Array && v.Kind() != reflect.Slice {
return nil, fmt.Errorf("cannot uniq %s", v.Kind())
}
size := v.Len()
ret := []any{}
eq := func(i int) bool {
for _, r := range ret {
if runtime.Equal(v.Index(i).Interface(), r) {
return true
}
}
return false
}
for i := 0; i < size; i += 1 {
if eq(i) {
continue
}
ret = append(ret, v.Index(i).Interface())
}
return ret, nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Interface, reflect.Slice, reflect.Array:
return arrayType, nil
default:
return anyType, fmt.Errorf("cannot uniq %s", args[0])
}
},
},
{
Name: "concat",
Safe: func(args ...any) (any, uint, error) {
if len(args) == 0 {
return nil, 0, fmt.Errorf("invalid number of arguments (expected at least 1, got 0)")
}
var size uint
var arr []any
for _, arg := range args {
v := reflect.ValueOf(arg)
if v.Kind() != reflect.Slice && v.Kind() != reflect.Array {
return nil, 0, fmt.Errorf("cannot concat %s", v.Kind())
}
size += uint(v.Len())
for i := 0; i < v.Len(); i++ {
item := v.Index(i)
arr = append(arr, item.Interface())
}
}
return arr, size, nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) == 0 {
return anyType, fmt.Errorf("invalid number of arguments (expected at least 1, got 0)")
}
for _, arg := range args {
switch kind(arg) {
case reflect.Interface, reflect.Slice, reflect.Array:
default:
return anyType, fmt.Errorf("cannot concat %s", arg)
}
}
return arrayType, nil
},
},
{
Name: "flatten",
Safe: func(args ...any) (any, uint, error) {
var size uint
if len(args) != 1 {
return nil, 0, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
v := reflect.ValueOf(args[0])
if v.Kind() != reflect.Array && v.Kind() != reflect.Slice {
return nil, size, fmt.Errorf("cannot flatten %s", v.Kind())
}
ret, err := flatten(v, 0)
if err != nil {
return nil, 0, err
}
size = uint(len(ret))
return ret, size, nil
},
Validate: func(args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
for _, arg := range args {
switch kind(arg) {
case reflect.Interface, reflect.Slice, reflect.Array:
default:
return anyType, fmt.Errorf("cannot flatten %s", arg)
}
}
return arrayType, nil
},
},
{
Name: "sort",
Safe: func(args ...any) (any, uint, error) {
if len(args) != 1 && len(args) != 2 {
return nil, 0, fmt.Errorf("invalid number of arguments (expected 1 or 2, got %d)", len(args))
}
var array []any
switch in := args[0].(type) {
case []any:
array = make([]any, len(in))
copy(array, in)
case []int:
array = make([]any, len(in))
for i, v := range in {
array[i] = v
}
case []float64:
array = make([]any, len(in))
for i, v := range in {
array[i] = v
}
case []string:
array = make([]any, len(in))
for i, v := range in {
array[i] = v
}
}
var desc bool
if len(args) == 2 {
order, ok := args[1].(string)
if !ok {
return nil, 0, fmt.Errorf("sort order argument must be a string (got %T)", args[1])
}
switch order {
case "asc":
desc = false
case "desc":
desc = true
default:
return nil, 0, fmt.Errorf("invalid order %s, expected asc or desc", order)
}
}
sortable := &runtime.Sort{
Desc: desc,
Array: array,
}
sort.Sort(sortable)
return sortable.Array, uint(len(array)), nil
},
Types: types(
new(func([]any, string) []any),
new(func([]int, string) []any),
new(func([]float64, string) []any),
new(func([]string, string) []any),
new(func([]any) []any),
new(func([]float64) []any),
new(func([]string) []any),
new(func([]int) []any),
),
},
bitFunc("bitand", func(x, y int) (any, error) {
return x & y, nil
}),
bitFunc("bitor", func(x, y int) (any, error) {
return x | y, nil
}),
bitFunc("bitxor", func(x, y int) (any, error) {
return x ^ y, nil
}),
bitFunc("bitnand", func(x, y int) (any, error) {
return x &^ y, nil
}),
bitFunc("bitshl", func(x, y int) (any, error) {
if y < 0 {
return nil, fmt.Errorf("invalid operation: negative shift count %d (type int)", y)
}
return x << y, nil
}),
bitFunc("bitshr", func(x, y int) (any, error) {
if y < 0 {
return nil, fmt.Errorf("invalid operation: negative shift count %d (type int)", y)
}
return x >> y, nil
}),
bitFunc("bitushr", func(x, y int) (any, error) {
if y < 0 {
return nil, fmt.Errorf("invalid operation: negative shift count %d (type int)", y)
}
return int(uint(x) >> y), nil
}),
{
Name: "bitnot",
Func: func(args ...any) (any, error) {
if len(args) != 1 {
return nil, fmt.Errorf("invalid number of arguments for bitnot (expected 1, got %d)", len(args))
}
x, err := toInt(args[0])
if err != nil {
return nil, fmt.Errorf("%v to call bitnot", err)
}
return ^x, nil
},
Types: types(new(func(int) int)),
},
}
================================================
FILE: builtin/builtin_test.go
================================================
package builtin_test
import (
"fmt"
"reflect"
"strings"
"testing"
"time"
"github.com/expr-lang/expr/internal/testify/assert"
"github.com/expr-lang/expr/internal/testify/require"
"github.com/expr-lang/expr"
"github.com/expr-lang/expr/builtin"
"github.com/expr-lang/expr/checker"
"github.com/expr-lang/expr/conf"
"github.com/expr-lang/expr/parser"
"github.com/expr-lang/expr/test/mock"
)
func TestBuiltin(t *testing.T) {
ArrayWithNil := []any{42}
env := map[string]any{
"ArrayOfString": []string{"foo", "bar", "baz"},
"ArrayOfInt": []int{1, 2, 3},
"ArrayOfFloat": []float64{1.5, 2.5, 3.5},
"ArrayOfInt32": []int32{1, 2, 3},
"ArrayOfAny": []any{1, "2", true},
"ArrayOfFoo": []mock.Foo{{Value: "a"}, {Value: "b"}, {Value: "c"}},
"PtrArrayWithNil": &ArrayWithNil,
"EmptyIntArray": []int{},
"EmptyFloatArray": []float64{},
"NestedIntArrays": []any{[]int{1, 2}, []int{3, 4}},
"NestedAnyArrays": []any{[]any{1, 2}, []any{3, 4}},
"MixedNestedArray": []any{1, []int{2, 3}, []float64{4.0, 5.0}},
"NestedInt32Array": []any{[]int32{1, 2}, []int32{3, 4}},
}
var tests = []struct {
input string
want any
}{
{`len(1..10)`, 10},
{`len({foo: 1, bar: 2})`, 2},
{`len("hello")`, 5},
{`abs(-5)`, 5},
{`abs(.5)`, .5},
{`abs(-.5)`, .5},
{`ceil(5.5)`, 6.0},
{`ceil(5)`, 5.0},
{`floor(5.5)`, 5.0},
{`floor(5)`, 5.0},
{`round(5.5)`, 6.0},
{`round(5)`, 5.0},
{`round(5.49)`, 5.0},
{`int(5.5)`, 5},
{`int(5)`, 5},
{`int("5")`, 5},
{`float(5)`, 5.0},
{`float(5.5)`, 5.5},
{`float("5.5")`, 5.5},
{`string(5)`, "5"},
{`string(5.5)`, "5.5"},
{`string("5.5")`, "5.5"},
{`trim(" foo ")`, "foo"},
{`trim("__foo___", "_")`, "foo"},
{`trimPrefix("prefix_foo", "prefix_")`, "foo"},
{`trimSuffix("foo_suffix", "_suffix")`, "foo"},
{`upper("foo")`, "FOO"},
{`lower("FOO")`, "foo"},
{`split("foo,bar,baz", ",")`, []string{"foo", "bar", "baz"}},
{`split("foo,bar,baz", ",", 2)`, []string{"foo", "bar,baz"}},
{`splitAfter("foo,bar,baz", ",")`, []string{"foo,", "bar,", "baz"}},
{`splitAfter("foo,bar,baz", ",", 2)`, []string{"foo,", "bar,baz"}},
{`replace("foo,bar,baz", ",", ";")`, "foo;bar;baz"},
{`replace("foo,bar,baz,goo", ",", ";", 2)`, "foo;bar;baz,goo"},
{`repeat("foo", 3)`, "foofoofoo"},
{`join(ArrayOfString, ",")`, "foo,bar,baz"},
{`join(ArrayOfString)`, "foobarbaz"},
{`join(["foo", "bar", "baz"], ",")`, "foo,bar,baz"},
{`join(["foo", "bar", "baz"])`, "foobarbaz"},
{`indexOf("foo,bar,baz", ",")`, 3},
{`lastIndexOf("foo,bar,baz", ",")`, 7},
{`hasPrefix("foo,bar,baz", "foo")`, true},
{`hasSuffix("foo,bar,baz", "baz")`, true},
{`max(1, 2, 3)`, 3},
{`max(1.5, 2.5, 3.5)`, 3.5},
{`max([1, 2, 3])`, 3},
{`max([1.5, 2.5, 3.5])`, 3.5},
{`max([1, 2, 4, 10], 20, [29, 23, -19])`, 29},
{`min([1, 2, 4, 10], 20, [29, 23, -19])`, -19},
{`min(1, 2, 3)`, 1},
{`min(1.5, 2.5, 3.5)`, 1.5},
{`min([1, 2, 3])`, 1},
{`min([1.5, 2.5, 3.5])`, 1.5},
{`min(-1, [1.5, 2.5, 3.5])`, -1},
{`max(ArrayOfInt)`, 3},
{`min(ArrayOfInt)`, 1},
{`max(ArrayOfFloat)`, 3.5},
{`min(ArrayOfFloat)`, 1.5},
{`max(EmptyIntArray, 5)`, 5},
{`min(EmptyFloatArray, 5)`, 5},
{`max(NestedIntArrays)`, 4},
{`min(NestedIntArrays)`, 1},
{`max(NestedAnyArrays)`, 4},
{`min(NestedAnyArrays)`, 1},
{`max(MixedNestedArray)`, 5.0},
{`min(MixedNestedArray)`, 1},
{`max(ArrayOfInt32)`, int32(3)},
{`min(ArrayOfInt32)`, int32(1)},
{`max(NestedInt32Array)`, int32(4)},
{`min(NestedInt32Array)`, int32(1)},
{`sum(1..9)`, 45},
{`sum([.5, 1.5, 2.5])`, 4.5},
{`sum([])`, 0},
{`sum([1, 2, 3.0, 4])`, 10.0},
{`mean(1..9)`, 5.0},
{`mean([.5, 1.5, 2.5])`, 1.5},
{`mean([])`, 0.0},
{`mean([1, 2, 3.0, 4])`, 2.5},
{`mean(10, [1, 2, 3], 1..9)`, 4.6923076923076925},
{`mean(-10, [1, 2, 3, 4])`, 0.0},
{`mean(10.9, 1..9)`, 5.59},
{`mean(ArrayOfInt)`, 2.0},
{`mean(ArrayOfFloat)`, 2.5},
{`mean(NestedIntArrays)`, 2.5},
{`mean(NestedAnyArrays)`, 2.5},
{`mean(MixedNestedArray)`, 3.0},
{`mean(ArrayOfInt32)`, 2.0},
{`mean(NestedInt32Array)`, 2.5},
{`median(1..9)`, 5.0},
{`median([.5, 1.5, 2.5])`, 1.5},
{`median([])`, 0.0},
{`median([1, 2, 3])`, 2.0},
{`median([1, 2, 3, 4])`, 2.5},
{`median(10, [1, 2, 3], 1..9)`, 4.0},
{`median(-10, [1, 2, 3, 4])`, 2.0},
{`median(1..5, 4.9)`, 3.5},
{`median(ArrayOfInt)`, 2.0},
{`median(ArrayOfFloat)`, 2.5},
{`median(NestedIntArrays)`, 2.5},
{`median(NestedAnyArrays)`, 2.5},
{`median(MixedNestedArray)`, 3.0},
{`median(ArrayOfInt32)`, 2.0},
{`median(NestedInt32Array)`, 2.5},
{`toJSON({foo: 1, bar: 2})`, "{\n \"bar\": 2,\n \"foo\": 1\n}"},
{`fromJSON("[1, 2, 3]")`, []any{1.0, 2.0, 3.0}},
{`toBase64("hello")`, "aGVsbG8="},
{`fromBase64("aGVsbG8=")`, "hello"},
{`now().Format("2006-01-02T15:04Z")`, time.Now().Format("2006-01-02T15:04Z")},
{`duration("1h")`, time.Hour},
{`date("2006-01-02T15:04:05Z")`, time.Date(2006, 1, 2, 15, 4, 5, 0, time.UTC)},
{`date("2006.01.02", "2006.01.02")`, time.Date(2006, 1, 2, 0, 0, 0, 0, time.UTC)},
{`date("2023-04-23T00:30:00.000+0100", "2006-01-02T15:04:05-0700", "America/Chicago").Format("2006-01-02")`, "2023-04-23"},
{`date("2023-04-23T00:30:00", "2006-01-02T15:04:05", "America/Chicago").Format("2006-01-02")`, "2023-04-23"},
{`date("2023-04-23", "2006-01-02", "America/Chicago").Format("2006-01-02")`, "2023-04-23"},
{`timezone("UTC").String()`, "UTC"},
{`timezone("Europe/Moscow").String()`, "Europe/Moscow"},
{`first(ArrayOfString)`, "foo"},
{`first(ArrayOfInt)`, 1},
{`first(ArrayOfAny)`, 1},
{`first([])`, nil},
{`last(ArrayOfString)`, "baz"},
{`last(ArrayOfInt)`, 3},
{`last(ArrayOfAny)`, true},
{`last([])`, nil},
{`get(ArrayOfString, 1)`, "bar"},
{`get(ArrayOfString, 99)`, nil},
{`get(ArrayOfInt, 1)`, 2},
{`get(ArrayOfInt, -1)`, 3},
{`get(ArrayOfAny, 1)`, "2"},
{`get({foo: 1, bar: 2}, "foo")`, 1},
{`get({foo: 1, bar: 2}, "unknown")`, nil},
{`take(ArrayOfString, 2)`, []string{"foo", "bar"}},
{`take(ArrayOfString, 99)`, []string{"foo", "bar", "baz"}},
{`"foo" in keys({foo: 1, bar: 2})`, true},
{`1 in values({foo: 1, bar: 2})`, true},
{`len(toPairs({foo: 1, bar: 2}))`, 2},
{`len(toPairs({}))`, 0},
{`fromPairs([["foo", 1], ["bar", 2]])`, map[any]any{"foo": 1, "bar": 2}},
{`fromPairs(toPairs({foo: 1, bar: 2}))`, map[any]any{"foo": 1, "bar": 2}},
{`groupBy(1..9, # % 2)`, map[any][]any{0: {2, 4, 6, 8}, 1: {1, 3, 5, 7, 9}}},
{`groupBy(1..9, # % 2)[0]`, []any{2, 4, 6, 8}},
{`groupBy(1..3, # > 1)[true]`, []any{2, 3}},
{`groupBy(1..3, # > 1 ? nil : "")[nil]`, []any{2, 3}},
{`groupBy(ArrayOfFoo, .Value).a`, []any{mock.Foo{Value: "a"}}},
{`reduce(1..9, # + #acc, 0)`, 45},
{`reduce(1..9, # + #acc)`, 45},
{`reduce([.5, 1.5, 2.5], # + #acc, 0)`, 4.5},
{`reduce([], 5, 0)`, 0},
{`reduce(10..1, # + #acc, 100)`, 100},
{`reduce([], # + #acc, 42)`, 42},
{`concat(ArrayOfString, ArrayOfInt)`, []any{"foo", "bar", "baz", 1, 2, 3}},
{`concat(PtrArrayWithNil, [nil])`, []any{42, nil}},
{`flatten([["a", "b"], [1, 2]])`, []any{"a", "b", 1, 2}},
{`flatten([["a", "b"], [1, 2, [3, 4]]])`, []any{"a", "b", 1, 2, 3, 4}},
{`flatten([["a", "b"], [1, 2, [3, [[[["c", "d"], "e"]]], 4]]])`, []any{"a", "b", 1, 2, 3, "c", "d", "e", 4}},
{`uniq([1, 15, "a", 2, 3, 5, 2, "a", 2, "b"])`, []any{1, 15, "a", 2, 3, 5, "b"}},
{`uniq([[1, 2], "a", 2, 3, [1, 2], [1, 3]])`, []any{[]any{1, 2}, "a", 2, 3, []any{1, 3}}},
}
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
program, err := expr.Compile(test.input, expr.Env(env))
require.NoError(t, err)
out, err := expr.Run(program, env)
require.NoError(t, err)
assert.Equal(t, test.want, out)
})
}
}
func TestBuiltin_works_with_any(t *testing.T) {
config := map[string]struct {
arity int
}{
"now": {0},
"get": {2},
"take": {2},
"sortBy": {2},
}
for _, b := range builtin.Builtins {
if b.Predicate {
continue
}
t.Run(b.Name, func(t *testing.T) {
arity := 1
if c, ok := config[b.Name]; ok {
arity = c.arity
}
if len(b.Types) > 0 {
arity = b.Types[0].NumIn()
}
args := make([]string, arity)
for i := 1; i <= arity; i++ {
args[i-1] = fmt.Sprintf("arg%d", i)
}
_, err := expr.Compile(fmt.Sprintf(`%s(%s)`, b.Name, strings.Join(args, ", "))) // expr.Env(env) is not needed
assert.NoError(t, err)
})
}
}
func TestBuiltin_errors(t *testing.T) {
var errorTests = []struct {
input string
err string
}{
{`len()`, `invalid number of arguments (expected 1, got 0)`},
{`len(1)`, `invalid argument for len (type int)`},
{`abs()`, `invalid number of arguments (expected 1, got 0)`},
{`abs(1, 2)`, `invalid number of arguments (expected 1, got 2)`},
{`abs("foo")`, `invalid argument for abs (type string)`},
{`int()`, `invalid number of arguments (expected 1, got 0)`},
{`int(1, 2)`, `invalid number of arguments (expected 1, got 2)`},
{`float()`, `invalid number of arguments (expected 1, got 0)`},
{`float(1, 2)`, `invalid number of arguments (expected 1, got 2)`},
{`string(1, 2)`, `too many arguments to call string`},
{`trim()`, `not enough arguments to call trim`},
{`max()`, `not enough arguments to call max`},
{`max(1, "2")`, `invalid argument for max (type string)`},
{`max([1, "2"])`, `invalid argument for max (type string)`},
{`min()`, `not enough arguments to call min`},
{`min(1, "2")`, `invalid argument for min (type string)`},
{`min([1, "2"])`, `invalid argument for min (type string)`},
{`median(1..9, "t")`, "invalid argument for median (type string)"},
{`mean("s", 1..9)`, "invalid argument for mean (type string)"},
{`duration("error")`, `invalid duration`},
{`date("error")`, `invalid date`},
{`get()`, `invalid number of arguments (expected 2, got 0)`},
{`get(1, 2)`, `type int does not support indexing`},
{`bitnot("1")`, "cannot use string as argument (type int) to call bitnot (1:8)"},
{`bitand("1", 1)`, "cannot use string as argument (type int) to call bitand (1:8)"},
{`"10" | bitor(1)`, "cannot use string as argument (type int) to call bitor (1:1)"},
{`bitshr("5", 1)`, "cannot use string as argument (type int) to call bitshr (1:8)"},
{`bitshr(-5, -2)`, "invalid operation: negative shift count -2 (type int) (1:1)"},
{`bitshl(1, -1)`, "invalid operation: negative shift count -1 (type int) (1:1)"},
{`bitushr(-5, -2)`, "invalid operation: negative shift count -2 (type int) (1:1)"},
{`now(nil)`, "invalid number of arguments (expected 0, got 1)"},
{`date(nil)`, "interface {} is nil, not string (1:1)"},
{`timezone(nil)`, "cannot use nil as argument (type string) to call timezone (1:10)"},
{`flatten([1, 2], [3, 4])`, "invalid number of arguments (expected 1, got 2)"},
{`flatten(1)`, "cannot flatten int"},
{`fromJSON("5e2482")`, "cannot unmarshal number"},
}
for _, test := range errorTests {
t.Run(test.input, func(t *testing.T) {
program, err := expr.Compile(test.input)
if err != nil {
assert.Error(t, err)
assert.Contains(t, err.Error(), test.err)
} else {
_, err = expr.Run(program, nil)
assert.Error(t, err)
assert.Contains(t, err.Error(), test.err)
}
})
}
}
func TestBuiltin_env_not_callable(t *testing.T) {
code := `$env(''matches'i'?t:get().UTC())`
env := map[string]any{"t": 1}
_, err := expr.Compile(code, expr.Env(env))
require.Error(t, err)
assert.Contains(t, err.Error(), "is not callable")
}
func TestBuiltin_types(t *testing.T) {
env := map[string]any{
"num": 42,
"str": "foo",
"ArrayOfString": []string{"foo", "bar", "baz"},
"ArrayOfInt": []int{1, 2, 3},
}
tests := []struct {
input string
want reflect.Kind
}{
{`get(ArrayOfString, 0)`, reflect.String},
{`get(ArrayOfInt, 0)`, reflect.Int},
{`first(ArrayOfString)`, reflect.String},
{`first(ArrayOfInt)`, reflect.Int},
{`last(ArrayOfString)`, reflect.String},
{`last(ArrayOfInt)`, reflect.Int},
{`get($env, 'str')`, reflect.String},
{`get($env, 'num')`, reflect.Int},
{`get($env, 'ArrayOfString')`, reflect.Slice},
}
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
tree, err := parser.Parse(test.input)
require.NoError(t, err)
rtype, err := checker.Check(tree, conf.New(env))
require.NoError(t, err)
require.True(t, rtype.Kind() == test.want, fmt.Sprintf("expected %s, got %s", test.want, rtype.Kind()))
})
}
}
func TestBuiltin_memory_limits(t *testing.T) {
tests := []struct {
input string
}{
{`repeat("\xc4<\xc4\xc4\xc4",10009999990)`},
}
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
timeout := make(chan bool, 1)
go func() {
time.Sleep(time.Second)
timeout <- true
}()
done := make(chan bool, 1)
go func() {
_, err := expr.Eval(test.input, nil)
assert.Error(t, err)
assert.Contains(t, err.Error(), "memory budget exceeded")
done <- true
}()
select {
case <-done:
// Success.
case <-timeout:
t.Fatal("timeout")
}
})
}
}
func TestBuiltin_allow_builtins_override(t *testing.T) {
t.Run("via env var", func(t *testing.T) {
for _, name := range builtin.Names {
t.Run(name, func(t *testing.T) {
env := map[string]any{
name: "hello world",
}
program, err := expr.Compile(name, expr.Env(env))
require.NoError(t, err)
out, err := expr.Run(program, env)
require.NoError(t, err)
assert.Equal(t, "hello world", out)
})
}
})
t.Run("via env func", func(t *testing.T) {
for _, name := range builtin.Names {
t.Run(name, func(t *testing.T) {
env := map[string]any{
name: func() int { return 1 },
}
program, err := expr.Compile(fmt.Sprintf("%s()", name), expr.Env(env))
require.NoError(t, err)
out, err := expr.Run(program, env)
require.NoError(t, err)
assert.Equal(t, 1, out)
})
}
})
t.Run("via expr.Function", func(t *testing.T) {
for _, name := range builtin.Names {
t.Run(name, func(t *testing.T) {
fn := expr.Function(name,
func(params ...any) (any, error) {
return 42, nil
},
new(func() int),
)
program, err := expr.Compile(fmt.Sprintf("%s()", name), fn)
require.NoError(t, err)
out, err := expr.Run(program, nil)
require.NoError(t, err)
assert.Equal(t, 42, out)
})
}
})
t.Run("via expr.Function as pipe", func(t *testing.T) {
for _, name := range builtin.Names {
t.Run(name, func(t *testing.T) {
fn := expr.Function(name,
func(params ...any) (any, error) {
return 42, nil
},
new(func(s string) int),
)
program, err := expr.Compile(fmt.Sprintf("'str' | %s()", name), fn)
require.NoError(t, err)
out, err := expr.Run(program, nil)
require.NoError(t, err)
assert.Equal(t, 42, out)
})
}
})
}
func TestBuiltin_override_and_still_accessible(t *testing.T) {
env := map[string]any{
"len": func() int { return 42 },
"all": []int{1, 2, 3},
}
program, err := expr.Compile(`::all(all, #>0) && len() == 42 && ::len(all) == 3`, expr.Env(env))
require.NoError(t, err)
out, err := expr.Run(program, env)
require.NoError(t, err)
assert.Equal(t, true, out)
}
func TestBuiltin_DisableBuiltin(t *testing.T) {
t.Run("via env", func(t *testing.T) {
for _, b := range builtin.Builtins {
if b.Predicate {
continue // TODO: allow to disable predicates
}
t.Run(b.Name, func(t *testing.T) {
env := map[string]any{
b.Name: func() int { return 42 },
}
program, err := expr.Compile(b.Name+"()", expr.Env(env), expr.DisableBuiltin(b.Name))
require.NoError(t, err)
out, err := expr.Run(program, env)
require.NoError(t, err)
assert.Equal(t, 42, out)
})
}
})
t.Run("via expr.Function", func(t *testing.T) {
for _, b := range builtin.Builtins {
if b.Predicate {
continue // TODO: allow to disable predicates
}
t.Run(b.Name, func(t *testing.T) {
fn := expr.Function(b.Name,
func(params ...any) (any, error) {
return 42, nil
},
new(func() int),
)
program, err := expr.Compile(b.Name+"()", fn, expr.DisableBuiltin(b.Name))
require.NoError(t, err)
out, err := expr.Run(program, nil)
require.NoError(t, err)
assert.Equal(t, 42, out)
})
}
})
}
func TestBuiltin_DisableAllBuiltins(t *testing.T) {
_, err := expr.Compile(`len("foo")`, expr.Env(nil), expr.DisableAllBuiltins())
require.Error(t, err)
assert.Contains(t, err.Error(), "unknown name len")
}
func TestBuiltin_EnableBuiltin(t *testing.T) {
t.Run("via env", func(t *testing.T) {
env := map[string]any{
"repeat": func() string { return "repeat" },
}
program, err := expr.Compile(`len(repeat())`, expr.Env(env), expr.DisableAllBuiltins(), expr.EnableBuiltin("len"))
require.NoError(t, err)
out, err := expr.Run(program, env)
require.NoError(t, err)
assert.Equal(t, 6, out)
})
t.Run("via expr.Function", func(t *testing.T) {
fn := expr.Function("repeat",
func(params ...any) (any, error) {
return "repeat", nil
},
new(func() string),
)
program, err := expr.Compile(`len(repeat())`, fn, expr.DisableAllBuiltins(), expr.EnableBuiltin("len"))
require.NoError(t, err)
out, err := expr.Run(program, nil)
require.NoError(t, err)
assert.Equal(t, 6, out)
})
}
func TestBuiltin_type(t *testing.T) {
type Foo struct{}
var b any = 1
var a any = &b
tests := []struct {
obj any
want string
}{
{nil, "nil"},
{true, "bool"},
{1, "int"},
{int8(1), "int"},
{uint(1), "uint"},
{1.0, "float"},
{float32(1.0), "float"},
{"string", "string"},
{[]string{"foo", "bar"}, "array"},
{map[string]any{"foo": "bar"}, "map"},
{func() {}, "func"},
{time.Now(), "time.Time"},
{time.Second, "time.Duration"},
{Foo{}, "github.com/expr-lang/expr/builtin_test.Foo"},
{struct{}{}, "struct"},
{a, "int"},
}
for _, test := range tests {
t.Run(test.want, func(t *testing.T) {
env := map[string]any{
"obj": test.obj,
}
program, err := expr.Compile(`type(obj)`, expr.Env(env))
require.NoError(t, err)
out, err := expr.Run(program, env)
require.NoError(t, err)
assert.Equal(t, test.want, out)
})
}
}
func TestBuiltin_reverse(t *testing.T) {
env := map[string]any{
"ArrayOfString": []string{"foo", "bar", "baz"},
"ArrayOfInt": []int{2, 1, 3},
"ArrayOfFloat": []float64{3.0, 2.0, 1.0},
"ArrayOfFoo": []mock.Foo{{Value: "c"}, {Value: "a"}, {Value: "b"}},
}
tests := []struct {
input string
want any
}{
{`reverse([])`, []any{}},
{`reverse(ArrayOfInt)`, []any{3, 1, 2}},
{`reverse(ArrayOfFloat)`, []any{1.0, 2.0, 3.0}},
{`reverse(ArrayOfFoo)`, []any{mock.Foo{Value: "b"}, mock.Foo{Value: "a"}, mock.Foo{Value: "c"}}},
{`reverse([[1,2], [2,2]])`, []any{[]any{2, 2}, []any{1, 2}}},
{`reverse(reverse([[1,2], [2,2]]))`, []any{[]any{1, 2}, []any{2, 2}}},
{`reverse([{"test": true}, {id:4}, {name: "value"}])`, []any{map[string]any{"name": "value"}, map[string]any{"id": 4}, map[string]any{"test": true}}},
}
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
program, err := expr.Compile(test.input, expr.Env(env))
require.NoError(t, err)
out, err := expr.Run(program, env)
require.NoError(t, err)
assert.Equal(t, test.want, out)
})
}
}
func TestBuiltin_sort(t *testing.T) {
env := map[string]any{
"ArrayOfString": []string{"foo", "bar", "baz"},
"ArrayOfInt": []int{3, 2, 1},
"ArrayOfFloat": []float64{3.0, 2.0, 1.0},
"ArrayOfFoo": []mock.Foo{{Value: "c"}, {Value: "a"}, {Value: "b"}},
}
tests := []struct {
input string
want any
}{
{`sort([])`, []any{}},
{`sort(ArrayOfInt)`, []any{1, 2, 3}},
{`sort(ArrayOfFloat)`, []any{1.0, 2.0, 3.0}},
{`sort(ArrayOfInt, 'desc')`, []any{3, 2, 1}},
{`sortBy(ArrayOfFoo, .Value)`, []any{mock.Foo{Value: "a"}, mock.Foo{Value: "b"}, mock.Foo{Value: "c"}}},
{`sortBy([{id: "a"}, {id: "b"}], .id, "desc")`, []any{map[string]any{"id": "b"}, map[string]any{"id": "a"}}},
}
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
program, err := expr.Compile(test.input, expr.Env(env))
require.NoError(t, err)
out, err := expr.Run(program, env)
require.NoError(t, err)
assert.Equal(t, test.want, out)
})
}
}
func TestBuiltin_sort_i64(t *testing.T) {
env := map[string]any{
"array": []int{1, 2, 3},
"i64": int64(1),
}
program, err := expr.Compile(`sort(map(array, i64))`, expr.Env(env))
require.NoError(t, err)
out, err := expr.Run(program, env)
require.NoError(t, err)
assert.Equal(t, []any{int64(1), int64(1), int64(1)}, out)
}
func TestBuiltin_bitOpsFunc(t *testing.T) {
tests := []struct {
input string
want int
}{
{`bitnot(156)`, -157},
{`bitand(bitnot(156), 255)`, 99},
{`bitor(987, -123)`, -33},
{`bitxor(15, 32)`, 47},
{`bitshl(39, 3)`, 312},
{`bitshr(5, 1)`, 2},
{`bitushr(-5, 2)`, 4611686018427387902},
{`bitnand(35, 9)`, 34},
}
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
program, err := expr.Compile(test.input, expr.Env(nil))
require.NoError(t, err)
out, err := expr.Run(program, nil)
fmt.Printf("%v : %v", test.input, out)
require.NoError(t, err)
assert.Equal(t, test.want, out)
})
}
}
type customInt int
func Test_int_unwraps_underlying_value(t *testing.T) {
env := map[string]any{
"customInt": customInt(42),
}
program, err := expr.Compile(`int(customInt) == 42`, expr.Env(env))
require.NoError(t, err)
out, err := expr.Run(program, env)
require.NoError(t, err)
assert.Equal(t, true, out)
}
func TestBuiltin_with_deref(t *testing.T) {
x := 42
arr := []int{1, 2, 3}
arrStr := []string{"1", "2", "3"}
m := map[string]any{"a": 1, "b": 2}
jsonString := `["1"]`
str := "1,2,3"
env := map[string]any{
"x": &x,
"arr": &arr,
"arrStr": &arrStr,
"m": &m,
"json": &jsonString,
"str": &str,
}
tests := []struct {
input string
want any
}{
{`all(arr, # > 0)`, true},
{`none(arr, # < 0)`, true},
{`any(arr, # > 0)`, true},
{`one(arr, # > 2)`, true},
{`filter(arr, # > 0)`, []any{1, 2, 3}},
{`map(arr, # * #)`, []any{1, 4, 9}},
{`count(arr, # > 0)`, 3},
{`sum(arr)`, 6},
{`find(arr, # > 0)`, 1},
{`findIndex(arr, # > 1)`, 1},
{`findLast(arr, # > 0)`, 3},
{`findLastIndex(arr, # > 0)`, 2},
{`groupBy(arr, # % 2 == 0)`, map[any][]any{false: {1, 3}, true: {2}}},
{`sortBy(arr, -#)`, []any{3, 2, 1}},
{`reduce(arr, # + #acc, x)`, 6 + 42},
{`ceil(x)`, 42.0},
{`floor(x)`, 42.0},
{`round(x)`, 42.0},
{`int(x)`, 42},
{`float(x)`, 42.0},
{`abs(x)`, 42},
{`first(arr)`, 1},
{`last(arr)`, 3},
{`take(arr, 1)`, []int{1}},
{`take(arr, x)`, []int{1, 2, 3}},
{`'a' in keys(m)`, true},
{`1 in values(m)`, true},
{`len(arr)`, 3},
{`type(arr)`, "array"},
{`type(m)`, "map"},
{`reverse(arr)`, []any{3, 2, 1}},
{`uniq(arr)`, []any{1, 2, 3}},
{`concat(arr, arr)`, []any{1, 2, 3, 1, 2, 3}},
{`flatten([arr, [arr]])`, []any{1, 2, 3, 1, 2, 3}},
{`flatten(arr)`, []any{1, 2, 3}},
{`toJSON(arr)`, "[\n 1,\n 2,\n 3\n]"},
{`fromJSON(json)`, []any{"1"}},
{`split(str, ",")`, []string{"1", "2", "3"}},
{`join(arrStr, ",")`, "1,2,3"},
}
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
program, err := expr.Compile(test.input, expr.Env(env))
require.NoError(t, err)
println(program.Disassemble())
out, err := expr.Run(program, env)
require.NoError(t, err)
assert.Equal(t, test.want, out)
out, err = expr.Eval(test.input, env)
require.NoError(t, err)
assert.Equal(t, test.want, out)
})
}
}
func TestBuiltin_flatten_recursion(t *testing.T) {
var s []any
s = append(s, &s) // s contains a pointer to itself
env := map[string]any{
"arr": s,
}
program, err := expr.Compile("flatten(arr)", expr.Env(env))
require.NoError(t, err)
_, err = expr.Run(program, env)
require.Error(t, err)
assert.Contains(t, err.Error(), builtin.ErrorMaxDepth.Error())
}
func TestBuiltin_flatten_recursion_slice(t *testing.T) {
s := make([]any, 1)
s[0] = s
env := map[string]any{
"arr": s,
}
program, err := expr.Compile("flatten(arr)", expr.Env(env))
require.NoError(t, err)
_, err = expr.Run(program, env)
require.Error(t, err)
assert.Contains(t, err.Error(), builtin.ErrorMaxDepth.Error())
}
func TestBuiltin_numerical_recursion(t *testing.T) {
s := make([]any, 1)
s[0] = s
env := map[string]any{
"arr": s,
}
tests := []string{
"max(arr)",
"min(arr)",
"mean(arr)",
"median(arr)",
}
for _, input := range tests {
t.Run(input, func(t *testing.T) {
program, err := expr.Compile(input, expr.Env(env))
require.NoError(t, err)
_, err = expr.Run(program, env)
require.Error(t, err)
assert.Contains(t, err.Error(), builtin.ErrorMaxDepth.Error())
})
}
}
func TestBuiltin_recursion_custom_max_depth(t *testing.T) {
originalMaxDepth := builtin.MaxDepth
defer func() {
builtin.MaxDepth = originalMaxDepth
}()
// Set a small depth limit
builtin.MaxDepth = 2
// Create a deeply nested array (depth 5)
// [1, [2, [3, [4, [5]]]]]
arr := []any{1, []any{2, []any{3, []any{4, []any{5}}}}}
env := map[string]any{
"arr": arr,
}
t.Run("flatten exceeds max depth", func(t *testing.T) {
program, err := expr.Compile("flatten(arr)", expr.Env(env))
require.NoError(t, err)
_, err = expr.Run(program, env)
require.Error(t, err)
assert.Contains(t, err.Error(), builtin.ErrorMaxDepth.Error())
})
t.Run("flatten within max depth", func(t *testing.T) {
// Depth 2: [1, [2]]
shallowArr := []any{1, []any{2}}
envShallow := map[string]any{"arr": shallowArr}
program, err := expr.Compile("flatten(arr)", expr.Env(envShallow))
require.NoError(t, err)
_, err = expr.Run(program, envShallow)
require.NoError(t, err)
})
}
func TestAbs_UnsignedIntegers(t *testing.T) {
// Test that abs() correctly handles unsigned integers
// Unsigned integers are always non-negative, so abs() should return them unchanged
tests := []struct {
name string
env map[string]any
expr string
want any
}{
{"uint", map[string]any{"x": uint(42)}, "abs(x)", uint(42)},
{"uint8", map[string]any{"x": uint8(42)}, "abs(x)", uint8(42)},
{"uint16", map[string]any{"x": uint16(42)}, "abs(x)", uint16(42)},
{"uint32", map[string]any{"x": uint32(42)}, "abs(x)", uint32(42)},
{"uint64", map[string]any{"x": uint64(42)}, "abs(x)", uint64(42)},
{"uint zero", map[string]any{"x": uint(0)}, "abs(x)", uint(0)},
{"uint8 zero", map[string]any{"x": uint8(0)}, "abs(x)", uint8(0)},
{"uint16 zero", map[string]any{"x": uint16(0)}, "abs(x)", uint16(0)},
{"uint32 zero", map[string]any{"x": uint32(0)}, "abs(x)", uint32(0)},
{"uint64 zero", map[string]any{"x": uint64(0)}, "abs(x)", uint64(0)},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
program, err := expr.Compile(tt.expr, expr.Env(tt.env))
require.NoError(t, err)
result, err := expr.Run(program, tt.env)
require.NoError(t, err)
assert.Equal(t, tt.want, result)
})
}
}
================================================
FILE: builtin/function.go
================================================
package builtin
import (
"reflect"
)
type Function struct {
Name string
Fast func(arg any) any
Func func(args ...any) (any, error)
Safe func(args ...any) (any, uint, error)
Types []reflect.Type
Validate func(args []reflect.Type) (reflect.Type, error)
Deref func(i int, arg reflect.Type) bool
Predicate bool
}
func (f *Function) Type() reflect.Type {
if len(f.Types) > 0 {
return f.Types[0]
}
return reflect.TypeOf(f.Func)
}
================================================
FILE: builtin/lib.go
================================================
package builtin
import (
"fmt"
"math"
"reflect"
"strconv"
"unicode/utf8"
"github.com/expr-lang/expr/internal/deref"
"github.com/expr-lang/expr/vm/runtime"
)
func Len(x any) any {
v := reflect.ValueOf(x)
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.Map:
return v.Len()
case reflect.String:
return utf8.RuneCountInString(v.String())
default:
panic(fmt.Sprintf("invalid argument for len (type %T)", x))
}
}
func Type(arg any) any {
if arg == nil {
return "nil"
}
v := reflect.ValueOf(arg)
if v.Type().Name() != "" && v.Type().PkgPath() != "" {
return fmt.Sprintf("%s.%s", v.Type().PkgPath(), v.Type().Name())
}
switch v.Type().Kind() {
case reflect.Invalid:
return "invalid"
case reflect.Bool:
return "bool"
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return "int"
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return "uint"
case reflect.Float32, reflect.Float64:
return "float"
case reflect.String:
return "string"
case reflect.Array, reflect.Slice:
return "array"
case reflect.Map:
return "map"
case reflect.Func:
return "func"
case reflect.Struct:
return "struct"
default:
return "unknown"
}
}
func Abs(x any) any {
switch x := x.(type) {
case float32:
if x < 0 {
return -x
} else {
return x
}
case float64:
if x < 0 {
return -x
} else {
return x
}
case int:
if x < 0 {
return -x
} else {
return x
}
case int8:
if x < 0 {
return -x
} else {
return x
}
case int16:
if x < 0 {
return -x
} else {
return x
}
case int32:
if x < 0 {
return -x
} else {
return x
}
case int64:
if x < 0 {
return -x
} else {
return x
}
case uint:
return x
case uint8:
return x
case uint16:
return x
case uint32:
return x
case uint64:
return x
}
panic(fmt.Sprintf("invalid argument for abs (type %T)", x))
}
func Ceil(x any) any {
switch x := x.(type) {
case float32:
return math.Ceil(float64(x))
case float64:
return math.Ceil(x)
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
return Float(x)
}
panic(fmt.Sprintf("invalid argument for ceil (type %T)", x))
}
func Floor(x any) any {
switch x := x.(type) {
case float32:
return math.Floor(float64(x))
case float64:
return math.Floor(x)
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
return Float(x)
}
panic(fmt.Sprintf("invalid argument for floor (type %T)", x))
}
func Round(x any) any {
switch x := x.(type) {
case float32:
return math.Round(float64(x))
case float64:
return math.Round(x)
case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
return Float(x)
}
panic(fmt.Sprintf("invalid argument for round (type %T)", x))
}
func Int(x any) any {
switch x := x.(type) {
case float32:
return int(x)
case float64:
return int(x)
case int:
return x
case int8:
return int(x)
case int16:
return int(x)
case int32:
return int(x)
case int64:
return int(x)
case uint:
return int(x)
case uint8:
return int(x)
case uint16:
return int(x)
case uint32:
return int(x)
case uint64:
return int(x)
case string:
i, err := strconv.Atoi(x)
if err != nil {
panic(fmt.Sprintf("invalid operation: int(%s)", x))
}
return i
default:
val := reflect.ValueOf(x)
if val.CanConvert(integerType) {
return val.Convert(integerType).Interface()
}
panic(fmt.Sprintf("invalid operation: int(%T)", x))
}
}
func Float(x any) any {
switch x := x.(type) {
case float32:
return float64(x)
case float64:
return x
case int:
return float64(x)
case int8:
return float64(x)
case int16:
return float64(x)
case int32:
return float64(x)
case int64:
return float64(x)
case uint:
return float64(x)
case uint8:
return float64(x)
case uint16:
return float64(x)
case uint32:
return float64(x)
case uint64:
return float64(x)
case string:
f, err := strconv.ParseFloat(x, 64)
if err != nil {
panic(fmt.Sprintf("invalid operation: float(%s)", x))
}
return f
default:
panic(fmt.Sprintf("invalid operation: float(%T)", x))
}
}
func String(arg any) any {
return fmt.Sprintf("%v", arg)
}
func minMax(name string, fn func(any, any) bool, depth int, args ...any) (any, error) {
if depth > MaxDepth {
return nil, ErrorMaxDepth
}
var val any
for _, arg := range args {
// Fast paths for common typed slices - avoid reflection and allocations
switch arr := arg.(type) {
case []int:
if len(arr) == 0 {
continue
}
m := arr[0]
for i := 1; i < len(arr); i++ {
if fn(m, arr[i]) {
m = arr[i]
}
}
if val == nil || fn(val, m) {
val = m
}
continue
case []float64:
if len(arr) == 0 {
continue
}
m := arr[0]
for i := 1; i < len(arr); i++ {
if fn(m, arr[i]) {
m = arr[i]
}
}
if val == nil || fn(val, m) {
val = m
}
continue
case []any:
// Fast path for []any with simple numeric types
for _, elem := range arr {
switch e := elem.(type) {
case int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64,
float32, float64:
if val == nil || fn(val, e) {
val = e
}
case []int, []float64, []any:
// Nested array - recurse
nested, err := minMax(name, fn, depth+1, e)
if err != nil {
return nil, err
}
if nested != nil && (val == nil || fn(val, nested)) {
val = nested
}
default:
// Could be another slice type, use reflection
rv := reflect.ValueOf(e)
if rv.Kind() == reflect.Slice || rv.Kind() == reflect.Array {
nested, err := minMax(name, fn, depth+1, e)
if err != nil {
return nil, err
}
if nested != nil && (val == nil || fn(val, nested)) {
val = nested
}
} else {
return nil, fmt.Errorf("invalid argument for %s (type %T)", name, e)
}
}
}
continue
}
// Slow path: use reflection for other types
rv := reflect.ValueOf(arg)
switch rv.Kind() {
case reflect.Array, reflect.Slice:
size := rv.Len()
for i := 0; i < size; i++ {
elemVal, err := minMax(name, fn, depth+1, rv.Index(i).Interface())
if err != nil {
return nil, err
}
switch elemVal.(type) {
case int, int8, int16, int32, int64,
uint, uint8, uint16, uint32, uint64,
float32, float64:
if elemVal != nil && (val == nil || fn(val, elemVal)) {
val = elemVal
}
default:
return nil, fmt.Errorf("invalid argument for %s (type %T)", name, elemVal)
}
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
reflect.Float32, reflect.Float64:
elemVal := rv.Interface()
if val == nil || fn(val, elemVal) {
val = elemVal
}
default:
if len(args) == 1 {
return args[0], nil
}
return nil, fmt.Errorf("invalid argument for %s (type %T)", name, arg)
}
}
return val, nil
}
func mean(depth int, args ...any) (int, float64, error) {
if depth > MaxDepth {
return 0, 0, ErrorMaxDepth
}
var total float64
var count int
for _, arg := range args {
// Fast paths for common typed slices - avoid reflection and allocations
switch arr := arg.(type) {
case []int:
for _, v := range arr {
total += float64(v)
}
count += len(arr)
continue
case []float64:
for _, v := range arr {
total += v
}
count += len(arr)
continue
case []any:
// Fast path for []any - single pass without recursive calls for flat arrays
for _, elem := range arr {
switch e := elem.(type) {
case int:
total += float64(e)
count++
case float64:
total += e
count++
case []int, []float64, []any:
// Nested array - recurse
nestedCount, nestedSum, err := mean(depth+1, e)
if err != nil {
return 0, 0, err
}
total += nestedSum
count += nestedCount
default:
// Other numeric types or slices - use reflection
rv := reflect.ValueOf(e)
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
total += float64(rv.Int())
count++
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
total += float64(rv.Uint())
count++
case reflect.Float32, reflect.Float64:
total += rv.Float()
count++
case reflect.Slice, reflect.Array:
nestedCount, nestedSum, err := mean(depth+1, e)
if err != nil {
return 0, 0, err
}
total += nestedSum
count += nestedCount
default:
return 0, 0, fmt.Errorf("invalid argument for mean (type %T)", e)
}
}
}
continue
}
// Slow path: use reflection for other types
rv := reflect.ValueOf(arg)
switch rv.Kind() {
case reflect.Array, reflect.Slice:
size := rv.Len()
for i := 0; i < size; i++ {
elemCount, elemSum, err := mean(depth+1, rv.Index(i).Interface())
if err != nil {
return 0, 0, err
}
total += elemSum
count += elemCount
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
total += float64(rv.Int())
count++
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
total += float64(rv.Uint())
count++
case reflect.Float32, reflect.Float64:
total += rv.Float()
count++
default:
return 0, 0, fmt.Errorf("invalid argument for mean (type %T)", arg)
}
}
return count, total, nil
}
func median(depth int, args ...any) ([]float64, error) {
if depth > MaxDepth {
return nil, ErrorMaxDepth
}
var values []float64
for _, arg := range args {
// Fast paths for common typed slices - avoid reflection and allocations
switch arr := arg.(type) {
case []int:
for _, v := range arr {
values = append(values, float64(v))
}
continue
case []float64:
values = append(values, arr...)
continue
case []any:
// Fast path for []any - single pass without recursive calls for flat arrays
for _, elem := range arr {
switch e := elem.(type) {
case int:
values = append(values, float64(e))
case float64:
values = append(values, e)
case []int, []float64, []any:
// Nested array - recurse
elems, err := median(depth+1, e)
if err != nil {
return nil, err
}
values = append(values, elems...)
default:
// Other numeric types or slices - use reflection
rv := reflect.ValueOf(e)
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
values = append(values, float64(rv.Int()))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
values = append(values, float64(rv.Uint()))
case reflect.Float32, reflect.Float64:
values = append(values, rv.Float())
case reflect.Slice, reflect.Array:
elems, err := median(depth+1, e)
if err != nil {
return nil, err
}
values = append(values, elems...)
default:
return nil, fmt.Errorf("invalid argument for median (type %T)", e)
}
}
}
continue
}
// Slow path: use reflection for other types
rv := reflect.ValueOf(arg)
switch rv.Kind() {
case reflect.Array, reflect.Slice:
size := rv.Len()
for i := 0; i < size; i++ {
elems, err := median(depth+1, rv.Index(i).Interface())
if err != nil {
return nil, err
}
values = append(values, elems...)
}
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
values = append(values, float64(rv.Int()))
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
values = append(values, float64(rv.Uint()))
case reflect.Float32, reflect.Float64:
values = append(values, rv.Float())
default:
return nil, fmt.Errorf("invalid argument for median (type %T)", arg)
}
}
return values, nil
}
func flatten(arg reflect.Value, depth int) ([]any, error) {
if depth > MaxDepth {
return nil, ErrorMaxDepth
}
ret := []any{}
for i := 0; i < arg.Len(); i++ {
v := deref.Value(arg.Index(i))
if v.Kind() == reflect.Array || v.Kind() == reflect.Slice {
x, err := flatten(v, depth+1)
if err != nil {
return nil, err
}
ret = append(ret, x...)
} else {
ret = append(ret, v.Interface())
}
}
return ret, nil
}
func get(params ...any) (out any, err error) {
if len(params) < 2 {
return nil, fmt.Errorf("invalid number of arguments (expected 2, got %d)", len(params))
}
from := params[0]
i := params[1]
v := reflect.ValueOf(from)
if from == nil {
return nil, nil
}
if v.Kind() == reflect.Invalid {
panic(fmt.Sprintf("cannot fetch %v from %T", i, from))
}
// Methods can be defined on any type.
if v.NumMethod() > 0 {
if methodName, ok := i.(string); ok {
method := v.MethodByName(methodName)
if method.IsValid() {
return method.Interface(), nil
}
}
}
switch v.Kind() {
case reflect.Array, reflect.Slice, reflect.String:
index := runtime.ToInt(i)
l := v.Len()
if index < 0 {
index = l + index
}
if 0 <= index && index < l {
value := v.Index(index)
if value.IsValid() {
return value.Interface(), nil
}
}
case reflect.Map:
var value reflect.Value
if i == nil {
value = v.MapIndex(reflect.Zero(v.Type().Key()))
} else {
value = v.MapIndex(reflect.ValueOf(i))
}
if value.IsValid() {
return value.Interface(), nil
}
case reflect.Struct:
fieldName := i.(string)
t := v.Type()
field, ok := t.FieldByNameFunc(func(name string) bool {
f, _ := t.FieldByName(name)
switch f.Tag.Get("expr") {
case "-":
return false
case fieldName:
return true
default:
return name == fieldName
}
})
if ok && field.IsExported() {
value := v.FieldByIndex(field.Index)
if value.IsValid() {
return value.Interface(), nil
}
}
}
// Main difference from runtime.Fetch
// is that we return `nil` instead of panic.
return nil, nil
}
================================================
FILE: builtin/utils.go
================================================
package builtin
import (
"fmt"
"reflect"
"time"
"github.com/expr-lang/expr/internal/deref"
)
var (
anyType = reflect.TypeOf(new(any)).Elem()
integerType = reflect.TypeOf(0)
floatType = reflect.TypeOf(float64(0))
arrayType = reflect.TypeOf([]any{})
mapType = reflect.TypeOf(map[any]any{})
timeType = reflect.TypeOf(new(time.Time)).Elem()
locationType = reflect.TypeOf(new(time.Location))
)
func kind(t reflect.Type) reflect.Kind {
if t == nil {
return reflect.Invalid
}
t = deref.Type(t)
return t.Kind()
}
func types(types ...any) []reflect.Type {
ts := make([]reflect.Type, len(types))
for i, t := range types {
t := reflect.TypeOf(t)
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Func {
panic("not a function")
}
ts[i] = t
}
return ts
}
func toInt(val any) (int, error) {
switch v := val.(type) {
case int:
return v, nil
case int8:
return int(v), nil
case int16:
return int(v), nil
case int32:
return int(v), nil
case int64:
return int(v), nil
case uint:
return int(v), nil
case uint8:
return int(v), nil
case uint16:
return int(v), nil
case uint32:
return int(v), nil
case uint64:
return int(v), nil
default:
return 0, fmt.Errorf("cannot use %T as argument (type int)", val)
}
}
func bitFunc(name string, fn func(x, y int) (any, error)) *Function {
return &Function{
Name: name,
Func: func(args ...any) (any, error) {
if len(args) != 2 {
return nil, fmt.Errorf("invalid number of arguments for %s (expected 2, got %d)", name, len(args))
}
x, err := toInt(args[0])
if err != nil {
return nil, fmt.Errorf("%v to call %s", err, name)
}
y, err := toInt(args[1])
if err != nil {
return nil, fmt.Errorf("%v to call %s", err, name)
}
return fn(x, y)
},
Types: types(new(func(int, int) int)),
}
}
================================================
FILE: builtin/validation.go
================================================
package builtin
import (
"fmt"
"reflect"
"github.com/expr-lang/expr/internal/deref"
)
func validateAggregateFunc(name string, args []reflect.Type) (reflect.Type, error) {
switch len(args) {
case 0:
return anyType, fmt.Errorf("not enough arguments to call %s", name)
default:
for _, arg := range args {
switch kind(deref.Type(arg)) {
case reflect.Interface, reflect.Array, reflect.Slice:
return anyType, nil
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, reflect.Float64:
default:
return anyType, fmt.Errorf("invalid argument for %s (type %s)", name, arg)
}
}
return args[0], nil
}
}
func validateRoundFunc(name string, args []reflect.Type) (reflect.Type, error) {
if len(args) != 1 {
return anyType, fmt.Errorf("invalid number of arguments (expected 1, got %d)", len(args))
}
switch kind(args[0]) {
case reflect.Float32, reflect.Float64, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Interface:
return floatType, nil
default:
return anyType, fmt.Errorf("invalid argument for %s (type %s)", name, args[0])
}
}
================================================
FILE: checker/checker.go
================================================
package checker
import (
"fmt"
"reflect"
"regexp"
"time"
"github.com/expr-lang/expr/ast"
"github.com/expr-lang/expr/builtin"
. "github.com/expr-lang/expr/checker/nature"
"github.com/expr-lang/expr/conf"
"github.com/expr-lang/expr/file"
"github.com/expr-lang/expr/parser"
)
var (
anyType = reflect.TypeOf(new(any)).Elem()
boolType = reflect.TypeOf(true)
intType = reflect.TypeOf(0)
floatType = reflect.TypeOf(float64(0))
stringType = reflect.TypeOf("")
arrayType = reflect.TypeOf([]any{})
mapType = reflect.TypeOf(map[string]any{})
timeType = reflect.TypeOf(time.Time{})
durationType = reflect.TypeOf(time.Duration(0))
byteSliceType = reflect.TypeOf([]byte(nil))
anyTypeSlice = []reflect.Type{anyType}
)
// ParseCheck parses input expression and checks its types. Also, it applies
// all provided patchers. In case of error, it returns error with a tree.
func ParseCheck(input string, config *conf.Config) (*parser.Tree, error) {
tree, err := parser.ParseWithConfig(input, config)
if err != nil {
return tree, err
}
_, err = new(Checker).PatchAndCheck(tree, config)
if err != nil {
return tree, err
}
return tree, nil
}
// Check calls Check on a disposable Checker.
func Check(tree *parser.Tree, config *conf.Config) (reflect.Type, error) {
return new(Checker).Check(tree, config)
}
type Checker struct {
config *conf.Config
predicateScopes []predicateScope
varScopes []varScope
err *file.Error
needsReset bool
}
type predicateScope struct {
collection Nature
vars []varScope
}
type varScope struct {
name string
nature Nature
}
// PatchAndCheck applies all patchers and checks the tree.
func (v *Checker) PatchAndCheck(tree *parser.Tree, config *conf.Config) (reflect.Type, error) {
v.reset(config)
if len(config.Visitors) > 0 {
// Run all patchers that dont support being run repeatedly first
v.runVisitors(tree, false)
// Run patchers that require multiple passes next (currently only Operator patching)
v.runVisitors(tree, true)
}
return v.Check(tree, config)
}
// Check checks types of the expression tree. It returns type of the expression
// and error if any. If config is nil, then default configuration will be used.
func (v *Checker) Check(tree *parser.Tree, config *conf.Config) (reflect.Type, error) {
v.reset(config)
return v.check(tree)
}
// Run visitors in a given config over the given tree
// runRepeatable controls whether to filter for only vistors that require multiple passes or not
func (v *Checker) runVisitors(tree *parser.Tree, runRepeatable bool) {
for {
more := false
for _, visitor := range v.config.Visitors {
// We need to perform types check, because some visitors may rely on
// types information available in the tree.
_, _ = v.Check(tree, v.config)
r, repeatable := visitor.(interface {
Reset()
ShouldRepeat() bool
})
if repeatable {
if runRepeatable {
r.Reset()
ast.Walk(&tree.Node, visitor)
more = more || r.ShouldRepeat()
}
} else {
if !runRepeatable {
ast.Walk(&tree.Node, visitor)
}
}
}
if !more {
break
}
}
}
func (v *Checker) check(tree *parser.Tree) (reflect.Type, error) {
nt := v.visit(tree.Node)
// To keep compatibility with previous versions, we should return any, if nature is unknown.
t := nt.Type
if t == nil {
t = anyType
}
if v.err != nil {
return t, v.err.Bind(tree.Source)
}
if v.config.Expect != reflect.Invalid {
if v.config.ExpectAny {
if nt.IsUnknown(&v.config.NtCache) {
return t, nil
}
}
switch v.config.Expect {
case reflect.Int, reflect.Int64, reflect.Float64:
if !nt.IsNumber() {
return nil, fmt.Errorf("expected %v, but got %s", v.config.Expect, nt.String())
}
default:
if nt.Kind != v.config.Expect {
return nil, fmt.Errorf("expected %v, but got %s", v.config.Expect, nt.String())
}
}
}
return t, nil
}
func (v *Checker) reset(config *conf.Config) {
if v.needsReset {
clearSlice(v.predicateScopes)
clearSlice(v.varScopes)
v.predicateScopes = v.predicateScopes[:0]
v.varScopes = v.varScopes[:0]
v.err = nil
}
v.needsReset = true
if config == nil {
config = conf.New(nil)
}
v.config = config
}
func clearSlice[S ~[]E, E any](s S) {
var zero E
for i := range s {
s[i] = zero
}
}
func (v *Checker) visit(node ast.Node) Nature {
var nt Nature
switch n := node.(type) {
case *ast.NilNode:
nt = v.config.NtCache.NatureOf(nil)
case *ast.IdentifierNode:
nt = v.identifierNode(n)
case *ast.IntegerNode:
nt = v.config.NtCache.FromType(intType)
case *ast.FloatNode:
nt = v.config.NtCache.FromType(floatType)
case *ast.BoolNode:
nt = v.config.NtCache.FromType(boolType)
case *ast.StringNode:
nt = v.config.NtCache.FromType(stringType)
case *ast.BytesNode:
nt = v.config.NtCache.FromType(byteSliceType)
case *ast.ConstantNode:
nt = v.config.NtCache.FromType(reflect.TypeOf(n.Value))
case *ast.UnaryNode:
nt = v.unaryNode(n)
case *ast.BinaryNode:
nt = v.binaryNode(n)
case *ast.ChainNode:
nt = v.chainNode(n)
case *ast.MemberNode:
nt = v.memberNode(n)
case *ast.SliceNode:
nt = v.sliceNode(n)
case *ast.CallNode:
nt = v.callNode(n)
case *ast.BuiltinNode:
nt = v.builtinNode(n)
case *ast.PredicateNode:
nt = v.predicateNode(n)
case *ast.PointerNode:
nt = v.pointerNode(n)
case *ast.VariableDeclaratorNode:
nt = v.variableDeclaratorNode(n)
case *ast.SequenceNode:
nt = v.sequenceNode(n)
case *ast.ConditionalNode:
nt = v.conditionalNode(n)
case *ast.ArrayNode:
nt = v.arrayNode(n)
case *ast.MapNode:
nt = v.mapNode(n)
case *ast.PairNode:
nt = v.pairNode(n)
default:
panic(fmt.Sprintf("undefined node type (%T)", node))
}
node.SetNature(nt)
return nt
}
func (v *Checker) error(node ast.Node, format string, args ...any) Nature {
if v.err == nil { // show first error
v.err = &file.Error{
Location: node.Location(),
Message: fmt.Sprintf(format, args...),
}
}
return Nature{}
}
func (v *Checker) identifierNode(node *ast.IdentifierNode) Nature {
for i := len(v.varScopes) - 1; i >= 0; i-- {
if v.varScopes[i].name == node.Value {
return v.varScopes[i].nature
}
}
if node.Value == "$env" {
return Nature{}
}
return v.ident(node, node.Value, v.config.Strict, true)
}
// ident method returns type of environment variable, builtin or function.
func (v *Checker) ident(node ast.Node, name string, strict, builtins bool) Nature {
if nt, ok := v.config.Env.Get(&v.config.NtCache, name); ok {
return nt
}
if builtins {
if fn, ok := v.config.Functions[name]; ok {
nt := v.config.NtCache.FromType(fn.Type())
if nt.TypeData == nil {
nt.TypeData = new(TypeData)
}
nt.TypeData.Func = fn
return nt
}
if fn, ok := v.config.Builtins[name]; ok {
nt := v.config.NtCache.FromType(fn.Type())
if nt.TypeData == nil {
nt.TypeData = new(TypeData)
}
nt.TypeData.Func = fn
return nt
}
}
if v.config.Strict && strict {
return v.error(node, "unknown name %s", name)
}
return Nature{}
}
func (v *Checker) unaryNode(node *ast.UnaryNode) Nature {
nt := v.visit(node.Node)
nt = nt.Deref(&v.config.NtCache)
switch node.Operator {
case "!", "not":
if nt.IsBool() {
return v.config.NtCache.FromType(boolType)
}
if nt.IsUnknown(&v.config.NtCache) {
return v.config.NtCache.FromType(boolType)
}
case "+", "-":
if nt.IsNumber() {
return nt
}
if nt.IsUnknown(&v.config.NtCache) {
return Nature{}
}
default:
return v.error(node, "unknown operator (%s)", node.Operator)
}
return v.error(node, `invalid operation: %s (mismatched type %s)`, node.Operator, nt.String())
}
func (v *Checker) binaryNode(node *ast.BinaryNode) Nature {
l := v.visit(node.Left)
r := v.visit(node.Right)
l = l.Deref(&v.config.NtCache)
r = r.Deref(&v.config.NtCache)
switch node.Operator {
case "==", "!=":
if l.ComparableTo(&v.config.NtCache, r) {
return v.config.NtCache.FromType(boolType)
}
case "or", "||", "and", "&&":
if l.IsBool() && r.IsBool() {
return v.config.NtCache.FromType(boolType)
}
if l.MaybeCompatible(&v.config.NtCache, r, BoolCheck) {
return v.config.NtCache.FromType(boolType)
}
case "<", ">", ">=", "<=":
if l.IsNumber() && r.IsNumber() {
return v.config.NtCache.FromType(boolType)
}
if l.IsString() && r.IsString() {
return v.config.NtCache.FromType(boolType)
}
if l.IsTime() && r.IsTime() {
return v.config.NtCache.FromType(boolType)
}
if l.IsDuration() && r.IsDuration() {
return v.config.NtCache.FromType(boolType)
}
if l.MaybeCompatible(&v.config.NtCache, r, NumberCheck, StringCheck, TimeCheck, DurationCheck) {
return v.config.NtCache.FromType(boolType)
}
case "-":
if l.IsNumber() && r.IsNumber() {
return l.PromoteNumericNature(&v.config.NtCache, r)
}
if l.IsTime() && r.IsTime() {
return v.config.NtCache.FromType(durationType)
}
if l.IsTime() && r.IsDuration() {
return v.config.NtCache.FromType(timeType)
}
if l.IsDuration() && r.IsDuration() {
return v.config.NtCache.FromType(durationType)
}
if l.MaybeCompatible(&v.config.NtCache, r, NumberCheck, TimeCheck, DurationCheck) {
return Nature{}
}
case "*":
if l.IsNumber() && r.IsNumber() {
return l.PromoteNumericNature(&v.config.NtCache, r)
}
if l.IsNumber() && r.IsDuration() {
return v.config.NtCache.FromType(durationType)
}
if l.IsDuration() && r.IsNumber() {
return v.config.NtCache.FromType(durationType)
}
if l.IsDuration() && r.IsDuration() {
return v.config.NtCache.FromType(durationType)
}
if l.MaybeCompatible(&v.config.NtCache, r, NumberCheck, DurationCheck) {
return Nature{}
}
case "/":
if l.IsNumber() && r.IsNumber() {
return v.config.NtCache.FromType(floatType)
}
if l.MaybeCompatible(&v.config.NtCache, r, NumberCheck) {
return v.config.NtCache.FromType(floatType)
}
case "**", "^":
if l.IsNumber() && r.IsNumber() {
return v.config.NtCache.FromType(floatType)
}
if l.MaybeCompatible(&v.config.NtCache, r, NumberCheck) {
return v.config.NtCache.FromType(floatType)
}
case "%":
if l.IsInteger && r.IsInteger {
return v.config.NtCache.FromType(intType)
}
if l.MaybeCompatible(&v.config.NtCache, r, IntegerCheck) {
return v.config.NtCache.FromType(intType)
}
case "+":
if l.IsNumber() && r.IsNumber() {
return l.PromoteNumericNature(&v.config.NtCache, r)
}
if l.IsString() && r.IsString() {
return v.config.NtCache.FromType(stringType)
}
if l.IsTime() && r.IsDuration() {
return v.config.NtCache.FromType(timeType)
}
if l.IsDuration() && r.IsTime() {
return v.config.NtCache.FromType(timeType)
}
if l.IsDuration() && r.IsDuration() {
return v.config.NtCache.FromType(durationType)
}
if l.MaybeCompatible(&v.config.NtCache, r, NumberCheck, StringCheck, TimeCheck, DurationCheck) {
return Nature{}
}
case "in":
if (l.IsString() || l.IsUnknown(&v.config.NtCache)) && r.IsStruct() {
return v.config.NtCache.FromType(boolType)
}
if r.IsMap() {
rKey := r.Key(&v.config.NtCache)
if !l.IsUnknown(&v.config.NtCache) && !l.AssignableTo(rKey) {
return v.error(node, "cannot use %s as type %s in map key", l.String(), rKey.String())
}
return v.config.NtCache.FromType(boolType)
}
if r.IsArray() {
rElem := r.Elem(&v.config.NtCache)
if !l.ComparableTo(&v.config.NtCache, rElem) {
return v.error(node, "cannot use %s as type %s in array", l.String(), rElem.String())
}
return v.config.NtCache.FromType(boolType)
}
if l.IsUnknown(&v.config.NtCache) && r.IsAnyOf(StringCheck, ArrayCheck, MapCheck) {
return v.config.NtCache.FromType(boolType)
}
if r.IsUnknown(&v.config.NtCache) {
return v.config.NtCache.FromType(boolType)
}
case "matches":
if s, ok := node.Right.(*ast.StringNode); ok {
_, err := regexp.Compile(s.Value)
if err != nil {
return v.error(node, err.Error())
}
}
if (l.IsString() || l.IsByteSlice()) && r.IsString() {
return v.config.NtCache.FromType(boolType)
}
if l.MaybeCompatible(&v.config.NtCache, r, StringCheck) {
return v.config.NtCache.FromType(boolType)
}
case "contains", "startsWith", "endsWith":
if l.IsString() && r.IsString() {
return v.config.NtCache.FromType(boolType)
}
if l.MaybeCompatible(&v.config.NtCache, r, StringCheck) {
return v.config.NtCache.FromType(boolType)
}
case "..":
if l.IsInteger && r.IsInteger || l.MaybeCompatible(&v.config.NtCache, r, IntegerCheck) {
return ArrayFromType(&v.config.NtCache, intType)
}
case "??":
if l.Nil && !r.Nil {
return r
}
if !l.Nil && r.Nil {
return l
}
if l.Nil && r.Nil {
return v.config.NtCache.NatureOf(nil)
}
if r.AssignableTo(l) {
return l
}
return Nature{}
default:
return v.error(node, "unknown operator (%s)", node.Operator)
}
return v.error(node, `invalid operation: %s (mismatched types %s and %s)`, node.Operator, l.String(), r.String())
}
func (v *Checker) chainNode(node *ast.ChainNode) Nature {
return v.visit(node.Node)
}
func (v *Checker) memberNode(node *ast.MemberNode) Nature {
// $env variable
if an, ok := node.Node.(*ast.IdentifierNode); ok && an.Value == "$env" {
if name, ok := node.Property.(*ast.StringNode); ok {
strict := v.config.Strict
if node.Optional {
// If user explicitly set optional flag, then we should not
// throw error if field is not found (as user trying to handle
// this case). But if user did not set optional flag, then we
// should throw error if field is not found & v.config.Strict.
strict = false
}
return v.ident(node, name.Value, strict, false /* no builtins and no functions */)
}
return Nature{}
}
base := v.visit(node.Node)
prop := v.visit(node.Property)
if base.IsUnknown(&v.config.NtCache) {
return Nature{}
}
if name, ok := node.Property.(*ast.StringNode); ok {
if base.Nil {
return v.error(node, "type nil has no field %s", name.Value)
}
// First, check methods defined on base type itself,
// independent of which type it is. Without dereferencing.
if m, ok := base.MethodByName(&v.config.NtCache, name.Value); ok {
return m
}
}
base = base.Deref(&v.config.NtCache)
switch base.Kind {
case reflect.Map:
// If the map key is a pointer, we should not dereference the property.
if !prop.AssignableTo(base.Key(&v.config.NtCache)) {
propDeref := prop.Deref(&v.config.NtCache)
if propDeref.AssignableTo(base.Key(&v.config.NtCache)) {
prop = propDeref
}
}
if !prop.AssignableTo(base.Key(&v.config.NtCache)) && !prop.IsUnknown(&v.config.NtCache) {
return v.error(node.Property, "cannot use %s to get an element from %s", prop.String(), base.String())
}
if prop, ok := node.Property.(*ast.StringNode); ok && base.TypeData != nil {
if field, ok := base.Fields[prop.Value]; ok {
return field
} else if base.Strict {
return v.error(node.Property, "unknown field %s", prop.Value)
}
}
return base.Elem(&v.config.NtCache)
case reflect.Array, reflect.Slice:
prop = prop.Deref(&v.config.NtCache)
if !prop.IsInteger && !prop.IsUnknown(&v.config.NtCache) {
return v.error(node.Property, "array elements can only be selected using an integer (got %s)", prop.String())
}
return base.Elem(&v.config.NtCache)
case reflect.Struct:
if name, ok := node.Property.(*ast.StringNode); ok {
propertyName := name.Value
if field, ok := base.FieldByName(&v.config.NtCache, propertyName); ok {
return v.config.NtCache.FromType(field.Type)
}
if node.Method {
return v.error(node, "type %v has no method %v", base.String(), propertyName)
}
return v.error(node, "type %v has no field %v", base.String(), propertyName)
}
}
// Not found.
if name, ok := node.Property.(*ast.StringNode); ok {
if node.Method {
return v.error(node, "type %v has no method %v", base.String(), name.Value)
}
return v.error(node, "type %v has no field %v", base.String(), name.Value)
}
return v.error(node, "type %v[%v] is undefined", base.String(), prop.String())
}
func (v *Checker) sliceNode(node *ast.SliceNode) Nature {
nt := v.visit(node.Node)
if nt.IsUnknown(&v.config.NtCache) {
return Nature{}
}
switch nt.Kind {
case reflect.String, reflect.Array, reflect.Slice:
// ok
default:
return v.error(node, "cannot slice %s", nt.String())
}
if node.From != nil {
from := v.visit(node.From)
from = from.Deref(&v.config.NtCache)
if !from.IsInteger && !from.IsUnknown(&v.config.NtCache) {
return v.error(node.From, "non-integer slice index %v", from.String())
}
}
if node.To != nil {
to := v.visit(node.To)
to = to.Deref(&v.config.NtCache)
if !to.IsInteger && !to.IsUnknown(&v.config.NtCache) {
return v.error(node.To, "non-integer slice index %v", to.String())
}
}
return nt
}
func (v *Checker) callNode(node *ast.CallNode) Nature {
// Check if type was set on node (for example, by patcher)
// and use node type instead of function return type.
//
// If node type is anyType, then we should use function
// return type. For example, on error we return anyType
// for a call `errCall().Method()` and method will be
// evaluated on `anyType.Method()`, so return type will
// be anyType `anyType.Method(): anyType`. Patcher can
// fix `errCall()` to return proper type, so on second
// checker pass we should replace anyType on method node
// with new correct function return type.
if typ := node.Type(); typ != nil && typ != anyType {
return *node.Nature()
}
// $env is not callable.
if id, ok := node.Callee.(*ast.IdentifierNode); ok && id.Value == "$env" {
return v.error(node, "%s is not callable", v.config.Env.String())
}
nt := v.visit(node.Callee)
if nt.IsUnknown(&v.config.NtCache) {
return Nature{}
}
if nt.TypeData != nil && nt.TypeData.Func != nil {
return v.checkFunction(nt.TypeData.Func, node, node.Arguments)
}
fnName := "function"
if identifier, ok := node.Callee.(*ast.IdentifierNode); ok {
fnName = identifier.Value
}
if member, ok := node.Callee.(*ast.MemberNode); ok {
if name, ok := member.Property.(*ast.StringNode); ok {
fnName = name.Value
}
}
if nt.Nil {
return v.error(node, "%v is nil; cannot call nil as function", fnName)
}
if nt.Kind == reflect.Func {
outType, err := v.checkArguments(fnName, nt, node.Arguments, node)
if err != nil {
if v.err == nil {
v.err = err
}
return Nature{}
}
return outType
}
return v.error(node, "%s is not callable", nt.String())
}
func (v *Checker) builtinNode(node *ast.BuiltinNode) Nature {
switch node.Name {
case "all", "none", "any", "one":
collection := v.visit(node.Arguments[0])
collection = collection.Deref(&v.config.NtCache)
if !collection.IsArray() && !collection.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection.String())
}
v.begin(collection)
predicate := v.visit(node.Arguments[1])
v.end()
if predicate.IsFunc() &&
predicate.NumOut() == 1 &&
predicate.NumIn() == 1 && predicate.IsFirstArgUnknown(&v.config.NtCache) {
predicateOut := predicate.Out(&v.config.NtCache, 0)
if !predicateOut.IsBool() && !predicateOut.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[1], "predicate should return boolean (got %s)", predicateOut.String())
}
return v.config.NtCache.FromType(boolType)
}
return v.error(node.Arguments[1], "predicate should has one input and one output param")
case "filter":
collection := v.visit(node.Arguments[0])
collection = collection.Deref(&v.config.NtCache)
if !collection.IsArray() && !collection.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection.String())
}
v.begin(collection)
predicate := v.visit(node.Arguments[1])
v.end()
if predicate.IsFunc() &&
predicate.NumOut() == 1 &&
predicate.NumIn() == 1 && predicate.IsFirstArgUnknown(&v.config.NtCache) {
predicateOut := predicate.Out(&v.config.NtCache, 0)
if !predicateOut.IsBool() && !predicateOut.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[1], "predicate should return boolean (got %s)", predicateOut.String())
}
if collection.IsUnknown(&v.config.NtCache) {
return v.config.NtCache.FromType(arrayType)
}
collection = collection.Elem(&v.config.NtCache)
return collection.MakeArrayOf(&v.config.NtCache)
}
return v.error(node.Arguments[1], "predicate should has one input and one output param")
case "map":
collection := v.visit(node.Arguments[0])
collection = collection.Deref(&v.config.NtCache)
if !collection.IsArray() && !collection.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection.String())
}
v.begin(collection, varScope{"index", v.config.NtCache.FromType(intType)})
predicate := v.visit(node.Arguments[1])
v.end()
if predicate.IsFunc() &&
predicate.NumOut() == 1 &&
predicate.NumIn() == 1 && predicate.IsFirstArgUnknown(&v.config.NtCache) {
return predicate.Ref.MakeArrayOf(&v.config.NtCache)
}
return v.error(node.Arguments[1], "predicate should has one input and one output param")
case "count":
collection := v.visit(node.Arguments[0])
collection = collection.Deref(&v.config.NtCache)
if !collection.IsArray() && !collection.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection.String())
}
if len(node.Arguments) == 1 {
return v.config.NtCache.FromType(intType)
}
v.begin(collection)
predicate := v.visit(node.Arguments[1])
v.end()
if predicate.IsFunc() &&
predicate.NumOut() == 1 &&
predicate.NumIn() == 1 && predicate.IsFirstArgUnknown(&v.config.NtCache) {
predicateOut := predicate.Out(&v.config.NtCache, 0)
if !predicateOut.IsBool() && !predicateOut.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[1], "predicate should return boolean (got %s)", predicateOut.String())
}
return v.config.NtCache.FromType(intType)
}
return v.error(node.Arguments[1], "predicate should has one input and one output param")
case "sum":
collection := v.visit(node.Arguments[0])
collection = collection.Deref(&v.config.NtCache)
if !collection.IsArray() && !collection.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection.String())
}
if len(node.Arguments) == 2 {
v.begin(collection)
predicate := v.visit(node.Arguments[1])
v.end()
if predicate.IsFunc() &&
predicate.NumOut() == 1 &&
predicate.NumIn() == 1 && predicate.IsFirstArgUnknown(&v.config.NtCache) {
return predicate.Out(&v.config.NtCache, 0)
}
} else {
if collection.IsUnknown(&v.config.NtCache) {
return Nature{}
}
return collection.Elem(&v.config.NtCache)
}
case "find", "findLast":
collection := v.visit(node.Arguments[0])
collection = collection.Deref(&v.config.NtCache)
if !collection.IsArray() && !collection.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection.String())
}
v.begin(collection)
predicate := v.visit(node.Arguments[1])
v.end()
if predicate.IsFunc() &&
predicate.NumOut() == 1 &&
predicate.NumIn() == 1 && predicate.IsFirstArgUnknown(&v.config.NtCache) {
predicateOut := predicate.Out(&v.config.NtCache, 0)
if !predicateOut.IsBool() && !predicateOut.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[1], "predicate should return boolean (got %s)", predicateOut.String())
}
if collection.IsUnknown(&v.config.NtCache) {
return Nature{}
}
return collection.Elem(&v.config.NtCache)
}
return v.error(node.Arguments[1], "predicate should has one input and one output param")
case "findIndex", "findLastIndex":
collection := v.visit(node.Arguments[0])
collection = collection.Deref(&v.config.NtCache)
if !collection.IsArray() && !collection.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection.String())
}
v.begin(collection)
predicate := v.visit(node.Arguments[1])
v.end()
if predicate.IsFunc() &&
predicate.NumOut() == 1 &&
predicate.NumIn() == 1 && predicate.IsFirstArgUnknown(&v.config.NtCache) {
predicateOut := predicate.Out(&v.config.NtCache, 0)
if !predicateOut.IsBool() && !predicateOut.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[1], "predicate should return boolean (got %s)", predicateOut.String())
}
return v.config.NtCache.FromType(intType)
}
return v.error(node.Arguments[1], "predicate should has one input and one output param")
case "groupBy":
collection := v.visit(node.Arguments[0])
collection = collection.Deref(&v.config.NtCache)
if !collection.IsArray() && !collection.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection.String())
}
v.begin(collection)
predicate := v.visit(node.Arguments[1])
v.end()
if predicate.IsFunc() &&
predicate.NumOut() == 1 &&
predicate.NumIn() == 1 && predicate.IsFirstArgUnknown(&v.config.NtCache) {
collection = collection.Elem(&v.config.NtCache)
collection = collection.MakeArrayOf(&v.config.NtCache)
nt := v.config.NtCache.NatureOf(map[any][]any{})
nt.Ref = &collection
return nt
}
return v.error(node.Arguments[1], "predicate should has one input and one output param")
case "sortBy":
collection := v.visit(node.Arguments[0])
collection = collection.Deref(&v.config.NtCache)
if !collection.IsArray() && !collection.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection.String())
}
v.begin(collection)
predicate := v.visit(node.Arguments[1])
v.end()
if len(node.Arguments) == 3 {
order := v.visit(node.Arguments[2])
if !order.IsString() && !order.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[2], "sortBy order argument must be a string (got %v)", order.String())
}
}
if predicate.IsFunc() &&
predicate.NumOut() == 1 &&
predicate.NumIn() == 1 && predicate.IsFirstArgUnknown(&v.config.NtCache) {
return collection
}
return v.error(node.Arguments[1], "predicate should has one input and one output param")
case "reduce":
collection := v.visit(node.Arguments[0])
collection = collection.Deref(&v.config.NtCache)
if !collection.IsArray() && !collection.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection.String())
}
v.begin(collection, varScope{"index", v.config.NtCache.FromType(intType)}, varScope{"acc", Nature{}})
predicate := v.visit(node.Arguments[1])
v.end()
if len(node.Arguments) == 3 {
_ = v.visit(node.Arguments[2])
}
if predicate.IsFunc() && predicate.NumOut() == 1 {
return *predicate.Ref
}
return v.error(node.Arguments[1], "predicate should has two input and one output param")
}
if id, ok := builtin.Index[node.Name]; ok {
switch node.Name {
case "get":
return v.checkBuiltinGet(node)
}
return v.checkFunction(builtin.Builtins[id], node, node.Arguments)
}
return v.error(node, "unknown builtin %v", node.Name)
}
func (v *Checker) begin(collectionNature Nature, vars ...varScope) {
v.predicateScopes = append(v.predicateScopes, predicateScope{
collection: collectionNature,
vars: vars,
})
}
func (v *Checker) end() {
v.predicateScopes = v.predicateScopes[:len(v.predicateScopes)-1]
}
func (v *Checker) checkBuiltinGet(node *ast.BuiltinNode) Nature {
if len(node.Arguments) != 2 {
return v.error(node, "invalid number of arguments (expected 2, got %d)", len(node.Arguments))
}
base := v.visit(node.Arguments[0])
prop := v.visit(node.Arguments[1])
prop = prop.Deref(&v.config.NtCache)
if id, ok := node.Arguments[0].(*ast.IdentifierNode); ok && id.Value == "$env" {
if s, ok := node.Arguments[1].(*ast.StringNode); ok {
if nt, ok := v.config.Env.Get(&v.config.NtCache, s.Value); ok {
return nt
}
}
return Nature{}
}
if base.IsUnknown(&v.config.NtCache) {
return Nature{}
}
switch base.Kind {
case reflect.Slice, reflect.Array:
if !prop.IsInteger && !prop.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[1], "non-integer slice index %s", prop.String())
}
return base.Elem(&v.config.NtCache)
case reflect.Map:
if !prop.AssignableTo(base.Key(&v.config.NtCache)) && !prop.IsUnknown(&v.config.NtCache) {
return v.error(node.Arguments[1], "cannot use %s to get an element from %s", prop.String(), base.String())
}
return base.Elem(&v.config.NtCache)
}
return v.error(node.Arguments[0], "type %v does not support indexing", base.String())
}
func (v *Checker) checkFunction(f *builtin.Function, node ast.Node, arguments []ast.Node) Nature {
if f.Validate != nil {
args := make([]reflect.Type, len(arguments))
for i, arg := range arguments {
argNature := v.visit(arg)
if argNature.IsUnknown(&v.config.NtCache) {
args[i] = anyType
} else {
args[i] = argNature.Type
}
}
t, err := f.Validate(args)
if err != nil {
return v.error(node, "%v", err)
}
return v.config.NtCache.FromType(t)
} else if len(f.Types) == 0 {
nt, err := v.checkArguments(f.Name, v.config.NtCache.FromType(f.Type()), arguments, node)
if err != nil {
if v.err == nil {
v.err = err
}
return Nature{}
}
// No type was specified, so we assume the function returns any.
return nt
}
var lastErr *file.Error
for _, t := range f.Types {
outNature, err := v.checkArguments(f.Name, v.config.NtCache.FromType(t), arguments, node)
if err != nil {
lastErr = err
continue
}
// As we found the correct function overload, we can stop the loop.
// Also, we need to set the correct nature of the callee so compiler,
// can correctly handle OpDeref opcode.
if callNode, ok := node.(*ast.CallNode); ok {
callNode.Callee.SetType(t)
}
return outNature
}
if lastErr != nil {
if v.err == nil {
v.err = lastErr
}
return Nature{}
}
return v.error(node, "no matching overload for %v", f.Name)
}
func (v *Checker) checkArguments(
name string,
fn Nature,
arguments []ast.Node,
node ast.Node,
) (Nature, *file.Error) {
if fn.IsUnknown(&v.config.NtCache) {
return Nature{}, nil
}
numOut := fn.NumOut()
if numOut == 0 {
return Nature{}, &file.Error{
Location: node.Location(),
Message: fmt.Sprintf("func %v doesn't return value", name),
}
}
if numOut > 2 {
return Nature{}, &file.Error{
Location: node.Location(),
Message: fmt.Sprintf("func %v returns more then two values", name),
}
}
// If func is method on an env, first argument should be a receiver,
// and actual arguments less than fnNumIn by one.
fnNumIn := fn.NumIn()
if fn.Method { // TODO: Move subtraction to the Nature.NumIn() and Nature.In() methods.
fnNumIn--
}
// Skip first argument in case of the receiver.
fnInOffset := 0
if fn.Method {
fnInOffset = 1
}
var err *file.Error
isVariadic := fn.IsVariadic()
if isVariadic {
if len(arguments) < fnNumIn-1 {
err = &file.Error{
Location: node.Location(),
Message: fmt.Sprintf("not enough arguments to call %v", name),
}
}
} else {
if len(arguments) > fnNumIn {
err = &file.Error{
Location: node.Location(),
Message: fmt.Sprintf("too many arguments to call %v", name),
}
}
if len(arguments) < fnNumIn {
err = &file.Error{
Location: node.Location(),
Message: fmt.Sprintf("not enough arguments to call %v", name),
}
}
}
if err != nil {
// If we have an error, we should still visit all arguments to
// type check them, as a patch can fix the error later.
for _, arg := range arguments {
_ = v.visit(arg)
}
return fn.Out(&v.config.NtCache, 0), err
}
for i, arg := range arguments {
argNature := v.visit(arg)
var in Nature
if isVariadic && i >= fnNumIn-1 {
// For variadic arguments fn(xs ...int), go replaces type of xs (int) with ([]int).
// As we compare arguments one by one, we need underling type.
in = fn.InElem(&v.config.NtCache, fnNumIn-1+fnInOffset)
} else {
in = fn.In(&v.config.NtCache, i+fnInOffset)
}
if in.IsFloat && argNature.IsInteger {
traverseAndReplaceIntegerNodesWithFloatNodes(&arguments[i], in)
continue
}
if in.IsInteger && argNature.IsInteger && argNature.Kind != in.Kind {
traverseAndReplaceIntegerNodesWithIntegerNodes(&arguments[i], in)
continue
}
if argNature.Nil {
if in.Kind == reflect.Ptr || in.Kind == reflect.Interface {
continue
}
return Nature{}, &file.Error{
Location: arg.Location(),
Message: fmt.Sprintf("cannot use nil as argument (type %s) to call %v", in.String(), name),
}
}
// Check if argument is assignable to the function input type.
// We check original type (like *time.Time), not dereferenced type,
// as function input type can be pointer to a struct.
assignable := argNature.AssignableTo(in)
// We also need to check if dereference arg type is assignable to the function input type.
// For example, func(int) and argument *int. In this case we will add OpDeref to the argument,
// so we can call the function with *int argument.
if !assignable && argNature.IsPointer() {
nt := argNature.Deref(&v.config.NtCache)
assignable = nt.AssignableTo(in)
}
if !assignable && !argNature.IsUnknown(&v.config.NtCache) {
return Nature{}, &file.Error{
Location: arg.Location(),
Message: fmt.Sprintf("cannot use %s as argument (type %s) to call %v ", argNature.String(), in.String(), name),
}
}
}
return fn.Out(&v.config.NtCache, 0), nil
}
func traverseAndReplaceIntegerNodesWithFloatNodes(node *ast.Node, newNature Nature) {
switch (*node).(type) {
case *ast.IntegerNode:
*node = &ast.FloatNode{Value: float64((*node).(*ast.IntegerNode).Value)}
(*node).SetType(newNature.Type)
case *ast.UnaryNode:
unaryNode := (*node).(*ast.UnaryNode)
traverseAndReplaceIntegerNodesWithFloatNodes(&unaryNode.Node, newNature)
case *ast.BinaryNode:
binaryNode := (*node).(*ast.BinaryNode)
switch binaryNode.Operator {
case "+", "-", "*":
traverseAndReplaceIntegerNodesWithFloatNodes(&binaryNode.Left, newNature)
traverseAndReplaceIntegerNodesWithFloatNodes(&binaryNode.Right, newNature)
}
}
}
func traverseAndReplaceIntegerNodesWithIntegerNodes(node *ast.Node, newNature Nature) {
switch (*node).(type) {
case *ast.IntegerNode:
(*node).SetType(newNature.Type)
case *ast.UnaryNode:
(*node).SetType(newNature.Type)
unaryNode := (*node).(*ast.UnaryNode)
traverseAndReplaceIntegerNodesWithIntegerNodes(&unaryNode.Node, newNature)
case *ast.BinaryNode:
// TODO: Binary node return type is dependent on the type of the operands. We can't just change the type of the node.
binaryNode := (*node).(*ast.BinaryNode)
switch binaryNode.Operator {
case "+", "-", "*":
traverseAndReplaceIntegerNodesWithIntegerNodes(&binaryNode.Left, newNature)
traverseAndReplaceIntegerNodesWithIntegerNodes(&binaryNode.Right, newNature)
}
}
}
func (v *Checker) predicateNode(node *ast.PredicateNode) Nature {
nt := v.visit(node.Node)
var out []reflect.Type
if nt.IsUnknown(&v.config.NtCache) {
out = append(out, anyType)
} else if !nt.Nil {
out = append(out, nt.Type)
}
n := v.config.NtCache.FromType(reflect.FuncOf(anyTypeSlice, out, false))
n.Ref = &nt
return n
}
func (v *Checker) pointerNode(node *ast.PointerNode) Nature {
if len(v.predicateScopes) == 0 {
return v.error(node, "cannot use pointer accessor outside predicate")
}
scope := v.predicateScopes[len(v.predicateScopes)-1]
if node.Name == "" {
if scope.collection.IsUnknown(&v.config.NtCache) {
return Nature{}
}
switch scope.collection.Kind {
case reflect.Array, reflect.Slice:
return scope.collection.Elem(&v.config.NtCache)
}
return v.error(node, "cannot use %v as array", scope)
}
if scope.vars != nil {
for i := range scope.vars {
if node.Name == scope.vars[i].name {
return scope.vars[i].nature
}
}
}
return v.error(node, "unknown pointer #%v", node.Name)
}
func (v *Checker) variableDeclaratorNode(node *ast.VariableDeclaratorNode) Nature {
if _, ok := v.config.Env.Get(&v.config.NtCache, node.Name); ok {
return v.error(node, "cannot redeclare %v", node.Name)
}
if _, ok := v.config.Functions[node.Name]; ok {
return v.error(node, "cannot redeclare function %v", node.Name)
}
if _, ok := v.config.Builtins[node.Name]; ok {
return v.error(node, "cannot redeclare builtin %v", node.Name)
}
for i := len(v.varScopes) - 1; i >= 0; i-- {
if v.varScopes[i].name == node.Name {
return v.error(node, "cannot redeclare variable %v", node.Name)
}
}
varNature := v.visit(node.Value)
v.varScopes = append(v.varScopes, varScope{node.Name, varNature})
exprNature := v.visit(node.Expr)
v.varScopes = v.varScopes[:len(v.varScopes)-1]
return exprNature
}
func (v *Checker) sequenceNode(node *ast.SequenceNode) Nature {
if len(node.Nodes) == 0 {
return v.error(node, "empty sequence expression")
}
var last Nature
for _, node := range node.Nodes {
last = v.visit(node)
}
return last
}
func (v *Checker) conditionalNode(node *ast.ConditionalNode) Nature {
c := v.visit(node.Cond)
c = c.Deref(&v.config.NtCache)
if !c.IsBool() && !c.IsUnknown(&v.config.NtCache) {
return v.error(node.Cond, "non-bool expression (type %v) used as condition", c.String())
}
t1 := v.visit(node.Exp1)
t2 := v.visit(node.Exp2)
if t1.Nil && !t2.Nil {
return t2
}
if !t1.Nil && t2.Nil {
return t1
}
if t1.Nil && t2.Nil {
return v.config.NtCache.NatureOf(nil)
}
if t1.AssignableTo(t2) {
if t1.IsArray() && t2.IsArray() {
e1 := t1.Elem(&v.config.NtCache)
e2 := t2.Elem(&v.config.NtCache)
if !e1.AssignableTo(e2) || !e2.AssignableTo(e1) {
return v.config.NtCache.FromType(arrayType)
}
}
return t1
}
return Nature{}
}
func (v *Checker) arrayNode(node *ast.ArrayNode) Nature {
var prev Nature
allElementsAreSameType := true
for i, node := range node.Nodes {
curr := v.visit(node)
if i > 0 {
if curr.Kind != prev.Kind {
allElementsAreSameType = false
}
}
prev = curr
}
if allElementsAreSameType {
return prev.MakeArrayOf(&v.config.NtCache)
}
return v.config.NtCache.FromType(arrayType)
}
func (v *Checker) mapNode(node *ast.MapNode) Nature {
for _, pair := range node.Pairs {
v.visit(pair)
}
return v.config.NtCache.FromType(mapType)
}
func (v *Checker) pairNode(node *ast.PairNode) Nature {
v.visit(node.Key)
v.visit(node.Value)
return v.config.NtCache.NatureOf(nil)
}
================================================
FILE: checker/checker_bench_test.go
================================================
package checker_test
import (
"runtime"
"testing"
"github.com/expr-lang/expr"
"github.com/expr-lang/expr/ast"
"github.com/expr-lang/expr/checker"
"github.com/expr-lang/expr/checker/nature"
"github.com/expr-lang/expr/conf"
"github.com/expr-lang/expr/parser"
)
func BenchmarkChecker(b *testing.B) {
cases := []struct {
name, input string
}{
{"function calls", `
func(
func(
func(func(a, 'a', 1, nil), func(a, 'a', 1, nil), func(a, 'a', 1, nil)),
func(func(a, 'a', 1, nil), func(a, 'a', 1, nil), func(a, 'a', 1, nil)),
func(func(a, 'a', 1, nil), func(a, 'a', 1, nil), func(a, 'a', 1, nil)),
),
func(
func(func(a, 'a', 1, nil), func(a, 'a', 1, nil), func(a, 'a', 1, nil)),
func(func(a, 'a', 1, nil), func(a, 'a', 1, nil), func(a, 'a', 1, nil)),
func(func(a, 'a', 1, nil), func(a, 'a', 1, nil), func(a, 'a', 1, nil)),
),
func(
func(func(a, 'a', 1, nil), func(a, 'a', 1, nil), func(a, 'a', 1, nil)),
func(func(a, 'a', 1, nil), func(a, 'a', 1, nil), func(a, 'a', 1, nil)),
func(func(a, 'a', 1, nil), func(a, 'a', 1, nil), func(a, 'a', 1, nil)),
)
)
`},
{"unary and binary operations", `
!b && !b || !b == !b && !b != !b || 1 < 1.0 && 0.1 > 1 || 0 <= 1.0 && 0.1 >= 1 &&
!b && !b || !b == !b && !b != !b || 1 < 1.0 && 0.1 > 1 || 0 <= 1.0 && 0.1 >= 1 &&
!b && !b || !b == !b && !b != !b || 1 < 1.0 && 0.1 > 1 || 0 <= 1.0 && 0.1 >= 1 &&
!b && !b || !b == !b && !b != !b || 1 < 1.0 && 0.1 > 1 || 0 <= 1.0 && 0.1 >= 1 &&
!b && !b || !b == !b && !b != !b || 1 < 1.0 && 0.1 > 1 || 0 <= 1.0 && 0.1 >= 1 &&
!b && !b || !b == !b && !b != !b || 1 < 1.0 && 0.1 > 1 || 0 <= 1.0 && 0.1 >= 1
`},
{"deep struct access", `
a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.
a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.
a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.
a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a
`},
}
f := func(params ...any) (any, error) { return nil, nil }
env := map[string]any{
"a": new(recursive),
"b": true,
"func": f,
}
config := conf.New(env)
expr.Function("func", f, f)(config)
expr.ConstExpr("func")(config)
for _, c := range cases {
batchSize := 100_000
if batchSize > b.N {
batchSize = b.N
}
trees := make([]*parser.Tree, 0, batchSize)
for i := 0; i < batchSize; i++ {
tree, err := parser.ParseWithConfig(c.input, config)
if err != nil {
b.Fatal(err)
}
trees = append(trees, tree)
}
runtime.GC() // try to cleanup the mess from the initialization
b.Run("name="+c.name, func(b *testing.B) {
var err error
for i := 0; i < b.N; i++ {
j := i
if j < 0 || j >= len(trees) {
b.StopTimer()
invalidateTrees(trees...)
j = 0
b.StartTimer()
}
_, err = checker.Check(trees[j], config)
}
b.StopTimer()
if err != nil {
b.Fatal(err)
}
})
}
}
type visitorFunc func(*ast.Node)
func (f visitorFunc) Visit(node *ast.Node) { f(node) }
func invalidateTrees(trees ...*parser.Tree) {
for _, tree := range trees {
ast.Walk(&tree.Node, visitorFunc(func(node *ast.Node) {
(*node).SetNature(nature.Nature{})
}))
}
}
type recursive struct {
Inner *recursive `expr:"a"`
}
================================================
FILE: checker/checker_test.go
================================================
package checker_test
import (
"context"
"fmt"
"reflect"
"regexp"
"strings"
"testing"
"github.com/expr-lang/expr/internal/testify/assert"
"github.com/expr-lang/expr/internal/testify/require"
"github.com/expr-lang/expr/types"
"github.com/expr-lang/expr"
"github.com/expr-lang/expr/ast"
"github.com/expr-lang/expr/checker"
"github.com/expr-lang/expr/conf"
"github.com/expr-lang/expr/parser"
"github.com/expr-lang/expr/test/mock"
)
func TestCheck(t *testing.T) {
var tests = []struct {
input string
}{
{"nil == nil"},
{"nil == IntPtr"},
{"nil == nil"},
{"nil in ArrayOfFoo"},
{"!Bool"},
{"!BoolPtr == Bool"},
{"'a' == 'b' + 'c'"},
{"'foo' contains 'bar'"},
{"'foo' endsWith 'bar'"},
{"'foo' startsWith 'bar'"},
{"(1 == 1) || (String matches Any)"},
{"Int % Int > 1"},
{"Int + Int + Int > 0"},
{"Int == Any"},
{"Int in Int..Int"},
{"IntPtrPtr + 1 > 0"},
{"1 + 2 + Int64 > 0"},
{"Int64 % 1 > 0"},
{"IntPtr == Int"},
{"FloatPtr == 1 + 2."},
{"1 + 2 + Float + 3 + 4 < 0"},
{"1 + Int + Float == 0.5"},
{"-1 + +1 == 0"},
{"1 / 2 == 0"},
{"2**3 + 1 != 0"},
{"2^3 + 1 != 0"},
{"Float == 1"},
{"Float < 1.0"},
{"Float <= 1.0"},
{"Float > 1.0"},
{"Float >= 1.0"},
{`"a" < "b"`},
{"String + (true ? String : String) == ''"},
{"(Any ? nil : '') == ''"},
{"(Any ? 0 : nil) == 0"},
{"(Any ? nil : nil) == nil"},
{"!(Any ? Foo : Foo.Bar).Anything"},
{"Int in ArrayOfInt"},
{"Int not in ArrayOfAny"},
{"String in ArrayOfAny"},
{"String in ArrayOfString"},
{"String in Foo"},
{"String in MapOfFoo"},
{"String matches 'ok'"},
{"String matches Any"},
{"String not matches Any"},
{"StringPtr == nil"},
{"[1, 2, 3] == []"},
{"len([]) > 0"},
{"Any matches Any"},
{"!Any.Things.Contains.Any"},
{"!ArrayOfAny[0].next.goes['any thing']"},
{"ArrayOfFoo[0].Bar.Baz == ''"},
{"ArrayOfFoo[0:10][0].Bar.Baz == ''"},
{"!ArrayOfAny[Any]"},
{"Bool && Any"},
{"FuncParam(true, 1, 'str')"},
{"FuncParamAny(nil)"},
{"!Fast(Any, String)"},
{"Foo.Method().Baz == ''"},
{"Foo.Bar == MapOfAny.id.Bar"},
{"Foo.Bar.Baz == ''"},
{"MapOfFoo['any'].Bar.Baz == ''"},
{"Func() == 0"},
{"FuncFoo(Foo) > 1"},
{"Any() > 0"},
{"Embed.EmbedString == ''"},
{"EmbedString == ''"},
{"EmbedMethod(0) == ''"},
{"Embed.EmbedMethod(0) == ''"},
{"Embed.EmbedString == ''"},
{"EmbedString == ''"},
{"{id: Foo.Bar.Baz, 'str': String} == {}"},
{"Variadic(0, 1, 2) || Variadic(0)"},
{"count(1..30, {# % 3 == 0}) > 0"},
{"map(1..3, {#}) == [1,2,3]"},
{"map(1..3, #index) == [0,1,2]"},
{"map(filter(ArrayOfFoo, {.Bar.Baz != ''}), {.Bar}) == []"},
{"filter(Any, {.AnyMethod()})[0] == ''"},
{"Time == Time"},
{"Any == Time"},
{"Any != Time"},
{"Any > Time"},
{"Any >= Time"},
{"Any < Time"},
{"Any <= Time"},
{"Any - Time > Duration"},
{"Any == Any"},
{"Any != Any"},
{"Any > Any"},
{"Any >= Any"},
{"Any < Any"},
{"Any <= Any"},
{"Any - Any < Duration"},
{"Time == Any"},
{"Time != Any"},
{"Time > Any"},
{"Time >= Any"},
{"Time < Any"},
{"Time <= Any"},
{"Time - Any == Duration"},
{"Time + Duration == Time"},
{"Duration + Time == Time"},
{"Duration + Any == Time"},
{"Any + Duration == Time"},
{"Any.A?.B == nil"},
{"(Any.Bool ?? Bool) > 0"},
{"Bool ?? Bool"},
{"let foo = 1; foo == 1"},
{"(Embed).EmbedPointerEmbedInt > 0"},
{"(true ? [1] : [[1]])[0][0] == 1"},
{"Foo.VariadicMethod('a', 'b', 'c')"},
}
c := new(checker.Checker)
for _, tt := range tests {
t.Run(tt.input, func(t *testing.T) {
var err error
tree, err := parser.Parse(tt.input)
require.NoError(t, err)
config := conf.New(mock.Env{})
expr.AsBool()(config)
_, err = c.Check(tree, config)
assert.NoError(t, err)
})
}
}
func TestCheck_error(t *testing.T) {
errorTests := []struct{ code, err string }{
{
`Foo.Bar.Not`,
`
type mock.Bar has no field Not (1:9)
| Foo.Bar.Not
| ........^
`,
},
{
`Noo`,
`
unknown name Noo (1:1)
| Noo
| ^
`,
},
{
`Foo()`, `
mock.Foo is not callable (1:1)
| Foo()
| ^
`,
},
{
`Foo['bar']`, `
type mock.Foo has no field bar (1:4)
| Foo['bar']
| ...^
`,
},
{
`Foo.Method(42)`,
`
too many arguments to call Method (1:5)
| Foo.Method(42)
| ....^
`,
},
{`Foo.Bar()`, `
mock.Bar is not callable (1:5)
| Foo.Bar()
| ....^
`,
},
{`Foo.Bar.Not()`, `
type mock.Bar has no method Not (1:9)
| Foo.Bar.Not()
| ........^
`,
},
{`ArrayOfFoo[0].Not`, `
type mock.Foo has no field Not (1:15)
| ArrayOfFoo[0].Not
| ..............^
`,
},
{`ArrayOfFoo[Not]`, `
unknown name Not (1:12)
| ArrayOfFoo[Not]
| ...........^
`,
},
{`Not[0]`, `
unknown name Not (1:1)
| Not[0]
| ^
`,
},
{`Not.Bar`, `
unknown name Not (1:1)
| Not.Bar
| ^
`,
},
{`ArrayOfFoo.Not`, `
array elements can only be selected using an integer (got string) (1:12)
| ArrayOfFoo.Not
| ...........^
`,
},
{`FuncParam(true)`, `
not enough arguments to call FuncParam (1:1)
| FuncParam(true)
| ^
`,
},
{`MapOfFoo['str'].Not`, `
type mock.Foo has no field Not (1:17)
| MapOfFoo['str'].Not
| ................^
`,
},
{`Bool && IntPtr`, `
invalid operation: && (mismatched types bool and int) (1:6)
| Bool && IntPtr
| .....^
`,
},
{`No ? Any.Bool : Any.Not`, `
unknown name No (1:1)
| No ? Any.Bool : Any.Not
| ^
`,
},
{`Any.Cond ? No : Any.Not`, `
unknown name No (1:12)
| Any.Cond ? No : Any.Not
| ...........^
`,
},
{`Any.Cond ? Any.Bool : No`, `
unknown name No (1:23)
| Any.Cond ? Any.Bool : No
| ......................^
`,
},
{`MapOfAny ? Any : Any`, `
non-bool expression (type map[string]interface {}) used as condition (1:1)
| MapOfAny ? Any : Any
| ^
`,
},
{`String matches Int`, `
invalid operation: matches (mismatched types string and int) (1:8)
| String matches Int
| .......^
`,
},
{`Int matches String`, `
invalid operation: matches (mismatched types int and string) (1:5)
| Int matches String
| ....^
`,
},
{`String contains Int`, `
invalid operation: contains (mismatched types string and int) (1:8)
| String contains Int
| .......^
`,
},
{`Int contains String`, `
invalid operation: contains (mismatched types int and string) (1:5)
| Int contains String
| ....^
`,
},
{`!Not`, `
unknown name Not (1:2)
| !Not
| .^
`,
},
{`Not == Any`, `
unknown name Not (1:1)
| Not == Any
| ^
`,
},
{`[Not]`, `
unknown name Not (1:2)
| [Not]
| .^
`,
},
{`{id: Not}`, `
unknown name Not (1:6)
| {id: Not}
| .....^
`,
},
{`(nil).Foo`, `
type nil has no field Foo (1:7)
| (nil).Foo
| ......^
`,
},
{`(nil)['Foo']`, `
type nil has no field Foo (1:6)
| (nil)['Foo']
| .....^
`,
},
{`1 and false`, `
invalid operation: and (mismatched types int and bool) (1:3)
| 1 and false
| ..^
`,
},
{`true or 0`, `
invalid operation: or (mismatched types bool and int) (1:6)
| true or 0
| .....^
`,
},
{`not IntPtr`, `
invalid operation: not (mismatched type int) (1:1)
| not IntPtr
| ^
`,
},
{`len(Not)`, `
unknown name Not (1:5)
| len(Not)
| ....^
`,
},
{`Int < Bool`, `
invalid operation: < (mismatched types int and bool) (1:5)
| Int < Bool
| ....^
`,
},
{`Int > Bool`, `
invalid operation: > (mismatched types int and bool) (1:5)
| Int > Bool
| ....^
`,
},
{`Int >= Bool`, `
invalid operation: >= (mismatched types int and bool) (1:5)
| Int >= Bool
| ....^
`,
},
{`Int <= Bool`, `
invalid operation: <= (mismatched types int and bool) (1:5)
| Int <= Bool
| ....^
`,
},
{`Int + Bool`, `
invalid operation: + (mismatched types int and bool) (1:5)
| Int + Bool
| ....^
`,
},
{`Int - Bool`, `
invalid operation: - (mismatched types int and bool) (1:5)
| Int - Bool
| ....^
`,
},
{`Int * Bool`, `
invalid operation: * (mismatched types int and bool) (1:5)
| Int * Bool
| ....^
`,
},
{`Int / Bool`, `
invalid operation: / (mismatched types int and bool) (1:5)
| Int / Bool
| ....^
`,
},
{`Int % Bool`, `
invalid operation: % (mismatched types int and bool) (1:5)
| Int % Bool
| ....^
`,
},
{`Int ** Bool`, `
invalid operation: ** (mismatched types int and bool) (1:5)
| Int ** Bool
| ....^
`,
},
{`Int .. Bool`, `
invalid operation: .. (mismatched types int and bool) (1:5)
| Int .. Bool
| ....^
`,
},
{`Any > Foo`, `
invalid operation: > (mismatched types interface {} and mock.Foo) (1:5)
| Any > Foo
| ....^
`,
},
{`NilFn() and BoolFn()`, `
func NilFn doesn't return value (1:1)
| NilFn() and BoolFn()
| ^
`,
},
{`'str' in String`, `
invalid operation: in (mismatched types string and string) (1:7)
| 'str' in String
| ......^
`,
},
{`1 in Foo`, `
invalid operation: in (mismatched types int and mock.Foo) (1:3)
| 1 in Foo
| ..^
`,
},
{`1 + ''`, `
invalid operation: + (mismatched types int and string) (1:3)
| 1 + ''
| ..^
`,
},
{`all(ArrayOfFoo, {#.Method() < 0})`, `
invalid operation: < (mismatched types mock.Bar and int) (1:29)
| all(ArrayOfFoo, {#.Method() < 0})
| ............................^
`,
},
{`Variadic()`, `
not enough arguments to call Variadic (1:1)
| Variadic()
| ^
`,
},
{`Variadic(0, '')`, `
cannot use string as argument (type int) to call Variadic (1:13)
| Variadic(0, '')
| ............^
`,
},
{`count(1, {#})`, `
builtin count takes only array (got int) (1:7)
| count(1, {#})
| ......^
`,
},
{`count(ArrayOfInt, {#})`, `
predicate should return boolean (got int) (1:19)
| count(ArrayOfInt, {#})
| ..................^
`,
},
{`all(ArrayOfInt, {# + 1})`, `
predicate should return boolean (got int) (1:17)
| all(ArrayOfInt, {# + 1})
| ................^
`,
},
{`filter(ArrayOfFoo, {.Bar.Baz})`, `
predicate should return boolean (got string) (1:20)
| filter(ArrayOfFoo, {.Bar.Baz})
| ...................^
`,
},
{`find(ArrayOfFoo, {.Bar.Baz})`, `
predicate should return boolean (got string) (1:18)
| find(ArrayOfFoo, {.Bar.Baz})
| .................^
`,
},
{`map(1, {2})`, `
builtin map takes only array (got int) (1:5)
| map(1, {2})
| ....^
`,
},
{`ArrayOfFoo[Foo]`, `
array elements can only be selected using an integer (got mock.Foo) (1:12)
| ArrayOfFoo[Foo]
| ...........^
`,
},
{`ArrayOfFoo[Bool:]`, `
non-integer slice index bool (1:12)
| ArrayOfFoo[Bool:]
| ...........^
`,
},
{`ArrayOfFoo[1:Bool]`, `
non-integer slice index bool (1:14)
| ArrayOfFoo[1:Bool]
| .............^
`,
},
{`Bool[:]`, `
cannot slice bool (1:5)
| Bool[:]
| ....^
`,
},
{`FuncTooManyReturns()`, `
func FuncTooManyReturns returns more then two values (1:1)
| FuncTooManyReturns()
| ^
`,
},
{`len(42)`, `
invalid argument for len (type int) (1:1)
| len(42)
| ^
`,
},
{`any(42, {#})`, `
builtin any takes only array (got int) (1:5)
| any(42, {#})
| ....^
`,
},
{`filter(42, {#})`, `
builtin filter takes only array (got int) (1:8)
| filter(42, {#})
| .......^
`,
},
{`MapOfAny[0]`, `
cannot use int to get an element from map[string]interface {} (1:10)
| MapOfAny[0]
| .........^
`,
},
{`1 /* one */ + "2"`, `
invalid operation: + (mismatched types int and string) (1:13)
| 1 /* one */ + "2"
| ............^
`,
},
{`FuncTyped(42)`, `
cannot use int as argument (type string) to call FuncTyped (1:11)
| FuncTyped(42)
| ..........^
`,
},
{`.0 in MapOfFoo`, `
cannot use float64 as type string in map key (1:4)
| .0 in MapOfFoo
| ...^
`,
},
{`1/2 in MapIntAny`, `
cannot use float64 as type int in map key (1:5)
| 1/2 in MapIntAny
| ....^
`,
},
{`0.5 in ArrayOfFoo`, `
cannot use float64 as type *mock.Foo in array (1:5)
| 0.5 in ArrayOfFoo
| ....^
`,
},
{`repeat("0", 1/0)`, `
cannot use float64 as argument (type int) to call repeat (1:14)
| repeat("0", 1/0)
| .............^
`,
},
{`let map = 42; map`, `
cannot redeclare builtin map (1:5)
| let map = 42; map
| ....^
`,
},
{`let len = 42; len`, `
cannot redeclare builtin len (1:5)
| let len = 42; len
| ....^
`,
},
{`let Float = 42; Float`, `
cannot redeclare Float (1:5)
| let Float = 42; Float
| ....^
`,
},
{`let foo = 1; let foo = 2; foo`, `
cannot redeclare variable foo (1:18)
| let foo = 1; let foo = 2; foo
| .................^
`,
},
{`map(1..9, #unknown)`, `
unknown pointer #unknown (1:11)
| map(1..9, #unknown)
| ..........^
`,
},
{`42 in ["a", "b", "c"]`, `
cannot use int as type string in array (1:4)
| 42 in ["a", "b", "c"]
| ...^
`,
},
{`"foo" matches "[+"`, `
error parsing regexp: missing closing ]: ` + "`[+`" + ` (1:7)
| "foo" matches "[+"
| ......^
`,
},
{`get(false, 2)`, `
type bool does not support indexing (1:5)
| get(false, 2)
| ....^
`,
},
{`get(1..2, 0.5)`, `
non-integer slice index float64 (1:11)
| get(1..2, 0.5)
| ..........^`,
},
{`trimPrefix(nil)`, `
cannot use nil as argument (type string) to call trimPrefix (1:12)
| trimPrefix(nil)
| ...........^
`,
},
{`1..3 | filter(# > 1) | filter(# == "str")`,
`
invalid operation: == (mismatched types int and string) (1:33)
| 1..3 | filter(# > 1) | filter(# == "str")
| ................................^
`,
},
{`1..3 | map("str") | filter(# > 1)`,
`
invalid operation: > (mismatched types string and int) (1:30)
| 1..3 | map("str") | filter(# > 1)
| .............................^
`,
},
{
`1; 2 + true; 3`,
`
invalid operation: + (mismatched types int and bool) (1:6)
| 1; 2 + true; 3
| .....^
`,
},
{
`$env()`,
`
mock.Env is not callable (1:1)
| $env()
| ^
`,
},
{
`$env(1)`,
`
mock.Env is not callable (1:1)
| $env(1)
| ^
`,
},
{
`$env(abs())`,
`
mock.Env is not callable (1:1)
| $env(abs())
| ^
`,
},
}
c := new(checker.Checker)
for _, tt := range errorTests {
t.Run(tt.code, func(t *testing.T) {
tree, err := parser.Parse(tt.code)
require.NoError(t, err)
_, err = c.Check(tree, conf.New(mock.Env{}))
if err == nil {
err = fmt.Errorf("<nil>")
}
assert.Equal(t, strings.Trim(tt.err, "\n"), err.Error())
})
}
}
func TestCheck_FloatVsInt(t *testing.T) {
tree, err := parser.Parse(`Int + Float`)
require.NoError(t, err)
typ, err := checker.Check(tree, conf.New(mock.Env{}))
assert.NoError(t, err)
assert.Equal(t, typ.Kind(), reflect.Float64)
}
func TestCheck_IntSums(t *testing.T) {
tree, err := parser.Parse(`Uint32 + Int32`)
require.NoError(t, err)
typ, err := checker.Check(tree, conf.New(mock.Env{}))
assert.NoError(t, err)
assert.Equal(t, typ.Kind(), reflect.Int)
}
func TestVisitor_ConstantNode(t *testing.T) {
tree, err := parser.Parse(`re("[a-z]")`)
require.NoError(t, err)
regexValue := regexp.MustCompile("[a-z]")
constNode := &ast.ConstantNode{Value: regexValue}
ast.Patch(&tree.Node, constNode)
_, err = checker.Check(tree, nil)
assert.NoError(t, err)
assert.Equal(t, reflect.TypeOf(regexValue), tree.Node.Type())
}
func TestCheck_AsBool(t *testing.T) {
tree, err := parser.Parse(`1+2`)
require.NoError(t, err)
config := &conf.Config{}
expr.AsBool()(config)
_, err = checker.Check(tree, config)
assert.Error(t, err)
assert.Equal(t, "expected bool, but got int", err.Error())
}
func TestCheck_AsInt64(t *testing.T) {
tree, err := parser.Parse(`true`)
require.NoError(t, err)
config := &conf.Config{}
expr.AsInt64()(config)
_, err = checker.Check(tree, config)
assert.Error(t, err)
assert.Equal(t, "expected int64, but got bool", err.Error())
}
func TestCheck_TaggedFieldName(t *testing.T) {
tree, err := parser.Parse(`foo.bar`)
require.NoError(t, err)
config := conf.CreateNew()
expr.Env(struct {
X struct {
Y bool `expr:"bar"`
} `expr:"foo"`
}{})(config)
expr.AsBool()(config)
_, err = checker.Check(tree, config)
assert.NoError(t, err)
}
func TestCheck_NoConfig(t *testing.T) {
tree, err := parser.Parse(`any`)
require.NoError(t, err)
_, err = checker.Check(tree, conf.CreateNew())
assert.NoError(t, err)
}
func TestCheck_AllowUndefinedVariables(t *testing.T) {
type Env struct {
A int
}
tree, err := parser.Parse(`Any + fn()`)
require.NoError(t, err)
config := conf.New(Env{})
expr.AllowUndefinedVariables()(config)
_, err = checker.Check(tree, config)
assert.NoError(t, err)
}
func TestCheck_AllowUndefinedVariables_DefaultType(t *testing.T) {
env := map[string]bool{}
tree, err := parser.Parse(`Any`)
require.NoError(t, err)
config := conf.New(env)
expr.AllowUndefinedVariables()(config)
expr.AsBool()(config)
_, err = checker.Check(tree, config)
assert.NoError(t, err)
}
func TestCheck_AllowUndefinedVariables_OptionalChaining(t *testing.T) {
type Env struct{}
tree, err := parser.Parse("Not?.A.B == nil")
require.NoError(t, err)
config := conf.New(Env{})
expr.AllowUndefinedVariables()(config)
_, err = checker.Check(tree, config)
assert.NoError(t, err)
}
func TestCheck_PointerNode(t *testing.T) {
_, err := checker.Check(&parser.Tree{Node: &ast.PointerNode{}}, nil)
assert.Error(t, err)
assert.Contains(t, err.Error(), "cannot use pointer accessor outside predicate")
}
func TestCheck_TypeWeights(t *testing.T) {
types := map[string]any{
"Uint": uint(1),
"Uint8": uint8(2),
"Uint16": uint16(3),
"Uint32": uint32(4),
"Uint64": uint64(5),
"Int": 6,
"Int8": int8(7),
"Int16": int16(8),
"Int32": int32(9),
"Int64": int64(10),
"Float32": float32(11),
"Float64": float64(12),
}
c := new(checker.Checker)
for a := range types {
for b := range types {
tree, err := parser.Parse(fmt.Sprintf("%s + %s", a, b))
require.NoError(t, err)
config := conf.New(types)
_, err = c.Check(tree, config)
require.NoError(t, err)
}
}
}
func TestCheck_works_with_nil_types(t *testing.T) {
env := map[string]any{
"null": nil,
}
tree, err := parser.Parse("null")
require.NoError(t, err)
_, err = checker.Check(tree, conf.New(env))
require.NoError(t, err)
}
func TestCheck_cast_to_expected_works_with_interface(t *testing.T) {
t.Run("float64", func(t *testing.T) {
type Env struct {
Any any
}
tree, err := parser.Parse("Any")
require.NoError(t, err)
config := conf.New(Env{})
expr.AsFloat64()(config)
expr.AsAny()(config)
_, err = checker.Check(tree, config)
require.NoError(t, err)
})
t.Run("kind", func(t *testing.T) {
env := map[string]any{
"Any": any("foo"),
}
tree, err := parser.Parse("Any")
require.NoError(t, err)
config := conf.New(env)
expr.AsKind(reflect.String)(config)
_, err = checker.Check(tree, config)
require.NoError(t, err)
})
}
func TestCheck_operator_in_works_with_interfaces(t *testing.T) {
tree, err := parser.Parse(`'Tom' in names`)
require.NoError(t, err)
config := conf.New(nil)
expr.AllowUndefinedVariables()(config)
_, err = checker.Check(tree, config)
require.NoError(t, err)
}
func TestCheck_Function_types_are_checked(t *testing.T) {
add := expr.Function(
"add",
func(p ...any) (any, error) {
out := 0
for _, each := range p {
out += each.(int)
}
return out, nil
},
new(func(int) int),
new(func(int, int) int),
new(func(int, int, int) int),
new(func(...int) int),
)
config := conf.CreateNew()
add(config)
c := new(checker.Checker)
tests := []string{
"add(1)",
"add(1, 2)",
"add(1, 2, 3)",
"add(1, 2, 3, 4)",
}
for _, test := range tests {
t.Run(test, func(t *testing.T) {
tree, err := parser.Parse(test)
require.NoError(t, err)
_, err = c.Check(tree, config)
require.NoError(t, err)
require.Equal(t, reflect.Int, tree.Node.Type().Kind())
})
}
t.Run("errors", func(t *testing.T) {
tree, err := parser.Parse("add(1, '2')")
require.NoError(t, err)
_, err = c.Check(tree, config)
require.Error(t, err)
require.Equal(t, "cannot use string as argument (type int) to call add (1:8)\n | add(1, '2')\n | .......^", err.Error())
})
}
func TestCheck_Function_without_types(t *testing.T) {
add := expr.Function(
"add",
func(p ...any) (any, error) {
out := 0
for _, each := range p {
out += each.(int)
}
return out, nil
},
)
tree, err := parser.Parse("add(1, 2, 3)")
require.NoError(t, err)
config := conf.CreateNew()
add(config)
_, err = checker.Check(tree, config)
require.NoError(t, err)
require.Equal(t, reflect.Interface, tree.Node.Type().Kind())
}
func TestCheck_dont_panic_on_nil_arguments_for_builtins(t *testing.T) {
tests := []string{
"len(nil)",
"abs(nil)",
"int(nil)",
"float(nil)",
}
for _, test := range tests {
t.Run(test, func(t *testing.T) {
tree, err := parser.Parse(test)
require.NoError(t, err)
_, err = checker.Check(tree, conf.New(nil))
require.Error(t, err)
})
}
}
func TestCheck_do_not_override_params_for_functions(t *testing.T) {
env := map[string]any{
"foo": func(p string) string {
return "foo"
},
}
config := conf.New(env)
expr.Function(
"bar",
func(p ...any) (any, error) {
return p[0].(string), nil
},
new(func(string) string),
)(config)
config.Check()
t.Run("func from env", func(t *testing.T) {
tree, err := parser.Parse("foo(1)")
require.NoError(t, err)
_, err = checker.Check(tree, config)
require.Error(t, err)
require.Contains(t, err.Error(), "cannot use int as argument")
})
t.Run("func from function", func(t *testing.T) {
tree, err := parser.Parse("bar(1)")
require.NoError(t, err)
_, err = checker.Check(tree, config)
require.Error(t, err)
require.Contains(t, err.Error(), "cannot use int as argument")
})
}
func TestCheck_env_keyword(t *testing.T) {
env := map[string]any{
"num": 42,
"str": "foo",
"name": "str",
}
tests := []struct {
input string
want reflect.Kind
}{
{`$env['str']`, reflect.String},
{`$env['num']`, reflect.Int},
{`$env[name]`, reflect.Interface},
}
c := new(checker.Checker)
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
tree, err := parser.Parse(test.input)
require.NoError(t, err)
rtype, err := c.Check(tree, conf.New(env))
require.NoError(t, err)
require.True(t, rtype.Kind() == test.want, fmt.Sprintf("expected %s, got %s", test.want, rtype.Kind()))
})
}
}
func TestCheck_builtin_without_call(t *testing.T) {
tests := []struct {
input string
err string
}{
{`len + 1`, "invalid operation: + (mismatched types func(...interface {}) (interface {}, error) and int) (1:5)\n | len + 1\n | ....^"},
{`string.A`, "type func(interface {}) string has no field A (1:8)\n | string.A\n | .......^"},
}
c := new(checker.Checker)
for _, test := range tests {
t.Run(test.input, func(t *testing.T) {
tree, err := parser.Parse(test.input)
require.NoError(t, err)
_, err = c.Check(tree, conf.New(nil))
require.Error(t, err)
require.Equal(t, test.err, err.Error())
})
}
}
func TestCheck_EmbeddedInterface(t *testing.T) {
t.Run("embedded interface lookup returns compile-error not panic", func(t *testing.T) {
type Env struct {
context.Context
Country string
}
type Wrapper struct {
Ctx Env
}
config := conf.New(Wrapper{
Ctx: Env{
Context: context.Background(),
Country: "TR",
},
})
expr.WithContext("Ctx")(config)
_, err := checker.ParseCheck("Ctx.C", config)
require.Error(t, err)
require.Contains(t, err.Error(), "has no field C")
})
}
func TestCheck_types(t *testing.T) {
env := types.Map{
"foo": types.Map{
"bar": types.Map{
"baz": types.String,
types.Extra: types.String,
},
},
"arr": types.Array(types.Map{
"value": types.String,
}),
types.Extra: types.Any,
}
noerr := "no error"
tests := []struct {
code string
err string
}{
{`unknown`, noerr},
{`[unknown + 42, another_unknown + "foo"]`, noerr},
{`foo.bar.baz > 0`, `invalid operation: > (mismatched types string and int)`},
{`foo.unknown.baz`, `unknown field unknown (1:5)`},
{`foo.bar.unknown`, noerr},
{`foo.bar.unknown + 42`, `invalid operation: + (mismatched types string and int)`},
{`[foo] | map(.unknown)`, `unknown field unknown`},
{`[foo] | map(.bar) | filter(.baz)`, `predicate should return boolean (got string)`},
{`arr | filter(.value > 0)`, `invalid operation: > (mismatched types string and int)`},
{`arr | filter(.value contains "a") | filter(.value == 0)`, `invalid operation: == (mismatched types string and int)`},
}
c := new(checker.Checker)
for _, test := range tests {
t.Run(test.code, func(t *testing.T) {
tree, err := parser.Parse(test.code)
require.NoError(t, err)
config := conf.New(env)
_, err = c.Check(tree, config)
if test.err == noerr {
require.NoError(t, err)
} else {
require.Error(t, err)
require.Contains(t, err.Error(), test.err)
}
})
}
}
================================================
FILE: checker/info.go
================================================
package checker
import (
"reflect"
"github.com/expr-lang/expr/ast"
. "github.com/expr-lang/expr/checker/nature"
"github.com/expr-lang/expr/vm"
)
func FieldIndex(c *Cache, env Nature, node ast.Node) (bool, []int, string) {
switch n := node.(type) {
case *ast.IdentifierNode:
if idx, ok := env.FieldIndex(c, n.Value); ok {
return true, idx, n.Value
}
case *ast.MemberNode:
base := n.Node.Nature().Deref(c)
if base.Kind == reflect.Struct {
if prop, ok := n.Property.(*ast.StringNode); ok {
if idx, ok := base.FieldIndex(c, prop.Value); ok {
return true, idx, prop.Value
}
}
}
}
return false, nil, ""
}
func MethodIndex(c *Cache, env Nature, node ast.Node) (bool, int, string) {
switch n := node.(type) {
case *ast.IdentifierNode:
if env.Kind == reflect.Struct {
if m, ok := env.Get(c, n.Value); ok && m.TypeData != nil {
return m.Method, m.MethodIndex, n.Value
}
}
case *ast.MemberNode:
if name, ok := n.Property.(*ast.StringNode); ok {
base := n.Node.Type()
if base != nil && base.Kind() != reflect.Interface {
if m, ok := base.MethodByName(name.Value); ok {
return true, m.Index, name.Value
}
}
}
}
return false, 0, ""
}
func TypedFuncIndex(fn reflect.Type, method bool) (int, bool) {
if fn == nil {
return 0, false
}
if fn.Kind() != reflect.Func {
return 0, false
}
// OnCallTyped doesn't work for functions with variadic arguments.
if fn.IsVariadic() {
return 0, false
}
// OnCallTyped doesn't work named function, like `type MyFunc func() int`.
if fn.PkgPath() != "" { // If PkgPath() is not empty, it means that function is named.
return 0, false
}
fnNumIn := fn.NumIn()
fnInOffset := 0
if method {
fnNumIn--
fnInOffset = 1
}
funcTypes:
for i := range vm.FuncTypes {
if i == 0 {
continue
}
typed := reflect.ValueOf(vm.FuncTypes[i]).Elem().Type()
if typed.Kind() != reflect.Func {
continue
}
if typed.NumOut() != fn.NumOut() {
continue
}
for j := 0; j < typed.NumOut(); j++ {
if typed.Out(j) != fn.Out(j) {
continue funcTypes
}
}
if typed.NumIn() != fnNumIn {
continue
}
for j := 0; j < typed.NumIn(); j++ {
if typed.In(j) != fn.In(j+fnInOffset) {
continue funcTypes
}
}
return i, true
}
return 0, false
}
func IsFastFunc(fn reflect.Type, method bool) bool {
if fn == nil {
return false
}
if fn.Kind() != reflect.Func {
return false
}
numIn := 1
if method {
numIn = 2
}
if fn.IsVariadic() &&
fn.NumIn() == numIn &&
fn.NumOut() == 1 &&
fn.Out(0).Kind() == reflect.Interface {
rest := fn.In(fn.NumIn() - 1) // function has only one param for functions and two for methods
if rest != nil && rest.Kind() == reflect.Slice && rest.Elem().Kind() == reflect.Interface {
return true
}
}
return false
}
================================================
FILE: checker/info_test.go
================================================
package checker_test
import (
"reflect"
"testing"
"time"
"github.com/expr-lang/expr/internal/testify/require"
"github.com/expr-lang/expr/checker"
"github.com/expr-lang/expr/test/mock"
)
func TestTypedFuncIndex(t *testing.T) {
fn := func() time.Duration {
return 1 * time.Second
}
index, ok := checker.TypedFuncIndex(reflect.TypeOf(fn), false)
require.True(t, ok)
require.Equal(t, 1, index)
}
func TestTypedFuncIndex_excludes_named_functions(t *testing.T) {
var fn mock.MyFunc
_, ok := checker.TypedFuncIndex(reflect.TypeOf(fn), false)
require.False(t, ok)
}
================================================
FILE: checker/nature/nature.go
================================================
package nature
import (
"fmt"
"reflect"
"time"
"github.com/expr-lang/expr/builtin"
"github.com/expr-lang/expr/internal/deref"
)
var (
intType = reflect.TypeOf(0)
floatType = reflect.TypeOf(float64(0))
arrayType = reflect.TypeOf([]any{})
byteSliceType = reflect.TypeOf([]byte{})
timeType = reflect.TypeOf(time.Time{})
durationType = reflect.TypeOf(time.Duration(0))
builtinInt = map[reflect.Type]struct{}{
reflect.TypeOf(int(0)): {},
reflect.TypeOf(int8(0)): {},
reflect.TypeOf(int16(0)): {},
reflect.TypeOf(int32(0)): {},
reflect.TypeOf(int64(0)): {},
reflect.TypeOf(uintptr(0)): {},
reflect.TypeOf(uint(0)): {},
reflect.TypeOf(uint8(0)): {},
reflect.TypeOf(uint16(0)): {},
reflect.TypeOf(uint32(0)): {},
reflect.TypeOf(uint64(0)): {},
}
builtinFloat = map[reflect.Type]struct{}{
reflect.TypeOf(float32(0)): {},
reflect.TypeOf(float64(0)): {},
}
)
type NatureCheck int
const (
_ NatureCheck = iota
BoolCheck
StringCheck
IntegerCheck
NumberCheck
MapCheck
ArrayCheck
TimeCheck
DurationCheck
)
type Nature struct {
// The order of the fields matter, check alignment before making changes.
Type reflect.Type // Type of the value. If nil, then value is unknown.
Kind reflect.Kind // Kind of the value.
*TypeData
// Ref is a reference used for multiple, disjoint purposes. When the Nature
// is for a:
// - Predicate: then Ref is the nature of the Out of the predicate.
// - Array-like types: then Ref is the Elem nature of array type (usually Type is []any, but ArrayOf can be any nature).
Ref *Nature
Nil bool // If value is nil.
Strict bool // If map is types.StrictMap.
Method bool // If value retrieved from method. Usually used to determine amount of in arguments.
IsInteger bool // If it's a builtin integer or unsigned integer type.
IsFloat bool // If it's a builtin float type.
}
type TypeData struct {
methodset *methodset // optional to avoid the map in *Cache
*structData
// map-only data
Fields map[string]Nature // Fields of map type.
DefaultMapValue *Nature // Default value of map type.
// callable-only data
Func *builtin.Function // Used to pass function type from callee to CallNode.
MethodIndex int // Index of method in type.
inElem, outZero *Nature
numIn, numOut int
isVariadic bool
isVariadicSet bool
numInSet bool
numOutSet bool
}
// Cache is a shared cache of type information. It is only used in the stages
// where type information becomes relevant, so packages like ast, parser, types,
// and lexer do not need to use the cache because they don't need any service
// from the Nature type, they only describe. However, when receiving a Nature
// from one of those packages, the cache must be set immediately.
type Cache struct {
methods map[reflect
gitextract_ewtnex4r/
├── .gitattributes
├── .github/
│ ├── FUNDING.yml
│ ├── images/
│ │ └── demo.tape
│ ├── scripts/
│ │ └── coverage.mjs
│ └── workflows/
│ ├── build.yml
│ ├── check.yml
│ ├── diff.yml
│ ├── fuzz.yml
│ └── test.yml
├── .gitignore
├── LICENSE
├── README.md
├── SECURITY.md
├── ast/
│ ├── dump.go
│ ├── find.go
│ ├── find_test.go
│ ├── node.go
│ ├── print.go
│ ├── print_test.go
│ ├── visitor.go
│ └── visitor_test.go
├── bench_test.go
├── builtin/
│ ├── builtin.go
│ ├── builtin_test.go
│ ├── function.go
│ ├── lib.go
│ ├── utils.go
│ └── validation.go
├── checker/
│ ├── checker.go
│ ├── checker_bench_test.go
│ ├── checker_test.go
│ ├── info.go
│ ├── info_test.go
│ └── nature/
│ ├── nature.go
│ └── utils.go
├── compiler/
│ ├── compiler.go
│ └── compiler_test.go
├── conf/
│ ├── config.go
│ └── env.go
├── debug/
│ ├── debugger.go
│ ├── go.mod
│ └── go.sum
├── docgen/
│ ├── README.md
│ ├── docgen.go
│ ├── docgen_test.go
│ └── markdown.go
├── docs/
│ ├── configuration.md
│ ├── environment.md
│ ├── functions.md
│ ├── getting-started.md
│ ├── language-definition.md
│ ├── patch.md
│ └── visitor.md
├── expr.go
├── expr_test.go
├── file/
│ ├── error.go
│ ├── location.go
│ ├── source.go
│ └── source_test.go
├── go.mod
├── internal/
│ ├── deref/
│ │ ├── deref.go
│ │ └── deref_test.go
│ ├── difflib/
│ │ ├── difflib.go
│ │ └── difflib_test.go
│ ├── ring/
│ │ ├── ring.go
│ │ └── ring_test.go
│ ├── spew/
│ │ ├── bypass.go
│ │ ├── bypasssafe.go
│ │ ├── common.go
│ │ ├── common_test.go
│ │ ├── config.go
│ │ ├── doc.go
│ │ ├── dump.go
│ │ ├── dump_test.go
│ │ ├── dumpcgo_test.go
│ │ ├── dumpnocgo_test.go
│ │ ├── example_test.go
│ │ ├── format.go
│ │ ├── format_test.go
│ │ ├── internal_test.go
│ │ ├── internalunsafe_test.go
│ │ ├── spew.go
│ │ ├── spew_test.go
│ │ └── testdata/
│ │ └── dumpcgo.go
│ └── testify/
│ ├── assert/
│ │ ├── assertion_compare.go
│ │ ├── assertion_compare_test.go
│ │ ├── assertion_format.go
│ │ ├── assertion_format.go.tmpl
│ │ ├── assertion_forward.go
│ │ ├── assertion_forward.go.tmpl
│ │ ├── assertion_order.go
│ │ ├── assertion_order_test.go
│ │ ├── assertions.go
│ │ ├── assertions_test.go
│ │ ├── doc.go
│ │ ├── errors.go
│ │ ├── forward_assertions.go
│ │ ├── forward_assertions_test.go
│ │ ├── http_assertions.go
│ │ ├── http_assertions_test.go
│ │ └── internal/
│ │ └── unsafetests/
│ │ ├── doc.go
│ │ └── unsafetests_test.go
│ └── require/
│ ├── doc.go
│ ├── forward_requirements.go
│ ├── forward_requirements_test.go
│ ├── require.go
│ ├── require.go.tmpl
│ ├── require_forward.go
│ ├── require_forward.go.tmpl
│ ├── requirements.go
│ └── requirements_test.go
├── optimizer/
│ ├── const_expr.go
│ ├── count_any.go
│ ├── count_any_test.go
│ ├── count_threshold.go
│ ├── count_threshold_test.go
│ ├── filter_first.go
│ ├── filter_last.go
│ ├── filter_len.go
│ ├── filter_map.go
│ ├── filter_map_test.go
│ ├── fold.go
│ ├── fold_test.go
│ ├── in_array.go
│ ├── in_range.go
│ ├── optimizer.go
│ ├── optimizer_test.go
│ ├── predicate_combination.go
│ ├── sum_array.go
│ ├── sum_array_test.go
│ ├── sum_map.go
│ ├── sum_map_test.go
│ ├── sum_range.go
│ └── sum_range_test.go
├── parser/
│ ├── bench_test.go
│ ├── lexer/
│ │ ├── lexer.go
│ │ ├── lexer_test.go
│ │ ├── state.go
│ │ ├── token.go
│ │ └── utils.go
│ ├── operator/
│ │ └── operator.go
│ ├── parser.go
│ ├── parser_test.go
│ └── utils/
│ └── utils.go
├── patcher/
│ ├── operator_override.go
│ ├── value/
│ │ ├── bench_test.go
│ │ ├── value.go
│ │ ├── value_example_test.go
│ │ └── value_test.go
│ ├── with_context.go
│ ├── with_context_test.go
│ ├── with_timezone.go
│ └── with_timezone_test.go
├── repl/
│ ├── go.mod
│ ├── go.sum
│ └── repl.go
├── test/
│ ├── bench/
│ │ └── bench_call_test.go
│ ├── coredns/
│ │ ├── coredns.go
│ │ └── coredns_test.go
│ ├── crowdsec/
│ │ ├── crowdsec.go
│ │ ├── crowdsec_test.go
│ │ └── funcs.go
│ ├── deref/
│ │ └── deref_test.go
│ ├── examples/
│ │ ├── examples_test.go
│ │ └── markdown.go
│ ├── fuzz/
│ │ ├── fuzz_corpus.sh
│ │ ├── fuzz_corpus.txt
│ │ ├── fuzz_env.go
│ │ ├── fuzz_expr.dict
│ │ └── fuzz_test.go
│ ├── gen/
│ │ ├── env.go
│ │ ├── gen.go
│ │ ├── gen_test.go
│ │ └── utils.go
│ ├── interface/
│ │ ├── interface_method_test.go
│ │ └── interface_test.go
│ ├── issues/
│ │ ├── 461/
│ │ │ └── issue_test.go
│ │ ├── 567/
│ │ │ └── issue_test.go
│ │ ├── 688/
│ │ │ └── issue_test.go
│ │ ├── 723/
│ │ │ └── issue_test.go
│ │ ├── 730/
│ │ │ └── issue_test.go
│ │ ├── 739/
│ │ │ └── issue_test.go
│ │ ├── 756/
│ │ │ └── issue_test.go
│ │ ├── 785/
│ │ │ └── issue_test.go
│ │ ├── 817/
│ │ │ └── issue_test.go
│ │ ├── 819/
│ │ │ └── issue_test.go
│ │ ├── 823/
│ │ │ └── issue_test.go
│ │ ├── 830/
│ │ │ └── issue_test.go
│ │ ├── 836/
│ │ │ └── issue_test.go
│ │ ├── 840/
│ │ │ └── issue_test.go
│ │ ├── 844/
│ │ │ └── issue_test.go
│ │ ├── 854/
│ │ │ └── issue_test.go
│ │ ├── 857/
│ │ │ └── issue_test.go
│ │ ├── 888/
│ │ │ └── issue_test.go
│ │ ├── 924/
│ │ │ └── issue_test.go
│ │ └── 934/
│ │ └── issue_test.go
│ ├── mock/
│ │ └── mock.go
│ ├── operator/
│ │ ├── issues584/
│ │ │ └── issues584_test.go
│ │ └── operator_test.go
│ ├── patch/
│ │ ├── change_ident_test.go
│ │ ├── patch_count_test.go
│ │ ├── patch_test.go
│ │ └── set_type/
│ │ └── set_type_test.go
│ ├── pipes/
│ │ └── pipes_test.go
│ ├── playground/
│ │ ├── data.go
│ │ └── env.go
│ └── time/
│ └── time_test.go
├── testdata/
│ ├── crash.txt
│ ├── crowdsec.json
│ ├── examples.md
│ └── generated.txt
├── types/
│ ├── types.go
│ └── types_test.go
└── vm/
├── debug.go
├── debug_off.go
├── debug_test.go
├── func_types/
│ └── main.go
├── func_types[generated].go
├── opcodes.go
├── program.go
├── program_test.go
├── runtime/
│ ├── helpers/
│ │ └── main.go
│ ├── helpers[generated].go
│ ├── helpers_test.go
│ ├── runtime.go
│ └── sort.go
├── utils.go
├── vm.go
├── vm_bench_test.go
└── vm_test.go
Showing preview only (225K chars total). Download the full file or copy to clipboard to get everything.
SYMBOL INDEX (2605 symbols across 187 files)
FILE: ast/dump.go
function Dump (line 9) | func Dump(node Node) string {
function dump (line 13) | func dump(v reflect.Value, ident string) string {
function isPrivate (line 57) | func isPrivate(s string) bool {
FILE: ast/find.go
function Find (line 3) | func Find(node Node, fn func(node Node) bool) Node {
type finder (line 9) | type finder struct
method Visit (line 14) | func (f *finder) Visit(node *Node) {
FILE: ast/find_test.go
function TestFind (line 11) | func TestFind(t *testing.T) {
FILE: ast/node.go
type Node (line 15) | type Node interface
function Patch (line 28) | func Patch(node *Node, newNode Node) {
type base (line 34) | type base struct
method Location (line 40) | func (n *base) Location() file.Location {
method SetLocation (line 45) | func (n *base) SetLocation(loc file.Location) {
method Nature (line 50) | func (n *base) Nature() *nature.Nature {
method SetNature (line 55) | func (n *base) SetNature(nature nature.Nature) {
method Type (line 60) | func (n *base) Type() reflect.Type {
method SetType (line 68) | func (n *base) SetType(t reflect.Type) {
type NilNode (line 73) | type NilNode struct
type IdentifierNode (line 78) | type IdentifierNode struct
type IntegerNode (line 84) | type IntegerNode struct
type FloatNode (line 90) | type FloatNode struct
type BoolNode (line 96) | type BoolNode struct
type StringNode (line 102) | type StringNode struct
type BytesNode (line 108) | type BytesNode struct
type ConstantNode (line 117) | type ConstantNode struct
type UnaryNode (line 123) | type UnaryNode struct
type BinaryNode (line 130) | type BinaryNode struct
type ChainNode (line 144) | type ChainNode struct
type MemberNode (line 157) | type MemberNode struct
type SliceNode (line 169) | type SliceNode struct
type CallNode (line 177) | type CallNode struct
type BuiltinNode (line 184) | type BuiltinNode struct
type PredicateNode (line 199) | type PredicateNode struct
type PointerNode (line 205) | type PointerNode struct
type ConditionalNode (line 211) | type ConditionalNode struct
type VariableDeclaratorNode (line 220) | type VariableDeclaratorNode struct
type SequenceNode (line 229) | type SequenceNode struct
type ArrayNode (line 235) | type ArrayNode struct
type MapNode (line 241) | type MapNode struct
type PairNode (line 247) | type PairNode struct
FILE: ast/print.go
method String (line 12) | func (n *NilNode) String() string {
method String (line 16) | func (n *IdentifierNode) String() string {
method String (line 20) | func (n *IntegerNode) String() string {
method String (line 24) | func (n *FloatNode) String() string {
method String (line 28) | func (n *BoolNode) String() string {
method String (line 32) | func (n *StringNode) String() string {
method String (line 36) | func (n *BytesNode) String() string {
method String (line 40) | func (n *ConstantNode) String() string {
method String (line 51) | func (n *UnaryNode) String() string {
method String (line 72) | func (n *BinaryNode) String() string {
method String (line 138) | func (n *ChainNode) String() string {
method String (line 142) | func (n *MemberNode) String() string {
method String (line 164) | func (n *SliceNode) String() string {
method String (line 177) | func (n *CallNode) String() string {
method String (line 185) | func (n *BuiltinNode) String() string {
method String (line 193) | func (n *PredicateNode) String() string {
method String (line 197) | func (n *PointerNode) String() string {
method String (line 201) | func (n *VariableDeclaratorNode) String() string {
method String (line 205) | func (n *SequenceNode) String() string {
method String (line 213) | func (n *ConditionalNode) String() string {
method String (line 243) | func (n *ArrayNode) String() string {
method String (line 251) | func (n *MapNode) String() string {
method String (line 259) | func (n *PairNode) String() string {
FILE: ast/print_test.go
function TestPrint (line 13) | func TestPrint(t *testing.T) {
function TestPrint_MemberNode (line 99) | func TestPrint_MemberNode(t *testing.T) {
function TestPrint_ConstantNode (line 110) | func TestPrint_ConstantNode(t *testing.T) {
FILE: ast/visitor.go
type Visitor (line 5) | type Visitor interface
function Walk (line 9) | func Walk(node *Node, v Visitor) {
FILE: ast/visitor_test.go
type visitor (line 11) | type visitor struct
method Visit (line 15) | func (v *visitor) Visit(node *ast.Node) {
function TestWalk (line 21) | func TestWalk(t *testing.T) {
type patcher (line 34) | type patcher struct
method Visit (line 36) | func (p *patcher) Visit(node *ast.Node) {
function TestWalk_patch (line 42) | func TestWalk_patch(t *testing.T) {
FILE: bench_test.go
function Benchmark_expr (line 12) | func Benchmark_expr(b *testing.B) {
function Benchmark_expr_eval (line 34) | func Benchmark_expr_eval(b *testing.B) {
function Benchmark_expr_reuseVm (line 54) | func Benchmark_expr_reuseVm(b *testing.B) {
function Benchmark_len (line 77) | func Benchmark_len(b *testing.B) {
function Benchmark_filter (line 96) | func Benchmark_filter(b *testing.B) {
function Benchmark_filterLen (line 121) | func Benchmark_filterLen(b *testing.B) {
function Benchmark_filterFirst (line 146) | func Benchmark_filterFirst(b *testing.B) {
function Benchmark_filterLast (line 171) | func Benchmark_filterLast(b *testing.B) {
function Benchmark_filterMap (line 197) | func Benchmark_filterMap(b *testing.B) {
function Benchmark_arrayIndex (line 223) | func Benchmark_arrayIndex(b *testing.B) {
function Benchmark_envStruct (line 245) | func Benchmark_envStruct(b *testing.B) {
function Benchmark_envStruct_noEnv (line 269) | func Benchmark_envStruct_noEnv(b *testing.B) {
function Benchmark_envMap (line 293) | func Benchmark_envMap(b *testing.B) {
type CallEnv (line 315) | type CallEnv struct
method Func (line 324) | func (CallEnv) Func() string {
type CallFoo (line 328) | type CallFoo struct
method Method (line 334) | func (CallFoo) Method() string {
function Benchmark_callFunc (line 338) | func Benchmark_callFunc(b *testing.B) {
function Benchmark_callMethod (line 355) | func Benchmark_callMethod(b *testing.B) {
function Benchmark_callField (line 372) | func Benchmark_callField(b *testing.B) {
function Benchmark_callFast (line 393) | func Benchmark_callFast(b *testing.B) {
function Benchmark_callConstExpr (line 416) | func Benchmark_callConstExpr(b *testing.B) {
function Benchmark_largeStructAccess (line 433) | func Benchmark_largeStructAccess(b *testing.B) {
function Benchmark_largeNestedStructAccess (line 455) | func Benchmark_largeNestedStructAccess(b *testing.B) {
function Benchmark_largeNestedArrayAccess (line 480) | func Benchmark_largeNestedArrayAccess(b *testing.B) {
function Benchmark_sort (line 502) | func Benchmark_sort(b *testing.B) {
function Benchmark_sortBy (line 521) | func Benchmark_sortBy(b *testing.B) {
function Benchmark_groupBy (line 547) | func Benchmark_groupBy(b *testing.B) {
function Benchmark_reduce (line 561) | func Benchmark_reduce(b *testing.B) {
function Benchmark_min (line 575) | func Benchmark_min(b *testing.B) {
function Benchmark_max (line 592) | func Benchmark_max(b *testing.B) {
function Benchmark_mean (line 609) | func Benchmark_mean(b *testing.B) {
function Benchmark_median (line 626) | func Benchmark_median(b *testing.B) {
FILE: builtin/builtin.go
function init (line 26) | func init() {
FILE: builtin/builtin_test.go
function TestBuiltin (line 21) | func TestBuiltin(t *testing.T) {
function TestBuiltin_works_with_any (line 214) | func TestBuiltin_works_with_any(t *testing.T) {
function TestBuiltin_errors (line 246) | func TestBuiltin_errors(t *testing.T) {
function TestBuiltin_env_not_callable (line 303) | func TestBuiltin_env_not_callable(t *testing.T) {
function TestBuiltin_types (line 312) | func TestBuiltin_types(t *testing.T) {
function TestBuiltin_memory_limits (line 347) | func TestBuiltin_memory_limits(t *testing.T) {
function TestBuiltin_allow_builtins_override (line 380) | func TestBuiltin_allow_builtins_override(t *testing.T) {
function TestBuiltin_override_and_still_accessible (line 449) | func TestBuiltin_override_and_still_accessible(t *testing.T) {
function TestBuiltin_DisableBuiltin (line 463) | func TestBuiltin_DisableBuiltin(t *testing.T) {
function TestBuiltin_DisableAllBuiltins (line 505) | func TestBuiltin_DisableAllBuiltins(t *testing.T) {
function TestBuiltin_EnableBuiltin (line 511) | func TestBuiltin_EnableBuiltin(t *testing.T) {
function TestBuiltin_type (line 539) | func TestBuiltin_type(t *testing.T) {
function TestBuiltin_reverse (line 579) | func TestBuiltin_reverse(t *testing.T) {
function TestBuiltin_sort (line 611) | func TestBuiltin_sort(t *testing.T) {
function TestBuiltin_sort_i64 (line 642) | func TestBuiltin_sort_i64(t *testing.T) {
function TestBuiltin_bitOpsFunc (line 656) | func TestBuiltin_bitOpsFunc(t *testing.T) {
type customInt (line 684) | type customInt
function Test_int_unwraps_underlying_value (line 686) | func Test_int_unwraps_underlying_value(t *testing.T) {
function TestBuiltin_with_deref (line 698) | func TestBuiltin_with_deref(t *testing.T) {
function TestBuiltin_flatten_recursion (line 776) | func TestBuiltin_flatten_recursion(t *testing.T) {
function TestBuiltin_flatten_recursion_slice (line 792) | func TestBuiltin_flatten_recursion_slice(t *testing.T) {
function TestBuiltin_numerical_recursion (line 808) | func TestBuiltin_numerical_recursion(t *testing.T) {
function TestBuiltin_recursion_custom_max_depth (line 835) | func TestBuiltin_recursion_custom_max_depth(t *testing.T) {
function TestAbs_UnsignedIntegers (line 873) | func TestAbs_UnsignedIntegers(t *testing.T) {
FILE: builtin/function.go
type Function (line 7) | type Function struct
method Type (line 18) | func (f *Function) Type() reflect.Type {
FILE: builtin/lib.go
function Len (line 14) | func Len(x any) any {
function Type (line 26) | func Type(arg any) any {
function Abs (line 60) | func Abs(x any) any {
function Ceil (line 118) | func Ceil(x any) any {
function Floor (line 130) | func Floor(x any) any {
function Round (line 142) | func Round(x any) any {
function Int (line 154) | func Int(x any) any {
function Float (line 195) | func Float(x any) any {
function String (line 232) | func String(arg any) any {
function minMax (line 236) | func minMax(name string, fn func(any, any) bool, depth int, args ...any)...
function mean (line 348) | func mean(depth int, args ...any) (int, float64, error) {
function median (line 445) | func median(depth int, args ...any) ([]float64, error) {
function flatten (line 526) | func flatten(arg reflect.Value, depth int) ([]any, error) {
function get (line 546) | func get(params ...any) (out any, err error) {
FILE: builtin/utils.go
function kind (line 21) | func kind(t reflect.Type) reflect.Kind {
function types (line 29) | func types(types ...any) []reflect.Type {
function toInt (line 44) | func toInt(val any) (int, error) {
function bitFunc (line 71) | func bitFunc(name string, fn func(x, y int) (any, error)) *Function {
FILE: builtin/validation.go
function validateAggregateFunc (line 10) | func validateAggregateFunc(name string, args []reflect.Type) (reflect.Ty...
function validateRoundFunc (line 28) | func validateRoundFunc(name string, args []reflect.Type) (reflect.Type, ...
FILE: checker/checker.go
function ParseCheck (line 34) | func ParseCheck(input string, config *conf.Config) (*parser.Tree, error) {
function Check (line 49) | func Check(tree *parser.Tree, config *conf.Config) (reflect.Type, error) {
type Checker (line 53) | type Checker struct
method PatchAndCheck (line 72) | func (v *Checker) PatchAndCheck(tree *parser.Tree, config *conf.Config...
method Check (line 86) | func (v *Checker) Check(tree *parser.Tree, config *conf.Config) (refle...
method runVisitors (line 93) | func (v *Checker) runVisitors(tree *parser.Tree, runRepeatable bool) {
method check (line 125) | func (v *Checker) check(tree *parser.Tree) (reflect.Type, error) {
method reset (line 160) | func (v *Checker) reset(config *conf.Config) {
method visit (line 183) | func (v *Checker) visit(node ast.Node) Nature {
method error (line 239) | func (v *Checker) error(node ast.Node, format string, args ...any) Nat...
method identifierNode (line 249) | func (v *Checker) identifierNode(node *ast.IdentifierNode) Nature {
method ident (line 263) | func (v *Checker) ident(node ast.Node, name string, strict, builtins b...
method unaryNode (line 291) | func (v *Checker) unaryNode(node *ast.UnaryNode) Nature {
method binaryNode (line 320) | func (v *Checker) binaryNode(node *ast.BinaryNode) Nature {
method chainNode (line 511) | func (v *Checker) chainNode(node *ast.ChainNode) Nature {
method memberNode (line 515) | func (v *Checker) memberNode(node *ast.MemberNode) Nature {
method sliceNode (line 605) | func (v *Checker) sliceNode(node *ast.SliceNode) Nature {
method callNode (line 638) | func (v *Checker) callNode(node *ast.CallNode) Nature {
method builtinNode (line 695) | func (v *Checker) builtinNode(node *ast.BuiltinNode) Nature {
method begin (line 948) | func (v *Checker) begin(collectionNature Nature, vars ...varScope) {
method end (line 955) | func (v *Checker) end() {
method checkBuiltinGet (line 959) | func (v *Checker) checkBuiltinGet(node *ast.BuiltinNode) Nature {
method checkFunction (line 996) | func (v *Checker) checkFunction(f *builtin.Function, node ast.Node, ar...
method checkArguments (line 1050) | func (v *Checker) checkArguments(
method predicateNode (line 1212) | func (v *Checker) predicateNode(node *ast.PredicateNode) Nature {
method pointerNode (line 1225) | func (v *Checker) pointerNode(node *ast.PointerNode) Nature {
method variableDeclaratorNode (line 1250) | func (v *Checker) variableDeclaratorNode(node *ast.VariableDeclaratorN...
method sequenceNode (line 1272) | func (v *Checker) sequenceNode(node *ast.SequenceNode) Nature {
method conditionalNode (line 1283) | func (v *Checker) conditionalNode(node *ast.ConditionalNode) Nature {
method arrayNode (line 1315) | func (v *Checker) arrayNode(node *ast.ArrayNode) Nature {
method mapNode (line 1333) | func (v *Checker) mapNode(node *ast.MapNode) Nature {
method pairNode (line 1340) | func (v *Checker) pairNode(node *ast.PairNode) Nature {
type predicateScope (line 61) | type predicateScope struct
type varScope (line 66) | type varScope struct
function clearSlice (line 176) | func clearSlice[S ~[]E, E any](s S) {
function traverseAndReplaceIntegerNodesWithFloatNodes (line 1175) | func traverseAndReplaceIntegerNodesWithFloatNodes(node *ast.Node, newNat...
function traverseAndReplaceIntegerNodesWithIntegerNodes (line 1193) | func traverseAndReplaceIntegerNodesWithIntegerNodes(node *ast.Node, newN...
FILE: checker/checker_bench_test.go
function BenchmarkChecker (line 15) | func BenchmarkChecker(b *testing.B) {
type visitorFunc (line 100) | type visitorFunc
method Visit (line 102) | func (f visitorFunc) Visit(node *ast.Node) { f(node) }
function invalidateTrees (line 104) | func invalidateTrees(trees ...*parser.Tree) {
type recursive (line 112) | type recursive struct
FILE: checker/checker_test.go
function TestCheck (line 23) | func TestCheck(t *testing.T) {
function TestCheck_error (line 157) | func TestCheck_error(t *testing.T) {
function TestCheck_FloatVsInt (line 728) | func TestCheck_FloatVsInt(t *testing.T) {
function TestCheck_IntSums (line 737) | func TestCheck_IntSums(t *testing.T) {
function TestVisitor_ConstantNode (line 746) | func TestVisitor_ConstantNode(t *testing.T) {
function TestCheck_AsBool (line 759) | func TestCheck_AsBool(t *testing.T) {
function TestCheck_AsInt64 (line 771) | func TestCheck_AsInt64(t *testing.T) {
function TestCheck_TaggedFieldName (line 783) | func TestCheck_TaggedFieldName(t *testing.T) {
function TestCheck_NoConfig (line 799) | func TestCheck_NoConfig(t *testing.T) {
function TestCheck_AllowUndefinedVariables (line 807) | func TestCheck_AllowUndefinedVariables(t *testing.T) {
function TestCheck_AllowUndefinedVariables_DefaultType (line 822) | func TestCheck_AllowUndefinedVariables_DefaultType(t *testing.T) {
function TestCheck_AllowUndefinedVariables_OptionalChaining (line 836) | func TestCheck_AllowUndefinedVariables_OptionalChaining(t *testing.T) {
function TestCheck_PointerNode (line 849) | func TestCheck_PointerNode(t *testing.T) {
function TestCheck_TypeWeights (line 855) | func TestCheck_TypeWeights(t *testing.T) {
function TestCheck_works_with_nil_types (line 884) | func TestCheck_works_with_nil_types(t *testing.T) {
function TestCheck_cast_to_expected_works_with_interface (line 896) | func TestCheck_cast_to_expected_works_with_interface(t *testing.T) {
function TestCheck_operator_in_works_with_interfaces (line 929) | func TestCheck_operator_in_works_with_interfaces(t *testing.T) {
function TestCheck_Function_types_are_checked (line 940) | func TestCheck_Function_types_are_checked(t *testing.T) {
function TestCheck_Function_without_types (line 987) | func TestCheck_Function_without_types(t *testing.T) {
function TestCheck_dont_panic_on_nil_arguments_for_builtins (line 1010) | func TestCheck_dont_panic_on_nil_arguments_for_builtins(t *testing.T) {
function TestCheck_do_not_override_params_for_functions (line 1028) | func TestCheck_do_not_override_params_for_functions(t *testing.T) {
function TestCheck_env_keyword (line 1063) | func TestCheck_env_keyword(t *testing.T) {
function TestCheck_builtin_without_call (line 1092) | func TestCheck_builtin_without_call(t *testing.T) {
function TestCheck_EmbeddedInterface (line 1114) | func TestCheck_EmbeddedInterface(t *testing.T) {
function TestCheck_types (line 1138) | func TestCheck_types(t *testing.T) {
FILE: checker/info.go
function FieldIndex (line 11) | func FieldIndex(c *Cache, env Nature, node ast.Node) (bool, []int, strin...
function MethodIndex (line 30) | func MethodIndex(c *Cache, env Nature, node ast.Node) (bool, int, string) {
function TypedFuncIndex (line 51) | func TypedFuncIndex(fn reflect.Type, method bool) (int, bool) {
function IsFastFunc (line 104) | func IsFastFunc(fn reflect.Type, method bool) bool {
FILE: checker/info_test.go
function TestTypedFuncIndex (line 14) | func TestTypedFuncIndex(t *testing.T) {
function TestTypedFuncIndex_excludes_named_functions (line 23) | func TestTypedFuncIndex_excludes_named_functions(t *testing.T) {
FILE: checker/nature/nature.go
type NatureCheck (line 39) | type NatureCheck
constant _ (line 42) | _ NatureCheck = iota
constant BoolCheck (line 43) | BoolCheck
constant StringCheck (line 44) | StringCheck
constant IntegerCheck (line 45) | IntegerCheck
constant NumberCheck (line 46) | NumberCheck
constant MapCheck (line 47) | MapCheck
constant ArrayCheck (line 48) | ArrayCheck
constant TimeCheck (line 49) | TimeCheck
constant DurationCheck (line 50) | DurationCheck
type Nature (line 53) | type Nature struct
method IsAny (line 215) | func (n *Nature) IsAny(c *Cache) bool {
method IsUnknown (line 219) | func (n *Nature) IsUnknown(c *Cache) bool {
method String (line 223) | func (n *Nature) String() string {
method Deref (line 230) | func (n *Nature) Deref(c *Cache) Nature {
method Key (line 238) | func (n *Nature) Key(c *Cache) Nature {
method Elem (line 245) | func (n *Nature) Elem(c *Cache) Nature {
method AssignableTo (line 263) | func (n *Nature) AssignableTo(nt Nature) bool {
method getMethodset (line 279) | func (n *Nature) getMethodset(c *Cache) *methodset {
method NumMethods (line 290) | func (n *Nature) NumMethods(c *Cache) int {
method MethodByName (line 297) | func (n *Nature) MethodByName(c *Cache, name string) (Nature, bool) {
method NumIn (line 306) | func (n *Nature) NumIn() int {
method InElem (line 315) | func (n *Nature) InElem(c *Cache, i int) Nature {
method In (line 324) | func (n *Nature) In(c *Cache, i int) Nature {
method IsFirstArgUnknown (line 328) | func (n *Nature) IsFirstArgUnknown(c *Cache) bool {
method NumOut (line 336) | func (n *Nature) NumOut() int {
method Out (line 345) | func (n *Nature) Out(c *Cache, i int) Nature {
method out (line 357) | func (n *Nature) out(c *Cache, i int) Nature {
method IsVariadic (line 364) | func (n *Nature) IsVariadic() bool {
method FieldByName (line 373) | func (n *Nature) FieldByName(c *Cache, name string) (Nature, bool) {
method IsFastMap (line 389) | func (n *Nature) IsFastMap() bool {
method Get (line 396) | func (n *Nature) Get(c *Cache, name string) (Nature, bool) {
method getSlow (line 404) | func (n *Nature) getSlow(c *Cache, name string) (Nature, bool) {
method FieldIndex (line 423) | func (n *Nature) FieldIndex(c *Cache, name string) ([]int, bool) {
method All (line 433) | func (n *Nature) All(c *Cache) map[string]Nature {
method IsNumber (line 476) | func (n *Nature) IsNumber() bool {
method PromoteNumericNature (line 480) | func (n *Nature) PromoteNumericNature(c *Cache, rhs Nature) Nature {
method IsTime (line 490) | func (n *Nature) IsTime() bool {
method IsDuration (line 494) | func (n *Nature) IsDuration() bool {
method IsBool (line 498) | func (n *Nature) IsBool() bool {
method IsString (line 502) | func (n *Nature) IsString() bool {
method IsByteSlice (line 506) | func (n *Nature) IsByteSlice() bool {
method IsArray (line 510) | func (n *Nature) IsArray() bool {
method IsMap (line 514) | func (n *Nature) IsMap() bool {
method IsStruct (line 518) | func (n *Nature) IsStruct() bool {
method IsFunc (line 522) | func (n *Nature) IsFunc() bool {
method IsPointer (line 526) | func (n *Nature) IsPointer() bool {
method IsAnyOf (line 530) | func (n *Nature) IsAnyOf(cs ...NatureCheck) bool {
method ComparableTo (line 557) | func (n *Nature) ComparableTo(c *Cache, rhs Nature) bool {
method MaybeCompatible (line 567) | func (n *Nature) MaybeCompatible(c *Cache, rhs Nature, cs ...NatureChe...
method MakeArrayOf (line 575) | func (n *Nature) MakeArrayOf(c *Cache) Nature {
type TypeData (line 74) | type TypeData struct
type Cache (line 100) | type Cache struct
method NatureOf (line 107) | func (c *Cache) NatureOf(i any) Nature {
method FromType (line 118) | func (c *Cache) FromType(t reflect.Type) Nature {
method getStruct (line 150) | func (c *Cache) getStruct(t reflect.Type) Nature {
method getMethodset (line 171) | func (c *Cache) getMethodset(t reflect.Type, k reflect.Kind) *methodset {
function NatureOf (line 197) | func NatureOf(i any) Nature {
function FromType (line 203) | func FromType(t reflect.Type) Nature {
function ArrayFromType (line 208) | func ArrayFromType(c *Cache, t reflect.Type) Nature {
FILE: checker/nature/utils.go
function fieldName (line 9) | func fieldName(fieldName string, tag reflect.StructTag) (string, bool) {
type structData (line 20) | type structData struct
method finished (line 34) | func (s *structData) finished() bool {
method structField (line 40) | func (s *structData) structField(c *Cache, parentEmbed *structData, na...
method findInEmbedded (line 112) | func (s *structData) findInEmbedded(
method trySet (line 156) | func (s *structData) trySet(name string, sf *structField) {
type structField (line 29) | type structField struct
function StructFields (line 170) | func StructFields(c *Cache, t reflect.Type) map[string]Nature {
type methodset (line 188) | type methodset struct
method method (line 200) | func (s *methodset) method(c *Cache, name string) *method {
type method (line 195) | type method struct
FILE: compiler/compiler.go
constant placeholder (line 22) | placeholder = 12345
function Compile (line 25) | func Compile(tree *parser.Tree, config *conf.Config) (program *Program, ...
type compiler (line 84) | type compiler struct
method nodeParent (line 107) | func (c *compiler) nodeParent() ast.Node {
method emitLocation (line 114) | func (c *compiler) emitLocation(loc file.Location, op Opcode, arg int)...
method emit (line 122) | func (c *compiler) emit(op Opcode, args ...int) int {
method emitPush (line 137) | func (c *compiler) emitPush(value any) int {
method addConstant (line 141) | func (c *compiler) addConstant(constant any) int {
method addVariable (line 169) | func (c *compiler) addVariable(name string) int {
method emitFunction (line 176) | func (c *compiler) emitFunction(fn *builtin.Function, argsLen int) {
method addFunction (line 193) | func (c *compiler) addFunction(name string, fn Function) int {
method patchJump (line 207) | func (c *compiler) patchJump(placeholder int) {
method calcBackwardJump (line 212) | func (c *compiler) calcBackwardJump(to int) int {
method compile (line 216) | func (c *compiler) compile(node ast.Node) {
method NilNode (line 296) | func (c *compiler) NilNode(_ *ast.NilNode) {
method IdentifierNode (line 300) | func (c *compiler) IdentifierNode(node *ast.IdentifierNode) {
method IntegerNode (line 332) | func (c *compiler) IntegerNode(node *ast.IntegerNode) {
method FloatNode (line 392) | func (c *compiler) FloatNode(node *ast.FloatNode) {
method BoolNode (line 403) | func (c *compiler) BoolNode(node *ast.BoolNode) {
method StringNode (line 411) | func (c *compiler) StringNode(node *ast.StringNode) {
method BytesNode (line 415) | func (c *compiler) BytesNode(node *ast.BytesNode) {
method ConstantNode (line 419) | func (c *compiler) ConstantNode(node *ast.ConstantNode) {
method UnaryNode (line 427) | func (c *compiler) UnaryNode(node *ast.UnaryNode) {
method BinaryNode (line 447) | func (c *compiler) BinaryNode(node *ast.BinaryNode) {
method equalBinaryNode (line 627) | func (c *compiler) equalBinaryNode(node *ast.BinaryNode) {
method ChainNode (line 660) | func (c *compiler) ChainNode(node *ast.ChainNode) {
method MemberNode (line 682) | func (c *compiler) MemberNode(node *ast.MemberNode) {
method SliceNode (line 761) | func (c *compiler) SliceNode(node *ast.SliceNode) {
method CallNode (line 778) | func (c *compiler) CallNode(node *ast.CallNode) {
method BuiltinNode (line 840) | func (c *compiler) BuiltinNode(node *ast.BuiltinNode) {
method emitCond (line 1183) | func (c *compiler) emitCond(body func()) {
method emitLoop (line 1195) | func (c *compiler) emitLoop(body func()) {
method emitLoopBackwards (line 1206) | func (c *compiler) emitLoopBackwards(body func()) {
method PredicateNode (line 1224) | func (c *compiler) PredicateNode(node *ast.PredicateNode) {
method PointerNode (line 1228) | func (c *compiler) PointerNode(node *ast.PointerNode) {
method VariableDeclaratorNode (line 1241) | func (c *compiler) VariableDeclaratorNode(node *ast.VariableDeclarator...
method SequenceNode (line 1250) | func (c *compiler) SequenceNode(node *ast.SequenceNode) {
method beginScope (line 1259) | func (c *compiler) beginScope(name string, index int) {
method endScope (line 1263) | func (c *compiler) endScope() {
method lookupVariable (line 1267) | func (c *compiler) lookupVariable(name string) (int, bool) {
method ConditionalNode (line 1276) | func (c *compiler) ConditionalNode(node *ast.ConditionalNode) {
method ArrayNode (line 1292) | func (c *compiler) ArrayNode(node *ast.ArrayNode) {
method MapNode (line 1301) | func (c *compiler) MapNode(node *ast.MapNode) {
method PairNode (line 1310) | func (c *compiler) PairNode(node *ast.PairNode) {
method derefInNeeded (line 1315) | func (c *compiler) derefInNeeded(node ast.Node) {
method derefParam (line 1325) | func (c *compiler) derefParam(in reflect.Type, param ast.Node) {
method optimize (line 1337) | func (c *compiler) optimize() {
type scope (line 102) | type scope struct
function isSimpleType (line 649) | func isSimpleType(node ast.Node) bool {
function kind (line 1350) | func kind(t reflect.Type) reflect.Kind {
FILE: compiler/compiler_test.go
type B (line 18) | type B struct
method FuncInB (line 29) | func (B) FuncInB() int {
type Env (line 33) | type Env struct
method AFunc (line 43) | func (e Env) AFunc() int {
method Func (line 47) | func (e Env) Func() B {
function TestCompile (line 51) | func TestCompile(t *testing.T) {
function TestCompile_panic (line 411) | func TestCompile_panic(t *testing.T) {
function TestCompile_FuncTypes (line 426) | func TestCompile_FuncTypes(t *testing.T) {
function TestCompile_FuncTypes_with_Method (line 438) | func TestCompile_FuncTypes_with_Method(t *testing.T) {
function TestCompile_FuncTypes_excludes_named_functions (line 446) | func TestCompile_FuncTypes_excludes_named_functions(t *testing.T) {
function TestCompile_OpCallFast (line 454) | func TestCompile_OpCallFast(t *testing.T) {
function TestCompile_optimizes_jumps (line 462) | func TestCompile_optimizes_jumps(t *testing.T) {
function TestCompile_IntegerArgsFunc (line 649) | func TestCompile_IntegerArgsFunc(t *testing.T) {
function TestCompile_call_on_nil (line 671) | func TestCompile_call_on_nil(t *testing.T) {
function TestCompile_Expect (line 680) | func TestCompile_Expect(t *testing.T) {
FILE: conf/config.go
type FunctionsTable (line 21) | type FunctionsTable
type Config (line 23) | type Config struct
method WithEnv (line 70) | func (c *Config) WithEnv(env any) {
method ConstExpr (line 76) | func (c *Config) ConstExpr(name string) {
method Check (line 91) | func (c *Config) Check() {
method IsOverridden (line 99) | func (c *Config) IsOverridden(name string) bool {
function CreateNew (line 47) | func CreateNew() *Config {
function New (line 64) | func New(env any) *Config {
type Checker (line 87) | type Checker interface
FILE: conf/env.go
function Env (line 15) | func Env(env any) Nature {
function EnvWithCache (line 19) | func EnvWithCache(c *Cache, env any) Nature {
FILE: debug/debugger.go
function StartDebugger (line 16) | func StartDebugger(program *Program, env any) {
function check (line 200) | func check(err error) {
FILE: docgen/docgen.go
type Kind (line 14) | type Kind
type Identifier (line 17) | type Identifier
type TypeName (line 20) | type TypeName
type Context (line 22) | type Context struct
method use (line 122) | func (c *Context) use(t reflect.Type, ops ...option) *Type {
type Type (line 28) | type Type struct
function CreateDoc (line 81) | func CreateDoc(i any) *Context {
type config (line 110) | type config struct
type option (line 114) | type option
function fromMethod (line 116) | func fromMethod(b bool) option {
function isPrivate (line 257) | func isPrivate(s string) bool {
function isProtobuf (line 261) | func isProtobuf(s string) bool {
FILE: docgen/docgen_test.go
type Tweet (line 14) | type Tweet struct
type Env (line 19) | type Env struct
method Duration (line 42) | func (*Env) Duration(s string) Duration {
type Weekday (line 30) | type Weekday
method String (line 32) | func (Weekday) String() string {
type Duration (line 36) | type Duration
method String (line 38) | func (Duration) String() string {
function TestCreateDoc (line 46) | func TestCreateDoc(t *testing.T) {
type A (line 137) | type A struct
type B (line 141) | type B struct
type C (line 145) | type C struct
type EnvAmbiguous (line 149) | type EnvAmbiguous struct
function TestCreateDoc_Ambiguous (line 155) | func TestCreateDoc_Ambiguous(t *testing.T) {
function TestCreateDoc_FromMap (line 208) | func TestCreateDoc_FromMap(t *testing.T) {
function TestContext_Markdown (line 257) | func TestContext_Markdown(t *testing.T) {
FILE: docgen/markdown.go
method Markdown (line 9) | func (c *Context) Markdown() string {
function link (line 65) | func link(t *Type) string {
function fields (line 81) | func fields(t *Type) string {
FILE: expr.go
type Option (line 22) | type Option
function Env (line 29) | func Env(env any) Option {
function AllowUndefinedVariables (line 37) | func AllowUndefinedVariables() Option {
function Operator (line 44) | func Operator(operator string, fn ...string) Option {
function ConstExpr (line 59) | func ConstExpr(fn string) Option {
function AsAny (line 66) | func AsAny() Option {
function AsKind (line 73) | func AsKind(kind reflect.Kind) Option {
function AsBool (line 81) | func AsBool() Option {
function AsInt (line 89) | func AsInt() Option {
function AsInt64 (line 97) | func AsInt64() Option {
function AsFloat64 (line 105) | func AsFloat64() Option {
function DisableIfOperator (line 114) | func DisableIfOperator() Option {
function WarnOnAny (line 121) | func WarnOnAny() Option {
function Optimize (line 131) | func Optimize(b bool) Option {
function DisableShortCircuit (line 138) | func DisableShortCircuit() Option {
function Patch (line 145) | func Patch(visitor ast.Visitor) Option {
function Function (line 152) | func Function(name string, fn func(params ...any) (any, error), types .....
function DisableAllBuiltins (line 174) | func DisableAllBuiltins() Option {
function DisableBuiltin (line 183) | func DisableBuiltin(name string) Option {
function EnableBuiltin (line 190) | func EnableBuiltin(name string) Option {
function WithContext (line 197) | func WithContext(name string) Option {
function Timezone (line 209) | func Timezone(name string) Option {
function MaxNodes (line 222) | func MaxNodes(n uint) Option {
function Compile (line 229) | func Compile(input string, ops ...Option) (*vm.Program, error) {
function Run (line 264) | func Run(program *vm.Program, env any) (any, error) {
function Eval (line 269) | func Eval(input string, env any) (any, error) {
FILE: expr_test.go
function ExampleEval (line 26) | func ExampleEval() {
function ExampleEval_runtime_error (line 41) | func ExampleEval_runtime_error() {
function ExampleCompile (line 50) | func ExampleCompile() {
function ExampleEval_bytes_literal (line 73) | func ExampleEval_bytes_literal() {
function TestDisableIfOperator_AllowsIfFunction (line 86) | func TestDisableIfOperator_AllowsIfFunction(t *testing.T) {
function ExampleEnv (line 97) | func ExampleEnv() {
function ExampleEnv_tagged_field_names (line 148) | func ExampleEnv_tagged_field_names() {
function ExampleEnv_hidden_tagged_field_names (line 170) | func ExampleEnv_hidden_tagged_field_names() {
function ExampleAsKind (line 249) | func ExampleAsKind() {
function ExampleAsBool (line 267) | func ExampleAsBool() {
function ExampleAsBool_error (line 289) | func ExampleAsBool_error() {
function ExampleAsInt (line 301) | func ExampleAsInt() {
function ExampleAsInt64 (line 319) | func ExampleAsInt64() {
function ExampleAsFloat64 (line 341) | func ExampleAsFloat64() {
function ExampleAsFloat64_error (line 359) | func ExampleAsFloat64_error() {
function ExampleWarnOnAny (line 367) | func ExampleWarnOnAny() {
function ExampleOperator (line 378) | func ExampleOperator() {
function ExampleOperator_with_decimal (line 421) | func ExampleOperator_with_decimal() {
function fib (line 462) | func fib(n int) int {
function ExampleConstExpr (line 469) | func ExampleConstExpr() {
function ExampleAllowUndefinedVariables (line 502) | func ExampleAllowUndefinedVariables() {
function ExampleAllowUndefinedVariables_zero_value (line 540) | func ExampleAllowUndefinedVariables_zero_value() {
function ExampleAllowUndefinedVariables_zero_value_functions (line 573) | func ExampleAllowUndefinedVariables_zero_value_functions() {
type patcher (line 600) | type patcher struct
method Visit (line 602) | func (p *patcher) Visit(node *ast.Node) {
function ExamplePatch (line 612) | func ExamplePatch() {
function ExampleWithContext (line 639) | func ExampleWithContext() {
function ExampleTimezone (line 680) | func ExampleTimezone() {
function TestExpr_readme_example (line 697) | func TestExpr_readme_example(t *testing.T) {
function TestExpr (line 715) | func TestExpr(t *testing.T) {
function TestExpr_error (line 1467) | func TestExpr_error(t *testing.T) {
function TestExpr_optional_chaining (line 1508) | func TestExpr_optional_chaining(t *testing.T) {
function TestExpr_optional_chaining_property (line 1518) | func TestExpr_optional_chaining_property(t *testing.T) {
function TestExpr_optional_chaining_nested_chains (line 1530) | func TestExpr_optional_chaining_nested_chains(t *testing.T) {
function TestExpr_optional_chaining_array (line 1549) | func TestExpr_optional_chaining_array(t *testing.T) {
function TestExpr_eval_with_env (line 1559) | func TestExpr_eval_with_env(t *testing.T) {
function TestExpr_fetch_from_func (line 1565) | func TestExpr_fetch_from_func(t *testing.T) {
function TestExpr_map_default_values (line 1573) | func TestExpr_map_default_values(t *testing.T) {
function TestExpr_map_default_values_compile_check (line 1589) | func TestExpr_map_default_values_compile_check(t *testing.T) {
function TestExpr_calls_with_nil (line 1609) | func TestExpr_calls_with_nil(t *testing.T) {
function TestExpr_call_float_arg_func_with_int (line 1632) | func TestExpr_call_float_arg_func_with_int(t *testing.T) {
function TestConstExpr_error_panic (line 1662) | func TestConstExpr_error_panic(t *testing.T) {
type divideError (line 1676) | type divideError struct
method Error (line 1678) | func (e divideError) Error() string {
function TestConstExpr_error_as_error (line 1682) | func TestConstExpr_error_as_error(t *testing.T) {
function TestConstExpr_error_wrong_type (line 1702) | func TestConstExpr_error_wrong_type(t *testing.T) {
function TestConstExpr_error_no_env (line 1715) | func TestConstExpr_error_no_env(t *testing.T) {
type stringerPatcher (line 1726) | type stringerPatcher struct
method Visit (line 1728) | func (p *stringerPatcher) Visit(node *ast.Node) {
function TestPatch (line 1743) | func TestPatch(t *testing.T) {
function TestCompile_exposed_error (line 1756) | func TestCompile_exposed_error(t *testing.T) {
function TestAsBool_exposed_error (line 1774) | func TestAsBool_exposed_error(t *testing.T) {
function TestEval_exposed_error (line 1783) | func TestEval_exposed_error(t *testing.T) {
function TestCompile_exposed_error_with_multiline_script (line 1794) | func TestCompile_exposed_error_with_multiline_script(t *testing.T) {
function TestIssue105 (line 1805) | func TestIssue105(t *testing.T) {
function TestIssue_nested_closures (line 1831) | func TestIssue_nested_closures(t *testing.T) {
function TestIssue138 (line 1842) | func TestIssue138(t *testing.T) {
function TestIssue154 (line 1853) | func TestIssue154(t *testing.T) {
function TestIssue270 (line 1913) | func TestIssue270(t *testing.T) {
function TestIssue271 (line 1973) | func TestIssue271(t *testing.T) {
type Issue346Array (line 1999) | type Issue346Array
method Len (line 2005) | func (i Issue346Array) Len() int {
type Issue346Type (line 2001) | type Issue346Type struct
function TestIssue346 (line 2009) | func TestIssue346(t *testing.T) {
function TestCompile_allow_to_use_interface_to_get_an_element_from_map (line 2025) | func TestCompile_allow_to_use_interface_to_get_an_element_from_map(t *te...
function TestFastCall (line 2056) | func TestFastCall(t *testing.T) {
function TestFastCall_OpCallFastErr (line 2072) | func TestFastCall_OpCallFastErr(t *testing.T) {
function TestRun_custom_func_returns_an_error_as_second_arg (line 2088) | func TestRun_custom_func_returns_an_error_as_second_arg(t *testing.T) {
function TestFunction (line 2101) | func TestFunction(t *testing.T) {
function TestRun_NilCoalescingOperator (line 2123) | func TestRun_NilCoalescingOperator(t *testing.T) {
function TestEval_nil_in_maps (line 2158) | func TestEval_nil_in_maps(t *testing.T) {
function TestEnv_keyword (line 2199) | func TestEnv_keyword(t *testing.T) {
function TestEnv_keyword_with_custom_functions (line 2295) | func TestEnv_keyword_with_custom_functions(t *testing.T) {
function TestIssue401 (line 2321) | func TestIssue401(t *testing.T) {
function TestEval_slices_out_of_bound (line 2335) | func TestEval_slices_out_of_bound(t *testing.T) {
function TestExpr_timeout (line 2355) | func TestExpr_timeout(t *testing.T) {
function TestIssue432 (line 2392) | func TestIssue432(t *testing.T) {
function TestIssue462 (line 2421) | func TestIssue462(t *testing.T) {
function TestIssue_embedded_pointer_struct (line 2431) | func TestIssue_embedded_pointer_struct(t *testing.T) {
function TestIssue474 (line 2504) | func TestIssue474(t *testing.T) {
function TestRaceCondition_variables (line 2558) | func TestRaceCondition_variables(t *testing.T) {
function TestOperatorDependsOnEnv (line 2577) | func TestOperatorDependsOnEnv(t *testing.T) {
function TestIssue624 (line 2591) | func TestIssue624(t *testing.T) {
function TestPredicateCombination (line 2618) | func TestPredicateCombination(t *testing.T) {
function TestArrayComparison (line 2651) | func TestArrayComparison(t *testing.T) {
function TestIssue_570 (line 2677) | func TestIssue_570(t *testing.T) {
function TestIssue_integer_truncated_by_compiler (line 2694) | func TestIssue_integer_truncated_by_compiler(t *testing.T) {
function TestExpr_crash (line 2708) | func TestExpr_crash(t *testing.T) {
function TestExpr_crash_with_zero (line 2716) | func TestExpr_crash_with_zero(t *testing.T) {
function TestExpr_nil_op_str (line 2722) | func TestExpr_nil_op_str(t *testing.T) {
function TestExpr_env_types_map (line 2756) | func TestExpr_env_types_map(t *testing.T) {
function TestExpr_env_types_map_error (line 2777) | func TestExpr_env_types_map_error(t *testing.T) {
function TestIssue758_filter_map_index (line 2791) | func TestIssue758_filter_map_index(t *testing.T) {
function TestExpr_wierd_cases (line 2812) | func TestExpr_wierd_cases(t *testing.T) {
function TestIssue785_get_nil (line 2820) | func TestIssue785_get_nil(t *testing.T) {
function TestMaxNodes (line 2841) | func TestMaxNodes(t *testing.T) {
function TestMaxNodesDisabled (line 2857) | func TestMaxNodesDisabled(t *testing.T) {
function TestMemoryBudget (line 2867) | func TestMemoryBudget(t *testing.T) {
function TestIssue802 (line 2893) | func TestIssue802(t *testing.T) {
function TestIssue807 (line 2910) | func TestIssue807(t *testing.T) {
function TestDisableShortCircuit (line 2927) | func TestDisableShortCircuit(t *testing.T) {
function TestBytesLiteral (line 2952) | func TestBytesLiteral(t *testing.T) {
function TestBytesLiteral_type (line 2980) | func TestBytesLiteral_type(t *testing.T) {
function TestBytesLiteral_errors (line 2994) | func TestBytesLiteral_errors(t *testing.T) {
FILE: file/error.go
type Error (line 8) | type Error struct
method Error (line 17) | func (e *Error) Error() string {
method Bind (line 23) | func (e *Error) Bind(source Source) *Error {
method Unwrap (line 66) | func (e *Error) Unwrap() error {
method Wrap (line 70) | func (e *Error) Wrap(err error) {
method format (line 74) | func (e *Error) format() string {
FILE: file/location.go
type Location (line 3) | type Location struct
FILE: file/source.go
type Source (line 5) | type Source struct
method String (line 15) | func (s Source) String() string {
method Snippet (line 19) | func (s Source) Snippet(line int) (string, bool) {
function NewSource (line 9) | func NewSource(contents string) Source {
FILE: file/source_test.go
constant unexpectedSnippet (line 8) | unexpectedSnippet = "%s got snippet '%s', want '%v'"
constant snippetNotFound (line 9) | snippetNotFound = "%s snippet not found, wanted '%v'"
constant snippetFound (line 10) | snippetFound = "%s snippet found at Line %d, wanted none"
function TestStringSource_SnippetMultiLine (line 13) | func TestStringSource_SnippetMultiLine(t *testing.T) {
function TestStringSource_SnippetSingleLine (line 42) | func TestStringSource_SnippetSingleLine(t *testing.T) {
FILE: internal/deref/deref.go
function Interface (line 8) | func Interface(p any) any {
function Type (line 29) | func Type(t reflect.Type) reflect.Type {
function Value (line 39) | func Value(v reflect.Value) reflect.Value {
function TypeKind (line 49) | func TypeKind(t reflect.Type, k reflect.Kind) (_ reflect.Type, _ reflect...
FILE: internal/deref/deref_test.go
function TestDeref (line 12) | func TestDeref(t *testing.T) {
function TestDeref_mix_ptr_with_interface (line 22) | func TestDeref_mix_ptr_with_interface(t *testing.T) {
function TestDeref_nil (line 32) | func TestDeref_nil(t *testing.T) {
function TestType (line 38) | func TestType(t *testing.T) {
function TestType_two_ptr_with_interface (line 48) | func TestType_two_ptr_with_interface(t *testing.T) {
function TestType_three_ptr_with_interface (line 57) | func TestType_three_ptr_with_interface(t *testing.T) {
function TestType_nil (line 66) | func TestType_nil(t *testing.T) {
function TestValue (line 70) | func TestValue(t *testing.T) {
function TestValue_two_ptr_with_interface (line 80) | func TestValue_two_ptr_with_interface(t *testing.T) {
function TestValue_three_ptr_with_interface (line 88) | func TestValue_three_ptr_with_interface(t *testing.T) {
function TestValue_nil (line 97) | func TestValue_nil(t *testing.T) {
function TestValue_nil_in_chain (line 102) | func TestValue_nil_in_chain(t *testing.T) {
FILE: internal/difflib/difflib.go
function min (line 26) | func min(a, b int) int {
function max (line 33) | func max(a, b int) int {
function calculateRatio (line 40) | func calculateRatio(matches, length int) float64 {
type Match (line 47) | type Match struct
type OpCode (line 53) | type OpCode struct
type SequenceMatcher (line 87) | type SequenceMatcher struct
method SetSeqs (line 115) | func (m *SequenceMatcher) SetSeqs(a, b []string) {
method SetSeq1 (line 129) | func (m *SequenceMatcher) SetSeq1(a []string) {
method SetSeq2 (line 140) | func (m *SequenceMatcher) SetSeq2(b []string) {
method chainB (line 151) | func (m *SequenceMatcher) chainB() {
method isBJunk (line 192) | func (m *SequenceMatcher) isBJunk(s string) bool {
method findLongestMatch (line 224) | func (m *SequenceMatcher) findLongestMatch(alo, ahi, blo, bhi int) Mat...
method GetMatchingBlocks (line 308) | func (m *SequenceMatcher) GetMatchingBlocks() []Match {
method GetOpCodes (line 376) | func (m *SequenceMatcher) GetOpCodes() []OpCode {
method GetGroupedOpCodes (line 416) | func (m *SequenceMatcher) GetGroupedOpCodes(n int) [][]OpCode {
method Ratio (line 468) | func (m *SequenceMatcher) Ratio() float64 {
method QuickRatio (line 480) | func (m *SequenceMatcher) QuickRatio() float64 {
method RealQuickRatio (line 512) | func (m *SequenceMatcher) RealQuickRatio() float64 {
function NewMatcher (line 100) | func NewMatcher(a, b []string) *SequenceMatcher {
function NewMatcherWithJunk (line 106) | func NewMatcherWithJunk(a, b []string, autoJunk bool,
function formatRangeUnified (line 518) | func formatRangeUnified(start, stop int) string {
type UnifiedDiff (line 532) | type UnifiedDiff struct
function WriteUnifiedDiff (line 562) | func WriteUnifiedDiff(writer io.Writer, diff UnifiedDiff) error {
function GetUnifiedDiffString (line 638) | func GetUnifiedDiffString(diff UnifiedDiff) (string, error) {
function formatRangeContext (line 645) | func formatRangeContext(start, stop int) string {
type ContextDiff (line 658) | type ContextDiff
function WriteContextDiff (line 677) | func WriteContextDiff(writer io.Writer, diff ContextDiff) error {
function GetContextDiffString (line 763) | func GetContextDiffString(diff ContextDiff) (string, error) {
function SplitLines (line 771) | func SplitLines(s string) []string {
FILE: internal/difflib/difflib_test.go
function assertAlmostEqual (line 12) | func assertAlmostEqual(t *testing.T, a, b float64, places int) {
function assertEqual (line 18) | func assertEqual(t *testing.T, a, b interface{}) {
function splitChars (line 24) | func splitChars(s string) []string {
function TestSequenceMatcherRatio (line 33) | func TestSequenceMatcherRatio(t *testing.T) {
function TestGetOptCodes (line 40) | func TestGetOptCodes(t *testing.T) {
function TestGroupedOpCodes (line 61) | func TestGroupedOpCodes(t *testing.T) {
function ExampleGetUnifiedDiffString (line 105) | func ExampleGetUnifiedDiffString() {
function ExampleGetContextDiffString (line 138) | func ExampleGetContextDiffString() {
function ExampleGetContextDiffString_second (line 175) | func ExampleGetContextDiffString_second() {
function rep (line 210) | func rep(s string, count int) string {
function TestWithAsciiOneInsert (line 214) | func TestWithAsciiOneInsert(t *testing.T) {
function TestWithAsciiOnDelete (line 230) | func TestWithAsciiOnDelete(t *testing.T) {
function TestWithAsciiBJunk (line 238) | func TestWithAsciiBJunk(t *testing.T) {
function TestSFBugsRatioForNullSeqn (line 258) | func TestSFBugsRatioForNullSeqn(t *testing.T) {
function TestSFBugsComparingEmptyLists (line 265) | func TestSFBugsComparingEmptyLists(t *testing.T) {
function TestOutputFormatRangeFormatUnified (line 278) | func TestOutputFormatRangeFormatUnified(t *testing.T) {
function TestOutputFormatRangeFormatContext (line 295) | func TestOutputFormatRangeFormatContext(t *testing.T) {
function TestOutputFormatTabDelimiter (line 319) | func TestOutputFormatTabDelimiter(t *testing.T) {
function TestOutputFormatNoTrailingTabOnEmptyFiledate (line 343) | func TestOutputFormatNoTrailingTabOnEmptyFiledate(t *testing.T) {
function TestOmitFilenames (line 360) | func TestOmitFilenames(t *testing.T) {
function TestSplitLines (line 395) | func TestSplitLines(t *testing.T) {
function benchmarkSplitLines (line 409) | func benchmarkSplitLines(b *testing.B, count int) {
function BenchmarkSplitLines100 (line 420) | func BenchmarkSplitLines100(b *testing.B) {
function BenchmarkSplitLines10000 (line 424) | func BenchmarkSplitLines10000(b *testing.B) {
FILE: internal/ring/ring.go
type Ring (line 7) | type Ring struct
function New (line 12) | func New[T any](chunkSize int) *Ring[T] {
method Len (line 21) | func (r *Ring[T]) Len() int {
method Cap (line 25) | func (r *Ring[T]) Cap() int {
method Reset (line 29) | func (r *Ring[T]) Reset() {
method Nth (line 40) | func (r *Ring[T]) Nth(n int) (v T, ok bool) {
method Dequeue (line 49) | func (r *Ring[T]) Dequeue() (v T, ok bool) {
method Enqueue (line 60) | func (r *Ring[T]) Enqueue(v T) {
method grow (line 69) | func (r *Ring[T]) grow() {
FILE: internal/ring/ring_test.go
function TestRing (line 8) | func TestRing(t *testing.T) {
constant opEnq (line 73) | opEnq = iota
constant opDeq (line 74) | opDeq
constant opRst (line 75) | opRst
type ringOp (line 78) | type ringOp struct
function testRing (line 85) | func testRing[T comparable](t *testing.T, r *Ring[T], ops ...ringOp[T]) {
function testRingOp (line 96) | func testRingOp[T comparable](t *testing.T, r *Ring[T], op ringOp[T]) {
FILE: internal/spew/bypass.go
constant UnsafeDisabled (line 34) | UnsafeDisabled = false
constant ptrSize (line 37) | ptrSize = unsafe.Sizeof((*byte)(nil))
type flag (line 40) | type flag
constant flagKindMask (line 55) | flagKindMask = flag(0x1f)
function flagField (line 81) | func flagField(v *reflect.Value) *flag {
function unsafeReflectValue (line 94) | func unsafeReflectValue(v reflect.Value) reflect.Value {
function init (line 106) | func init() {
FILE: internal/spew/bypasssafe.go
constant UnsafeDisabled (line 29) | UnsafeDisabled = true
function unsafeReflectValue (line 37) | func unsafeReflectValue(v reflect.Value) reflect.Value {
FILE: internal/spew/common.go
function catchPanic (line 72) | func catchPanic(w io.Writer, v reflect.Value) {
function handleMethods (line 85) | func handleMethods(cs *ConfigState, w io.Writer, v reflect.Value) (handl...
function printBool (line 144) | func printBool(w io.Writer, val bool) {
function printInt (line 153) | func printInt(w io.Writer, val int64, base int) {
function printUint (line 158) | func printUint(w io.Writer, val uint64, base int) {
function printFloat (line 164) | func printFloat(w io.Writer, val float64, precision int) {
function printComplex (line 170) | func printComplex(w io.Writer, c complex128, floatPrecision int) {
function printHexPtr (line 185) | func printHexPtr(w io.Writer, p uintptr) {
type valuesSorter (line 219) | type valuesSorter struct
method Len (line 279) | func (s *valuesSorter) Len() int {
method Swap (line 285) | func (s *valuesSorter) Swap(i, j int) {
method Less (line 326) | func (s *valuesSorter) Less(i, j int) bool {
function newValuesSorter (line 228) | func newValuesSorter(values []reflect.Value, cs *ConfigState) sort.Inter...
function canSortSimply (line 256) | func canSortSimply(kind reflect.Kind) bool {
function valueSortLess (line 295) | func valueSortLess(a, b reflect.Value) bool {
function sortValues (line 336) | func sortValues(values []reflect.Value, cs *ConfigState) {
FILE: internal/spew/common_test.go
type stringer (line 28) | type stringer
method String (line 32) | func (s stringer) String() string {
type pstringer (line 37) | type pstringer
method String (line 41) | func (s *pstringer) String() string {
type xref1 (line 47) | type xref1 struct
type xref2 (line 50) | type xref2 struct
type indirCir1 (line 56) | type indirCir1 struct
type indirCir2 (line 59) | type indirCir2 struct
type indirCir3 (line 62) | type indirCir3 struct
type embed (line 67) | type embed struct
type embedwrap (line 72) | type embedwrap struct
type panicer (line 79) | type panicer
method String (line 81) | func (p panicer) String() string {
type customError (line 86) | type customError
method Error (line 88) | func (e customError) Error() string {
function stringizeWants (line 94) | func stringizeWants(wants []string) string {
function testFailed (line 108) | func testFailed(result string, wants []string) bool {
type sortableStruct (line 117) | type sortableStruct struct
method String (line 121) | func (ss sortableStruct) String() string {
type unsortableStruct (line 125) | type unsortableStruct struct
type sortTestCase (line 129) | type sortTestCase struct
function helpTestSortValues (line 134) | func helpTestSortValues(tests []sortTestCase, cs *spew.ConfigState, t *t...
function TestSortValues (line 159) | func TestSortValues(t *testing.T) {
function TestSortValuesWithMethods (line 233) | func TestSortValuesWithMethods(t *testing.T) {
function TestSortValuesWithSpew (line 268) | func TestSortValuesWithSpew(t *testing.T) {
FILE: internal/spew/config.go
type ConfigState (line 37) | type ConfigState struct
method Errorf (line 115) | func (c *ConfigState) Errorf(format string, a ...interface{}) (err err...
method Fprint (line 127) | func (c *ConfigState) Fprint(w io.Writer, a ...interface{}) (n int, er...
method Fprintf (line 139) | func (c *ConfigState) Fprintf(w io.Writer, format string, a ...interfa...
method Fprintln (line 150) | func (c *ConfigState) Fprintln(w io.Writer, a ...interface{}) (n int, ...
method Print (line 162) | func (c *ConfigState) Print(a ...interface{}) (n int, err error) {
method Printf (line 174) | func (c *ConfigState) Printf(format string, a ...interface{}) (n int, ...
method Println (line 186) | func (c *ConfigState) Println(a ...interface{}) (n int, err error) {
method Sprint (line 197) | func (c *ConfigState) Sprint(a ...interface{}) string {
method Sprintf (line 208) | func (c *ConfigState) Sprintf(format string, a ...interface{}) string {
method Sprintln (line 219) | func (c *ConfigState) Sprintln(a ...interface{}) string {
method NewFormatter (line 240) | func (c *ConfigState) NewFormatter(v interface{}) fmt.Formatter {
method Fdump (line 246) | func (c *ConfigState) Fdump(w io.Writer, a ...interface{}) {
method Dump (line 273) | func (c *ConfigState) Dump(a ...interface{}) {
method Sdump (line 279) | func (c *ConfigState) Sdump(a ...interface{}) string {
method convertArgs (line 288) | func (c *ConfigState) convertArgs(args []interface{}) (formatters []in...
function NewDefaultConfig (line 304) | func NewDefaultConfig() *ConfigState {
FILE: internal/spew/dump.go
type dumpState (line 51) | type dumpState struct
method indent (line 62) | func (d *dumpState) indent() {
method unpackValue (line 73) | func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
method dumpPtr (line 81) | func (d *dumpState) dumpPtr(v reflect.Value) {
method dumpSlice (line 161) | func (d *dumpState) dumpSlice(v reflect.Value) {
method dump (line 251) | func (d *dumpState) dump(v reflect.Value) {
function fdump (line 453) | func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
function Fdump (line 472) | func Fdump(w io.Writer, a ...interface{}) {
function Sdump (line 478) | func Sdump(a ...interface{}) string {
function Dump (line 507) | func Dump(a ...interface{}) {
FILE: internal/spew/dump_test.go
type dumpTest (line 74) | type dumpTest struct
function addDumpTest (line 84) | func addDumpTest(in interface{}, wants ...string) {
function addIntDumpTests (line 89) | func addIntDumpTests() {
function addUintDumpTests (line 156) | func addUintDumpTests() {
function addBoolDumpTests (line 223) | func addBoolDumpTests() {
function addFloatDumpTests (line 249) | func addFloatDumpTests() {
function addComplexDumpTests (line 277) | func addComplexDumpTests() {
function addArrayDumpTests (line 305) | func addArrayDumpTests() {
function addSliceDumpTests (line 403) | func addSliceDumpTests() {
function addStringDumpTests (line 508) | func addStringDumpTests() {
function addInterfaceDumpTests (line 524) | func addInterfaceDumpTests() {
function addMapDumpTests (line 550) | func addMapDumpTests() {
function addStructDumpTests (line 651) | func addStructDumpTests() {
function addUintptrDumpTests (line 742) | func addUintptrDumpTests() {
function addUnsafePointerDumpTests (line 769) | func addUnsafePointerDumpTests() {
function addChanDumpTests (line 797) | func addChanDumpTests() {
function addFuncDumpTests (line 823) | func addFuncDumpTests() {
function addCircularDumpTests (line 866) | func addCircularDumpTests() {
function addPanicDumpTests (line 929) | func addPanicDumpTests() {
function addErrorDumpTests (line 944) | func addErrorDumpTests() {
function TestDump (line 960) | func TestDump(t *testing.T) {
function TestDumpSortedKeys (line 994) | func TestDumpSortedKeys(t *testing.T) {
FILE: internal/spew/dumpcgo_test.go
function addCgoDumpTests (line 33) | func addCgoDumpTests() {
FILE: internal/spew/dumpnocgo_test.go
function addCgoDumpTests (line 24) | func addCgoDumpTests() {
FILE: internal/spew/example_test.go
type Flag (line 25) | type Flag
method String (line 37) | func (f Flag) String() string {
constant flagOne (line 28) | flagOne Flag = iota
constant flagTwo (line 29) | flagTwo
type Bar (line 44) | type Bar struct
type Foo (line 48) | type Foo struct
function ExampleDump (line 54) | func ExampleDump() {
function ExamplePrintf (line 121) | func ExamplePrintf() {
function ExampleConfigState (line 145) | func ExampleConfigState() {
function ExampleConfigState_Dump (line 164) | func ExampleConfigState_Dump() {
function ExampleConfigState_Printf (line 202) | func ExampleConfigState_Printf() {
FILE: internal/spew/format.go
constant supportedFlags (line 28) | supportedFlags = "0-+# "
type formatState (line 34) | type formatState struct
method buildDefaultFormat (line 47) | func (f *formatState) buildDefaultFormat() (format string) {
method constructOrigFormat (line 65) | func (f *formatState) constructOrigFormat(verb rune) (format string) {
method unpackValue (line 94) | func (f *formatState) unpackValue(v reflect.Value) reflect.Value {
method formatPtr (line 105) | func (f *formatState) formatPtr(v reflect.Value) {
method format (line 201) | func (f *formatState) format(v reflect.Value) {
method Format (line 371) | func (f *formatState) Format(fs fmt.State, verb rune) {
function newFormatter (line 394) | func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
function NewFormatter (line 417) | func NewFormatter(v interface{}) fmt.Formatter {
FILE: internal/spew/format_test.go
type formatterTest (line 79) | type formatterTest struct
function addFormatterTest (line 90) | func addFormatterTest(format string, in interface{}, wants ...string) {
function addIntFormatterTests (line 95) | func addIntFormatterTests() {
function addUintFormatterTests (line 222) | func addUintFormatterTests() {
function addBoolFormatterTests (line 349) | func addBoolFormatterTests() {
function addFloatFormatterTests (line 396) | func addFloatFormatterTests() {
function addComplexFormatterTests (line 448) | func addComplexFormatterTests() {
function addArrayFormatterTests (line 500) | func addArrayFormatterTests() {
function addSliceFormatterTests (line 585) | func addSliceFormatterTests() {
function addStringFormatterTests (line 693) | func addStringFormatterTests() {
function addInterfaceFormatterTests (line 720) | func addInterfaceFormatterTests() {
function addMapFormatterTests (line 767) | func addMapFormatterTests() {
function addStructFormatterTests (line 886) | func addStructFormatterTests() {
function addUintptrFormatterTests (line 1036) | func addUintptrFormatterTests() {
function addUnsafePointerFormatterTests (line 1084) | func addUnsafePointerFormatterTests() {
function addChanFormatterTests (line 1132) | func addChanFormatterTests() {
function addFuncFormatterTests (line 1179) | func addFuncFormatterTests() {
function addCircularFormatterTests (line 1258) | func addCircularFormatterTests() {
function addPanicFormatterTests (line 1370) | func addPanicFormatterTests() {
function addErrorFormatterTests (line 1397) | func addErrorFormatterTests() {
function addPassthroughFormatterTests (line 1424) | func addPassthroughFormatterTests() {
function TestFormatter (line 1465) | func TestFormatter(t *testing.T) {
type testStruct (line 1500) | type testStruct struct
method String (line 1504) | func (ts testStruct) String() string {
type testStructP (line 1508) | type testStructP struct
method String (line 1512) | func (ts *testStructP) String() string {
function TestPrintSortedKeys (line 1516) | func TestPrintSortedKeys(t *testing.T) {
FILE: internal/spew/internal_test.go
type dummyFmtState (line 34) | type dummyFmtState struct
method Flag (line 38) | func (dfs *dummyFmtState) Flag(f int) bool {
method Precision (line 42) | func (dfs *dummyFmtState) Precision() (int, bool) {
method Width (line 46) | func (dfs *dummyFmtState) Width() (int, bool) {
function TestInvalidReflectValue (line 54) | func TestInvalidReflectValue(t *testing.T) {
function SortValues (line 82) | func SortValues(values []reflect.Value, cs *ConfigState) {
FILE: internal/spew/internalunsafe_test.go
function changeKind (line 40) | func changeKind(v *reflect.Value, readOnly bool) {
function TestAddedReflectValue (line 53) | func TestAddedReflectValue(t *testing.T) {
FILE: internal/spew/spew.go
function Errorf (line 32) | func Errorf(format string, a ...interface{}) (err error) {
function Fprint (line 44) | func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
function Fprintf (line 56) | func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err e...
function Fprintln (line 67) | func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
function Print (line 79) | func Print(a ...interface{}) (n int, err error) {
function Printf (line 91) | func Printf(format string, a ...interface{}) (n int, err error) {
function Println (line 103) | func Println(a ...interface{}) (n int, err error) {
function Sprint (line 114) | func Sprint(a ...interface{}) string {
function Sprintf (line 125) | func Sprintf(format string, a ...interface{}) string {
function Sprintln (line 136) | func Sprintln(a ...interface{}) string {
function convertArgs (line 142) | func convertArgs(args []interface{}) (formatters []interface{}) {
FILE: internal/spew/spew_test.go
type spewFunc (line 31) | type spewFunc
method String (line 82) | func (f spewFunc) String() string {
constant fCSFdump (line 34) | fCSFdump spewFunc = iota
constant fCSFprint (line 35) | fCSFprint
constant fCSFprintf (line 36) | fCSFprintf
constant fCSFprintln (line 37) | fCSFprintln
constant fCSPrint (line 38) | fCSPrint
constant fCSPrintln (line 39) | fCSPrintln
constant fCSSdump (line 40) | fCSSdump
constant fCSSprint (line 41) | fCSSprint
constant fCSSprintf (line 42) | fCSSprintf
constant fCSSprintln (line 43) | fCSSprintln
constant fCSErrorf (line 44) | fCSErrorf
constant fCSNewFormatter (line 45) | fCSNewFormatter
constant fErrorf (line 46) | fErrorf
constant fFprint (line 47) | fFprint
constant fFprintln (line 48) | fFprintln
constant fPrint (line 49) | fPrint
constant fPrintln (line 50) | fPrintln
constant fSdump (line 51) | fSdump
constant fSprint (line 52) | fSprint
constant fSprintf (line 53) | fSprintf
constant fSprintln (line 54) | fSprintln
type spewTest (line 91) | type spewTest struct
function redirStdout (line 109) | func redirStdout(f func()) ([]byte, error) {
function initSpewTests (line 126) | func initSpewTests() {
function TestSpew (line 210) | func TestSpew(t *testing.T) {
FILE: internal/spew/testdata/dumpcgo.go
function GetCgoNullCharPointer (line 45) | func GetCgoNullCharPointer() interface{} {
function GetCgoCharPointer (line 51) | func GetCgoCharPointer() interface{} {
function GetCgoCharArray (line 57) | func GetCgoCharArray() (interface{}, int, int) {
function GetCgoUnsignedCharArray (line 63) | func GetCgoUnsignedCharArray() (interface{}, int, int) {
function GetCgoSignedCharArray (line 69) | func GetCgoSignedCharArray() (interface{}, int, int) {
function GetCgoUint8tArray (line 75) | func GetCgoUint8tArray() (interface{}, int, int) {
function GetCgoTypedefedUnsignedCharArray (line 81) | func GetCgoTypedefedUnsignedCharArray() (interface{}, int, int) {
FILE: internal/testify/assert/assertion_compare.go
type compareResult (line 13) | type compareResult
constant compareLess (line 16) | compareLess compareResult = iota - 1
constant compareEqual (line 17) | compareEqual
constant compareGreater (line 18) | compareGreater
function compare (line 45) | func compare(obj1, obj2 interface{}, kind reflect.Kind) (compareResult, ...
function Greater (line 389) | func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...i...
function GreaterOrEqual (line 402) | func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndAr...
function Less (line 414) | func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inte...
function LessOrEqual (line 427) | func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...
function Positive (line 438) | func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
function Negative (line 450) | func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) bool {
function compareTwoValues (line 458) | func compareTwoValues(t TestingT, e1 interface{}, e2 interface{}, allowe...
function containsValue (line 481) | func containsValue(values []compareResult, value compareResult) bool {
FILE: internal/testify/assert/assertion_compare_test.go
function TestCompare (line 12) | func TestCompare(t *testing.T) {
type outputT (line 97) | type outputT struct
method Errorf (line 103) | func (t *outputT) Errorf(format string, args ...interface{}) {
method Helper (line 108) | func (t *outputT) Helper() {
function callerName (line 117) | func callerName(skip int) string {
function TestGreater (line 129) | func TestGreater(t *testing.T) {
function TestGreaterOrEqual (line 173) | func TestGreaterOrEqual(t *testing.T) {
function TestLess (line 217) | func TestLess(t *testing.T) {
function TestLessOrEqual (line 261) | func TestLessOrEqual(t *testing.T) {
function TestPositive (line 305) | func TestPositive(t *testing.T) {
function TestNegative (line 344) | func TestNegative(t *testing.T) {
function Test_compareTwoValuesDifferentValuesTypes (line 383) | func Test_compareTwoValuesDifferentValuesTypes(t *testing.T) {
function Test_compareTwoValuesNotComparableValues (line 401) | func Test_compareTwoValuesNotComparableValues(t *testing.T) {
function Test_compareTwoValuesCorrectCompareResult (line 420) | func Test_compareTwoValuesCorrectCompareResult(t *testing.T) {
function Test_containsValue (line 440) | func Test_containsValue(t *testing.T) {
function TestComparingMsgAndArgsForwarding (line 456) | func TestComparingMsgAndArgsForwarding(t *testing.T) {
FILE: internal/testify/assert/assertion_format.go
function Conditionf (line 12) | func Conditionf(t TestingT, comp Comparison, msg string, args ...interfa...
function Containsf (line 25) | func Containsf(t TestingT, s interface{}, contains interface{}, msg stri...
function DirExistsf (line 34) | func DirExistsf(t TestingT, path string, msg string, args ...interface{}...
function ElementsMatchf (line 46) | func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, ms...
function Emptyf (line 57) | func Emptyf(t TestingT, object interface{}, msg string, args ...interfac...
function Equalf (line 71) | func Equalf(t TestingT, expected interface{}, actual interface{}, msg st...
function EqualErrorf (line 83) | func EqualErrorf(t TestingT, theError error, errString string, msg strin...
function EqualExportedValuesf (line 100) | func EqualExportedValuesf(t TestingT, expected interface{}, actual inter...
function EqualValuesf (line 111) | func EqualValuesf(t TestingT, expected interface{}, actual interface{}, ...
function Errorf (line 124) | func Errorf(t TestingT, err error, msg string, args ...interface{}) bool {
function ErrorAsf (line 133) | func ErrorAsf(t TestingT, err error, target interface{}, msg string, arg...
function ErrorContainsf (line 145) | func ErrorContainsf(t TestingT, theError error, contains string, msg str...
function ErrorIsf (line 154) | func ErrorIsf(t TestingT, err error, target error, msg string, args ...i...
function Eventuallyf (line 165) | func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duratio...
function EventuallyWithTf (line 190) | func EventuallyWithTf(t TestingT, condition func(collect *CollectT), wai...
function Exactlyf (line 200) | func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg ...
function Failf (line 208) | func Failf(t TestingT, failureMessage string, msg string, args ...interf...
function FailNowf (line 216) | func FailNowf(t TestingT, failureMessage string, msg string, args ...int...
function Falsef (line 226) | func Falsef(t TestingT, value bool, msg string, args ...interface{}) bool {
function FileExistsf (line 235) | func FileExistsf(t TestingT, path string, msg string, args ...interface{...
function Greaterf (line 247) | func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, ar...
function GreaterOrEqualf (line 260) | func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg str...
function HTTPBodyContainsf (line 273) | func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method stri...
function HTTPBodyNotContainsf (line 286) | func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method s...
function HTTPErrorf (line 298) | func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url...
function HTTPRedirectf (line 310) | func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, ...
function HTTPStatusCodef (line 322) | func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string...
function HTTPSuccessf (line 334) | func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, u...
function Implementsf (line 344) | func Implementsf(t TestingT, interfaceObject interface{}, object interfa...
function InDeltaf (line 354) | func InDeltaf(t TestingT, expected interface{}, actual interface{}, delt...
function InDeltaMapValuesf (line 362) | func InDeltaMapValuesf(t TestingT, expected interface{}, actual interfac...
function InDeltaSlicef (line 370) | func InDeltaSlicef(t TestingT, expected interface{}, actual interface{},...
function InEpsilonf (line 378) | func InEpsilonf(t TestingT, expected interface{}, actual interface{}, ep...
function InEpsilonSlicef (line 386) | func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{...
function IsDecreasingf (line 398) | func IsDecreasingf(t TestingT, object interface{}, msg string, args ...i...
function IsIncreasingf (line 410) | func IsIncreasingf(t TestingT, object interface{}, msg string, args ...i...
function IsNonDecreasingf (line 422) | func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ....
function IsNonIncreasingf (line 434) | func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ....
function IsTypef (line 442) | func IsTypef(t TestingT, expectedType interface{}, object interface{}, m...
function JSONEqf (line 452) | func JSONEqf(t TestingT, expected string, actual string, msg string, arg...
function Lenf (line 463) | func Lenf(t TestingT, object interface{}, length int, msg string, args ....
function Lessf (line 475) | func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...
function LessOrEqualf (line 488) | func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string...
function Negativef (line 499) | func Negativef(t TestingT, e interface{}, msg string, args ...interface{...
function Neverf (line 510) | func Neverf(t TestingT, condition func() bool, waitFor time.Duration, ti...
function Nilf (line 520) | func Nilf(t TestingT, object interface{}, msg string, args ...interface{...
function NoDirExistsf (line 529) | func NoDirExistsf(t TestingT, path string, msg string, args ...interface...
function NoErrorf (line 542) | func NoErrorf(t TestingT, err error, msg string, args ...interface{}) bo...
function NoFileExistsf (line 551) | func NoFileExistsf(t TestingT, path string, msg string, args ...interfac...
function NotContainsf (line 564) | func NotContainsf(t TestingT, s interface{}, contains interface{}, msg s...
function NotEmptyf (line 577) | func NotEmptyf(t TestingT, object interface{}, msg string, args ...inter...
function NotEqualf (line 590) | func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg...
function NotEqualValuesf (line 600) | func NotEqualValuesf(t TestingT, expected interface{}, actual interface{...
function NotErrorIsf (line 609) | func NotErrorIsf(t TestingT, err error, target error, msg string, args ....
function NotImplementsf (line 619) | func NotImplementsf(t TestingT, interfaceObject interface{}, object inte...
function NotNilf (line 629) | func NotNilf(t TestingT, object interface{}, msg string, args ...interfa...
function NotPanicsf (line 639) | func NotPanicsf(t TestingT, f PanicTestFunc, msg string, args ...interfa...
function NotRegexpf (line 650) | func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string,...
function NotSamef (line 663) | func NotSamef(t TestingT, expected interface{}, actual interface{}, msg ...
function NotSubsetf (line 676) | func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg st...
function NotZerof (line 684) | func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}...
function Panicsf (line 694) | func Panicsf(t TestingT, f PanicTestFunc, msg string, args ...interface{...
function PanicsWithErrorf (line 706) | func PanicsWithErrorf(t TestingT, errString string, f PanicTestFunc, msg...
function PanicsWithValuef (line 717) | func PanicsWithValuef(t TestingT, expected interface{}, f PanicTestFunc,...
function Positivef (line 728) | func Positivef(t TestingT, e interface{}, msg string, args ...interface{...
function Regexpf (line 739) | func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, ar...
function Samef (line 752) | func Samef(t TestingT, expected interface{}, actual interface{}, msg str...
function Subsetf (line 764) | func Subsetf(t TestingT, list interface{}, subset interface{}, msg strin...
function Truef (line 774) | func Truef(t TestingT, value bool, msg string, args ...interface{}) bool {
function WithinDurationf (line 784) | func WithinDurationf(t TestingT, expected time.Time, actual time.Time, d...
function WithinRangef (line 794) | func WithinRangef(t TestingT, actual time.Time, start time.Time, end tim...
function Zerof (line 802) | func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) b...
FILE: internal/testify/assert/assertion_forward.go
method Condition (line 12) | func (a *Assertions) Condition(comp Comparison, msgAndArgs ...interface{...
method Conditionf (line 20) | func (a *Assertions) Conditionf(comp Comparison, msg string, args ...int...
method Contains (line 33) | func (a *Assertions) Contains(s interface{}, contains interface{}, msgAn...
method Containsf (line 46) | func (a *Assertions) Containsf(s interface{}, contains interface{}, msg ...
method DirExists (line 55) | func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) b...
method DirExistsf (line 64) | func (a *Assertions) DirExistsf(path string, msg string, args ...interfa...
method ElementsMatch (line 76) | func (a *Assertions) ElementsMatch(listA interface{}, listB interface{},...
method ElementsMatchf (line 88) | func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}...
method Empty (line 99) | func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}...
method Emptyf (line 110) | func (a *Assertions) Emptyf(object interface{}, msg string, args ...inte...
method Equal (line 124) | func (a *Assertions) Equal(expected interface{}, actual interface{}, msg...
method EqualError (line 136) | func (a *Assertions) EqualError(theError error, errString string, msgAnd...
method EqualErrorf (line 148) | func (a *Assertions) EqualErrorf(theError error, errString string, msg s...
method EqualExportedValues (line 165) | func (a *Assertions) EqualExportedValues(expected interface{}, actual in...
method EqualExportedValuesf (line 182) | func (a *Assertions) EqualExportedValuesf(expected interface{}, actual i...
method EqualValues (line 193) | func (a *Assertions) EqualValues(expected interface{}, actual interface{...
method EqualValuesf (line 204) | func (a *Assertions) EqualValuesf(expected interface{}, actual interface...
method Equalf (line 218) | func (a *Assertions) Equalf(expected interface{}, actual interface{}, ms...
method Error (line 231) | func (a *Assertions) Error(err error, msgAndArgs ...interface{}) bool {
method ErrorAs (line 240) | func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ....
method ErrorAsf (line 249) | func (a *Assertions) ErrorAsf(err error, target interface{}, msg string,...
method ErrorContains (line 261) | func (a *Assertions) ErrorContains(theError error, contains string, msgA...
method ErrorContainsf (line 273) | func (a *Assertions) ErrorContainsf(theError error, contains string, msg...
method ErrorIs (line 282) | func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...inte...
method ErrorIsf (line 291) | func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...
method Errorf (line 304) | func (a *Assertions) Errorf(err error, msg string, args ...interface{}) ...
method Eventually (line 315) | func (a *Assertions) Eventually(condition func() bool, waitFor time.Dura...
method EventuallyWithT (line 340) | func (a *Assertions) EventuallyWithT(condition func(collect *CollectT), ...
method EventuallyWithTf (line 365) | func (a *Assertions) EventuallyWithTf(condition func(collect *CollectT),...
method Eventuallyf (line 376) | func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Dur...
method Exactly (line 386) | func (a *Assertions) Exactly(expected interface{}, actual interface{}, m...
method Exactlyf (line 396) | func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, ...
method Fail (line 404) | func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface...
method FailNow (line 412) | func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interf...
method FailNowf (line 420) | func (a *Assertions) FailNowf(failureMessage string, msg string, args .....
method Failf (line 428) | func (a *Assertions) Failf(failureMessage string, msg string, args ...in...
method False (line 438) | func (a *Assertions) False(value bool, msgAndArgs ...interface{}) bool {
method Falsef (line 448) | func (a *Assertions) Falsef(value bool, msg string, args ...interface{})...
method FileExists (line 457) | func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) ...
method FileExistsf (line 466) | func (a *Assertions) FileExistsf(path string, msg string, args ...interf...
method Greater (line 478) | func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...
method GreaterOrEqual (line 491) | func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgA...
method GreaterOrEqualf (line 504) | func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg...
method Greaterf (line 516) | func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string...
method HTTPBodyContains (line 529) | func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method s...
method HTTPBodyContainsf (line 542) | func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method ...
method HTTPBodyNotContains (line 555) | func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, metho...
method HTTPBodyNotContainsf (line 568) | func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, meth...
method HTTPError (line 580) | func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, ...
method HTTPErrorf (line 592) | func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string,...
method HTTPRedirect (line 604) | func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method strin...
method HTTPRedirectf (line 616) | func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method stri...
method HTTPStatusCode (line 628) | func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method str...
method HTTPStatusCodef (line 640) | func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method st...
method HTTPSuccess (line 652) | func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string...
method HTTPSuccessf (line 664) | func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method strin...
method Implements (line 674) | func (a *Assertions) Implements(interfaceObject interface{}, object inte...
method Implementsf (line 684) | func (a *Assertions) Implementsf(interfaceObject interface{}, object int...
method InDelta (line 694) | func (a *Assertions) InDelta(expected interface{}, actual interface{}, d...
method InDeltaMapValues (line 702) | func (a *Assertions) InDeltaMapValues(expected interface{}, actual inter...
method InDeltaMapValuesf (line 710) | func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual inte...
method InDeltaSlice (line 718) | func (a *Assertions) InDeltaSlice(expected interface{}, actual interface...
method InDeltaSlicef (line 726) | func (a *Assertions) InDeltaSlicef(expected interface{}, actual interfac...
method InDeltaf (line 736) | func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, ...
method InEpsilon (line 744) | func (a *Assertions) InEpsilon(expected interface{}, actual interface{},...
method InEpsilonSlice (line 752) | func (a *Assertions) InEpsilonSlice(expected interface{}, actual interfa...
method InEpsilonSlicef (line 760) | func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interf...
method InEpsilonf (line 768) | func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}...
method IsDecreasing (line 780) | func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...inte...
method IsDecreasingf (line 792) | func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...
method IsIncreasing (line 804) | func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...inte...
method IsIncreasingf (line 816) | func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...
method IsNonDecreasing (line 828) | func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...i...
method IsNonDecreasingf (line 840) | func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, ar...
method IsNonIncreasing (line 852) | func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...i...
method IsNonIncreasingf (line 864) | func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, ar...
method IsType (line 872) | func (a *Assertions) IsType(expectedType interface{}, object interface{}...
method IsTypef (line 880) | func (a *Assertions) IsTypef(expectedType interface{}, object interface{...
method JSONEq (line 890) | func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ....
method JSONEqf (line 900) | func (a *Assertions) JSONEqf(expected string, actual string, msg string,...
method Len (line 911) | func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...i...
method Lenf (line 922) | func (a *Assertions) Lenf(object interface{}, length int, msg string, ar...
method Less (line 934) | func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ......
method LessOrEqual (line 947) | func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndA...
method LessOrEqualf (line 960) | func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg st...
method Lessf (line 972) | func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, a...
method Negative (line 983) | func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) ...
method Negativef (line 994) | func (a *Assertions) Negativef(e interface{}, msg string, args ...interf...
method Never (line 1005) | func (a *Assertions) Never(condition func() bool, waitFor time.Duration,...
method Neverf (line 1016) | func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration...
method Nil (line 1026) | func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) ...
method Nilf (line 1036) | func (a *Assertions) Nilf(object interface{}, msg string, args ...interf...
method NoDirExists (line 1045) | func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{})...
method NoDirExistsf (line 1054) | func (a *Assertions) NoDirExistsf(path string, msg string, args ...inter...
method NoError (line 1067) | func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) bool {
method NoErrorf (line 1080) | func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}...
method NoFileExists (line 1089) | func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}...
method NoFileExistsf (line 1098) | func (a *Assertions) NoFileExistsf(path string, msg string, args ...inte...
method NotContains (line 1111) | func (a *Assertions) NotContains(s interface{}, contains interface{}, ms...
method NotContainsf (line 1124) | func (a *Assertions) NotContainsf(s interface{}, contains interface{}, m...
method NotEmpty (line 1137) | func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interfac...
method NotEmptyf (line 1150) | func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...i...
method NotEqual (line 1163) | func (a *Assertions) NotEqual(expected interface{}, actual interface{}, ...
method NotEqualValues (line 1173) | func (a *Assertions) NotEqualValues(expected interface{}, actual interfa...
method NotEqualValuesf (line 1183) | func (a *Assertions) NotEqualValuesf(expected interface{}, actual interf...
method NotEqualf (line 1196) | func (a *Assertions) NotEqualf(expected interface{}, actual interface{},...
method NotErrorIs (line 1205) | func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...i...
method NotErrorIsf (line 1214) | func (a *Assertions) NotErrorIsf(err error, target error, msg string, ar...
method NotImplements (line 1224) | func (a *Assertions) NotImplements(interfaceObject interface{}, object i...
method NotImplementsf (line 1234) | func (a *Assertions) NotImplementsf(interfaceObject interface{}, object ...
method NotNil (line 1244) | func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{...
method NotNilf (line 1254) | func (a *Assertions) NotNilf(object interface{}, msg string, args ...int...
method NotPanics (line 1264) | func (a *Assertions) NotPanics(f PanicTestFunc, msgAndArgs ...interface{...
method NotPanicsf (line 1274) | func (a *Assertions) NotPanicsf(f PanicTestFunc, msg string, args ...int...
method NotRegexp (line 1285) | func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndAr...
method NotRegexpf (line 1296) | func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg str...
method NotSame (line 1309) | func (a *Assertions) NotSame(expected interface{}, actual interface{}, m...
method NotSamef (line 1322) | func (a *Assertions) NotSamef(expected interface{}, actual interface{}, ...
method NotSubset (line 1335) | func (a *Assertions) NotSubset(list interface{}, subset interface{}, msg...
method NotSubsetf (line 1348) | func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, ms...
method NotZero (line 1356) | func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) b...
method NotZerof (line 1364) | func (a *Assertions) NotZerof(i interface{}, msg string, args ...interfa...
method Panics (line 1374) | func (a *Assertions) Panics(f PanicTestFunc, msgAndArgs ...interface{}) ...
method PanicsWithError (line 1386) | func (a *Assertions) PanicsWithError(errString string, f PanicTestFunc, ...
method PanicsWithErrorf (line 1398) | func (a *Assertions) PanicsWithErrorf(errString string, f PanicTestFunc,...
method PanicsWithValue (line 1409) | func (a *Assertions) PanicsWithValue(expected interface{}, f PanicTestFu...
method PanicsWithValuef (line 1420) | func (a *Assertions) PanicsWithValuef(expected interface{}, f PanicTestF...
method Panicsf (line 1430) | func (a *Assertions) Panicsf(f PanicTestFunc, msg string, args ...interf...
method Positive (line 1441) | func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) ...
method Positivef (line 1452) | func (a *Assertions) Positivef(e interface{}, msg string, args ...interf...
method Regexp (line 1463) | func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...
method Regexpf (line 1474) | func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string...
method Same (line 1487) | func (a *Assertions) Same(expected interface{}, actual interface{}, msgA...
method Samef (line 1500) | func (a *Assertions) Samef(expected interface{}, actual interface{}, msg...
method Subset (line 1512) | func (a *Assertions) Subset(list interface{}, subset interface{}, msgAnd...
method Subsetf (line 1524) | func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg s...
method True (line 1534) | func (a *Assertions) True(value bool, msgAndArgs ...interface{}) bool {
method Truef (line 1544) | func (a *Assertions) Truef(value bool, msg string, args ...interface{}) ...
method WithinDuration (line 1554) | func (a *Assertions) WithinDuration(expected time.Time, actual time.Time...
method WithinDurationf (line 1564) | func (a *Assertions) WithinDurationf(expected time.Time, actual time.Tim...
method WithinRange (line 1574) | func (a *Assertions) WithinRange(actual time.Time, start time.Time, end ...
method WithinRangef (line 1584) | func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end...
method Zero (line 1592) | func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) bool {
method Zerof (line 1600) | func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{...
FILE: internal/testify/assert/assertion_order.go
function isOrdered (line 9) | func isOrdered(t TestingT, object interface{}, allowedComparesResults []...
function IsIncreasing (line 52) | func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interfac...
function IsNonIncreasing (line 61) | func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...inter...
function IsDecreasing (line 70) | func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interfac...
function IsNonDecreasing (line 79) | func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...inter...
FILE: internal/testify/assert/assertion_order_test.go
function TestIsIncreasing (line 8) | func TestIsIncreasing(t *testing.T) {
function TestIsNonIncreasing (line 53) | func TestIsNonIncreasing(t *testing.T) {
function TestIsDecreasing (line 98) | func TestIsDecreasing(t *testing.T) {
function TestIsNonDecreasing (line 143) | func TestIsNonDecreasing(t *testing.T) {
function TestOrderingMsgAndArgsForwarding (line 188) | func TestOrderingMsgAndArgsForwarding(t *testing.T) {
FILE: internal/testify/assert/assertions.go
type TestingT (line 28) | type TestingT interface
type ComparisonAssertionFunc (line 34) | type ComparisonAssertionFunc
type ValueAssertionFunc (line 38) | type ValueAssertionFunc
type BoolAssertionFunc (line 42) | type BoolAssertionFunc
type ErrorAssertionFunc (line 46) | type ErrorAssertionFunc
type Comparison (line 53) | type Comparison
function ObjectsAreEqual (line 62) | func ObjectsAreEqual(expected, actual interface{}) bool {
function copyExportedFields (line 84) | func copyExportedFields(expected interface{}) interface{} {
function ObjectsExportedFieldsAreEqual (line 154) | func ObjectsExportedFieldsAreEqual(expected, actual interface{}) bool {
function ObjectsAreEqualValues (line 162) | func ObjectsAreEqualValues(expected, actual interface{}) bool {
function isNumericType (line 199) | func isNumericType(t reflect.Type) bool {
function CallerInfo (line 210) | func CallerInfo() []string {
function isTest (line 273) | func isTest(name, prefix string) bool {
function messageFromMsgAndArgs (line 284) | func messageFromMsgAndArgs(msgAndArgs ...interface{}) string {
function indentMessageLines (line 305) | func indentMessageLines(message string, longestLabelLen int) string {
type failNower (line 320) | type failNower interface
function FailNow (line 325) | func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{...
function Fail (line 346) | func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) ...
type labeledContent (line 372) | type labeledContent struct
function labeledOutput (line 386) | func labeledOutput(content ...labeledContent) string {
function Implements (line 403) | func Implements(t TestingT, interfaceObject interface{}, object interfac...
function NotImplements (line 422) | func NotImplements(t TestingT, interfaceObject interface{}, object inter...
function IsType (line 439) | func IsType(t TestingT, expectedType interface{}, object interface{}, ms...
function Equal (line 458) | func Equal(t TestingT, expected, actual interface{}, msgAndArgs ...inter...
function validateEqualArgs (line 481) | func validateEqualArgs(expected, actual interface{}) error {
function Same (line 498) | func Same(t TestingT, expected, actual interface{}, msgAndArgs ...interf...
function NotSame (line 518) | func NotSame(t TestingT, expected, actual interface{}, msgAndArgs ...int...
function samePointers (line 533) | func samePointers(first, second interface{}) bool {
function formatUnequalValues (line 554) | func formatUnequalValues(expected, actual interface{}) (e string, a stri...
function truncatingFormat (line 570) | func truncatingFormat(data interface{}) string {
function EqualValues (line 583) | func EqualValues(t TestingT, expected, actual interface{}, msgAndArgs .....
function EqualExportedValues (line 610) | func EqualExportedValues(t TestingT, expected, actual interface{}, msgAn...
function Exactly (line 654) | func Exactly(t TestingT, expected, actual interface{}, msgAndArgs ...int...
function NotNil (line 673) | func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) b...
function isNil (line 684) | func isNil(object interface{}) bool {
function Nil (line 705) | func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) bool {
function isEmpty (line 716) | func isEmpty(object interface{}) bool {
function Empty (line 748) | func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) bo...
function NotEmpty (line 767) | func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{})...
function getLen (line 782) | func getLen(x interface{}) (length int, ok bool) {
function Len (line 794) | func Len(t TestingT, object interface{}, length int, msgAndArgs ...inter...
function True (line 812) | func True(t TestingT, value bool, msgAndArgs ...interface{}) bool {
function False (line 827) | func False(t TestingT, value bool, msgAndArgs ...interface{}) bool {
function NotEqual (line 845) | func NotEqual(t TestingT, expected, actual interface{}, msgAndArgs ...in...
function NotEqualValues (line 865) | func NotEqualValues(t TestingT, expected, actual interface{}, msgAndArgs...
function containsElement (line 881) | func containsElement(list interface{}, element interface{}) (ok, found b...
function Contains (line 926) | func Contains(t TestingT, s, contains interface{}, msgAndArgs ...interfa...
function NotContains (line 949) | func NotContains(t TestingT, s, contains interface{}, msgAndArgs ...inte...
function Subset (line 971) | func Subset(t TestingT, list, subset interface{}, msgAndArgs ...interfac...
function NotSubset (line 1029) | func NotSubset(t TestingT, list, subset interface{}, msgAndArgs ...inter...
function ElementsMatch (line 1086) | func ElementsMatch(t TestingT, listA, listB interface{}, msgAndArgs ...i...
function isList (line 1108) | func isList(t TestingT, list interface{}, msgAndArgs ...interface{}) (ok...
function diffLists (line 1120) | func diffLists(listA, listB interface{}) (extraA, extraB []interface{}) {
function formatListDiff (line 1157) | func formatListDiff(listA, listB interface{}, extraA, extraB []interface...
function Condition (line 1178) | func Condition(t TestingT, comp Comparison, msgAndArgs ...interface{}) b...
type PanicTestFunc (line 1191) | type PanicTestFunc
function didPanic (line 1194) | func didPanic(f PanicTestFunc) (didPanic bool, message interface{}, stac...
function Panics (line 1214) | func Panics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) bool {
function PanicsWithValue (line 1230) | func PanicsWithValue(t TestingT, expected interface{}, f PanicTestFunc, ...
function PanicsWithError (line 1251) | func PanicsWithError(t TestingT, errString string, f PanicTestFunc, msgA...
function NotPanics (line 1271) | func NotPanics(t TestingT, f PanicTestFunc, msgAndArgs ...interface{}) b...
function WithinDuration (line 1286) | func WithinDuration(t TestingT, expected, actual time.Time, delta time.D...
function WithinRange (line 1302) | func WithinRange(t TestingT, actual, start, end time.Time, msgAndArgs .....
function toFloat (line 1320) | func toFloat(x interface{}) (float64, bool) {
function InDelta (line 1361) | func InDelta(t TestingT, expected, actual interface{}, delta float64, ms...
function InDeltaSlice (line 1394) | func InDeltaSlice(t TestingT, expected, actual interface{}, delta float6...
function InDeltaMapValues (line 1418) | func InDeltaMapValues(t TestingT, expected, actual interface{}, delta fl...
function calcRelativeError (line 1461) | func calcRelativeError(expected, actual interface{}) (float64, error) {
function InEpsilon (line 1484) | func InEpsilon(t TestingT, expected, actual interface{}, epsilon float64...
function InEpsilonSlice (line 1504) | func InEpsilonSlice(t TestingT, expected, actual interface{}, epsilon fl...
function NoError (line 1544) | func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool {
function Error (line 1561) | func Error(t TestingT, err error, msgAndArgs ...interface{}) bool {
function EqualError (line 1577) | func EqualError(t TestingT, theError error, errString string, msgAndArgs...
function ErrorContains (line 1600) | func ErrorContains(t TestingT, theError error, contains string, msgAndAr...
function matchRegexp (line 1617) | func matchRegexp(rx interface{}, str interface{}) bool {
function Regexp (line 1634) | func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...i...
function NotRegexp (line 1652) | func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ....
function Zero (line 1667) | func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
function NotZero (line 1678) | func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) bool {
function FileExists (line 1690) | func FileExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
function NoFileExists (line 1709) | func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) bo...
function DirExists (line 1725) | func DirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
function NoDirExists (line 1744) | func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) bool {
function JSONEq (line 1764) | func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...in...
function typeAndKind (line 1781) | func typeAndKind(v interface{}) (reflect.Type, reflect.Kind) {
function diff (line 1794) | func diff(expected interface{}, actual interface{}) string {
function isFunction (line 1837) | func isFunction(arg interface{}) bool {
function Eventually (line 1869) | func Eventually(t TestingT, condition func() bool, waitFor time.Duration...
type CollectT (line 1899) | type CollectT struct
method Errorf (line 1904) | func (c *CollectT) Errorf(format string, args ...interface{}) {
method FailNow (line 1909) | func (*CollectT) FailNow() {
method Reset (line 1914) | func (*CollectT) Reset() {
method Copy (line 1919) | func (*CollectT) Copy(TestingT) {
function EventuallyWithT (line 1941) | func EventuallyWithT(t TestingT, condition func(collect *CollectT), wait...
function Never (line 1986) | func Never(t TestingT, condition func() bool, waitFor time.Duration, tic...
function ErrorIs (line 2017) | func ErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}) b...
function NotErrorIs (line 2040) | func NotErrorIs(t TestingT, err, target error, msgAndArgs ...interface{}...
function ErrorAs (line 2063) | func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...in...
function buildErrorChainString (line 2079) | func buildErrorChainString(err error) string {
FILE: internal/testify/assert/assertions_test.go
type AssertionTesterInterface (line 89) | type AssertionTesterInterface interface
type AssertionTesterConformingObject (line 94) | type AssertionTesterConformingObject struct
method TestMethod (line 97) | func (a *AssertionTesterConformingObject) TestMethod() {
type AssertionTesterNonConformingObject (line 101) | type AssertionTesterNonConformingObject struct
function TestObjectsAreEqual (line 104) | func TestObjectsAreEqual(t *testing.T) {
function TestObjectsAreEqualValues (line 140) | func TestObjectsAreEqualValues(t *testing.T) {
type Nested (line 176) | type Nested struct
type S (line 181) | type S struct
type S2 (line 188) | type S2 struct
type S3 (line 192) | type S3 struct
type S4 (line 197) | type S4 struct
type S5 (line 201) | type S5 struct
type S6 (line 205) | type S6 struct
function TestObjectsExportedFieldsAreEqual (line 210) | func TestObjectsExportedFieldsAreEqual(t *testing.T) {
function TestCopyExportedFields (line 285) | func TestCopyExportedFields(t *testing.T) {
function TestEqualExportedValues (line 368) | func TestEqualExportedValues(t *testing.T) {
function TestImplements (line 472) | func TestImplements(t *testing.T) {
function TestNotImplements (line 488) | func TestNotImplements(t *testing.T) {
function TestIsType (line 504) | func TestIsType(t *testing.T) {
function TestEqual (line 517) | func TestEqual(t *testing.T) {
function ptr (line 558) | func ptr(i int) *int {
function TestSame (line 562) | func TestSame(t *testing.T) {
function TestNotSame (line 581) | func TestNotSame(t *testing.T) {
function Test_samePointers (line 600) | func Test_samePointers(t *testing.T) {
type bufferT (line 647) | type bufferT struct
method Errorf (line 651) | func (t *bufferT) Errorf(format string, args ...interface{}) {
function TestStringEqual (line 687) | func TestStringEqual(t *testing.T) {
function TestEqualFormatting (line 702) | func TestEqualFormatting(t *testing.T) {
function TestFormatUnequalValues (line 720) | func TestFormatUnequalValues(t *testing.T) {
function TestNotNil (line 746) | func TestNotNil(t *testing.T) {
function TestNil (line 762) | func TestNil(t *testing.T) {
function TestTrue (line 778) | func TestTrue(t *testing.T) {
function TestFalse (line 791) | func TestFalse(t *testing.T) {
function TestExactly (line 804) | func TestExactly(t *testing.T) {
function TestNotEqual (line 835) | func TestNotEqual(t *testing.T) {
function TestNotEqualValues (line 875) | func TestNotEqualValues(t *testing.T) {
function TestContainsNotContains (line 918) | func TestContainsNotContains(t *testing.T) {
function TestContainsNotContainsFailMessage (line 982) | func TestContainsNotContainsFailMessage(t *testing.T) {
function TestContainsNotContainsOnNilValue (line 1038) | func TestContainsNotContainsOnNilValue(t *testing.T) {
function TestSubsetNotSubset (line 1054) | func TestSubsetNotSubset(t *testing.T) {
function TestNotSubsetNil (line 1138) | func TestNotSubsetNil(t *testing.T) {
function Test_containsElement (line 1146) | func Test_containsElement(t *testing.T) {
function TestElementsMatch (line 1197) | func TestElementsMatch(t *testing.T) {
function TestDiffLists (line 1238) | func TestDiffLists(t *testing.T) {
function TestCondition (line 1322) | func TestCondition(t *testing.T) {
function TestDidPanic (line 1335) | func TestDidPanic(t *testing.T) {
function TestPanics (line 1358) | func TestPanics(t *testing.T) {
function TestPanicsWithValue (line 1375) | func TestPanicsWithValue(t *testing.T) {
function TestPanicsWithError (line 1403) | func TestPanicsWithError(t *testing.T) {
function TestNotPanics (line 1431) | func TestNotPanics(t *testing.T) {
function TestNoError (line 1448) | func TestNoError(t *testing.T) {
type customError (line 1475) | type customError struct
method Error (line 1477) | func (*customError) Error() string { return "fail" }
function TestError (line 1479) | func TestError(t *testing.T) {
function TestEqualError (line 1509) | func TestEqualError(t *testing.T) {
function TestErrorContains (line 1525) | func TestErrorContains(t *testing.T) {
function Test_isEmpty (line 1543) | func Test_isEmpty(t *testing.T) {
function TestEmpty (line 1570) | func TestEmpty(t *testing.T) {
function TestNotEmpty (line 1615) | func TestNotEmpty(t *testing.T) {
function Test_getLen (line 1638) | func Test_getLen(t *testing.T) {
function TestLen (line 1683) | func TestLen(t *testing.T) {
function TestWithinDuration (line 1729) | func TestWithinDuration(t *testing.T) {
function TestWithinRange (line 1748) | func TestWithinRange(t *testing.T) {
function TestInDelta (line 1767) | func TestInDelta(t *testing.T) {
function TestInDeltaSlice (line 1805) | func TestInDeltaSlice(t *testing.T) {
function TestInDeltaMapValues (line 1826) | func TestInDeltaMapValues(t *testing.T) {
function TestInEpsilon (line 1904) | func TestInEpsilon(t *testing.T) {
function TestInEpsilonSlice (line 1951) | func TestInEpsilonSlice(t *testing.T) {
function TestRegexp (line 1967) | func TestRegexp(t *testing.T) {
function testAutogeneratedFunction (line 2001) | func testAutogeneratedFunction() {
function TestCallerInfoWithAutogeneratedFunctions (line 2015) | func TestCallerInfoWithAutogeneratedFunctions(t *testing.T) {
function TestZero (line 2021) | func TestZero(t *testing.T) {
function TestNotZero (line 2033) | func TestNotZero(t *testing.T) {
function TestFileExists (line 2045) | func TestFileExists(t *testing.T) {
function TestNoFileExists (line 2079) | func TestNoFileExists(t *testing.T) {
function getTempSymlinkPath (line 2113) | func getTempSymlinkPath(file string) (string, error) {
function cleanUpTempFiles (line 2119) | func cleanUpTempFiles(paths []string) []error {
function TestDirExists (line 2130) | func TestDirExists(t *testing.T) {
function TestNoDirExists (line 2164) | func TestNoDirExists(t *testing.T) {
function TestJSONEq_EqualSONString (line 2198) | func TestJSONEq_EqualSONString(t *testing.T) {
function TestJSONEq_EquivalentButNotEqual (line 2203) | func TestJSONEq_EquivalentButNotEqual(t *testing.T) {
function TestJSONEq_HashOfArraysAndHashes (line 2208) | func TestJSONEq_HashOfArraysAndHashes(t *testing.T) {
function TestJSONEq_Array (line 2214) | func TestJSONEq_Array(t *testing.T) {
function TestJSONEq_HashAndArrayNotEquivalent (line 2219) | func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) {
function TestJSONEq_HashesNotEquivalent (line 2224) | func TestJSONEq_HashesNotEquivalent(t *testing.T) {
function TestJSONEq_ActualIsNotJSON (line 2229) | func TestJSONEq_ActualIsNotJSON(t *testing.T) {
function TestJSONEq_ExpectedIsNotJSON (line 2234) | func TestJSONEq_ExpectedIsNotJSON(t *testing.T) {
function TestJSONEq_ExpectedAndActualNotJSON (line 2239) | func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) {
function TestJSONEq_ArraysOfDifferentOrder (line 2244) | func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) {
type diffTestingStruct (line 2249) | type diffTestingStruct struct
method String (line 2254) | func (d *diffTestingStruct) String() string {
function TestDiff (line 2258) | func TestDiff(t *testing.T) {
function TestTimeEqualityErrorFormatting (line 2392) | func TestTimeEqualityErrorFormatting(t *testing.T) {
function TestDiffEmptyCases (line 2401) | func TestDiffEmptyCases(t *testing.T) {
function TestDiffRace (line 2411) | func TestDiffRace(t *testing.T) {
type mockTestingT (line 2444) | type mockTestingT struct
method errorString (line 2449) | func (m *mockTestingT) errorString() string {
method Errorf (line 2453) | func (m *mockTestingT) Errorf(format string, args ...interface{}) {
method Failed (line 2458) | func (m *mockTestingT) Failed() bool {
function TestFailNowWithPlainTestingT (line 2462) | func TestFailNowWithPlainTestingT(t *testing.T) {
type mockFailNowTestingT (line 2470) | type mockFailNowTestingT struct
method Errorf (line 2473) | func (m *mockFailNowTestingT) Errorf(format string, args ...interface{...
method FailNow (line 2475) | func (m *mockFailNowTestingT) FailNow() {}
function TestFailNowWithFullTestingT (line 2477) | func TestFailNowWithFullTestingT(t *testing.T) {
function TestBytesEqual (line 2485) | func TestBytesEqual(t *testing.T) {
function BenchmarkBytesEqual (line 2498) | func BenchmarkBytesEqual(b *testing.B) {
function BenchmarkNotNil (line 2514) | func BenchmarkNotNil(b *testing.B) {
function ExampleComparisonAssertionFunc (line 2520) | func ExampleComparisonAssertionFunc() {
function TestComparisonAssertionFunc (line 2550) | func TestComparisonAssertionFunc(t *testing.T) {
function ExampleValueAssertionFunc (line 2583) | func ExampleValueAssertionFunc() {
function TestValueAssertionFunc (line 2611) | func TestValueAssertionFunc(t *testing.T) {
function ExampleBoolAssertionFunc (line 2632) | func ExampleBoolAssertionFunc() {
function TestBoolAssertionFunc (line 2657) | func TestBoolAssertionFunc(t *testing.T) {
function ExampleErrorAssertionFunc (line 2674) | func ExampleErrorAssertionFunc() {
function TestErrorAssertionFunc (line 2700) | func TestErrorAssertionFunc(t *testing.T) {
function ExamplePanicAssertionFunc (line 2717) | func ExamplePanicAssertionFunc() {
function TestPanicAssertionFunc (line 2736) | func TestPanicAssertionFunc(t *testing.T) {
function TestEventuallyFalse (line 2753) | func TestEventuallyFalse(t *testing.T) {
function TestEventuallyTrue (line 2763) | func TestEventuallyTrue(t *testing.T) {
type errorsCapturingT (line 2776) | type errorsCapturingT struct
method Errorf (line 2780) | func (t *errorsCapturingT) Errorf(format string, args ...interface{}) {
method Helper (line 2784) | func (t *errorsCapturingT) Helper() {}
function TestEventuallyWithTFalse (line 2786) | func TestEventuallyWithTFalse(t *testing.T) {
function TestEventuallyWithTTrue (line 2797) | func TestEventuallyWithTTrue(t *testing.T) {
function TestEventuallyWithT_ConcurrencySafe (line 2812) | func TestEventuallyWithT_ConcurrencySafe(t *testing.T) {
function TestEventuallyWithT_ReturnsTheLatestFinishedConditionErrors (line 2824) | func TestEventuallyWithT_ReturnsTheLatestFinishedConditionErrors(t *test...
function TestNeverFalse (line 2847) | func TestNeverFalse(t *testing.T) {
function TestNeverTrue (line 2856) | func TestNeverTrue(t *testing.T) {
function TestEventuallyTimeout (line 2876) | func TestEventuallyTimeout(t *testing.T) {
function Test_validateEqualArgs (line 2897) | func Test_validateEqualArgs(t *testing.T) {
function Test_truncatingFormat (line 2911) | func Test_truncatingFormat(t *testing.T) {
function parseLabeledOutput (line 2928) | func parseLabeledOutput(output string) []labeledContent {
type captureTestingT (line 2963) | type captureTestingT struct
method Errorf (line 2967) | func (ctt *captureTestingT) Errorf(format string, args ...interface{}) {
method checkResultAndErrMsg (line 2971) | func (ctt *captureTestingT) checkResultAndErrMsg(t *testing.T, expecte...
function TestErrorIs (line 2999) | func TestErrorIs(t *testing.T) {
function TestNotErrorIs (line 3069) | func TestNotErrorIs(t *testing.T) {
function TestErrorAs (line 3135) | func TestErrorAs(t *testing.T) {
FILE: internal/testify/assert/forward_assertions.go
type Assertions (line 5) | type Assertions struct
function New (line 10) | func New(t TestingT) *Assertions {
FILE: internal/testify/assert/forward_assertions_test.go
function TestImplementsWrapper (line 10) | func TestImplementsWrapper(t *testing.T) {
function TestIsTypeWrapper (line 21) | func TestIsTypeWrapper(t *testing.T) {
function TestEqualWrapper (line 33) | func TestEqualWrapper(t *testing.T) {
function TestEqualValuesWrapper (line 53) | func TestEqualValuesWrapper(t *testing.T) {
function TestNotNilWrapper (line 61) | func TestNotNilWrapper(t *testing.T) {
function TestNilWrapper (line 73) | func TestNilWrapper(t *testing.T) {
function TestTrueWrapper (line 85) | func TestTrueWrapper(t *testing.T) {
function TestFalseWrapper (line 97) | func TestFalseWrapper(t *testing.T) {
function TestExactlyWrapper (line 109) | func TestExactlyWrapper(t *testing.T) {
function TestNotEqualWrapper (line 136) | func TestNotEqualWrapper(t *testing.T) {
function TestNotEqualValuesWrapper (line 157) | func TestNotEqualValuesWrapper(t *testing.T) {
function TestContainsWrapper (line 181) | func TestContainsWrapper(t *testing.T) {
function TestNotContainsWrapper (line 202) | func TestNotContainsWrapper(t *testing.T) {
function TestConditionWrapper (line 223) | func TestConditionWrapper(t *testing.T) {
function TestDidPanicWrapper (line 237) | func TestDidPanicWrapper(t *testing.T) {
function TestPanicsWrapper (line 252) | func TestPanicsWrapper(t *testing.T) {
function TestNotPanicsWrapper (line 269) | func TestNotPanicsWrapper(t *testing.T) {
function TestNoErrorWrapper (line 286) | func TestNoErrorWrapper(t *testing.T) {
function TestErrorWrapper (line 302) | func TestErrorWrapper(t *testing.T) {
function TestErrorContainsWrapper (line 318) | func TestErrorContainsWrapper(t *testing.T) {
function TestEqualErrorWrapper (line 337) | func TestEqualErrorWrapper(t *testing.T) {
function TestEmptyWrapper (line 354) | func TestEmptyWrapper(t *testing.T) {
function TestNotEmptyWrapper (line 372) | func TestNotEmptyWrapper(t *testing.T) {
function TestLenWrapper (line 390) | func TestLenWrapper(t *testing.T) {
function TestWithinDurationWrapper (line 430) | func TestWithinDurationWrapper(t *testing.T) {
function TestInDeltaWrapper (line 449) | func TestInDeltaWrapper(t *testing.T) {
function TestInEpsilonWrapper (line 483) | func TestInEpsilonWrapper(t *testing.T) {
function TestRegexpWrapper (line 521) | func TestRegexpWrapper(t *testing.T) {
function TestZeroWrapper (line 556) | func TestZeroWrapper(t *testing.T) {
function TestNotZeroWrapper (line 569) | func TestNotZeroWrapper(t *testing.T) {
function TestJSONEqWrapper_EqualSONString (line 582) | func TestJSONEqWrapper_EqualSONString(t *testing.T) {
function TestJSONEqWrapper_EquivalentButNotEqual (line 590) | func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) {
function TestJSONEqWrapper_HashOfArraysAndHashes (line 598) | func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) {
function TestJSONEqWrapper_Array (line 606) | func TestJSONEqWrapper_Array(t *testing.T) {
function TestJSONEqWrapper_HashAndArrayNotEquivalent (line 614) | func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
function TestJSONEqWrapper_HashesNotEquivalent (line 621) | func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) {
function TestJSONEqWrapper_ActualIsNotJSON (line 628) | func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) {
function TestJSONEqWrapper_ExpectedIsNotJSON (line 635) | func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) {
function TestJSONEqWrapper_ExpectedAndActualNotJSON (line 642) | func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) {
function TestJSONEqWrapper_ArraysOfDifferentOrder (line 649) | func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) {
FILE: internal/testify/assert/http_assertions.go
function httpCode (line 13) | func httpCode(handler http.HandlerFunc, method, url string, values url.V...
function HTTPSuccess (line 29) | func HTTPSuccess(t TestingT, handler http.HandlerFunc, method, url strin...
function HTTPRedirect (line 51) | func HTTPRedirect(t TestingT, handler http.HandlerFunc, method, url stri...
function HTTPError (line 73) | func HTTPError(t TestingT, handler http.HandlerFunc, method, url string,...
function HTTPStatusCode (line 95) | func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method, url st...
function HTTPBody (line 114) | func HTTPBody(handler http.HandlerFunc, method, url string, values url.V...
function HTTPBodyContains (line 133) | func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method, url ...
function HTTPBodyNotContains (line 153) | func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method, u...
FILE: internal/testify/assert/http_assertions_test.go
function httpOK (line 11) | func httpOK(w http.ResponseWriter, r *http.Request) {
function httpReadBody (line 15) | func httpReadBody(w http.ResponseWriter, r *http.Request) {
function httpRedirect (line 21) | func httpRedirect(w http.ResponseWriter, r *http.Request) {
function httpError (line 25) | func httpError(w http.ResponseWriter, r *http.Request) {
function httpStatusCode (line 29) | func httpStatusCode(w http.ResponseWriter, r *http.Request) {
function TestHTTPSuccess (line 33) | func TestHTTPSuccess(t *testing.T) {
function TestHTTPRedirect (line 61) | func TestHTTPRedirect(t *testing.T) {
function TestHTTPError (line 85) | func TestHTTPError(t *testing.T) {
function TestHTTPStatusCode (line 109) | func TestHTTPStatusCode(t *testing.T) {
function TestHTTPStatusesWrapper (line 133) | func TestHTTPStatusesWrapper(t *testing.T) {
function httpHelloName (line 150) | func httpHelloName(w http.ResponseWriter, r *http.Request) {
function TestHTTPRequestWithNoParams (line 155) | func TestHTTPRequestWithNoParams(t *testing.T) {
function TestHTTPRequestWithParams (line 168) | func TestHTTPRequestWithParams(t *testing.T) {
function TestHttpBody (line 184) | func TestHttpBody(t *testing.T) {
function TestHttpBodyWrappers (line 203) | func TestHttpBodyWrappers(t *testing.T) {
FILE: internal/testify/assert/internal/unsafetests/unsafetests_test.go
type ignoreTestingT (line 11) | type ignoreTestingT struct
method Helper (line 15) | func (ignoreTestingT) Helper() {}
method Errorf (line 17) | func (ignoreTestingT) Errorf(format string, args ...interface{}) {
function TestUnsafePointers (line 23) | func TestUnsafePointers(t *testing.T) {
FILE: internal/testify/require/forward_requirements.go
type Assertions (line 5) | type Assertions struct
function New (line 10) | func New(t TestingT) *Assertions {
FILE: internal/testify/require/forward_requirements_test.go
function TestImplementsWrapper (line 9) | func TestImplementsWrapper(t *testing.T) {
function TestIsTypeWrapper (line 22) | func TestIsTypeWrapper(t *testing.T) {
function TestEqualWrapper (line 34) | func TestEqualWrapper(t *testing.T) {
function TestNotEqualWrapper (line 46) | func TestNotEqualWrapper(t *testing.T) {
function TestExactlyWrapper (line 58) | func TestExactlyWrapper(t *testing.T) {
function TestNotNilWrapper (line 75) | func TestNotNilWrapper(t *testing.T) {
function TestNilWrapper (line 87) | func TestNilWrapper(t *testing.T) {
function TestTrueWrapper (line 99) | func TestTrueWrapper(t *testing.T) {
function TestFalseWrapper (line 111) | func TestFalseWrapper(t *testing.T) {
function TestContainsWrapper (line 123) | func TestContainsWrapper(t *testing.T) {
function TestNotContainsWrapper (line 135) | func TestNotContainsWrapper(t *testing.T) {
function TestPanicsWrapper (line 147) | func TestPanicsWrapper(t *testing.T) {
function TestNotPanicsWrapper (line 161) | func TestNotPanicsWrapper(t *testing.T) {
function TestNoErrorWrapper (line 175) | func TestNoErrorWrapper(t *testing.T) {
function TestErrorWrapper (line 187) | func TestErrorWrapper(t *testing.T) {
function TestErrorContainsWrapper (line 199) | func TestErrorContainsWrapper(t *testing.T) {
function TestEqualErrorWrapper (line 211) | func TestEqualErrorWrapper(t *testing.T) {
function TestEmptyWrapper (line 223) | func TestEmptyWrapper(t *testing.T) {
function TestNotEmptyWrapper (line 235) | func TestNotEmptyWrapper(t *testing.T) {
function TestWithinDurationWrapper (line 247) | func TestWithinDurationWrapper(t *testing.T) {
function TestInDeltaWrapper (line 262) | func TestInDeltaWrapper(t *testing.T) {
function TestZeroWrapper (line 274) | func TestZeroWrapper(t *testing.T) {
function TestNotZeroWrapper (line 286) | func TestNotZeroWrapper(t *testing.T) {
function TestJSONEqWrapper_EqualSONString (line 298) | func TestJSONEqWrapper_EqualSONString(t *testing.T) {
function TestJSONEqWrapper_EquivalentButNotEqual (line 308) | func TestJSONEqWrapper_EquivalentButNotEqual(t *testing.T) {
function TestJSONEqWrapper_HashOfArraysAndHashes (line 318) | func TestJSONEqWrapper_HashOfArraysAndHashes(t *testing.T) {
function TestJSONEqWrapper_Array (line 329) | func TestJSONEqWrapper_Array(t *testing.T) {
function TestJSONEqWrapper_HashAndArrayNotEquivalent (line 339) | func TestJSONEqWrapper_HashAndArrayNotEquivalent(t *testing.T) {
function TestJSONEqWrapper_HashesNotEquivalent (line 349) | func TestJSONEqWrapper_HashesNotEquivalent(t *testing.T) {
function TestJSONEqWrapper_ActualIsNotJSON (line 359) | func TestJSONEqWrapper_ActualIsNotJSON(t *testing.T) {
function TestJSONEqWrapper_ExpectedIsNotJSON (line 369) | func TestJSONEqWrapper_ExpectedIsNotJSON(t *testing.T) {
function TestJSONEqWrapper_ExpectedAndActualNotJSON (line 379) | func TestJSONEqWrapper_ExpectedAndActualNotJSON(t *testing.T) {
function TestJSONEqWrapper_ArraysOfDifferentOrder (line 389) | func TestJSONEqWrapper_ArraysOfDifferentOrder(t *testing.T) {
FILE: internal/testify/require/require.go
function Condition (line 14) | func Condition(t TestingT, comp assert.Comparison, msgAndArgs ...interfa...
function Conditionf (line 25) | func Conditionf(t TestingT, comp assert.Comparison, msg string, args ......
function Contains (line 41) | func Contains(t TestingT, s interface{}, contains interface{}, msgAndArg...
function Containsf (line 57) | func Containsf(t TestingT, s interface{}, contains interface{}, msg stri...
function DirExists (line 69) | func DirExists(t TestingT, path string, msgAndArgs ...interface{}) {
function DirExistsf (line 81) | func DirExistsf(t TestingT, path string, msg string, args ...interface{}) {
function ElementsMatch (line 96) | func ElementsMatch(t TestingT, listA interface{}, listB interface{}, msg...
function ElementsMatchf (line 111) | func ElementsMatchf(t TestingT, listA interface{}, listB interface{}, ms...
function Empty (line 125) | func Empty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
function Emptyf (line 139) | func Emptyf(t TestingT, object interface{}, msg string, args ...interfac...
function Equal (line 156) | func Equal(t TestingT, expected interface{}, actual interface{}, msgAndA...
function EqualError (line 171) | func EqualError(t TestingT, theError error, errString string, msgAndArgs...
function EqualErrorf (line 186) | func EqualErrorf(t TestingT, theError error, errString string, msg strin...
function EqualExportedValues (line 206) | func EqualExportedValues(t TestingT, expected interface{}, actual interf...
function EqualExportedValuesf (line 226) | func EqualExportedValuesf(t TestingT, expected interface{}, actual inter...
function EqualValues (line 240) | func EqualValues(t TestingT, expected interface{}, actual interface{}, m...
function EqualValuesf (line 254) | func EqualValuesf(t TestingT, expected interface{}, actual interface{}, ...
function Equalf (line 271) | func Equalf(t TestingT, expected interface{}, actual interface{}, msg st...
function Error (line 287) | func Error(t TestingT, err error, msgAndArgs ...interface{}) {
function ErrorAs (line 299) | func ErrorAs(t TestingT, err error, target interface{}, msgAndArgs ...in...
function ErrorAsf (line 311) | func ErrorAsf(t TestingT, err error, target interface{}, msg string, arg...
function ErrorContains (line 326) | func ErrorContains(t TestingT, theError error, contains string, msgAndAr...
function ErrorContainsf (line 341) | func ErrorContainsf(t TestingT, theError error, contains string, msg str...
function ErrorIs (line 353) | func ErrorIs(t TestingT, err error, target error, msgAndArgs ...interfac...
function ErrorIsf (line 365) | func ErrorIsf(t TestingT, err error, target error, msg string, args ...i...
function Errorf (line 381) | func Errorf(t TestingT, err error, msg string, args ...interface{}) {
function Eventually (line 395) | func Eventually(t TestingT, condition func() bool, waitFor time.Duration...
function EventuallyWithT (line 423) | func EventuallyWithT(t TestingT, condition func(collect *assert.CollectT...
function EventuallyWithTf (line 451) | func EventuallyWithTf(t TestingT, condition func(collect *assert.Collect...
function Eventuallyf (line 465) | func Eventuallyf(t TestingT, condition func() bool, waitFor time.Duratio...
function Exactly (line 478) | func Exactly(t TestingT, expected interface{}, actual interface{}, msgAn...
function Exactlyf (line 491) | func Exactlyf(t TestingT, expected interface{}, actual interface{}, msg ...
function Fail (line 502) | func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) {
function FailNow (line 513) | func FailNow(t TestingT, failureMessage string, msgAndArgs ...interface{...
function FailNowf (line 524) | func FailNowf(t TestingT, failureMessage string, msg string, args ...int...
function Failf (line 535) | func Failf(t TestingT, failureMessage string, msg string, args ...interf...
function False (line 548) | func False(t TestingT, value bool, msgAndArgs ...interface{}) {
function Falsef (line 561) | func Falsef(t TestingT, value bool, msg string, args ...interface{}) {
function FileExists (line 573) | func FileExists(t TestingT, path string, msgAndArgs ...interface{}) {
function FileExistsf (line 585) | func FileExistsf(t TestingT, path string, msg string, args ...interface{...
function Greater (line 600) | func Greater(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...i...
function GreaterOrEqual (line 616) | func GreaterOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndAr...
function GreaterOrEqualf (line 632) | func GreaterOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg str...
function Greaterf (line 647) | func Greaterf(t TestingT, e1 interface{}, e2 interface{}, msg string, ar...
function HTTPBodyContains (line 663) | func HTTPBodyContains(t TestingT, handler http.HandlerFunc, method strin...
function HTTPBodyContainsf (line 679) | func HTTPBodyContainsf(t TestingT, handler http.HandlerFunc, method stri...
function HTTPBodyNotContains (line 695) | func HTTPBodyNotContains(t TestingT, handler http.HandlerFunc, method st...
function HTTPBodyNotContainsf (line 711) | func HTTPBodyNotContainsf(t TestingT, handler http.HandlerFunc, method s...
function HTTPError (line 726) | func HTTPError(t TestingT, handler http.HandlerFunc, method string, url ...
function HTTPErrorf (line 741) | func HTTPErrorf(t TestingT, handler http.HandlerFunc, method string, url...
function HTTPRedirect (line 756) | func HTTPRedirect(t TestingT, handler http.HandlerFunc, method string, u...
function HTTPRedirectf (line 771) | func HTTPRedirectf(t TestingT, handler http.HandlerFunc, method string, ...
function HTTPStatusCode (line 786) | func HTTPStatusCode(t TestingT, handler http.HandlerFunc, method string,...
function HTTPStatusCodef (line 801) | func HTTPStatusCodef(t TestingT, handler http.HandlerFunc, method string...
function HTTPSuccess (line 816) | func HTTPSuccess(t TestingT, handler http.HandlerFunc, method string, ur...
function HTTPSuccessf (line 831) | func HTTPSuccessf(t TestingT, handler http.HandlerFunc, method string, u...
function Implements (line 844) | func Implements(t TestingT, interfaceObject interface{}, object interfac...
function Implementsf (line 857) | func Implementsf(t TestingT, interfaceObject interface{}, object interfa...
function InDelta (line 870) | func InDelta(t TestingT, expected interface{}, actual interface{}, delta...
function InDeltaMapValues (line 881) | func InDeltaMapValues(t TestingT, expected interface{}, actual interface...
function InDeltaMapValuesf (line 892) | func InDeltaMapValuesf(t TestingT, expected interface{}, actual interfac...
function InDeltaSlice (line 903) | func InDeltaSlice(t TestingT, expected interface{}, actual interface{}, ...
function InDeltaSlicef (line 914) | func InDeltaSlicef(t TestingT, expected interface{}, actual interface{},...
function InDeltaf (line 927) | func InDeltaf(t TestingT, expected interface{}, actual interface{}, delt...
function InEpsilon (line 938) | func InEpsilon(t TestingT, expected interface{}, actual interface{}, eps...
function InEpsilonSlice (line 949) | func InEpsilonSlice(t TestingT, expected interface{}, actual interface{}...
function InEpsilonSlicef (line 960) | func InEpsilonSlicef(t TestingT, expected interface{}, actual interface{...
function InEpsilonf (line 971) | func InEpsilonf(t TestingT, expected interface{}, actual interface{}, ep...
function IsDecreasing (line 986) | func IsDecreasing(t TestingT, object interface{}, msgAndArgs ...interfac...
function IsDecreasingf (line 1001) | func IsDecreasingf(t TestingT, object interface{}, msg string, args ...i...
function IsIncreasing (line 1016) | func IsIncreasing(t TestingT, object interface{}, msgAndArgs ...interfac...
function IsIncreasingf (line 1031) | func IsIncreasingf(t TestingT, object interface{}, msg string, args ...i...
function IsNonDecreasing (line 1046) | func IsNonDecreasing(t TestingT, object interface{}, msgAndArgs ...inter...
function IsNonDecreasingf (line 1061) | func IsNonDecreasingf(t TestingT, object interface{}, msg string, args ....
function IsNonIncreasing (line 1076) | func IsNonIncreasing(t TestingT, object interface{}, msgAndArgs ...inter...
function IsNonIncreasingf (line 1091) | func IsNonIncreasingf(t TestingT, object interface{}, msg string, args ....
function IsType (line 1102) | func IsType(t TestingT, expectedType interface{}, object interface{}, ms...
function IsTypef (line 1113) | func IsTypef(t TestingT, expectedType interface{}, object interface{}, m...
function JSONEq (line 1126) | func JSONEq(t TestingT, expected string, actual string, msgAndArgs ...in...
function JSONEqf (line 1139) | func JSONEqf(t TestingT, expected string, actual string, msg string, arg...
function Len (line 1153) | func Len(t TestingT, object interface{}, length int, msgAndArgs ...inter...
function Lenf (line 1167) | func Lenf(t TestingT, object interface{}, length int, msg string, args ....
function Less (line 1182) | func Less(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...inte...
function LessOrEqual (line 1198) | func LessOrEqual(t TestingT, e1 interface{}, e2 interface{}, msgAndArgs ...
function LessOrEqualf (line 1214) | func LessOrEqualf(t TestingT, e1 interface{}, e2 interface{}, msg string...
function Lessf (line 1229) | func Lessf(t TestingT, e1 interface{}, e2 interface{}, msg string, args ...
function Negative (line 1243) | func Negative(t TestingT, e interface{}, msgAndArgs ...interface{}) {
function Negativef (line 1257) | func Negativef(t TestingT, e interface{}, msg string, args ...interface{...
function Never (line 1271) | func Never(t TestingT, condition func() bool, waitFor time.Duration, tic...
function Neverf (line 1285) | func Neverf(t TestingT, condition func() bool, waitFor time.Duration, ti...
function Nil (line 1298) | func Nil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
function Nilf (line 1311) | func Nilf(t TestingT, object interface{}, msg string, args ...interface{...
function NoDirExists (line 1323) | func NoDirExists(t TestingT, path string, msgAndArgs ...interface{}) {
function NoDirExistsf (line 1335) | func NoDirExistsf(t TestingT, path string, msg string, args ...interface...
function NoError (line 1351) | func NoError(t TestingT, err error, msgAndArgs ...interface{}) {
function NoErrorf (line 1367) | func NoErrorf(t TestingT, err error, msg string, args ...interface{}) {
function NoFileExists (line 1379) | func NoFileExists(t TestingT, path string, msgAndArgs ...interface{}) {
function NoFileExistsf (line 1391) | func NoFileExistsf(t TestingT, path string, msg string, args ...interfac...
function NotContains (line 1407) | func NotContains(t TestingT, s interface{}, contains interface{}, msgAnd...
function NotContainsf (line 1423) | func NotContainsf(t TestingT, s interface{}, contains interface{}, msg s...
function NotEmpty (line 1439) | func NotEmpty(t TestingT, object interface{}, msgAndArgs ...interface{}) {
function NotEmptyf (line 1455) | func NotEmptyf(t TestingT, object interface{}, msg string, args ...inter...
function NotEqual (line 1471) | func NotEqual(t TestingT, expected interface{}, actual interface{}, msgA...
function NotEqualValues (line 1484) | func NotEqualValues(t TestingT, expected interface{}, actual interface{}...
function NotEqualValuesf (line 1497) | func NotEqualValuesf(t TestingT, expected interface{}, actual interface{...
function NotEqualf (line 1513) | func NotEqualf(t TestingT, expected interface{}, actual interface{}, msg...
function NotErrorIs (line 1525) | func NotErrorIs(t TestingT, err error, target error, msgAndArgs ...inter...
function NotErrorIsf (line 1537) | func NotErrorIsf(t TestingT, err error, target error, msg string, args ....
function NotImplements (line 1550) | func NotImplements(t TestingT, interfaceObject interface{}, object inter...
function NotImplementsf (line 1563) | func NotImplementsf(t TestingT, interfaceObject interface{}, object inte...
function NotNil (line 1576) | func NotNil(t TestingT, object interface{}, msgAndArgs ...interface{}) {
function NotNilf (line 1589) | func NotNilf(t TestingT, object interface{}, msg string, args ...interfa...
function NotPanics (line 1602) | func NotPanics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interfa...
function NotPanicsf (line 1615) | func NotPanicsf(t TestingT, f assert.PanicTestFunc, msg string, args ......
function NotRegexp (line 1629) | func NotRegexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ....
function NotRegexpf (line 1643) | func NotRegexpf(t TestingT, rx interface{}, str interface{}, msg string,...
function NotSame (line 1659) | func NotSame(t TestingT, expected interface{}, actual interface{}, msgAn...
function NotSamef (line 1675) | func NotSamef(t TestingT, expected interface{}, actual interface{}, msg ...
function NotSubset (line 1691) | func NotSubset(t TestingT, list interface{}, subset interface{}, msgAndA...
function NotSubsetf (line 1707) | func NotSubsetf(t TestingT, list interface{}, subset interface{}, msg st...
function NotZero (line 1718) | func NotZero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
function NotZerof (line 1729) | func NotZerof(t TestingT, i interface{}, msg string, args ...interface{}) {
function Panics (line 1742) | func Panics(t TestingT, f assert.PanicTestFunc, msgAndArgs ...interface{...
function PanicsWithError (line 1757) | func PanicsWithError(t TestingT, errString string, f assert.PanicTestFun...
function PanicsWithErrorf (line 1772) | func PanicsWithErrorf(t TestingT, errString string, f assert.PanicTestFu...
function PanicsWithValue (line 1786) | func PanicsWithValue(t TestingT, expected interface{}, f assert.PanicTes...
function PanicsWithValuef (line 1800) | func PanicsWithValuef(t TestingT, expected interface{}, f assert.PanicTe...
function Panicsf (line 1813) | func Panicsf(t TestingT, f assert.PanicTestFunc, msg string, args ...int...
function Positive (line 1827) | func Positive(t TestingT, e interface{}, msgAndArgs ...interface{}) {
function Positivef (line 1841) | func Positivef(t TestingT, e interface{}, msg string, args ...interface{...
function Regexp (line 1855) | func Regexp(t TestingT, rx interface{}, str interface{}, msgAndArgs ...i...
function Regexpf (line 1869) | func Regexpf(t TestingT, rx interface{}, str interface{}, msg string, ar...
function Same (line 1885) | func Same(t TestingT, expected interface{}, actual interface{}, msgAndAr...
function Samef (line 1901) | func Samef(t TestingT, expected interface{}, actual interface{}, msg str...
function Subset (line 1916) | func Subset(t TestingT, list interface{}, subset interface{}, msgAndArgs...
function Subsetf (line 1931) | func Subsetf(t TestingT, list interface{}, subset interface{}, msg strin...
function True (line 1944) | func True(t TestingT, value bool, msgAndArgs ...interface{}) {
function Truef (line 1957) | func Truef(t TestingT, value bool, msg string, args ...interface{}) {
function WithinDuration (line 1970) | func WithinDuration(t TestingT, expected time.Time, actual time.Time, de...
function WithinDurationf (line 1983) | func WithinDurationf(t TestingT, expected time.Time, actual time.Time, d...
function WithinRange (line 1996) | func WithinRange(t TestingT, actual time.Time, start time.Time, end time...
function WithinRangef (line 2009) | func WithinRangef(t TestingT, actual time.Time, start time.Time, end tim...
function Zero (line 2020) | func Zero(t TestingT, i interface{}, msgAndArgs ...interface{}) {
function Zerof (line 2031) | func Zerof(t TestingT, i interface{}, msg string, args ...interface{}) {
FILE: internal/testify/require/require_forward.go
method Condition (line 14) | func (a *Assertions) Condition(comp assert.Comparison, msgAndArgs ...int...
method Conditionf (line 22) | func (a *Assertions) Conditionf(comp assert.Comparison, msg string, args...
method Contains (line 35) | func (a *Assertions) Contains(s interface{}, contains interface{}, msgAn...
method Containsf (line 48) | func (a *Assertions) Containsf(s interface{}, contains interface{}, msg ...
method DirExists (line 57) | func (a *Assertions) DirExists(path string, msgAndArgs ...interface{}) {
method DirExistsf (line 66) | func (a *Assertions) DirExistsf(path string, msg string, args ...interfa...
method ElementsMatch (line 78) | func (a *Assertions) ElementsMatch(listA interface{}, listB interface{},...
method ElementsMatchf (line 90) | func (a *Assertions) ElementsMatchf(listA interface{}, listB interface{}...
method Empty (line 101) | func (a *Assertions) Empty(object interface{}, msgAndArgs ...interface{}) {
method Emptyf (line 112) | func (a *Assertions) Emptyf(object interface{}, msg string, args ...inte...
method Equal (line 126) | func (a *Assertions) Equal(expected interface{}, actual interface{}, msg...
method EqualError (line 138) | func (a *Assertions) EqualError(theError error, errString string, msgAnd...
method EqualErrorf (line 150) | func (a *Assertions) EqualErrorf(theError error, errString string, msg s...
method EqualExportedValues (line 167) | func (a *Assertions) EqualExportedValues(expected interface{}, actual in...
method EqualExportedValuesf (line 184) | func (a *Assertions) EqualExportedValuesf(expected interface{}, actual i...
method EqualValues (line 195) | func (a *Assertions) EqualValues(expected interface{}, actual interface{...
method EqualValuesf (line 206) | func (a *Assertions) EqualValuesf(expected interface{}, actual interface...
method Equalf (line 220) | func (a *Assertions) Equalf(expected interface{}, actual interface{}, ms...
method Error (line 233) | func (a *Assertions) Error(err error, msgAndArgs ...interface{}) {
method ErrorAs (line 242) | func (a *Assertions) ErrorAs(err error, target interface{}, msgAndArgs ....
method ErrorAsf (line 251) | func (a *Assertions) ErrorAsf(err error, target interface{}, msg string,...
method ErrorContains (line 263) | func (a *Assertions) ErrorContains(theError error, contains string, msgA...
method ErrorContainsf (line 275) | func (a *Assertions) ErrorContainsf(theError error, contains string, msg...
method ErrorIs (line 284) | func (a *Assertions) ErrorIs(err error, target error, msgAndArgs ...inte...
method ErrorIsf (line 293) | func (a *Assertions) ErrorIsf(err error, target error, msg string, args ...
method Errorf (line 306) | func (a *Assertions) Errorf(err error, msg string, args ...interface{}) {
method Eventually (line 317) | func (a *Assertions) Eventually(condition func() bool, waitFor time.Dura...
method EventuallyWithT (line 342) | func (a *Assertions) EventuallyWithT(condition func(collect *assert.Coll...
method EventuallyWithTf (line 367) | func (a *Assertions) EventuallyWithTf(condition func(collect *assert.Col...
method Eventuallyf (line 378) | func (a *Assertions) Eventuallyf(condition func() bool, waitFor time.Dur...
method Exactly (line 388) | func (a *Assertions) Exactly(expected interface{}, actual interface{}, m...
method Exactlyf (line 398) | func (a *Assertions) Exactlyf(expected interface{}, actual interface{}, ...
method Fail (line 406) | func (a *Assertions) Fail(failureMessage string, msgAndArgs ...interface...
method FailNow (line 414) | func (a *Assertions) FailNow(failureMessage string, msgAndArgs ...interf...
method FailNowf (line 422) | func (a *Assertions) FailNowf(failureMessage string, msg string, args .....
method Failf (line 430) | func (a *Assertions) Failf(failureMessage string, msg string, args ...in...
method False (line 440) | func (a *Assertions) False(value bool, msgAndArgs ...interface{}) {
method Falsef (line 450) | func (a *Assertions) Falsef(value bool, msg string, args ...interface{}) {
method FileExists (line 459) | func (a *Assertions) FileExists(path string, msgAndArgs ...interface{}) {
method FileExistsf (line 468) | func (a *Assertions) FileExistsf(path string, msg string, args ...interf...
method Greater (line 480) | func (a *Assertions) Greater(e1 interface{}, e2 interface{}, msgAndArgs ...
method GreaterOrEqual (line 493) | func (a *Assertions) GreaterOrEqual(e1 interface{}, e2 interface{}, msgA...
method GreaterOrEqualf (line 506) | func (a *Assertions) GreaterOrEqualf(e1 interface{}, e2 interface{}, msg...
method Greaterf (line 518) | func (a *Assertions) Greaterf(e1 interface{}, e2 interface{}, msg string...
method HTTPBodyContains (line 531) | func (a *Assertions) HTTPBodyContains(handler http.HandlerFunc, method s...
method HTTPBodyContainsf (line 544) | func (a *Assertions) HTTPBodyContainsf(handler http.HandlerFunc, method ...
method HTTPBodyNotContains (line 557) | func (a *Assertions) HTTPBodyNotContains(handler http.HandlerFunc, metho...
method HTTPBodyNotContainsf (line 570) | func (a *Assertions) HTTPBodyNotContainsf(handler http.HandlerFunc, meth...
method HTTPError (line 582) | func (a *Assertions) HTTPError(handler http.HandlerFunc, method string, ...
method HTTPErrorf (line 594) | func (a *Assertions) HTTPErrorf(handler http.HandlerFunc, method string,...
method HTTPRedirect (line 606) | func (a *Assertions) HTTPRedirect(handler http.HandlerFunc, method strin...
method HTTPRedirectf (line 618) | func (a *Assertions) HTTPRedirectf(handler http.HandlerFunc, method stri...
method HTTPStatusCode (line 630) | func (a *Assertions) HTTPStatusCode(handler http.HandlerFunc, method str...
method HTTPStatusCodef (line 642) | func (a *Assertions) HTTPStatusCodef(handler http.HandlerFunc, method st...
method HTTPSuccess (line 654) | func (a *Assertions) HTTPSuccess(handler http.HandlerFunc, method string...
method HTTPSuccessf (line 666) | func (a *Assertions) HTTPSuccessf(handler http.HandlerFunc, method strin...
method Implements (line 676) | func (a *Assertions) Implements(interfaceObject interface{}, object inte...
method Implementsf (line 686) | func (a *Assertions) Implementsf(interfaceObject interface{}, object int...
method InDelta (line 696) | func (a *Assertions) InDelta(expected interface{}, actual interface{}, d...
method InDeltaMapValues (line 704) | func (a *Assertions) InDeltaMapValues(expected interface{}, actual inter...
method InDeltaMapValuesf (line 712) | func (a *Assertions) InDeltaMapValuesf(expected interface{}, actual inte...
method InDeltaSlice (line 720) | func (a *Assertions) InDeltaSlice(expected interface{}, actual interface...
method InDeltaSlicef (line 728) | func (a *Assertions) InDeltaSlicef(expected interface{}, actual interfac...
method InDeltaf (line 738) | func (a *Assertions) InDeltaf(expected interface{}, actual interface{}, ...
method InEpsilon (line 746) | func (a *Assertions) InEpsilon(expected interface{}, actual interface{},...
method InEpsilonSlice (line 754) | func (a *Assertions) InEpsilonSlice(expected interface{}, actual interfa...
method InEpsilonSlicef (line 762) | func (a *Assertions) InEpsilonSlicef(expected interface{}, actual interf...
method InEpsilonf (line 770) | func (a *Assertions) InEpsilonf(expected interface{}, actual interface{}...
method IsDecreasing (line 782) | func (a *Assertions) IsDecreasing(object interface{}, msgAndArgs ...inte...
method IsDecreasingf (line 794) | func (a *Assertions) IsDecreasingf(object interface{}, msg string, args ...
method IsIncreasing (line 806) | func (a *Assertions) IsIncreasing(object interface{}, msgAndArgs ...inte...
method IsIncreasingf (line 818) | func (a *Assertions) IsIncreasingf(object interface{}, msg string, args ...
method IsNonDecreasing (line 830) | func (a *Assertions) IsNonDecreasing(object interface{}, msgAndArgs ...i...
method IsNonDecreasingf (line 842) | func (a *Assertions) IsNonDecreasingf(object interface{}, msg string, ar...
method IsNonIncreasing (line 854) | func (a *Assertions) IsNonIncreasing(object interface{}, msgAndArgs ...i...
method IsNonIncreasingf (line 866) | func (a *Assertions) IsNonIncreasingf(object interface{}, msg string, ar...
method IsType (line 874) | func (a *Assertions) IsType(expectedType interface{}, object interface{}...
method IsTypef (line 882) | func (a *Assertions) IsTypef(expectedType interface{}, object interface{...
method JSONEq (line 892) | func (a *Assertions) JSONEq(expected string, actual string, msgAndArgs ....
method JSONEqf (line 902) | func (a *Assertions) JSONEqf(expected string, actual string, msg string,...
method Len (line 913) | func (a *Assertions) Len(object interface{}, length int, msgAndArgs ...i...
method Lenf (line 924) | func (a *Assertions) Lenf(object interface{}, length int, msg string, ar...
method Less (line 936) | func (a *Assertions) Less(e1 interface{}, e2 interface{}, msgAndArgs ......
method LessOrEqual (line 949) | func (a *Assertions) LessOrEqual(e1 interface{}, e2 interface{}, msgAndA...
method LessOrEqualf (line 962) | func (a *Assertions) LessOrEqualf(e1 interface{}, e2 interface{}, msg st...
method Lessf (line 974) | func (a *Assertions) Lessf(e1 interface{}, e2 interface{}, msg string, a...
method Negative (line 985) | func (a *Assertions) Negative(e interface{}, msgAndArgs ...interface{}) {
method Negativef (line 996) | func (a *Assertions) Negativef(e interface{}, msg string, args ...interf...
method Never (line 1007) | func (a *Assertions) Never(condition func() bool, waitFor time.Duration,...
method Neverf (line 1018) | func (a *Assertions) Neverf(condition func() bool, waitFor time.Duration...
method Nil (line 1028) | func (a *Assertions) Nil(object interface{}, msgAndArgs ...interface{}) {
method Nilf (line 1038) | func (a *Assertions) Nilf(object interface{}, msg string, args ...interf...
method NoDirExists (line 1047) | func (a *Assertions) NoDirExists(path string, msgAndArgs ...interface{}) {
method NoDirExistsf (line 1056) | func (a *Assertions) NoDirExistsf(path string, msg string, args ...inter...
method NoError (line 1069) | func (a *Assertions) NoError(err error, msgAndArgs ...interface{}) {
method NoErrorf (line 1082) | func (a *Assertions) NoErrorf(err error, msg string, args ...interface{}) {
method NoFileExists (line 1091) | func (a *Assertions) NoFileExists(path string, msgAndArgs ...interface{}) {
method NoFileExistsf (line 1100) | func (a *Assertions) NoFileExistsf(path string, msg string, args ...inte...
method NotContains (line 1113) | func (a *Assertions) NotContains(s interface{}, contains interface{}, ms...
method NotContainsf (line 1126) | func (a *Assertions) NotContainsf(s interface{}, contains interface{}, m...
method NotEmpty (line 1139) | func (a *Assertions) NotEmpty(object interface{}, msgAndArgs ...interfac...
method NotEmptyf (line 1152) | func (a *Assertions) NotEmptyf(object interface{}, msg string, args ...i...
method NotEqual (line 1165) | func (a *Assertions) NotEqual(expected interface{}, actual interface{}, ...
method NotEqualValues (line 1175) | func (a *Assertions) NotEqualValues(expected interface{}, actual interfa...
method NotEqualValuesf (line 1185) | func (a *Assertions) NotEqualValuesf(expected interface{}, actual interf...
method NotEqualf (line 1198) | func (a *Assertions) NotEqualf(expected interface{}, actual interface{},...
method NotErrorIs (line 1207) | func (a *Assertions) NotErrorIs(err error, target error, msgAndArgs ...i...
method NotErrorIsf (line 1216) | func (a *Assertions) NotErrorIsf(err error, target error, msg string, ar...
method NotImplements (line 1226) | func (a *Assertions) NotImplements(interfaceObject interface{}, object i...
method NotImplementsf (line 1236) | func (a *Assertions) NotImplementsf(interfaceObject interface{}, object ...
method NotNil (line 1246) | func (a *Assertions) NotNil(object interface{}, msgAndArgs ...interface{...
method NotNilf (line 1256) | func (a *Assertions) NotNilf(object interface{}, msg string, args ...int...
method NotPanics (line 1266) | func (a *Assertions) NotPanics(f assert.PanicTestFunc, msgAndArgs ...int...
method NotPanicsf (line 1276) | func (a *Assertions) NotPanicsf(f assert.PanicTestFunc, msg string, args...
method NotRegexp (line 1287) | func (a *Assertions) NotRegexp(rx interface{}, str interface{}, msgAndAr...
method NotRegexpf (line 1298) | func (a *Assertions) NotRegexpf(rx interface{}, str interface{}, msg str...
method NotSame (line 1311) | func (a *Assertions) NotSame(expected interface{}, actual interface{}, m...
method NotSamef (line 1324) | func (a *Assertions) NotSamef(expected interface{}, actual interface{}, ...
method NotSubset (line 1337) | func (a *Assertions) NotSubset(list interface{}, subset interface{}, msg...
method NotSubsetf (line 1350) | func (a *Assertions) NotSubsetf(list interface{}, subset interface{}, ms...
method NotZero (line 1358) | func (a *Assertions) NotZero(i interface{}, msgAndArgs ...interface{}) {
method NotZerof (line 1366) | func (a *Assertions) NotZerof(i interface{}, msg string, args ...interfa...
method Panics (line 1376) | func (a *Assertions) Panics(f assert.PanicTestFunc, msgAndArgs ...interf...
method PanicsWithError (line 1388) | func (a *Assertions) PanicsWithError(errString string, f assert.PanicTes...
method PanicsWithErrorf (line 1400) | func (a *Assertions) PanicsWithErrorf(errString string, f assert.PanicTe...
method PanicsWithValue (line 1411) | func (a *Assertions) PanicsWithValue(expected interface{}, f assert.Pani...
method PanicsWithValuef (line 1422) | func (a *Assertions) PanicsWithValuef(expected interface{}, f assert.Pan...
method Panicsf (line 1432) | func (a *Assertions) Panicsf(f assert.PanicTestFunc, msg string, args .....
method Positive (line 1443) | func (a *Assertions) Positive(e interface{}, msgAndArgs ...interface{}) {
method Positivef (line 1454) | func (a *Assertions) Positivef(e interface{}, msg string, args ...interf...
method Regexp (line 1465) | func (a *Assertions) Regexp(rx interface{}, str interface{}, msgAndArgs ...
method Regexpf (line 1476) | func (a *Assertions) Regexpf(rx interface{}, str interface{}, msg string...
method Same (line 1489) | func (a *Assertions) Same(expected interface{}, actual interface{}, msgA...
method Samef (line 1502) | func (a *Assertions) Samef(expected interface{}, actual interface{}, msg...
method Subset (line 1514) | func (a *Assertions) Subset(list interface{}, subset interface{}, msgAnd...
method Subsetf (line 1526) | func (a *Assertions) Subsetf(list interface{}, subset interface{}, msg s...
method True (line 1536) | func (a *Assertions) True(value bool, msgAndArgs ...interface{}) {
method Truef (line 1546) | func (a *Assertions) Truef(value bool, msg string, args ...interface{}) {
method WithinDuration (line 1556) | func (a *Assertions) WithinDuration(expected time.Time, actual time.Time...
method WithinDurationf (line 1566) | func (a *Assertions) WithinDurationf(expected time.Time, actual time.Tim...
method WithinRange (line 1576) | func (a *Assertions) WithinRange(actual time.Time, start time.Time, end ...
method WithinRangef (line 1586) | func (a *Assertions) WithinRangef(actual time.Time, start time.Time, end...
method Zero (line 1594) | func (a *Assertions) Zero(i interface{}, msgAndArgs ...interface{}) {
method Zerof (line 1602) | func (a *Assertions) Zerof(i interface{}, msg string, args ...interface{...
FILE: internal/testify/require/requirements.go
type TestingT (line 4) | type TestingT interface
type ComparisonAssertionFunc (line 15) | type ComparisonAssertionFunc
type ValueAssertionFunc (line 19) | type ValueAssertionFunc
type BoolAssertionFunc (line 23) | type BoolAssertionFunc
type ErrorAssertionFunc (line 27) | type ErrorAssertionFunc
FILE: internal/testify/require/requirements_test.go
type AssertionTesterInterface (line 11) | type AssertionTesterInterface interface
type AssertionTesterConformingObject (line 16) | type AssertionTesterConformingObject struct
method TestMethod (line 19) | func (a *AssertionTesterConformingObject) TestMethod() {
type AssertionTesterNonConformingObject (line 23) | type AssertionTesterNonConformingObject struct
type MockT (line 26) | type MockT struct
method FailNow (line 30) | func (t *MockT) FailNow() {
method Errorf (line 34) | func (t *MockT) Errorf(format string, args ...interface{}) {
function TestImplements (line 38) | func TestImplements(t *testing.T) {
function TestIsType (line 49) | func TestIsType(t *testing.T) {
function TestEqual (line 60) | func TestEqual(t *testing.T) {
function TestNotEqual (line 72) | func TestNotEqual(t *testing.T) {
function TestExactly (line 82) | func TestExactly(t *testing.T) {
function TestNotNil (line 97) | func TestNotNil(t *testing.T) {
function TestNil (line 108) | func TestNil(t *testing.T) {
function TestTrue (line 119) | func TestTrue(t *testing.T) {
function TestFalse (line 130) | func TestFalse(t *testing.T) {
function TestContains (line 141) | func TestContains(t *testing.T) {
function TestNotContains (line 152) | func TestNotContains(t *testing.T) {
function TestPanics (line 163) | func TestPanics(t *testing.T) {
function TestNotPanics (line 176) | func TestNotPanics(t *testing.T) {
function TestNoError (line 189) | func TestNoError(t *testing.T) {
function TestError (line 200) | func TestError(t *testing.T) {
function TestErrorContains (line 211) | func TestErrorContains(t *testing.T) {
function TestEqualError (line 222) | func TestEqualError(t *testing.T) {
function TestEmpty (line 233) | func TestEmpty(t *testing.T) {
function TestNotEmpty (line 244) | func TestNotEmpty(t *testing.T) {
function TestWithinDuration (line 255) | func TestWithinDuration(t *testing.T) {
function TestInDelta (line 269) | func TestInDelta(t *testing.T) {
function TestZero (line 280) | func TestZero(t *testing.T) {
function TestNotZero (line 291) | func TestNotZero(t *testing.T) {
function TestJSONEq_EqualSONString (line 302) | func TestJSONEq_EqualSONString(t *testing.T) {
function TestJSONEq_EquivalentButNotEqual (line 310) | func TestJSONEq_EquivalentButNotEqual(t *testing.T) {
function TestJSONEq_HashOfArraysAndHashes (line 318) | func TestJSONEq_HashOfArraysAndHashes(t *testing.T) {
function TestJSONEq_Array (line 327) | func TestJSONEq_Array(t *testing.T) {
function TestJSONEq_HashAndArrayNotEquivalent (line 335) | func TestJSONEq_HashAndArrayNotEquivalent(t *testing.T) {
function TestJSONEq_HashesNotEquivalent (line 343) | func TestJSONEq_HashesNotEquivalent(t *testing.T) {
function TestJSONEq_ActualIsNotJSON (line 351) | func TestJSONEq_ActualIsNotJSON(t *testing.T) {
function TestJSONEq_ExpectedIsNotJSON (line 359) | func TestJSONEq_ExpectedIsNotJSON(t *testing.T) {
function TestJSONEq_ExpectedAndActualNotJSON (line 367) | func TestJSONEq_ExpectedAndActualNotJSON(t *testing.T) {
function TestJSONEq_ArraysOfDifferentOrder (line 375) | func TestJSONEq_ArraysOfDifferentOrder(t *testing.T) {
function ExampleComparisonAssertionFunc (line 383) | func ExampleComparisonAssertionFunc() {
function TestComparisonAssertionFunc (line 413) | func TestComparisonAssertionFunc(t *testing.T) {
function ExampleValueAssertionFunc (line 446) | func ExampleValueAssertionFunc() {
function TestValueAssertionFunc (line 474) | func TestValueAssertionFunc(t *testing.T) {
function ExampleBoolAssertionFunc (line 495) | func ExampleBoolAssertionFunc() {
function TestBoolAssertionFunc (line 520) | func TestBoolAssertionFunc(t *testing.T) {
function ExampleErrorAssertionFunc (line 537) | func ExampleErrorAssertionFunc() {
function TestErrorAssertionFunc (line 563) | func TestErrorAssertionFunc(t *testing.T) {
FILE: optimizer/const_expr.go
type constExpr (line 14) | type constExpr struct
method Visit (line 20) | func (c *constExpr) Visit(node *Node) {
FILE: optimizer/count_any.go
type countAny (line 11) | type countAny struct
method Visit (line 13) | func (*countAny) Visit(node *Node) {
FILE: optimizer/count_any_test.go
function TestOptimize_count_any (line 15) | func TestOptimize_count_any(t *testing.T) {
function TestOptimize_count_any_gte_one (line 38) | func TestOptimize_count_any_gte_one(t *testing.T) {
function TestOptimize_count_any_correctness (line 61) | func TestOptimize_count_any_correctness(t *testing.T) {
function TestOptimize_count_no_optimization (line 89) | func TestOptimize_count_no_optimization(t *testing.T) {
function BenchmarkCountGtZero (line 117) | func BenchmarkCountGtZero(b *testing.B) {
function BenchmarkCountGtZeroLargeEarlyMatch (line 127) | func BenchmarkCountGtZeroLargeEarlyMatch(b *testing.B) {
function BenchmarkCountGtZeroNoMatch (line 137) | func BenchmarkCountGtZeroNoMatch(b *testing.B) {
function BenchmarkCountGteOneEarlyMatch (line 148) | func BenchmarkCountGteOneEarlyMatch(b *testing.B) {
function BenchmarkCountGteOneNoMatch (line 158) | func BenchmarkCountGteOneNoMatch(b *testing.B) {
FILE: optimizer/count_threshold.go
type countThreshold (line 14) | type countThreshold struct
method Visit (line 16) | func (*countThreshold) Visit(node *Node) {
FILE: optimizer/count_threshold_test.go
function TestOptimize_count_threshold_gt (line 15) | func TestOptimize_count_threshold_gt(t *testing.T) {
function TestOptimize_count_threshold_gte (line 34) | func TestOptimize_count_threshold_gte(t *testing.T) {
function TestOptimize_count_threshold_lt (line 53) | func TestOptimize_count_threshold_lt(t *testing.T) {
function TestOptimize_count_threshold_lte (line 72) | func TestOptimize_count_threshold_lte(t *testing.T) {
function TestOptimize_count_threshold_correctness (line 91) | func TestOptimize_count_threshold_correctness(t *testing.T) {
function TestOptimize_count_threshold_no_optimization (line 136) | func TestOptimize_count_threshold_no_optimization(t *testing.T) {
function BenchmarkCountThresholdEarlyMatch (line 177) | func BenchmarkCountThresholdEarlyMatch(b *testing.B) {
function BenchmarkCountThresholdGteEarlyMatch (line 190) | func BenchmarkCountThresholdGteEarlyMatch(b *testing.B) {
function BenchmarkCountThresholdNoEarlyExit (line 203) | func BenchmarkCountThresholdNoEarlyExit(b *testing.B) {
function BenchmarkCountThresholdLargeEarlyMatch (line 216) | func BenchmarkCountThresholdLargeEarlyMatch(b *testing.B) {
function BenchmarkCountThresholdLtEarlyExit (line 229) | func BenchmarkCountThresholdLtEarlyExit(b *testing.B) {
function BenchmarkCountThresholdLteEarlyExit (line 242) | func BenchmarkCountThresholdLteEarlyExit(b *testing.B) {
function BenchmarkCountThresholdLtNoEarlyExit (line 255) | func BenchmarkCountThresholdLtNoEarlyExit(b *testing.B) {
function BenchmarkCountThresholdLteNoEarlyExit (line 268) | func BenchmarkCountThresholdLteNoEarlyExit(b *testing.B) {
FILE: optimizer/filter_first.go
type filterFirst (line 7) | type filterFirst struct
method Visit (line 9) | func (*filterFirst) Visit(node *Node) {
FILE: optimizer/filter_last.go
type filterLast (line 7) | type filterLast struct
method Visit (line 9) | func (*filterLast) Visit(node *Node) {
FILE: optimizer/filter_len.go
type filterLen (line 7) | type filterLen struct
method Visit (line 9) | func (*filterLen) Visit(node *Node) {
FILE: optimizer/filter_map.go
type filterMap (line 7) | type filterMap struct
method Visit (line 9) | func (*filterMap) Visit(node *Node) {
function isIndexPointer (line 28) | func isIndexPointer(node Node) bool {
FILE: optimizer/filter_map_test.go
function TestOptimize_filter_map (line 13) | func TestOptimize_filter_map(t *testing.T) {
function TestOptimize_filter_map_with_index_pointer (line 44) | func TestOptimize_filter_map_with_index_pointer(t *testing.T) {
function TestOptimize_filter_map_with_index_pointer_with_index_pointer_in_first_argument (line 76) | func TestOptimize_filter_map_with_index_pointer_with_index_pointer_in_fi...
FILE: optimizer/fold.go
type fold (line 10) | type fold struct
method Visit (line 15) | func (fold *fold) Visit(node *Node) {
function toString (line 313) | func toString(n Node) *StringNode {
function toInteger (line 321) | func toInteger(n Node) *IntegerNode {
function toFloat (line 329) | func toFloat(n Node) *FloatNode {
function toBool (line 337) | func toBool(n Node) *BoolNode {
FILE: optimizer/fold_test.go
function TestOptimize_constant_folding (line 14) | func TestOptimize_constant_folding(t *testing.T) {
function TestOptimize_constant_folding_with_floats (line 29) | func TestOptimize_constant_folding_with_floats(t *testing.T) {
function TestOptimize_constant_folding_with_bools (line 42) | func TestOptimize_constant_folding_with_bools(t *testing.T) {
function TestOptimize_constant_folding_filter_filter (line 54) | func TestOptimize_constant_folding_filter_filter(t *testing.T) {
FILE: optimizer/in_array.go
type inArray (line 9) | type inArray struct
method Visit (line 11) | func (*inArray) Visit(node *Node) {
FILE: optimizer/in_range.go
type inRange (line 9) | type inRange struct
method Visit (line 11) | func (*inRange) Visit(node *Node) {
FILE: optimizer/optimizer.go
function Optimize (line 11) | func Optimize(node *Node, config *conf.Config) error {
function patchWithType (line 58) | func patchWithType(node *Node, newNode Node) {
function patchCopyType (line 78) | func patchCopyType(node *Node, newNode Node) {
FILE: optimizer/optimizer_test.go
function TestOptimize (line 19) | func TestOptimize(t *testing.T) {
function TestOptimize_in_array (line 94) | func TestOptimize_in_array(t *testing.T) {
function TestOptimize_in_range (line 115) | func TestOptimize_in_range(t *testing.T) {
function TestOptimize_in_range_with_floats (line 149) | func TestOptimize_in_range_with_floats(t *testing.T) {
function TestOptimize_const_expr (line 155) | func TestOptimize_const_expr(t *testing.T) {
function TestOptimize_filter_len (line 176) | func TestOptimize_filter_len(t *testing.T) {
function TestOptimize_filter_0 (line 203) | func TestOptimize_filter_0(t *testing.T) {
function TestOptimize_filter_first (line 231) | func TestOptimize_filter_first(t *testing.T) {
function TestOptimize_filter_minus_1 (line 259) | func TestOptimize_filter_minus_1(t *testing.T) {
function TestOptimize_filter_last (line 287) | func TestOptimize_filter_last(t *testing.T) {
function TestOptimize_filter_map_first (line 315) | func TestOptimize_filter_map_first(t *testing.T) {
function TestOptimize_predicate_combination (line 347) | func TestOptimize_predicate_combination(t *testing.T) {
function TestOptimize_predicate_combination_nested (line 413) | func TestOptimize_predicate_combination_nested(t *testing.T) {
FILE: optimizer/predicate_combination.go
type predicateCombination (line 16) | type predicateCombination struct
method Visit (line 18) | func (v *predicateCombination) Visit(node *Node) {
function combinedOperator (line 46) | func combinedOperator(fn, op string) (string, bool) {
FILE: optimizer/sum_array.go
type sumArray (line 9) | type sumArray struct
method Visit (line 11) | func (*sumArray) Visit(node *Node) {
function sumArrayFold (line 22) | func sumArrayFold(array *ArrayNode) *BinaryNode {
FILE: optimizer/sum_array_test.go
function BenchmarkSumArray (line 16) | func BenchmarkSumArray(b *testing.B) {
function TestOptimize_sum_array (line 38) | func TestOptimize_sum_array(t *testing.T) {
function TestOptimize_sum_array_3 (line 54) | func TestOptimize_sum_array_3(t *testing.T) {
FILE: optimizer/sum_map.go
type sumMap (line 7) | type sumMap struct
method Visit (line 9) | func (*sumMap) Visit(node *Node) {
FILE: optimizer/sum_map_test.go
function TestOptimize_sum_map (line 14) | func TestOptimize_sum_map(t *testing.T) {
FILE: optimizer/sum_range.go
type sumRange (line 7) | type sumRange struct
method Visit (line 9) | func (*sumRange) Visit(node *Node) {
function isPointerPlusAcc (line 71) | func isPointerPlusAcc(node Node) bool {
function applySumPredicate (line 113) | func applySumPredicate(sum, count int, predicateArg Node) (int, bool) {
function extractPointerAndConstantWithPosition (line 156) | func extractPointerAndConstantWithPosition(binary *BinaryNode) (*Pointer...
FILE: optimizer/sum_range_test.go
function TestOptimize_sum_range (line 14) | func TestOptimize_sum_range(t *testing.T) {
function TestOptimize_sum_range_different_values (line 26) | func TestOptimize_sum_range_different_values(t *testing.T) {
function TestOptimize_sum_range_with_predicate (line 52) | func TestOptimize_sum_range_with_predicate(t *testing.T) {
function TestOptimize_sum_range_with_predicate_ast (line 103) | func TestOptimize_sum_range_with_predicate_ast(t *testing.T) {
function TestOptimize_reduce_range_sum (line 116) | func TestOptimize_reduce_range_sum(t *testing.T) {
function TestOptimize_reduce_range_sum_different_values (line 128) | func TestOptimize_reduce_range_sum_different_values(t *testing.T) {
function TestOptimize_reduce_range_sum_reverse_order (line 153) | func TestOptimize_reduce_range_sum_reverse_order(t *testing.T) {
function TestOptimize_reduce_range_sum_with_initial_value (line 166) | func TestOptimize_reduce_range_sum_with_initial_value(t *testing.T) {
function TestOptimize_reduce_range_sum_with_initial_value_different_values (line 179) | func TestOptimize_reduce_range_sum_with_initial_value_different_values(t...
function TestOptimize_sum_range_reversed (line 203) | func TestOptimize_sum_range_reversed(t *testing.T) {
function TestOptimize_sum_range_reversed_not_optimized (line 227) | func TestOptimize_sum_range_reversed_not_optimized(t *testing.T) {
function TestOptimize_reduce_range_reversed_errors (line 240) | func TestOptimize_reduce_range_reversed_errors(t *testing.T) {
function BenchmarkSumRange_Optimized (line 249) | func BenchmarkSumRange_Optimized(b *testing.B) {
function BenchmarkReduceRangeSum_Optimized (line 263) | func BenchmarkReduceRangeSum_Optimized(b *testing.B) {
function BenchmarkSumRange_Unoptimized (line 277) | func BenchmarkSumRange_Unoptimized(b *testing.B) {
FILE: parser/bench_test.go
function BenchmarkParser (line 5) | func BenchmarkParser(b *testing.B) {
FILE: parser/lexer/lexer.go
constant ringChunkSize (line 13) | ringChunkSize = 10
function Lex (line 16) | func Lex(source file.Source) ([]Token, error) {
function New (line 34) | func New() *Lexer {
type Lexer (line 40) | type Lexer struct
method Reset (line 54) | func (l *Lexer) Reset(source file.Source) {
method Next (line 60) | func (l *Lexer) Next() (Token, error) {
method commit (line 75) | func (l *Lexer) commit() {
method next (line 79) | func (l *Lexer) next() rune {
method peek (line 90) | func (l *Lexer) peek() rune {
method backup (line 98) | func (l *Lexer) backup() {
method emit (line 108) | func (l *Lexer) emit(t Kind) {
method emitValue (line 112) | func (l *Lexer) emitValue(t Kind, value string) {
method emitEOF (line 121) | func (l *Lexer) emitEOF() {
method skip (line 137) | func (l *Lexer) skip() {
method word (line 141) | func (l *Lexer) word() string {
method accept (line 145) | func (l *Lexer) accept(valid string) bool {
method acceptRun (line 153) | func (l *Lexer) acceptRun(valid string) {
method skipSpaces (line 158) | func (l *Lexer) skipSpaces() {
method error (line 163) | func (l *Lexer) error(format string, args ...any) stateFn {
method scanDigits (line 192) | func (l *Lexer) scanDigits(ch rune, base, n int) rune {
method scanEscape (line 203) | func (l *Lexer) scanEscape(quote rune) rune {
method scanString (line 254) | func (l *Lexer) scanString(quote rune) (n int) {
method scanRawString (line 271) | func (l *Lexer) scanRawString(quote rune) (n int) {
constant eof (line 73) | eof rune = -1
function digitVal (line 180) | func digitVal(ch rune) int {
function lower (line 190) | func lower(ch rune) rune { return ('a' - 'A') | ch }
FILE: parser/lexer/lexer_test.go
function TestLex (line 14) | func TestLex(t *testing.T) {
function compareTokens (line 364) | func compareTokens(i1, i2 []Token) bool {
function TestLex_location (line 379) | func TestLex_location(t *testing.T) {
constant errorTests (line 394) | errorTests = `
function TestLex_error (line 441) | func TestLex_error(t *testing.T) {
FILE: parser/lexer/state.go
type stateFn (line 9) | type stateFn
function root (line 11) | func root(l *Lexer) stateFn {
function number (line 72) | func number(l *Lexer) stateFn {
method scanNumber (line 80) | func (l *Lexer) scanNumber() bool {
function dot (line 118) | func dot(l *Lexer) stateFn {
function identifier (line 129) | func identifier(l *Lexer) stateFn {
function not (line 157) | func not(l *Lexer) stateFn {
function questionMark (line 184) | func questionMark(l *Lexer) stateFn {
function slash (line 190) | func slash(l *Lexer) stateFn {
function singleLineComment (line 201) | func singleLineComment(l *Lexer) stateFn {
function multiLineComment (line 212) | func multiLineComment(l *Lexer) stateFn {
function pointer (line 226) | func pointer(l *Lexer) stateFn {
FILE: parser/lexer/token.go
type Kind (line 9) | type Kind
constant Identifier (line 12) | Identifier Kind = "Identifier"
constant Number (line 13) | Number Kind = "Number"
constant String (line 14) | String Kind = "String"
constant Bytes (line 15) | Bytes Kind = "Bytes"
constant Operator (line 16) | Operator Kind = "Operator"
constant Bracket (line 17) | Bracket Kind = "Bracket"
constant EOF (line 18) | EOF Kind = "EOF"
type Token (line 21) | type Token struct
method String (line 27) | func (t Token) String() string {
method Is (line 34) | func (t Token) Is(kind Kind, values ...string) bool {
FILE: parser/lexer/utils.go
function unescape (line 15) | func unescape(value string) (string, error) {
function unescapeBytes (line 58) | func unescapeBytes(value string) (string, error) {
function unescapeChar (line 110) | func unescapeChar(s string) (value rune, multibyte bool, tail string, er...
function unescapeByteChar (line 261) | func unescapeByteChar(s string) (value rune, multibyte bool, tail string...
function unhex (line 339) | func unhex(b byte) (rune, bool) {
FILE: parser/operator/operator.go
type Associativity (line 3) | type Associativity
constant Left (line 6) | Left Associativity = iota + 1
constant Right (line 7) | Right
type Operator (line 10) | type Operator struct
function Less (line 15) | func Less(a, b string) bool {
function IsBoolean (line 19) | func IsBoolean(op string) bool {
function AllowedNegateSuffix (line 23) | func AllowedNegateSuffix(op string) bool {
function IsComparison (line 67) | func IsComparison(op string) bool {
FILE: parser/parser.go
type arg (line 20) | type arg
constant expr (line 23) | expr arg = 1 << iota
constant predicate (line 24) | predicate
constant optional (line 27) | optional arg = 1 << 7
type Parser (line 50) | type Parser struct
method Parse (line 60) | func (p *Parser) Parse(input string, config *conf.Config) (*Tree, erro...
method checkNodeLimit (line 100) | func (p *Parser) checkNodeLimit() error {
method createNode (line 116) | func (p *Parser) createNode(n Node, loc file.Location) Node {
method createMemberNode (line 127) | func (p *Parser) createMemberNode(n *MemberNode, loc file.Location) *M...
method error (line 151) | func (p *Parser) error(format string, args ...any) {
method errorAt (line 155) | func (p *Parser) errorAt(token Token, format string, args ...any) {
method next (line 164) | func (p *Parser) next() {
method expect (line 189) | func (p *Parser) expect(kind Kind, values ...string) {
method parseSequenceExpression (line 199) | func (p *Parser) parseSequenceExpression() Node {
method parseExpression (line 220) | func (p *Parser) parseExpression(precedence int) Node {
method parseVariableDeclaration (line 323) | func (p *Parser) parseVariableDeclaration() Node {
method parseConditionalIf (line 338) | func (p *Parser) parseConditionalIf() Node {
method parseConditional (line 366) | func (p *Parser) parseConditional(node Node) Node {
method parsePrimary (line 394) | func (p *Parser) parsePrimary() Node {
method parseSecondary (line 447) | func (p *Parser) parseSecondary() Node {
method toIntegerNode (line 553) | func (p *Parser) toIntegerNode(number int64) Node {
method toFloatNode (line 561) | func (p *Parser) toFloatNode(number float64) Node {
method parseCall (line 569) | func (p *Parser) parseCall(token Token, arguments []Node, checkOverrid...
method parseArguments (line 647) | func (p *Parser) parseArguments(arguments []Node) []Node {
method parsePredicate (line 668) | func (p *Parser) parsePredicate() Node {
method parseArrayExpression (line 700) | func (p *Parser) parseArrayExpression(token Token) Node {
method parseMapExpression (line 724) | func (p *Parser) parseMapExpression(token Token) Node {
method parsePostfixExpression (line 777) | func (p *Parser) parsePostfixExpression(node Node) Node {
method parseComparison (line 907) | func (p *Parser) parseComparison(left Node, token Token, precedence in...
type Tree (line 138) | type Tree struct
function Parse (line 143) | func Parse(input string) (*Tree, error) {
function ParseWithConfig (line 147) | func ParseWithConfig(input string, config *conf.Config) (*Tree, error) {
FILE: parser/parser_test.go
function TestParse (line 16) | func TestParse(t *testing.T) {
function TestParse_error (line 980) | func TestParse_error(t *testing.T) {
function TestParse_optional_chaining (line 1094) | func TestParse_optional_chaining(t *testing.T) {
function TestParse_pipe_operator (line 1201) | func TestParse_pipe_operator(t *testing.T) {
function TestNodeBudget (line 1224) | func TestNodeBudget(t *testing.T) {
function TestNodeBudgetDisabled (line 1287) | func TestNodeBudgetDisabled(t *testing.T) {
FILE: parser/utils/utils.go
function IsValidIdentifier (line 8) | func IsValidIdentifier(str string) bool {
function IsSpace (line 24) | func IsSpace(r rune) bool {
function IsAlphaNumeric (line 28) | func IsAlphaNumeric(r rune) bool {
function IsAlphabetic (line 32) | func IsAlphabetic(r rune) bool {
FILE: patcher/operator_override.go
type OperatorOverloading (line 13) | type OperatorOverloading struct
method Visit (line 22) | func (p *OperatorOverloading) Visit(node *ast.Node) {
method Reset (line 48) | func (p *OperatorOverloading) Reset() {
method ShouldRepeat (line 52) | func (p *OperatorOverloading) ShouldRepeat() bool {
method FindSuitableOperatorOverload (line 56) | func (p *OperatorOverloading) FindSuitableOperatorOverload(l, r reflec...
method findSuitableOperatorOverloadInTypes (line 64) | func (p *OperatorOverloading) findSuitableOperatorOverloadInTypes(l, r...
method findSuitableOperatorOverloadInFunctions (line 82) | func (p *OperatorOverloading) findSuitableOperatorOverloadInFunctions(...
method Check (line 111) | func (p *OperatorOverloading) Check() {
function checkTypeSuits (line 99) | func checkTypeSuits(t reflect.Type, l reflect.Type, r reflect.Type, firs...
function checkType (line 129) | func checkType(fnType nature.Nature, fn string, operator string) {
function checkFunc (line 139) | func checkFunc(fn *builtin.Function, name string, operator string) {
FILE: patcher/value/bench_test.go
function Benchmark_valueAdd (line 12) | func Benchmark_valueAdd(b *testing.B) {
function Benchmark_valueUntypedAdd (line 33) | func Benchmark_valueUntypedAdd(b *testing.B) {
function Benchmark_valueTypedAdd (line 54) | func Benchmark_valueTypedAdd(b *testing.B) {
FILE: patcher/value/value.go
type AnyValuer (line 35) | type AnyValuer interface
type IntValuer (line 39) | type IntValuer interface
type BoolValuer (line 43) | type BoolValuer interface
type Int8Valuer (line 47) | type Int8Valuer interface
type Int16Valuer (line 51) | type Int16Valuer interface
type Int32Valuer (line 55) | type Int32Valuer interface
type Int64Valuer (line 59) | type Int64Valuer interface
type UintValuer (line 63) | type UintValuer interface
type Uint8Valuer (line 67) | type Uint8Valuer interface
type Uint16Valuer (line 71) | type Uint16Valuer interface
type Uint32Valuer (line 75) | type Uint32Valuer interface
type Uint64Valuer (line 79) | type Uint64Valuer interface
type Float32Valuer (line 83) | type Float32Valuer interface
type Float64Valuer (line 87) | type Float64Valuer interface
type StringValuer (line 91) | type StringValuer interface
type TimeValuer (line 95) | type TimeValuer interface
type DurationValuer (line 99) | type DurationValuer interface
type ArrayValuer (line 103) | type ArrayValuer interface
type MapValuer (line 107) | type MapValuer interface
type patcher (line 133) | type patcher struct
method Visit (line 135) | func (patcher) Visit(node *ast.Node) {
function getValue (line 151) | func getValue(params ...any) (any, error) {
FILE: patcher/value/value_example_test.go
type myInt (line 11) | type myInt struct
method AsInt (line 15) | func (v *myInt) AsInt() int {
method AsAny (line 19) | func (v *myInt) AsAny() any {
function ExampleAnyValuer (line 23) | func ExampleAnyValuer() {
FILE: patcher/value/value_test.go
type customInt (line 12) | type customInt struct
method AsInt (line 16) | func (v *customInt) AsInt() int {
method AsAny (line 20) | func (v *customInt) AsAny() any {
type customTypedInt (line 24) | type customTypedInt struct
method AsInt (line 28) | func (v *customTypedInt) AsInt() int {
type customUntypedInt (line 32) | type customUntypedInt struct
method AsAny (line 36) | func (v *customUntypedInt) AsAny() any {
type customString (line 40) | type customString struct
method AsString (line 44) | func (v *customString) AsString() string {
method AsAny (line 48) | func (v *customString) AsAny() any {
type customTypedString (line 52) | type customTypedString struct
method AsString (line 56) | func (v *customTypedString) AsString() string {
type customUntypedString (line 60) | type customUntypedString struct
method AsAny (line 64) | func (v *customUntypedString) AsAny() any {
type customTypedArray (line 68) | type customTypedArray struct
method AsArray (line 72) | func (v *customTypedArray) AsArray() []any {
type customTypedMap (line 76) | type customTypedMap struct
method AsMap (line 80) | func (v *customTypedMap) AsMap() map[string]any {
function Test_valueAddInt (line 84) | func Test_valueAddInt(t *testing.T) {
function Test_valueUntypedAddInt (line 97) | func Test_valueUntypedAddInt(t *testing.T) {
function Test_valueTypedAddInt (line 111) | func Test_valueTypedAddInt(t *testing.T) {
function Test_valueTypedAddMismatch (line 125) | func Test_valueTypedAddMismatch(t *testing.T) {
function Test_valueUntypedAddMismatch (line 134) | func Test_valueUntypedAddMismatch(t *testing.T) {
function Test_valueTypedArray (line 147) | func Test_valueTypedArray(t *testing.T) {
function Test_valueTypedMap (line 160) | func Test_valueTypedMap(t *testing.T) {
FILE: patcher/with_context.go
type WithContext (line 12) | type WithContext struct
method Visit (line 20) | func (w WithContext) Visit(node *ast.Node) {
FILE: patcher/with_context_test.go
function TestWithContext (line 13) | func TestWithContext(t *testing.T) {
function TestWithContext_with_env_Function (line 34) | func TestWithContext_with_env_Function(t *testing.T) {
type testEnvContext (line 65) | type testEnvContext struct
method Fn (line 69) | func (testEnvContext) Fn(ctx context.Context, a int) int {
function TestWithContext_env_struct (line 73) | func TestWithContext_env_struct(t *testing.T) {
type TestFoo (line 89) | type TestFoo struct
method GetValue (line 93) | func (f *TestFoo) GetValue(a int) int64 {
function TestWithContext_with_env_method_chain (line 97) | func TestWithContext_with_env_method_chain(t *testing.T) {
function TestWithContext_issue529 (line 132) | func TestWithContext_issue529(t *testing.T) {
FILE: patcher/with_timezone.go
type WithTimezone (line 10) | type WithTimezone struct
method Visit (line 14) | func (t WithTimezone) Visit(node *ast.Node) {
FILE: patcher/with_timezone_test.go
function TestWithTimezone_date (line 12) | func TestWithTimezone_date(t *testing.T) {
function TestWithTimezone_now (line 21) | func TestWithTimezone_now(t *testing.T) {
FILE: repl/repl.go
function main (line 28) | func main() {
type completer (line 105) | type completer struct
method Do (line 109) | func (c completer) Do(line []rune, pos int) ([][]rune, int) {
function memoryUsage (line 128) | func memoryUsage() uint64 {
function humanizeBytes (line 134) | func humanizeBytes(b uint64) string {
FILE: test/bench/bench_call_test.go
type Env (line 11) | type Env struct
function BenchmarkCall_callTyped (line 15) | func BenchmarkCall_callTyped(b *testing.B) {
function BenchmarkCall_eval (line 41) | func BenchmarkCall_eval(b *testing.B) {
FILE: test/coredns/coredns.go
function DefaultEnv (line 9) | func DefaultEnv(ctx context.Context, state *Request) map[string]any {
type Request (line 41) | type Request struct
method NewWithQuestion (line 47) | func (r *Request) NewWithQuestion(name string, typ uint16) Request {
method IP (line 51) | func (r *Request) IP() string {
method LocalIP (line 55) | func (r *Request) LocalIP() string {
method Port (line 59) | func (r *Request) Port() string {
method LocalPort (line 63) | func (r *Request) LocalPort() string {
method RemoteAddr (line 67) | func (r *Request) RemoteAddr() string { return r.W.RemoteAddr().String...
method LocalAddr (line 69) | func (r *Request) LocalAddr() string { return r.W.LocalAddr().String() }
method Proto (line 71) | func (r *Request) Proto() string {
method Family (line 75) | func (r *Request) Family() int {
method Do (line 79) | func (r *Request) Do() bool {
method Len (line 83) | func (r *Request) Len() int { return 0 }
method Size (line 85) | func (r *Request) Size() int {
method SizeAndDo (line 89) | func (r *Request) SizeAndDo(m *Msg) bool {
method Scrub (line 93) | func (r *Request) Scrub(reply *Msg) *Msg {
method Type (line 97) | func (r *Request) Type() string {
method QType (line 101) | func (r *Request) QType() uint16 {
method Name (line 105) | func (r *Request) Name() string {
method QName (line 109) | func (r *Request) QName() string {
method Class (line 113) | func (r *Request) Class() string {
method QClass (line 117) | func (r *Request) QClass() uint16 {
method Clear (line 121) | func (r *Request) Clear() {
method Match (line 124) | func (r *Request) Match(reply *Msg) bool {
type Msg (line 128) | type Msg struct
type MsgHdr (line 137) | type MsgHdr struct
type Question (line 151) | type Question struct
type RR (line 157) | type RR interface
type RR_Header (line 162) | type RR_Header struct
type ResponseWriter (line 170) | type ResponseWriter interface
FILE: test/coredns/coredns_test.go
function TestCoreDNS (line 13) | func TestCoreDNS(t *testing.T) {
FILE: test/crowdsec/crowdsec.go
type Event (line 7) | type Event struct
method GetType (line 26) | func (e *Event) GetType() string {
method GetMeta (line 30) | func (e *Event) GetMeta(key string) string {
type Alert (line 34) | type Alert struct
method HasRemediation (line 58) | func (a *Alert) HasRemediation() bool {
method GetScope (line 62) | func (a *Alert) GetScope() string {
method GetValue (line 66) | func (a *Alert) GetValue() string {
method GetScenario (line 70) | func (a *Alert) GetScenario() string {
method GetEventsCount (line 74) | func (a *Alert) GetEventsCount() int32 {
method GetMeta (line 78) | func (a *Alert) GetMeta(_ string) string {
type AlertEdges (line 94) | type AlertEdges struct
method OwnerOrErr (line 101) | func (e AlertEdges) OwnerOrErr() (*Machine, error) {
method DecisionsOrErr (line 105) | func (e AlertEdges) DecisionsOrErr() ([]*Decision, error) {
method EventsOrErr (line 109) | func (e AlertEdges) EventsOrErr() ([]*Event, error) {
method MetasOrErr (line 113) | func (e AlertEdges) MetasOrErr() ([]*Meta, error) {
type Machine (line 117) | type Machine struct
type MachineEdges (line 134) | type MachineEdges struct
type Decision (line 138) | type Decision struct
type Line (line 151) | type Line struct
type ScopeType (line 160) | type ScopeType struct
type RuntimeAlert (line 165) | type RuntimeAlert struct
method GetSources (line 175) | func (r RuntimeAlert) GetSources() []string {
type Source (line 179) | type Source struct
method GetValue (line 82) | func (s Source) GetValue() string {
method GetScope (line 86) | func (s Source) GetScope() string {
method GetAsNumberName (line 90) | func (s Source) GetAsNumberName() string {
type Meta (line 191) | type Meta
type MetaItems0 (line 193) | type MetaItems0 struct
FILE: test/crowdsec/crowdsec_test.go
function TestCrowdsec (line 14) | func TestCrowdsec(t *testing.T) {
FILE: test/deref/deref_test.go
function TestDeref_binary (line 14) | func TestDeref_binary(t *testing.T) {
function TestDeref_unary (line 48) | func TestDeref_unary(t *testing.T) {
function TestDeref_eval (line 66) | func TestDeref_eval(t *testing.T) {
function TestDeref_emptyCtx (line 79) | func TestDeref_emptyCtx(t *testing.T) {
function TestDeref_emptyCtx_Eval (line 90) | func TestDeref_emptyCtx_Eval(t *testing.T) {
function TestDeref_context_WithValue (line 98) | func TestDeref_context_WithValue(t *testing.T) {
function TestDeref_method_on_int_pointer (line 109) | func TestDeref_method_on_int_pointer(t *testing.T) {
type foo (line 117) | type foo
method Bar (line 119) | func (f *foo) Bar() int {
function TestDeref_multiple_pointers (line 123) | func TestDeref_multiple_pointers(t *testing.T) {
function TestDeref_pointer_of_interface (line 144) | func TestDeref_pointer_of_interface(t *testing.T) {
function TestDeref_nil (line 166) | func TestDeref_nil(t *testing.T) {
function TestDeref_nil_in_pointer_of_interface (line 186) | func TestDeref_nil_in_pointer_of_interface(t *testing.T) {
function TestDeref_commutative (line 207) | func TestDeref_commutative(t *testing.T) {
function TestDeref_fetch_from_interface_mix_pointer (line 243) | func TestDeref_fetch_from_interface_mix_pointer(t *testing.T) {
function TestDeref_func_args (line 258) | func TestDeref_func_args(t *testing.T) {
function TestDeref_struct_func_args (line 275) | func TestDeref_struct_func_args(t *testing.T) {
function TestDeref_ignore_func_args (line 291) | func TestDeref_ignore_func_args(t *testing.T) {
function TestDeref_ignore_struct_func_args (line 308) | func TestDeref_ignore_struct_func_args(t *testing.T) {
function TestDeref_keep_pointer_if_arg_in_interface (line 324) | func TestDeref_keep_pointer_if_arg_in_interface(t *testing.T) {
FILE: test/examples/examples_test.go
function init (line 13) | func init() {
function TestExamples (line 21) | func TestExamples(t *testing.T) {
FILE: test/examples/markdown.go
type CodeBlock (line 8) | type CodeBlock struct
function extractCodeBlocksWithTitle (line 13) | func extractCodeBlocksWithTitle(markdown string) []CodeBlock {
FILE: test/fuzz/fuzz_env.go
function NewEnv (line 9) | func NewEnv() map[string]any {
function Func (line 34) | func Func() expr.Option {
type Foo (line 40) | type Foo struct
method String (line 44) | func (f Foo) String() string {
method Qux (line 48) | func (f Foo) Qux(s string) string {
FILE: test/fuzz/fuzz_test.go
function FuzzExpr (line 16) | func FuzzExpr(f *testing.F) {
FILE: test/gen/env.go
type Foo (line 15) | type Foo struct
method String (line 19) | func (f Foo) String() string {
FILE: test/gen/gen.go
function init (line 52) | func init() {
function main (line 79) | func main() {
type fn (line 138) | type fn
function node (line 140) | func node(depth int) string {
function nilNode (line 172) | func nilNode(_ int) string {
function envNode (line 176) | func envNode(_ int) string {
function floatNode (line 180) | func floatNode(_ int) string {
function integerNode (line 184) | func integerNode(_ int) string {
function stringNode (line 191) | func stringNode(_ int) string {
function booleanNode (line 195) | func booleanNode(_ int) string {
function identifierNode (line 199) | func identifierNode(_ int) string {
function memberNode (line 206) | func memberNode(depth int) string {
function unaryNode (line 221) | func unaryNode(depth int) string {
function binaryNode (line 230) | func binaryNode(depth int) string {
function methodNode (line 234) | func methodNode(depth int) string {
function funcNode (line 246) | func funcNode(_ int) string {
function callNode (line 250) | func callNode(depth int) string {
function pipeNode (line 271) | func pipeNode(depth int) string {
function builtinNode (line 282) | func builtinNode(depth int) string {
function predicateNode (line 295) | func predicateNode(depth int) string {
function pointerNode (line 307) | func pointerNode(_ int) string {
function arrayNode (line 317) | func arrayNode(depth int) string {
function mapNode (line 329) | func mapNode(depth int) string {
function sliceNode (line 341) | func sliceNode(depth int) string {
function conditionalNode (line 350) | func conditionalNode(depth int) string {
function sequenceNode (line 359) | func sequenceNode(depth int) string {
function variableNode (line 373) | func variableNode(depth int) string {
FILE: test/gen/gen_test.go
function TestGenerated (line 16) | func TestGenerated(t *testing.T) {
FILE: test/gen/utils.go
function maybe (line 7) | func maybe() bool {
type list (line 11) | type list
type element (line 13) | type element struct
function oneOf (line 18) | func oneOf[T any](cases []element[T]) T {
function random (line 33) | func random[T any](array []T) T {
FILE: test/interface/interface_method_test.go
type Bar (line 12) | type Bar interface
type FooImpl (line 16) | type FooImpl struct
method Foo (line 18) | func (f FooImpl) Foo() Bar {
type BarImpl (line 22) | type BarImpl struct
method Aba (line 27) | func (b BarImpl) Aba() bool {
method Bar (line 31) | func (b BarImpl) Bar() int {
function TestInterfaceMethod (line 35) | func TestInterfaceMethod(t *testing.T) {
FILE: test/interface/interface_test.go
type StoreInterface (line 10) | type StoreInterface interface
type StoreImpt (line 14) | type StoreImpt struct
method Get (line 16) | func (f StoreImpt) Get(s string) int {
method Set (line 20) | func (f StoreImpt) Set(s string, i int) bool {
type Env (line 24) | type Env struct
function TestInterfaceHide (line 28) | func TestInterfaceHide(t *testing.T) {
FILE: test/issues/461/issue_test.go
function TestIssue461 (line 10) | func TestIssue461(t *testing.T) {
FILE: test/issues/567/issue_test.go
function TestIssue567 (line 12) | func TestIssue567(t *testing.T) {
FILE: test/issues/688/issue_test.go
type Foo (line 10) | type Foo interface
type FooImpl (line 14) | type FooImpl struct
method Add (line 17) | func (*FooImpl) Add(a int, b *int) int {
type Env (line 21) | type Env struct
method Any (line 25) | func (Env) Any(x any) any {
function TestNoInterfaceMethodWithNil (line 29) | func TestNoInterfaceMethodWithNil(t *testing.T) {
function TestNoInterfaceMethodWithNil_with_env (line 37) | func TestNoInterfaceMethodWithNil_with_env(t *testing.T) {
function TestNoInterfaceMethodWithNil_with_any (line 45) | func TestNoInterfaceMethodWithNil_with_any(t *testing.T) {
FILE: test/issues/723/issue_test.go
function TestIssue723 (line 10) | func TestIssue723(t *testing.T) {
FILE: test/issues/730/issue_test.go
type ModeEnum (line 10) | type ModeEnum
constant ModeEnumA (line 13) | ModeEnumA ModeEnum = 1
type Env (line 16) | type Env struct
function TestIssue730 (line 20) | func TestIssue730(t *testing.T) {
function TestIssue730_warn_about_different_types (line 37) | func TestIssue730_warn_about_different_types(t *testing.T) {
function TestIssue730_eval (line 45) | func TestIssue730_eval(t *testing.T) {
FILE: test/issues/739/issue_test.go
function TestIssue739 (line 10) | func TestIssue739(t *testing.T) {
FILE: test/issues/756/issue_test.go
type X (line 11) | type X struct
method HelloCtx (line 13) | func (x *X) HelloCtx(ctx context.Context, text string) error {
function TestIssue756 (line 17) | func TestIssue756(t *testing.T) {
FILE: test/issues/785/issue_test.go
function TestIssue785 (line 10) | func TestIssue785(t *testing.T) {
FILE: test/issues/817/issue_test.go
function TestIssue817_1 (line 11) | func TestIssue817_1(t *testing.T) {
function TestIssue817_2 (line 22) | func TestIssue817_2(t *testing.T) {
FILE: test/issues/819/issue_test.go
function TestIssue819 (line 10) | func TestIssue819(t *testing.T) {
FILE: test/issues/823/issue_test.go
type env (line 12) | type env struct
function TestIssue823 (line 19) | func TestIssue823(t *testing.T) {
type envWithMethods (line 61) | type envWithMethods struct
method Now2 (line 65) | func (e *envWithMethods) Now2(ctx context.Context) time.Time {
method Date2 (line 69) | func (e *envWithMethods) Date2(ctx context.Context) time.Time {
function TestIssue823_EnvMethods (line 73) | func TestIssue823_EnvMethods(t *testing.T) {
Condensed preview — 230 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (3,159K chars).
[
{
"path": ".gitattributes",
"chars": 40,
"preview": "*\\[generated\\].go linguist-language=txt\n"
},
{
"path": ".github/FUNDING.yml",
"chars": 18,
"preview": "github: antonmedv\n"
},
{
"path": ".github/images/demo.tape",
"chars": 761,
"preview": "Set Shell zsh\nSleep 500ms\nType \"repl\"\nEnter\nSleep 500ms\nType \"1..9 | filter(\"\nSleep 500ms\nType \"# \"\nSleep 500ms\nType \"% "
},
{
"path": ".github/scripts/coverage.mjs",
"chars": 1470,
"preview": "#!/usr/bin/env zx\n\nconst expected = 90\nconst exclude = [\n 'expr/test', // We do not need to test the test package.\n 'c"
},
{
"path": ".github/workflows/build.yml",
"chars": 511,
"preview": "name: build\n\non:\n push:\n branches: [ master ]\n pull_request:\n branches: [ master ]\n\njobs:\n test:\n runs-on: u"
},
{
"path": ".github/workflows/check.yml",
"chars": 353,
"preview": "name: check\n\non:\n push:\n branches: [ master ]\n pull_request:\n branches: [ master ]\n\njobs:\n coverage:\n runs-o"
},
{
"path": ".github/workflows/diff.yml",
"chars": 982,
"preview": "name: diff\n\non:\n pull_request:\n branches: [ master ]\n\njobs:\n bench:\n runs-on: ubuntu-latest\n steps:\n - n"
},
{
"path": ".github/workflows/fuzz.yml",
"chars": 1080,
"preview": "name: fuzz\non: [pull_request]\npermissions: {}\njobs:\n fuzzing:\n runs-on: ubuntu-latest\n permissions:\n securit"
},
{
"path": ".github/workflows/test.yml",
"chars": 990,
"preview": "name: test\n\non:\n push:\n branches: [ master ]\n pull_request:\n branches: [ master ]\n\njobs:\n test:\n runs-on: ub"
},
{
"path": ".gitignore",
"chars": 85,
"preview": "*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n*.test\n*.out\n*.html\ncustom_tests.json\npro/\ntest/avs/\n"
},
{
"path": "LICENSE",
"chars": 1071,
"preview": "MIT License\n\nCopyright (c) 2018 Anton Medvedev\n\nPermission is hereby granted, free of charge, to any person obtaining a "
},
{
"path": "README.md",
"chars": 7818,
"preview": "<h1><a href=\"https://expr-lang.org\"><img src=\"https://expr-lang.org/img/logo.png\" alt=\"Zx logo\" height=\"48\"align=\"right\""
},
{
"path": "SECURITY.md",
"chars": 798,
"preview": "# Security Policy\n\n## Supported Versions\n\nExpr is generally backwards compatible with very few exceptions, so we\nrecomme"
},
{
"path": "ast/dump.go",
"chars": 1165,
"preview": "package ast\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n)\n\nfunc Dump(node Node) string {\n\treturn dump(reflect.ValueOf(node), \""
},
{
"path": "ast/find.go",
"chars": 261,
"preview": "package ast\n\nfunc Find(node Node, fn func(node Node) bool) Node {\n\tv := &finder{fn: fn}\n\tWalk(&node, v)\n\treturn v.node\n}"
},
{
"path": "ast/find_test.go",
"chars": 507,
"preview": "package ast_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/require\"\n\n\t\"github.com/expr-lang/exp"
},
{
"path": "ast/node.go",
"chars": 6245,
"preview": "package ast\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/expr-lang/expr/checker/nature\"\n\t\"github.com/expr-lang/expr/file\"\n)\n\nvar ("
},
{
"path": "ast/print.go",
"chars": 6310,
"preview": "package ast\n\nimport (\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/expr-lang/expr/parser/operator\"\n\t\"github.com/expr"
},
{
"path": "ast/print_test.go",
"chars": 3430,
"preview": "package ast_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\t\"github.com/expr-lang/expr/"
},
{
"path": "ast/visitor.go",
"chars": 1395,
"preview": "package ast\n\nimport \"fmt\"\n\ntype Visitor interface {\n\tVisit(node *Node)\n}\n\nfunc Walk(node *Node, v Visitor) {\n\tif *node ="
},
{
"path": "ast/visitor_test.go",
"chars": 1143,
"preview": "package ast_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\n\t\"github.com/expr-lang/expr"
},
{
"path": "bench_test.go",
"chars": 14131,
"preview": "package expr_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/require\"\n\n\t\"github.com/expr-lang/ex"
},
{
"path": "builtin/builtin.go",
"chars": 27329,
"preview": "package builtin\n\nimport (\n\t\"encoding/base64\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t\""
},
{
"path": "builtin/builtin_test.go",
"chars": 27064,
"preview": "package builtin_test\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/expr-lang/expr/internal/tes"
},
{
"path": "builtin/function.go",
"chars": 470,
"preview": "package builtin\n\nimport (\n\t\"reflect\"\n)\n\ntype Function struct {\n\tName string\n\tFast func(arg any) any\n\tFunc "
},
{
"path": "builtin/lib.go",
"chars": 14104,
"preview": "package builtin\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"reflect\"\n\t\"strconv\"\n\t\"unicode/utf8\"\n\n\t\"github.com/expr-lang/expr/internal/der"
},
{
"path": "builtin/utils.go",
"chars": 1863,
"preview": "package builtin\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/expr-lang/expr/internal/deref\"\n)\n\nvar (\n\tanyType "
},
{
"path": "builtin/validation.go",
"chars": 1298,
"preview": "package builtin\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/expr-lang/expr/internal/deref\"\n)\n\nfunc validateAggregateFunc(n"
},
{
"path": "checker/checker.go",
"chars": 38927,
"preview": "package checker\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"time\"\n\n\t\"github.com/expr-lang/expr/ast\"\n\t\"github.com/expr-lang/e"
},
{
"path": "checker/checker_bench_test.go",
"chars": 3265,
"preview": "package checker_test\n\nimport (\n\t\"runtime\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/ast\"\n\t\"gi"
},
{
"path": "checker/checker_test.go",
"chars": 24591,
"preview": "package checker_test\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr"
},
{
"path": "checker/info.go",
"chars": 2809,
"preview": "package checker\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/expr-lang/expr/ast\"\n\t. \"github.com/expr-lang/expr/checker/nature\"\n\t\"g"
},
{
"path": "checker/info_test.go",
"chars": 580,
"preview": "package checker_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/expr-lang/expr/internal/testify/require\"\n\n\t\"g"
},
{
"path": "checker/nature/nature.go",
"chars": 12975,
"preview": "package nature\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/expr-lang/expr/builtin\"\n\t\"github.com/expr-lang/expr/int"
},
{
"path": "checker/nature/utils.go",
"chars": 5519,
"preview": "package nature\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/expr-lang/expr/internal/deref\"\n)\n\nfunc fieldName(fieldName string, tag"
},
{
"path": "compiler/compiler.go",
"chars": 29945,
"preview": "package compiler\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"runtime/debug\"\n\n\t\"github.com/expr-lang/expr/ast\"\n\t\"gith"
},
{
"path": "compiler/compiler_test.go",
"chars": 13148,
"preview": "package compiler_test\n\nimport (\n\t\"math\"\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\t\"gi"
},
{
"path": "conf/config.go",
"chars": 2531,
"preview": "package conf\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/expr-lang/expr/ast\"\n\t\"github.com/expr-lang/expr/builtin\"\n\t\"github"
},
{
"path": "conf/env.go",
"chars": 1391,
"preview": "package conf\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\n\t. \"github.com/expr-lang/expr/checker/nature\"\n\t\"github.com/expr-lang/expr/inte"
},
{
"path": "debug/debugger.go",
"chars": 4509,
"preview": "package debug\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/gdamore/tcell/v2\"\n\t\"github.com/rivo/tvi"
},
{
"path": "debug/go.mod",
"chars": 557,
"preview": "module github.com/expr-lang/expr/debug\n\ngo 1.18\n\nrequire (\n\tgithub.com/expr-lang/expr v0.0.0\n\tgithub.com/gdamore/tcell/v"
},
{
"path": "debug/go.sum",
"chars": 4417,
"preview": "github.com/gdamore/encoding v1.0.0 h1:+7OoQ1Bc6eTm5niUzBa0Ctsh6JbMW6Ra+YNuAtDBdko=\ngithub.com/gdamore/encoding v1.0.0/go"
},
{
"path": "docgen/README.md",
"chars": 743,
"preview": "# DocGen\n\nThis package provides documentation generator with JSON or Markdown output.\n\n## Usage\n\nCreate a file and put n"
},
{
"path": "docgen/docgen.go",
"chars": 8456,
"preview": "package docgen\n\nimport (\n\t\"reflect\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/expr-lang/expr/checker/nature\"\n\t\"github.com/expr-"
},
{
"path": "docgen/docgen_test.go",
"chars": 4578,
"preview": "package docgen_test\n\nimport (\n\t\"math\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\t\"github."
},
{
"path": "docgen/markdown.go",
"chars": 2351,
"preview": "package docgen\n\nimport (\n\t\"fmt\"\n\t\"sort\"\n\t\"strings\"\n)\n\nfunc (c *Context) Markdown() string {\n\tvar variables []string\n\tfor"
},
{
"path": "docs/configuration.md",
"chars": 4570,
"preview": "# Configuration\n\n## Return type\n\nUsually, the return type of expression is anything. But we can instruct type checker to"
},
{
"path": "docs/environment.md",
"chars": 2841,
"preview": "# Environment\n\nThe environment is a map or a struct that contains the variables and functions that the expression can ac"
},
{
"path": "docs/functions.md",
"chars": 2114,
"preview": "# Functions\n\nExpr comes with a set of [builtin](language-definition.md) functions, but you can also define your own func"
},
{
"path": "docs/getting-started.md",
"chars": 3917,
"preview": "# Getting Started\n\n**Expr** is a simple, fast and extensible expression language for Go. It is\ndesigned to be easy to us"
},
{
"path": "docs/language-definition.md",
"chars": 21860,
"preview": "# Language Definition\n\n**Expr** is a simple expression language that can be used to evaluate expressions.\n\n## Literals\n\n"
},
{
"path": "docs/patch.md",
"chars": 3891,
"preview": "# Patch\n\nSometimes it may be necessary to modify an expression before the compilation.\nFor example, you may want to repl"
},
{
"path": "docs/visitor.md",
"chars": 1565,
"preview": "# Visitor\n\nExpr provides an interface to traverse the <span title=\"Abstract Syntax Tree\" style={{borderBottom: \"1px dott"
},
{
"path": "expr.go",
"chars": 6954,
"preview": "package expr\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"time\"\n\n\t\"github.com/expr-lang/expr/ast\"\n\t\"github.com/expr-lang/expr"
},
{
"path": "expr_test.go",
"chars": 57925,
"preview": "package expr_test\n\nimport (\n\t\"context\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"os\"\n\t\"reflect\"\n\t\"strings\"\n\t\"sync\"\n\t\"testing\"\n\t\"time\"\n\n\t"
},
{
"path": "file/error.go",
"chars": 1491,
"preview": "package file\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n)\n\ntype Error struct {\n\tLocation\n\tLine int `json:\"line\"`\n\tColumn int "
},
{
"path": "file/location.go",
"chars": 85,
"preview": "package file\n\ntype Location struct {\n\tFrom int `json:\"from\"`\n\tTo int `json:\"to\"`\n}\n"
},
{
"path": "file/source.go",
"chars": 571,
"preview": "package file\n\nimport \"strings\"\n\ntype Source struct {\n\traw string\n}\n\nfunc NewSource(contents string) Source {\n\treturn Sou"
},
{
"path": "file/source_test.go",
"chars": 1623,
"preview": "package file\n\nimport (\n\t\"testing\"\n)\n\nconst (\n\tunexpectedSnippet = \"%s got snippet '%s', want '%v'\"\n\tsnippetNotFound = "
},
{
"path": "go.mod",
"chars": 42,
"preview": "module github.com/expr-lang/expr\n\ngo 1.18\n"
},
{
"path": "internal/deref/deref.go",
"chars": 848,
"preview": "package deref\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n)\n\nfunc Interface(p any) any {\n\tif p == nil {\n\t\treturn nil\n\t}\n\n\tv := reflect.V"
},
{
"path": "internal/deref/deref_test.go",
"chars": 2017,
"preview": "package deref_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\n\t\"github.com/e"
},
{
"path": "internal/difflib/difflib.go",
"chars": 22868,
"preview": "// Package difflib is a partial port of Python difflib module.\n//\n// It provides tools to compare sequences of strings a"
},
{
"path": "internal/difflib/difflib_test.go",
"chars": 10402,
"preview": "package difflib\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"math\"\n\t\"reflect\"\n\t\"strings\"\n\t\"testing\"\n)\n\nfunc assertAlmostEqual(t *testing."
},
{
"path": "internal/ring/ring.go",
"chars": 1898,
"preview": "package ring\n\n// Ring is a very simple ring buffer implementation that uses a slice. The\n// internal slice will only gro"
},
{
"path": "internal/ring/ring_test.go",
"chars": 4536,
"preview": "package ring\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n)\n\nfunc TestRing(t *testing.T) {\n\ttype op = ringOp[int]\n\ttestRing(t, New[int](3"
},
{
"path": "internal/spew/bypass.go",
"chars": 4780,
"preview": "// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>\n//\n// Permission to use, copy, modify, and distribute this sof"
},
{
"path": "internal/spew/bypasssafe.go",
"chars": 1803,
"preview": "// Copyright (c) 2015-2016 Dave Collins <dave@davec.name>\n//\n// Permission to use, copy, modify, and distribute this sof"
},
{
"path": "internal/spew/common.go",
"chars": 10362,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "internal/spew/common_test.go",
"chars": 7941,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "internal/spew/config.go",
"chars": 12840,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "internal/spew/doc.go",
"chars": 8624,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "internal/spew/dump.go",
"chars": 13803,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "internal/spew/dump_test.go",
"chars": 33789,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "internal/spew/dumpcgo_test.go",
"chars": 4028,
"preview": "// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n//\n// Permission to use, copy, modify, and distribute this sof"
},
{
"path": "internal/spew/dumpnocgo_test.go",
"chars": 1247,
"preview": "// Copyright (c) 2013 Dave Collins <dave@davec.name>\n//\n// Permission to use, copy, modify, and distribute this software"
},
{
"path": "internal/spew/example_test.go",
"chars": 5588,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "internal/spew/format.go",
"chars": 11311,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "internal/spew/format_test.go",
"chars": 57474,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "internal/spew/internal_test.go",
"chars": 2541,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "internal/spew/internalunsafe_test.go",
"chars": 3288,
"preview": "// Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n\n// Permission to use, copy, modify, and distribute this softw"
},
{
"path": "internal/spew/spew.go",
"chars": 5969,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "internal/spew/spew_test.go",
"chars": 9649,
"preview": "/*\n * Copyright (c) 2013-2016 Dave Collins <dave@davec.name>\n *\n * Permission to use, copy, modify, and distribute this "
},
{
"path": "internal/spew/testdata/dumpcgo.go",
"chars": 3312,
"preview": "// Copyright (c) 2013 Dave Collins <dave@davec.name>\n//\n// Permission to use, copy, modify, and distribute this software"
},
{
"path": "internal/testify/assert/assertion_compare.go",
"chars": 12446,
"preview": "package assert\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"time\"\n)\n\n// Deprecated: CompareType has only ever been for interna"
},
{
"path": "internal/testify/assert/assertion_compare_test.go",
"chars": 17595,
"preview": "package assert\n\nimport (\n\t\"bytes\"\n\t\"fmt\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestCompare(t *testing.T) {\n\tt"
},
{
"path": "internal/testify/assert/assertion_format.go",
"chars": 32948,
"preview": "// Code generated with github.com/expr-lang/expr/internal/_codegen; DO NOT EDIT.\n\npackage assert\n\nimport (\n\thttp \"net/ht"
},
{
"path": "internal/testify/assert/assertion_format.go.tmpl",
"chars": 184,
"preview": "{{.CommentFormat}}\nfunc {{.DocInfo.Name}}f(t TestingT, {{.ParamsFormat}}) bool {\n\tif h, ok := t.(tHelper); ok { h.Helper"
},
{
"path": "internal/testify/assert/assertion_forward.go",
"chars": 58582,
"preview": "// Code generated with github.com/expr-lang/expr/internal/_codegen; DO NOT EDIT.\n\npackage assert\n\nimport (\n\thttp \"net/ht"
},
{
"path": "internal/testify/assert/assertion_forward.go.tmpl",
"chars": 185,
"preview": "{{.CommentWithoutT \"a\"}}\nfunc (a *Assertions) {{.DocInfo.Name}}({{.Params}}) bool {\n\tif h, ok := a.t.(tHelper); ok { h.H"
},
{
"path": "internal/testify/assert/assertion_order.go",
"chars": 2789,
"preview": "package assert\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n)\n\n// isOrdered checks that collection contains orderable elements.\nfunc isOr"
},
{
"path": "internal/testify/assert/assertion_order_test.go",
"chars": 7717,
"preview": "package assert\n\nimport (\n\t\"bytes\"\n\t\"testing\"\n)\n\nfunc TestIsIncreasing(t *testing.T) {\n\tmockT := new(testing.T)\n\n\tif !IsI"
},
{
"path": "internal/testify/assert/assertions.go",
"chars": 60170,
"preview": "package assert\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"math\"\n\t\"os\"\n\t\"reflect\"\n\t\"regexp\"\n\t\"runtim"
},
{
"path": "internal/testify/assert/assertions_test.go",
"chars": 80524,
"preview": "package assert\n\nimport (\n\t\"bufio\"\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"refl"
},
{
"path": "internal/testify/assert/doc.go",
"chars": 1359,
"preview": "// Package assert provides a set of comprehensive testing tools for use with the normal Go testing system.\n//\n// # Examp"
},
{
"path": "internal/testify/assert/errors.go",
"chars": 326,
"preview": "package assert\n\nimport (\n\t\"errors\"\n)\n\n// AnError is an error instance useful for testing. If the code does not care\n// "
},
{
"path": "internal/testify/assert/forward_assertions.go",
"chars": 428,
"preview": "package assert\n\n// Assertions provides assertion methods around the\n// TestingT interface.\ntype Assertions struct {\n\tt T"
},
{
"path": "internal/testify/assert/forward_assertions_test.go",
"chars": 18524,
"preview": "package assert\n\nimport (\n\t\"errors\"\n\t\"regexp\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestImplementsWrapper(t *testing.T) {\n\tassert :="
},
{
"path": "internal/testify/assert/http_assertions.go",
"chars": 5748,
"preview": "package assert\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"net/http/httptest\"\n\t\"net/url\"\n\t\"strings\"\n)\n\n// httpCode is a helper that r"
},
{
"path": "internal/testify/assert/http_assertions_test.go",
"chars": 7284,
"preview": "package assert\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"net/http\"\n\t\"net/url\"\n\t\"testing\"\n)\n\nfunc httpOK(w http.ResponseWriter, r *http.Re"
},
{
"path": "internal/testify/assert/internal/unsafetests/doc.go",
"chars": 152,
"preview": "// This package exists just to isolate tests that reference the [unsafe] package.\n//\n// The tests in this package are to"
},
{
"path": "internal/testify/assert/internal/unsafetests/unsafetests_test.go",
"chars": 1040,
"preview": "package unsafetests_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"unsafe\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n)\n\n"
},
{
"path": "internal/testify/require/doc.go",
"chars": 871,
"preview": "// Package require implements the same assertions as the `assert` package but\n// stops test execution when a test fails."
},
{
"path": "internal/testify/require/forward_requirements.go",
"chars": 428,
"preview": "package require\n\n// Assertions provides assertion methods around the\n// TestingT interface.\ntype Assertions struct {\n\tt "
},
{
"path": "internal/testify/require/forward_requirements_test.go",
"chars": 8747,
"preview": "package require\n\nimport (\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n)\n\nfunc TestImplementsWrapper(t *testing.T) {\n\trequire := New(t)\n"
},
{
"path": "internal/testify/require/require.go",
"chars": 62520,
"preview": "// Code generated with github.com/expr-lang/expr/internal/_codegen; DO NOT EDIT.\n\npackage require\n\nimport (\n\thttp \"net/h"
},
{
"path": "internal/testify/require/require.go.tmpl",
"chars": 187,
"preview": "{{.Comment}}\nfunc {{.DocInfo.Name}}(t TestingT, {{.Params}}) {\n\tif h, ok := t.(tHelper); ok { h.Helper() }\n\tif assert.{{"
},
{
"path": "internal/testify/require/require_forward.go",
"chars": 57000,
"preview": "// Code generated with github.com/expr-lang/expr/internal/_codegen; DO NOT EDIT.\n\npackage require\n\nimport (\n\thttp \"net/h"
},
{
"path": "internal/testify/require/require_forward.go.tmpl",
"chars": 173,
"preview": "{{.CommentWithoutT \"a\"}}\nfunc (a *Assertions) {{.DocInfo.Name}}({{.Params}}) {\n\tif h, ok := a.t.(tHelper); ok { h.Helper"
},
{
"path": "internal/testify/require/requirements.go",
"chars": 1133,
"preview": "package require\n\n// TestingT is an interface wrapper around *testing.T\ntype TestingT interface {\n\tErrorf(format string, "
},
{
"path": "internal/testify/require/requirements_test.go",
"chars": 11712,
"preview": "package require\n\nimport (\n\t\"encoding/json\"\n\t\"errors\"\n\t\"testing\"\n\t\"time\"\n)\n\n// AssertionTesterInterface defines an interf"
},
{
"path": "optimizer/const_expr.go",
"chars": 1869,
"preview": "package optimizer\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\n\t. \"github.com/expr-lang/expr/ast\"\n\t\"github.com/expr-lang/expr"
},
{
"path": "optimizer/count_any.go",
"chars": 755,
"preview": "package optimizer\n\nimport (\n\t. \"github.com/expr-lang/expr/ast\"\n)\n\n// countAny optimizes count comparisons to use any for"
},
{
"path": "optimizer/count_any_test.go",
"chars": 3965,
"preview": "package optimizer_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t. \"github.com/expr-lang/expr/ast\"\n\t\"github.co"
},
{
"path": "optimizer/count_threshold.go",
"chars": 1359,
"preview": "package optimizer\n\nimport (\n\t. \"github.com/expr-lang/expr/ast\"\n)\n\n// countThreshold optimizes count comparisons by setti"
},
{
"path": "optimizer/count_threshold_test.go",
"chars": 9027,
"preview": "package optimizer_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t. \"github.com/expr-lang/expr/ast\"\n\t\"github.co"
},
{
"path": "optimizer/filter_first.go",
"chars": 1047,
"preview": "package optimizer\n\nimport (\n\t. \"github.com/expr-lang/expr/ast\"\n)\n\ntype filterFirst struct{}\n\nfunc (*filterFirst) Visit(n"
},
{
"path": "optimizer/filter_last.go",
"chars": 1053,
"preview": "package optimizer\n\nimport (\n\t. \"github.com/expr-lang/expr/ast\"\n)\n\ntype filterLast struct{}\n\nfunc (*filterLast) Visit(nod"
},
{
"path": "optimizer/filter_len.go",
"chars": 450,
"preview": "package optimizer\n\nimport (\n\t. \"github.com/expr-lang/expr/ast\"\n)\n\ntype filterLen struct{}\n\nfunc (*filterLen) Visit(node "
},
{
"path": "optimizer/filter_map.go",
"chars": 817,
"preview": "package optimizer\n\nimport (\n\t. \"github.com/expr-lang/expr/ast\"\n)\n\ntype filterMap struct{}\n\nfunc (*filterMap) Visit(node "
},
{
"path": "optimizer/filter_map_test.go",
"chars": 2487,
"preview": "package optimizer_test\n\nimport (\n\t\"testing\"\n\n\t. \"github.com/expr-lang/expr/ast\"\n\t\"github.com/expr-lang/expr/internal/tes"
},
{
"path": "optimizer/fold.go",
"chars": 7308,
"preview": "package optimizer\n\nimport (\n\t\"math\"\n\n\t. \"github.com/expr-lang/expr/ast\"\n\t\"github.com/expr-lang/expr/file\"\n)\n\ntype fold s"
},
{
"path": "optimizer/fold_test.go",
"chars": 2034,
"preview": "package optimizer_test\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/ast\"\n\t\"github.com/expr-lang/expr/int"
},
{
"path": "optimizer/in_array.go",
"chars": 1527,
"preview": "package optimizer\n\nimport (\n\t\"reflect\"\n\n\t. \"github.com/expr-lang/expr/ast\"\n)\n\ntype inArray struct{}\n\nfunc (*inArray) Vis"
},
{
"path": "optimizer/in_range.go",
"chars": 816,
"preview": "package optimizer\n\nimport (\n\t\"reflect\"\n\n\t. \"github.com/expr-lang/expr/ast\"\n)\n\ntype inRange struct{}\n\nfunc (*inRange) Vis"
},
{
"path": "optimizer/optimizer.go",
"chars": 1687,
"preview": "package optimizer\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\n\t. \"github.com/expr-lang/expr/ast\"\n\t\"github.com/expr-lang/expr/conf\"\n)\n\nf"
},
{
"path": "optimizer/optimizer_test.go",
"chars": 12109,
"preview": "package optimizer_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\t\"gi"
},
{
"path": "optimizer/predicate_combination.go",
"chars": 1718,
"preview": "package optimizer\n\nimport (\n\t. \"github.com/expr-lang/expr/ast\"\n\t\"github.com/expr-lang/expr/parser/operator\"\n)\n\n/*\npredic"
},
{
"path": "optimizer/sum_array.go",
"chars": 828,
"preview": "package optimizer\n\nimport (\n\t\"fmt\"\n\n\t. \"github.com/expr-lang/expr/ast\"\n)\n\ntype sumArray struct{}\n\nfunc (*sumArray) Visit"
},
{
"path": "optimizer/sum_array_test.go",
"chars": 1555,
"preview": "package optimizer_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\t\"github.com/expr-lang"
},
{
"path": "optimizer/sum_map.go",
"chars": 535,
"preview": "package optimizer\n\nimport (\n\t. \"github.com/expr-lang/expr/ast\"\n)\n\ntype sumMap struct{}\n\nfunc (*sumMap) Visit(node *Node)"
},
{
"path": "optimizer/sum_map_test.go",
"chars": 779,
"preview": "package optimizer_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\t\"github.com/expr-lang"
},
{
"path": "optimizer/sum_range.go",
"chars": 5253,
"preview": "package optimizer\n\nimport (\n\t. \"github.com/expr-lang/expr/ast\"\n)\n\ntype sumRange struct{}\n\nfunc (*sumRange) Visit(node *N"
},
{
"path": "optimizer/sum_range_test.go",
"chars": 7279,
"preview": "package optimizer_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/ast\"\n\t\"github.com/"
},
{
"path": "parser/bench_test.go",
"chars": 383,
"preview": "package parser\n\nimport \"testing\"\n\nfunc BenchmarkParser(b *testing.B) {\n\tconst source = `\n\t\t/*\n\t\t\tShowing worst case scen"
},
{
"path": "parser/lexer/lexer.go",
"chars": 5885,
"preview": "package lexer\n\nimport (\n\t\"fmt\"\n\t\"io\"\n\t\"strings\"\n\t\"unicode/utf8\"\n\n\t\"github.com/expr-lang/expr/file\"\n\t\"github.com/expr-lan"
},
{
"path": "parser/lexer/lexer_test.go",
"chars": 10125,
"preview": "package lexer_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/file\"\n\t\"github.com/expr-lang/expr"
},
{
"path": "parser/lexer/state.go",
"chars": 4293,
"preview": "package lexer\n\nimport (\n\t\"strings\"\n\n\t\"github.com/expr-lang/expr/parser/utils\"\n)\n\ntype stateFn func(*Lexer) stateFn\n\nfunc"
},
{
"path": "parser/lexer/token.go",
"chars": 682,
"preview": "package lexer\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/expr-lang/expr/file\"\n)\n\ntype Kind string\n\nconst (\n\tIdentifier Kind = \"Ident"
},
{
"path": "parser/lexer/utils.go",
"chars": 8627,
"preview": "package lexer\n\nimport (\n\t\"fmt\"\n\t\"math\"\n\t\"strings\"\n\t\"unicode/utf8\"\n)\n\nvar (\n\tnewlineNormalizer = strings.NewReplacer(\"\\r\\"
},
{
"path": "parser/operator/operator.go",
"chars": 1439,
"preview": "package operator\n\ntype Associativity int\n\nconst (\n\tLeft Associativity = iota + 1\n\tRight\n)\n\ntype Operator struct {\n\tPrece"
},
{
"path": "parser/parser.go",
"chars": 21012,
"preview": "package parser\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"math\"\n\t\"strconv\"\n\t\"strings\"\n\n\t. \"github.com/expr-lang/expr/ast\"\n\t\"gith"
},
{
"path": "parser/parser_test.go",
"chars": 29659,
"preview": "package parser_test\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/conf\"\n\t\"github.com/expr-lang/exp"
},
{
"path": "parser/utils/utils.go",
"chars": 536,
"preview": "package utils\n\nimport (\n\t\"unicode\"\n\t\"unicode/utf8\"\n)\n\nfunc IsValidIdentifier(str string) bool {\n\tif len(str) == 0 {\n\t\tre"
},
{
"path": "patcher/operator_override.go",
"chars": 4172,
"preview": "package patcher\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\n\t\"github.com/expr-lang/expr/ast\"\n\t\"github.com/expr-lang/expr/builtin\"\n\t\"git"
},
{
"path": "patcher/value/bench_test.go",
"chars": 1471,
"preview": "package value\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/require\"\n\n\t\"github.com/expr-lang/expr\"\n"
},
{
"path": "patcher/value/value.go",
"chars": 5539,
"preview": "// Package value provides a Patcher that uses interfaces to allow custom types that can be represented as standard go va"
},
{
"path": "patcher/value/value_example_test.go",
"chars": 609,
"preview": "package value_test\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/patcher/value\"\n\t\"github.co"
},
{
"path": "patcher/value/value_test.go",
"chars": 3439,
"preview": "package value\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/require\"\n\n\t\"github.com/expr-lang/expr\"\n"
},
{
"path": "patcher/with_context.go",
"chars": 1976,
"preview": "package patcher\n\nimport (\n\t\"reflect\"\n\n\t\"github.com/expr-lang/expr/ast\"\n\t\"github.com/expr-lang/expr/checker/nature\"\n\t\"git"
},
{
"path": "patcher/with_context_test.go",
"chars": 3220,
"preview": "package patcher_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/require\"\n\n\t\"github.co"
},
{
"path": "patcher/with_timezone.go",
"chars": 511,
"preview": "package patcher\n\nimport (\n\t\"time\"\n\n\t\"github.com/expr-lang/expr/ast\"\n)\n\n// WithTimezone passes Location to date() and now"
},
{
"path": "patcher/with_timezone_test.go",
"chars": 725,
"preview": "package patcher_test\n\nimport (\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/expr-lang/expr/internal/testify/require\"\n\n\t\"github.com/e"
},
{
"path": "repl/go.mod",
"chars": 783,
"preview": "module github.com/expr-lang/expr/repl\n\ngo 1.20\n\nrequire (\n\tgithub.com/bettercap/readline v0.0.0-20210228151553-655e48bcb"
},
{
"path": "repl/go.sum",
"chars": 4978,
"preview": "github.com/bettercap/readline v0.0.0-20210228151553-655e48bcb7bf h1:pwGPRc5PIp4KCF9QbKn0iLVMhfigUMw4IzGZEZ81m1I=\ngithub."
},
{
"path": "repl/repl.go",
"chars": 2666,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"os\"\n\t\"runtime\"\n\t\"strings\"\n\n\t\"github.com/expr-lang/expr/test/fuzz\"\n\n\t\"github.com/betterca"
},
{
"path": "test/bench/bench_call_test.go",
"chars": 1035,
"preview": "package bench_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/requi"
},
{
"path": "test/coredns/coredns.go",
"chars": 3099,
"preview": "package coredns\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"net\"\n)\n\nfunc DefaultEnv(ctx context.Context, state *Request) map[string"
},
{
"path": "test/coredns/coredns_test.go",
"chars": 822,
"preview": "package coredns_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\n\t\"github.com"
},
{
"path": "test/crowdsec/crowdsec.go",
"chars": 6481,
"preview": "package crowdsec\n\nimport (\n\t\"time\"\n)\n\ntype Event struct {\n\tType int `yaml:\"Type,omitempty\" json"
},
{
"path": "test/crowdsec/crowdsec_test.go",
"chars": 842,
"preview": "package crowdsec_test\n\nimport (\n\t\"encoding/json\"\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/require\""
},
{
"path": "test/crowdsec/funcs.go",
"chars": 4932,
"preview": "package crowdsec\n\nimport (\n\t\"time\"\n)\n\nvar CustomFunctions = []struct {\n\tName string\n\tFunc []any\n}{\n\t{\n\t\tName: \"Distance\""
},
{
"path": "test/deref/deref_test.go",
"chars": 7232,
"preview": "package deref_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\t\"githu"
},
{
"path": "test/examples/examples_test.go",
"chars": 590,
"preview": "package main\n\nimport (\n\t\"os\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/requi"
},
{
"path": "test/examples/markdown.go",
"chars": 1384,
"preview": "package main\n\nimport (\n\t\"strings\"\n)\n\n// CodeBlock holds the optional title and content of a code block.\ntype CodeBlock s"
},
{
"path": "test/fuzz/fuzz_corpus.sh",
"chars": 327,
"preview": "#!/bin/bash\n\ninputfile=./fuzz_corpus.txt\nzipname=fuzz_expr_seed_corpus.zip\n\nif [ ! -f \"$inputfile\" ]; then\n echo \"Error"
},
{
"path": "test/fuzz/fuzz_corpus.txt",
"chars": 370597,
"preview": "!!!false\n!!(1 <= f64)\n!!(1 > 0.5)\n!!(i64 != f64)\n!!all(array, ok)\n!!false\n!!ok\n!!true\n!(\"bar\" != \"bar\")\n!(\"bar\" != \"foo\""
},
{
"path": "test/fuzz/fuzz_env.go",
"chars": 926,
"preview": "package fuzz\n\nimport (\n\t\"fmt\"\n\n\t\"github.com/expr-lang/expr\"\n)\n\nfunc NewEnv() map[string]any {\n\treturn map[string]any{\n\t\t"
},
{
"path": "test/fuzz/fuzz_expr.dict",
"chars": 693,
"preview": "\"{\"\n\"}\"\n\",\"\n\"[\"\n\"]\"\n\"(\"\n\")\"\n\":\"\n\"'\"\n\"\\\"\"\n\"0.1\"\n\"1.2\"\n\"2.3\"\n\"-3.4\"\n\"-4.5\"\n\"-5.6\"\n\"1e2\"\n\"2e3\"\n\"-3e4\"\n\"-4e5\"\n\"0\"\n\"1\"\n\"2\"\n\"-"
},
{
"path": "test/fuzz/fuzz_test.go",
"chars": 3431,
"preview": "package fuzz\n\nimport (\n\t_ \"embed\"\n\t\"regexp\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/e"
},
{
"path": "test/gen/env.go",
"chars": 383,
"preview": "package main\n\nvar Env = map[string]any{\n\t\"ok\": true,\n\t\"i\": 1,\n\t\"str\": \"str\",\n\t\"f64\": .5,\n\t\"array\": []int{1, 2"
},
{
"path": "test/gen/gen.go",
"chars": 8028,
"preview": "package main\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"runtime\"\n\t\"runtime/debug\"\n\t\"strings\"\n\t\"sync\"\n\n\t\"github.com/expr-lang/expr\"\n\t\""
},
{
"path": "test/gen/gen_test.go",
"chars": 1334,
"preview": "package main\n\nimport (\n\t\"bufio\"\n\t\"flag\"\n\t\"os\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang"
},
{
"path": "test/gen/utils.go",
"chars": 487,
"preview": "package main\n\nimport (\n\t\"math/rand\"\n)\n\nfunc maybe() bool {\n\treturn rand.Intn(2) == 0\n}\n\ntype list[T any] []element[T]\n\nt"
},
{
"path": "test/interface/interface_method_test.go",
"chars": 917,
"preview": "package interface_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\t\"github.com/expr-lang"
},
{
"path": "test/interface/interface_test.go",
"chars": 794,
"preview": "package interface_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/a"
},
{
"path": "test/issues/461/issue_test.go",
"chars": 2026,
"preview": "package issue_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/requi"
},
{
"path": "test/issues/567/issue_test.go",
"chars": 648,
"preview": "package expr_test\n\nimport (\n\t\"bytes\"\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/int"
},
{
"path": "test/issues/688/issue_test.go",
"chars": 1022,
"preview": "package issue_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/requi"
},
{
"path": "test/issues/723/issue_test.go",
"chars": 480,
"preview": "package issue_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/requi"
},
{
"path": "test/issues/730/issue_test.go",
"chars": 1081,
"preview": "package issue_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/requi"
},
{
"path": "test/issues/739/issue_test.go",
"chars": 366,
"preview": "package issue_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/requi"
},
{
"path": "test/issues/756/issue_test.go",
"chars": 601,
"preview": "package issue_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/te"
},
{
"path": "test/issues/785/issue_test.go",
"chars": 876,
"preview": "package issue_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/requi"
},
{
"path": "test/issues/817/issue_test.go",
"chars": 634,
"preview": "package issue_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testif"
},
{
"path": "test/issues/819/issue_test.go",
"chars": 729,
"preview": "package issue_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/requi"
},
{
"path": "test/issues/823/issue_test.go",
"chars": 2309,
"preview": "package issue_test\n\nimport (\n\t\"context\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/int"
},
{
"path": "test/issues/830/issue_test.go",
"chars": 510,
"preview": "package issues\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\t"
},
{
"path": "test/issues/836/issue_test.go",
"chars": 2375,
"preview": "package issue_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/requi"
},
{
"path": "test/issues/840/issue_test.go",
"chars": 541,
"preview": "package issue_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/requi"
},
{
"path": "test/issues/844/issue_test.go",
"chars": 5040,
"preview": "package main\n\nimport (\n\t\"strings\"\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/checker\"\n\t\"github"
},
{
"path": "test/issues/854/issue_test.go",
"chars": 486,
"preview": "package main\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/require\"\n\t\""
},
{
"path": "test/issues/857/issue_test.go",
"chars": 599,
"preview": "package main\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/require\"\n)\n"
},
{
"path": "test/issues/888/issue_test.go",
"chars": 845,
"preview": "package main\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/require\"\n)\n"
},
{
"path": "test/issues/924/issue_test.go",
"chars": 580,
"preview": "package issue_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/requi"
},
{
"path": "test/issues/934/issue_test.go",
"chars": 1286,
"preview": "package issue934\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr\"\n\t\"github.com/expr-lang/expr/internal/testify/require"
},
{
"path": "test/mock/mock.go",
"chars": 4195,
"preview": "package mock\n\nimport (\n\t\"fmt\"\n\t\"reflect\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/expr-lang/expr/ast\"\n)\n\ntype Env struct {\n\tEmbe"
},
{
"path": "test/operator/issues584/issues584_test.go",
"chars": 1343,
"preview": "package issues584_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\n\t\"github.com/expr-lan"
},
{
"path": "test/operator/operator_test.go",
"chars": 5781,
"preview": "package operator_test\n\nimport (\n\t\"fmt\"\n\t\"testing\"\n\t\"time\"\n\n\t\"github.com/expr-lang/expr/internal/testify/assert\"\n\t\"github"
},
{
"path": "test/patch/change_ident_test.go",
"chars": 1083,
"preview": "package patch_test\n\nimport (\n\t\"testing\"\n\n\t\"github.com/expr-lang/expr/internal/testify/require\"\n\n\t\"github.com/expr-lang/e"
}
]
// ... and 30 more files (download for full content)
About this extraction
This page contains the full source code of the expr-lang/expr GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 230 files (2.8 MB), approximately 735.6k tokens, and a symbol index with 2605 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.