lep

package module
v0.0.0-...-86f0316 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 4, 2023 License: MIT Imports: 16 Imported by: 0

README

logic-expression-parser

Build Status Go Report Card Codecov

This library provide generic boolean expression parser to go structures.

Installation

$ go get -u github.com/solo-finance/logic-expression-parser

(optional) Run unit tests

$ make test

(optional) Run benchmarks

$ make bench

Examples

package main

import (
	"github.com/davecgh/go-spew/spew"
	lep "github.com/mgudov/logic-expression-parser"
)

func main() {
	expression := `a=false && b>=c && (d<1000 || e in [1,2,3])`

	result, err := lep.ParseExpression(expression)
	if err != nil {
		panic(err)
	}

	dump := spew.NewDefaultConfig()
	dump.DisablePointerAddresses = true
	dump.DisableMethods = true
	dump.Dump(result)
}

This library would parse the expression and return the following struct:

(*lep.AndX)({
  Conjuncts: ([]lep.Expression) (len=3 cap=4) {
    (*lep.EqualsX)({
      Param: (*lep.ParamX)({
        Name: (string) (len=1) "a"
      }),
      Value: (*lep.BooleanX)({
        Val: (bool) false
      })
    }),
    (*lep.GreaterThanEqualX)({
      Param: (*lep.ParamX)({
        Name: (string) (len=1) "b"
      }),
      Value: (*lep.ParamX)({
        Name: (string) (len=1) "c"
      })
    }),
    (*lep.OrX)({
      Disjunctions: ([]lep.Expression) (len=2 cap=2) {
        (*lep.LessThanX)({
          Param: (*lep.ParamX)({
            Name: (string) (len=1) "d"
          }),
          Value: (*lep.IntegerX)({
            Val: (int64) 1000
          })
        }),
        (*lep.InSliceX)({
          Param: (*lep.ParamX)({
            Name: (string) (len=1) "e"
          }),
          Slice: (*lep.SliceX)({
            Values: ([]lep.Value) (len=3 cap=4) {
              (*lep.IntegerX)({
                Val: (int64) 1
              }),
              (*lep.IntegerX)({
                Val: (int64) 2
              }),
              (*lep.IntegerX)({
                Val: (int64) 3
              })
            }
          })
        })
      }
    })
  }
})

Use can also create expression string from code:

package main

import (
	"fmt"
	lep "github.com/mgudov/logic-expression-parser"
)

func main() {
	expression := lep.And(
		lep.Equals(lep.Param("a"), lep.Boolean(false)),
		lep.GreaterThanEqual(lep.Param("b"), lep.Param("c")),
		lep.Or(
			lep.LessThan(lep.Param("d"), lep.Integer(1000)),
			lep.InSlice(
				lep.Param("e"),
				lep.Slice(lep.Integer(1), lep.Integer(2), lep.Integer(3)),
			),
		),
	)

	fmt.Println(expression.String())
}
a=false && b>=c && (d<1000 || e in [1,2,3])

Real life examples

Create SQL query from expression string
package main

import (
	"fmt"
	"github.com/davecgh/go-spew/spew"
	sb "github.com/huandu/go-sqlbuilder"
	lep "github.com/mgudov/logic-expression-parser"
)

func traverse(sql *sb.SelectBuilder, expr lep.Expression) (string, error) {
	switch e := expr.(type) {
	default:
		return "", fmt.Errorf("not implemented: %T", e)
	case *lep.OrX:
		var args []string
		for _, disjunction := range e.Disjunctions {
			arg, err := traverse(sql, disjunction)
			if err != nil {
				return "", err
			}
			args = append(args, arg)
		}
		return sql.Or(args...), nil
	case *lep.AndX:
		var args []string
		for _, conjunct := range e.Conjuncts {
			arg, err := traverse(sql, conjunct)
			if err != nil {
				return "", err
			}
			args = append(args, arg)
		}
		return sql.And(args...), nil
	case *lep.EqualsX:
		value := e.Value.Value()
		if value == nil {
			return sql.IsNotNull(e.Param.String()), nil
		}
		return sql.Equal(e.Param.String(), value), nil
	case *lep.NotEqualsX:
		value := e.Value.Value()
		if value == nil {
			return sql.IsNotNull(e.Param.String()), nil
		}
		return sql.NotEqual(e.Param.String(), value), nil
	case *lep.GreaterThanX:
		return sql.GreaterThan(e.Param.String(), e.Value.Value()), nil
	case *lep.InSliceX:
		var items []interface{}
		for _, value := range e.Slice.Values {
			items = append(items, value.Value())
		}
		return sql.In(e.Param.String(), items...), nil

		// TODO: other cases
	}
}

func main() {
	query := `active=true && email!=null && (last_login>dt:"2010-01-01" || role in ["client","customer"])`

	expr, err := lep.ParseExpression(query)
	if err != nil {
		panic(err)
	}

	sql := sb.Select("*").From("users")
	where, err := traverse(sql, expr)
	if err != nil {
		panic(err)
	}
	sql.Where(where)

	spew.Dump(sql.Build())
}
(string) (len=99) "SELECT * FROM users WHERE (active = ? AND email IS NOT NULL AND (last_login > ? OR role IN (?, ?)))"
([]interface {}) (len=4 cap=4) {
 (bool) true,
 (time.Time) 2010-01-01 00:00:00 +0000 UTC,
 (string) (len=6) "client",
 (string) (len=8) "customer"
}

Operators and types

  • Comparators: = != > >= < <= (left - param, right - param or value)
  • Logical operations: || && (left, right - any statements)
  • Numeric constants: integer 64-bit (12345678), float 64-bit with floating point (12345.678)
  • String constants (double quotes: "foo bar", "foo "bar"")
  • String operations: starts_with, ends_with (left - param, right - param or string)
  • Regexp operations: =~ (match regexp a =~ /[a-z]+/), !~ (not match b !~ /[0-9]+/)
  • Date constants (double quotes after dt:): dt:"2020-03-04 10:20:30" (for parsing datetime used dateparse)
  • Arrays (any values separated by , within square bracket: [1,2,"foo",dt:"1999-09-09"])
  • Array operations: in not_in (a in [1,2,3])
  • Boolean constants: true false
  • Null constant: null

Benchmarks

Here are the results output from a benchmark run on a Macbook Pro 2018:

go test -benchmem -bench=.
goos: darwin
goarch: amd64
pkg: github.com/mgudov/logic-expression-parser
cpu: Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
BenchmarkSmallQuery-16                     26547             45293 ns/op           19353 B/op        332 allocs/op
BenchmarkMediumQuery-16                    10000            106334 ns/op           42931 B/op        807 allocs/op
BenchmarkLargeQuery-16                      3268            331438 ns/op          114500 B/op       2385 allocs/op
BenchmarkSmallQueryWithMemo-16             14696             79791 ns/op           82590 B/op        276 allocs/op
BenchmarkMediumQueryWithMemo-16             4924            246504 ns/op          257072 B/op        746 allocs/op
BenchmarkLargeQueryWithMemo-16              2071            590092 ns/op          594584 B/op       1627 allocs/op
PASS
ok      github.com/mgudov/logic-expression-parser       8.744s

Used Libraries

For parsing string the pigeon parser generator is used (Licensed under BSD 3-Clause).

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IncorrectType

func IncorrectType(funcName string, expected, received interface{}) error

func IncorrectValue

func IncorrectValue(funcName string, expected, received interface{}) error

func Parse

func Parse(filename string, b []byte, opts ...Option) (interface{}, error)

Parse parses the data from b using filename as information in the error messages.

func ParseFile

func ParseFile(filename string, opts ...Option) (i interface{}, err error)

ParseFile parses the file identified by filename.

func ParseReader

func ParseReader(filename string, r io.Reader, opts ...Option) (interface{}, error)

ParseReader parses the data from r using filename as information in the error messages.

Types

type AndX

type AndX struct {
	Conjuncts []Expression
}

func And

func And(expr ...Expression) *AndX

func (AndX) Equals

func (e AndX) Equals(other Expression) bool

func (AndX) String

func (e AndX) String() string

type Between

type Between struct {
	Start Value
	End   Value
	// contains filtered or unexported fields
}

func BetweenXandY

func BetweenXandY(param *ParamX, start Value, end Value) *Between

func (Between) Equals

func (s Between) Equals(other Expression) bool

func (Between) GetParam

func (s Between) GetParam() *ParamX

func (Between) GetValue

func (s Between) GetValue() Value

func (Between) String

func (s Between) String() string

type BooleanX

type BooleanX struct {
	Val bool
}

func Boolean

func Boolean(val bool) *BooleanX

func (BooleanX) Equals

func (v BooleanX) Equals(other Expression) bool

func (BooleanX) String

func (v BooleanX) String() string

func (BooleanX) Value

func (v BooleanX) Value() interface{}

type Cloner

type Cloner interface {
	Clone() interface{}
}

Cloner is implemented by any value that has a Clone method, which returns a copy of the value. This is mainly used for types which are not passed by value (e.g map, slice, chan) or structs that contain such types.

This is used in conjunction with the global state feature to create proper copies of the state to allow the parser to properly restore the state in the case of backtracking.

type DateTimeX

type DateTimeX struct {
	Val    time.Time
	Format string
}

func DateTime

func DateTime(dt time.Time, format string) *DateTimeX

func (DateTimeX) Equals

func (v DateTimeX) Equals(other Expression) bool

func (DateTimeX) String

func (v DateTimeX) String() string

func (DateTimeX) Value

func (v DateTimeX) Value() interface{}

type EndsWithX

type EndsWithX struct {
	Param *ParamX
	Value Stringify
}

func EndsWith

func EndsWith(param *ParamX, value Stringify) *EndsWithX

func (EndsWithX) Equals

func (e EndsWithX) Equals(other Expression) bool

func (EndsWithX) GetParam

func (e EndsWithX) GetParam() *ParamX

func (EndsWithX) GetValue

func (e EndsWithX) GetValue() Value

func (EndsWithX) String

func (e EndsWithX) String() string

type EqualsX

type EqualsX struct {
	// contains filtered or unexported fields
}

func Equals

func Equals(param *ParamX, value Value) *EqualsX

func (EqualsX) Equals

func (e EqualsX) Equals(other Expression) bool

func (EqualsX) GetParam

func (s EqualsX) GetParam() *ParamX

func (EqualsX) GetValue

func (s EqualsX) GetValue() Value

func (EqualsX) String

func (e EqualsX) String() string

type ErrIncorrectType

type ErrIncorrectType struct {
	FuncName string
	Expected interface{}
	Received interface{}
}

func (ErrIncorrectType) Error

func (e ErrIncorrectType) Error() string

type ErrIncorrectValue

type ErrIncorrectValue struct {
	FuncName string
	Expected interface{}
	Received interface{}
}

func (ErrIncorrectValue) Error

func (e ErrIncorrectValue) Error() string

type Expression

type Expression interface {
	Equals(Expression) bool
	String() string
}

func ParseExpression

func ParseExpression(data string, opts ...Option) (Expression, error)

type FloatX

type FloatX struct {
	Val float64
}

func Float

func Float(val float64) *FloatX

func (FloatX) Equals

func (f FloatX) Equals(other Expression) bool

func (FloatX) String

func (f FloatX) String() string

func (FloatX) Value

func (f FloatX) Value() interface{}

type GreaterThanEqualX

type GreaterThanEqualX struct {
	// contains filtered or unexported fields
}

func GreaterThanEqual

func GreaterThanEqual(param *ParamX, value Value) *GreaterThanEqualX

func (GreaterThanEqualX) Equals

func (s GreaterThanEqualX) Equals(other Expression) bool

func (GreaterThanEqualX) GetParam

func (s GreaterThanEqualX) GetParam() *ParamX

func (GreaterThanEqualX) GetValue

func (s GreaterThanEqualX) GetValue() Value

func (GreaterThanEqualX) String

func (s GreaterThanEqualX) String() string

type GreaterThanX

type GreaterThanX struct {
	// contains filtered or unexported fields
}

func GreaterThan

func GreaterThan(param *ParamX, value Value) *GreaterThanX

func (GreaterThanX) Equals

func (s GreaterThanX) Equals(other Expression) bool

func (GreaterThanX) GetParam

func (s GreaterThanX) GetParam() *ParamX

func (GreaterThanX) GetValue

func (s GreaterThanX) GetValue() Value

func (GreaterThanX) String

func (s GreaterThanX) String() string

type HasAllX

type HasAllX struct {
	Param *ParamX
	Slice *SliceX
}

func HasAll

func HasAll(param *ParamX, slice *SliceX) *HasAllX

func (HasAllX) Equals

func (e HasAllX) Equals(other Expression) bool

func (HasAllX) GetParam

func (e HasAllX) GetParam() *ParamX

func (HasAllX) GetValue

func (e HasAllX) GetValue() Value

func (HasAllX) String

func (e HasAllX) String() string

type HasAnyX

type HasAnyX struct {
	Param *ParamX
	Slice *SliceX
}

func HasAny

func HasAny(param *ParamX, slice *SliceX) *HasAnyX

func (HasAnyX) Equals

func (e HasAnyX) Equals(other Expression) bool

func (HasAnyX) GetParam

func (e HasAnyX) GetParam() *ParamX

func (HasAnyX) GetValue

func (e HasAnyX) GetValue() Value

func (HasAnyX) String

func (e HasAnyX) String() string

type HasX

type HasX struct {
	// contains filtered or unexported fields
}

func Has

func Has(param *ParamX, value Value) *HasX

func (HasX) Equals

func (e HasX) Equals(other Expression) bool

func (HasX) GetParam

func (s HasX) GetParam() *ParamX

func (HasX) GetValue

func (s HasX) GetValue() Value

func (HasX) String

func (e HasX) String() string

type InSliceX

type InSliceX struct {
	Param *ParamX
	Slice *SliceX
}

func InSlice

func InSlice(param *ParamX, slice *SliceX) *InSliceX

func (InSliceX) Equals

func (e InSliceX) Equals(other Expression) bool

func (InSliceX) GetParam

func (e InSliceX) GetParam() *ParamX

func (InSliceX) GetValue

func (e InSliceX) GetValue() Value

func (InSliceX) String

func (e InSliceX) String() string

type IntegerX

type IntegerX struct {
	Val int64
}

func Integer

func Integer(val int64) *IntegerX

func (IntegerX) Equals

func (i IntegerX) Equals(other Expression) bool

func (IntegerX) String

func (i IntegerX) String() string

func (IntegerX) Value

func (i IntegerX) Value() interface{}

type LessThanEqualX

type LessThanEqualX struct {
	// contains filtered or unexported fields
}

func LessThanEqual

func LessThanEqual(param *ParamX, value Value) *LessThanEqualX

func (LessThanEqualX) Equals

func (s LessThanEqualX) Equals(other Expression) bool

func (LessThanEqualX) GetParam

func (s LessThanEqualX) GetParam() *ParamX

func (LessThanEqualX) GetValue

func (s LessThanEqualX) GetValue() Value

func (LessThanEqualX) String

func (s LessThanEqualX) String() string

type LessThanX

type LessThanX struct {
	// contains filtered or unexported fields
}

func LessThan

func LessThan(param *ParamX, value Value) *LessThanX

func (LessThanX) Equals

func (s LessThanX) Equals(other Expression) bool

func (LessThanX) GetParam

func (s LessThanX) GetParam() *ParamX

func (LessThanX) GetValue

func (s LessThanX) GetValue() Value

func (LessThanX) String

func (s LessThanX) String() string

type LikeX

type LikeX struct {
	// contains filtered or unexported fields
}

func Like

func Like(param *ParamX, value Value) *LikeX

func (LikeX) Equals

func (e LikeX) Equals(other Expression) bool

func (LikeX) GetParam

func (s LikeX) GetParam() *ParamX

func (LikeX) GetValue

func (s LikeX) GetValue() Value

func (LikeX) String

func (e LikeX) String() string

type MatchRegexpX

type MatchRegexpX struct {
	Param  *ParamX
	Regexp *RegexpX
}

func MatchRegexp

func MatchRegexp(param *ParamX, regexp *RegexpX) *MatchRegexpX

func (MatchRegexpX) Equals

func (e MatchRegexpX) Equals(other Expression) bool

func (MatchRegexpX) GetParam

func (e MatchRegexpX) GetParam() *ParamX

func (MatchRegexpX) GetValue

func (e MatchRegexpX) GetValue() Value

func (MatchRegexpX) String

func (e MatchRegexpX) String() string

type NotEqualsX

type NotEqualsX struct {
	// contains filtered or unexported fields
}

func NotEquals

func NotEquals(param *ParamX, value Value) *NotEqualsX

func (NotEqualsX) Equals

func (e NotEqualsX) Equals(other Expression) bool

func (NotEqualsX) GetParam

func (s NotEqualsX) GetParam() *ParamX

func (NotEqualsX) GetValue

func (s NotEqualsX) GetValue() Value

func (NotEqualsX) String

func (e NotEqualsX) String() string

type NotHasX

type NotHasX struct {
	// contains filtered or unexported fields
}

func NotHas

func NotHas(param *ParamX, value Value) *NotHasX

func (NotHasX) Equals

func (e NotHasX) Equals(other Expression) bool

func (NotHasX) GetParam

func (s NotHasX) GetParam() *ParamX

func (NotHasX) GetValue

func (s NotHasX) GetValue() Value

func (NotHasX) String

func (e NotHasX) String() string

type NotInSliceX

type NotInSliceX struct {
	Param *ParamX
	Slice *SliceX
}

func NotInSlice

func NotInSlice(param *ParamX, slice *SliceX) *NotInSliceX

func (NotInSliceX) Equals

func (e NotInSliceX) Equals(other Expression) bool

func (NotInSliceX) GetParam

func (e NotInSliceX) GetParam() *ParamX

func (NotInSliceX) GetValue

func (e NotInSliceX) GetValue() Value

func (NotInSliceX) String

func (e NotInSliceX) String() string

type NotLikeX

type NotLikeX struct {
	// contains filtered or unexported fields
}

func NotLike

func NotLike(param *ParamX, value Value) *NotLikeX

func (NotLikeX) Equals

func (e NotLikeX) Equals(other Expression) bool

func (NotLikeX) GetParam

func (s NotLikeX) GetParam() *ParamX

func (NotLikeX) GetValue

func (s NotLikeX) GetValue() Value

func (NotLikeX) String

func (e NotLikeX) String() string

type NotMatchRegexpX

type NotMatchRegexpX struct {
	Param  *ParamX
	Regexp *RegexpX
}

func NotMatchRegexp

func NotMatchRegexp(param *ParamX, regexp *RegexpX) *NotMatchRegexpX

func (NotMatchRegexpX) Equals

func (e NotMatchRegexpX) Equals(other Expression) bool

func (NotMatchRegexpX) GetParam

func (e NotMatchRegexpX) GetParam() *ParamX

func (NotMatchRegexpX) GetValue

func (e NotMatchRegexpX) GetValue() Value

func (NotMatchRegexpX) String

func (e NotMatchRegexpX) String() string

type NullX

type NullX struct{}

func Null

func Null() *NullX

func (NullX) Equals

func (NullX) Equals(other Expression) bool

func (NullX) String

func (NullX) String() string

func (NullX) Value

func (NullX) Value() interface{}

type Option

type Option func(*parser) Option

Option is a function that can set an option on the parser. It returns the previous setting as an Option.

func AllowInvalidUTF8

func AllowInvalidUTF8(b bool) Option

AllowInvalidUTF8 creates an Option to allow invalid UTF-8 bytes. Every invalid UTF-8 byte is treated as a utf8.RuneError (U+FFFD) by character class matchers and is matched by the any matcher. The returned matched value, c.text and c.offset are NOT affected.

The default is false.

func Debug

func Debug(b bool) Option

Debug creates an Option to set the debug flag to b. When set to true, debugging information is printed to stdout while parsing.

The default is false.

func Entrypoint

func Entrypoint(ruleName string) Option

Entrypoint creates an Option to set the rule name to use as entrypoint. The rule name must have been specified in the -alternate-entrypoints if generating the parser with the -optimize-grammar flag, otherwise it may have been optimized out. Passing an empty string sets the entrypoint to the first rule in the grammar.

The default is to start parsing at the first rule in the grammar.

func GlobalStore

func GlobalStore(key string, value interface{}) Option

GlobalStore creates an Option to set a key to a certain value in the globalStore.

func InitState

func InitState(key string, value interface{}) Option

InitState creates an Option to set a key to a certain value in the global "state" store.

func MaxExpressions

func MaxExpressions(maxExprCnt uint64) Option

MaxExpressions creates an Option to stop parsing after the provided number of expressions have been parsed, if the value is 0 then the parser will parse for as many steps as needed (possibly an infinite number).

The default for maxExprCnt is 0.

func Memoize

func Memoize(b bool) Option

Memoize creates an Option to set the memoize flag to b. When set to true, the parser will cache all results so each expression is evaluated only once. This guarantees linear parsing time even for pathological cases, at the expense of more memory and slower times for typical cases.

The default is false.

func Recover

func Recover(b bool) Option

Recover creates an Option to set the recover flag to b. When set to true, this causes the parser to recover from panics and convert it to an error. Setting it to false can be useful while debugging to access the full stack trace.

The default is true.

func Statistics

func Statistics(stats *Stats, choiceNoMatch string) Option

Statistics adds a user provided Stats struct to the parser to allow the user to process the results after the parsing has finished. Also the key for the "no match" counter is set.

Example usage:

input := "input"
stats := Stats{}
_, err := Parse("input-file", []byte(input), Statistics(&stats, "no match"))
if err != nil {
    log.Panicln(err)
}
b, err := json.MarshalIndent(stats.ChoiceAltCnt, "", "  ")
if err != nil {
    log.Panicln(err)
}
fmt.Println(string(b))

type OrX

type OrX struct {
	Disjunctions []Expression
}

func Or

func Or(expr ...Expression) *OrX

func (OrX) Equals

func (e OrX) Equals(other Expression) bool

func (OrX) String

func (e OrX) String() string

type ParamX

type ParamX struct {
	Name string
}

func Param

func Param(name string) *ParamX

func (ParamX) Equals

func (p ParamX) Equals(other Expression) bool

func (ParamX) IsStringify

func (p ParamX) IsStringify() bool

func (ParamX) String

func (p ParamX) String() string

func (ParamX) Value

func (p ParamX) Value() interface{}

type RegexpX

type RegexpX struct {
	Regexp *regexp.Regexp
}

func Regexp

func Regexp(regexp *regexp.Regexp) *RegexpX

func (RegexpX) Equals

func (e RegexpX) Equals(other Expression) bool

func (RegexpX) String

func (e RegexpX) String() string

func (RegexpX) Value

func (e RegexpX) Value() interface{}

type SliceX

type SliceX struct {
	Values []Value
}

func Slice

func Slice(values ...Value) *SliceX

func (SliceX) Equals

func (e SliceX) Equals(other Expression) bool

func (SliceX) String

func (e SliceX) String() string

func (SliceX) Value

func (e SliceX) Value() interface{}

type StartsWithX

type StartsWithX struct {
	Param *ParamX
	Value Stringify
}

func StartsWith

func StartsWith(param *ParamX, value Stringify) *StartsWithX

func (StartsWithX) Equals

func (e StartsWithX) Equals(other Expression) bool

func (StartsWithX) GetParam

func (e StartsWithX) GetParam() *ParamX

func (StartsWithX) GetValue

func (e StartsWithX) GetValue() Value

func (StartsWithX) String

func (e StartsWithX) String() string

type Statement

type Statement interface {
	GetParam() *ParamX
	GetValue() Value
}

type Stats

type Stats struct {
	// ExprCnt counts the number of expressions processed during parsing
	// This value is compared to the maximum number of expressions allowed
	// (set by the MaxExpressions option).
	ExprCnt uint64

	// ChoiceAltCnt is used to count for each ordered choice expression,
	// which alternative is used how may times.
	// These numbers allow to optimize the order of the ordered choice expression
	// to increase the performance of the parser
	//
	// The outer key of ChoiceAltCnt is composed of the name of the rule as well
	// as the line and the column of the ordered choice.
	// The inner key of ChoiceAltCnt is the number (one-based) of the matching alternative.
	// For each alternative the number of matches are counted. If an ordered choice does not
	// match, a special counter is incremented. The name of this counter is set with
	// the parser option Statistics.
	// For an alternative to be included in ChoiceAltCnt, it has to match at least once.
	ChoiceAltCnt map[string]map[string]int
}

Stats stores some statistics, gathered during parsing

type StringX

type StringX struct {
	Val string
}

func String

func String(val string) *StringX

func (StringX) Equals

func (s StringX) Equals(other Expression) bool

func (StringX) IsStringify

func (s StringX) IsStringify() bool

func (StringX) String

func (s StringX) String() string

func (StringX) Value

func (s StringX) Value() interface{}

type Stringify

type Stringify interface {
	Value
	IsStringify() bool
}

type Value

type Value interface {
	Expression
	Value() interface{}
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL