Compare commits
7 Commits
1757298eb4
...
9fb611aa20
Author | SHA1 | Date | |
---|---|---|---|
9fb611aa20 | |||
56d6d06d15 | |||
d9f7e5b1ad | |||
0f54e01ef3 | |||
63f5db00b3 | |||
9745a5d909 | |||
0bb4c96481 |
@ -67,7 +67,7 @@ func boolFunc(ctx ExprContext, name string, args []any) (result any, err error)
|
|||||||
case string:
|
case string:
|
||||||
result = len(v) > 0
|
result = len(v) > 0
|
||||||
default:
|
default:
|
||||||
err = errCantConvert(name, v, "bool")
|
err = ErrCantConvert(name, v, "bool")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -90,7 +90,7 @@ func intFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
|||||||
result = int64(i)
|
result = int64(i)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
err = errCantConvert(name, v, "int")
|
err = ErrCantConvert(name, v, "int")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ func decFunc(ctx ExprContext, name string, args []any) (result any, err error) {
|
|||||||
case *FractionType:
|
case *FractionType:
|
||||||
result = v.toFloat()
|
result = v.toFloat()
|
||||||
default:
|
default:
|
||||||
err = errCantConvert(name, v, "float")
|
err = ErrCantConvert(name, v, "float")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -127,9 +127,9 @@ func fractFunc(ctx ExprContext, name string, args []any) (result any, err error)
|
|||||||
if len(args) > 1 {
|
if len(args) > 1 {
|
||||||
var ok bool
|
var ok bool
|
||||||
if den, ok = args[1].(int64); !ok {
|
if den, ok = args[1].(int64); !ok {
|
||||||
err = errExpectedGot(name, "integer", args[1])
|
err = ErrExpectedGot(name, "integer", args[1])
|
||||||
} else if den == 0 {
|
} else if den == 0 {
|
||||||
err = errFuncDivisionByZero(name)
|
err = ErrFuncDivisionByZero(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@ -148,7 +148,7 @@ func fractFunc(ctx ExprContext, name string, args []any) (result any, err error)
|
|||||||
case *FractionType:
|
case *FractionType:
|
||||||
result = v
|
result = v
|
||||||
default:
|
default:
|
||||||
err = errCantConvert(name, v, "float")
|
err = ErrCantConvert(name, v, "float")
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ func doJoinStr(funcName string, sep string, it Iterator) (result any, err error)
|
|||||||
if s, ok := v.(string); ok {
|
if s, ok := v.(string); ok {
|
||||||
sb.WriteString(s)
|
sb.WriteString(s)
|
||||||
} else {
|
} else {
|
||||||
err = errExpectedGot(funcName, TypeString, v)
|
err = ErrExpectedGot(funcName, TypeString, v)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,13 +45,13 @@ func joinStrFunc(ctx ExprContext, name string, args []any) (result any, err erro
|
|||||||
} else if it, ok := args[1].(Iterator); ok {
|
} else if it, ok := args[1].(Iterator); ok {
|
||||||
result, err = doJoinStr(name, sep, it)
|
result, err = doJoinStr(name, sep, it)
|
||||||
} else {
|
} else {
|
||||||
err = errInvalidParameterValue(name, ParamParts, args[1])
|
err = ErrInvalidParameterValue(name, ParamParts, args[1])
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
result, err = doJoinStr(name, sep, NewArrayIterator(args[1:]))
|
result, err = doJoinStr(name, sep, NewArrayIterator(args[1:]))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
err = errWrongParamType(name, ParamSeparator, TypeString, args[0])
|
err = ErrWrongParamType(name, ParamSeparator, TypeString, args[0])
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -63,14 +63,14 @@ func subStrFunc(ctx ExprContext, name string, args []any) (result any, err error
|
|||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
if source, ok = args[0].(string); !ok {
|
if source, ok = args[0].(string); !ok {
|
||||||
return nil, errWrongParamType(name, ParamSource, TypeString, args[0])
|
return nil, ErrWrongParamType(name, ParamSource, TypeString, args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
if start, err = toInt(args[1], name+"()"); err != nil {
|
if start, err = ToInt(args[1], name+"()"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if count, err = toInt(args[2], name+"()"); err != nil {
|
if count, err = ToInt(args[2], name+"()"); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ func trimStrFunc(ctx ExprContext, name string, args []any) (result any, err erro
|
|||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
if source, ok = args[0].(string); !ok {
|
if source, ok = args[0].(string); !ok {
|
||||||
return nil, errWrongParamType(name, ParamSource, TypeString, args[0])
|
return nil, ErrWrongParamType(name, ParamSource, TypeString, args[0])
|
||||||
}
|
}
|
||||||
result = strings.TrimSpace(source)
|
result = strings.TrimSpace(source)
|
||||||
return
|
return
|
||||||
@ -104,7 +104,7 @@ func startsWithStrFunc(ctx ExprContext, name string, args []any) (result any, er
|
|||||||
result = false
|
result = false
|
||||||
|
|
||||||
if source, ok = args[0].(string); !ok {
|
if source, ok = args[0].(string); !ok {
|
||||||
return result, errWrongParamType(name, ParamSource, TypeString, args[0])
|
return result, ErrWrongParamType(name, ParamSource, TypeString, args[0])
|
||||||
}
|
}
|
||||||
for i, targetSpec := range args[1:] {
|
for i, targetSpec := range args[1:] {
|
||||||
if target, ok := targetSpec.(string); ok {
|
if target, ok := targetSpec.(string); ok {
|
||||||
@ -127,7 +127,7 @@ func endsWithStrFunc(ctx ExprContext, name string, args []any) (result any, err
|
|||||||
result = false
|
result = false
|
||||||
|
|
||||||
if source, ok = args[0].(string); !ok {
|
if source, ok = args[0].(string); !ok {
|
||||||
return result, errWrongParamType(name, ParamSource, TypeString, args[0])
|
return result, ErrWrongParamType(name, ParamSource, TypeString, args[0])
|
||||||
}
|
}
|
||||||
for i, targetSpec := range args[1:] {
|
for i, targetSpec := range args[1:] {
|
||||||
if target, ok := targetSpec.(string); ok {
|
if target, ok := targetSpec.(string); ok {
|
||||||
@ -150,7 +150,7 @@ func splitStrFunc(ctx ExprContext, name string, args []any) (result any, err err
|
|||||||
var ok bool
|
var ok bool
|
||||||
|
|
||||||
if source, ok = args[0].(string); !ok {
|
if source, ok = args[0].(string); !ok {
|
||||||
return result, errWrongParamType(name, ParamSource, TypeString, args[0])
|
return result, ErrWrongParamType(name, ParamSource, TypeString, args[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
if sep, ok = args[1].(string); !ok {
|
if sep, ok = args[1].(string); !ok {
|
||||||
@ -182,34 +182,34 @@ func splitStrFunc(ctx ExprContext, name string, args []any) (result any, err err
|
|||||||
|
|
||||||
// Import above functions in the context
|
// Import above functions in the context
|
||||||
func ImportStringFuncs(ctx ExprContext) {
|
func ImportStringFuncs(ctx ExprContext) {
|
||||||
ctx.RegisterFunc("joinStr", NewGolangFunctor(joinStrFunc), TypeString, []ExprFuncParam{
|
ctx.RegisterFunc("strJoin", NewGolangFunctor(joinStrFunc), TypeString, []ExprFuncParam{
|
||||||
NewFuncParam(ParamSeparator),
|
NewFuncParam(ParamSeparator),
|
||||||
NewFuncParamFlag(ParamItem, PfRepeat),
|
NewFuncParamFlag(ParamItem, PfRepeat),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("subStr", NewGolangFunctor(subStrFunc), TypeString, []ExprFuncParam{
|
ctx.RegisterFunc("strSub", NewGolangFunctor(subStrFunc), TypeString, []ExprFuncParam{
|
||||||
NewFuncParam(ParamSource),
|
NewFuncParam(ParamSource),
|
||||||
NewFuncParamFlagDef(ParamStart, PfDefault, int64(0)),
|
NewFuncParamFlagDef(ParamStart, PfDefault, int64(0)),
|
||||||
NewFuncParamFlagDef(ParamCount, PfDefault, int64(-1)),
|
NewFuncParamFlagDef(ParamCount, PfDefault, int64(-1)),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("splitStr", NewGolangFunctor(splitStrFunc), "list of "+TypeString, []ExprFuncParam{
|
ctx.RegisterFunc("strSplit", NewGolangFunctor(splitStrFunc), "list of "+TypeString, []ExprFuncParam{
|
||||||
NewFuncParam(ParamSource),
|
NewFuncParam(ParamSource),
|
||||||
NewFuncParamFlagDef(ParamSeparator, PfDefault, ""),
|
NewFuncParamFlagDef(ParamSeparator, PfDefault, ""),
|
||||||
NewFuncParamFlagDef(ParamCount, PfDefault, int64(-1)),
|
NewFuncParamFlagDef(ParamCount, PfDefault, int64(-1)),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("trimStr", NewGolangFunctor(trimStrFunc), TypeString, []ExprFuncParam{
|
ctx.RegisterFunc("strTrim", NewGolangFunctor(trimStrFunc), TypeString, []ExprFuncParam{
|
||||||
NewFuncParam(ParamSource),
|
NewFuncParam(ParamSource),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("startsWithStr", NewGolangFunctor(startsWithStrFunc), TypeBoolean, []ExprFuncParam{
|
ctx.RegisterFunc("strStartsWith", NewGolangFunctor(startsWithStrFunc), TypeBoolean, []ExprFuncParam{
|
||||||
NewFuncParam(ParamSource),
|
NewFuncParam(ParamSource),
|
||||||
NewFuncParam(ParamPrefix),
|
NewFuncParam(ParamPrefix),
|
||||||
NewFuncParamFlag("other "+ParamPrefix, PfRepeat),
|
NewFuncParamFlag("other "+ParamPrefix, PfRepeat),
|
||||||
})
|
})
|
||||||
|
|
||||||
ctx.RegisterFunc("endsWithStr", NewGolangFunctor(endsWithStrFunc), TypeBoolean, []ExprFuncParam{
|
ctx.RegisterFunc("strEndsWith", NewGolangFunctor(endsWithStrFunc), TypeBoolean, []ExprFuncParam{
|
||||||
NewFuncParam(ParamSource),
|
NewFuncParam(ParamSource),
|
||||||
NewFuncParam(ParamSuffix),
|
NewFuncParam(ParamSuffix),
|
||||||
NewFuncParamFlag("other "+ParamSuffix, PfRepeat),
|
NewFuncParamFlag("other "+ParamSuffix, PfRepeat),
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
func errTooFewParams(funcName string, minArgs, maxArgs, argCount int) (err error) {
|
func ErrTooFewParams(funcName string, minArgs, maxArgs, argCount int) (err error) {
|
||||||
if maxArgs < 0 {
|
if maxArgs < 0 {
|
||||||
err = fmt.Errorf("%s(): too few params -- expected %d or more, got %d", funcName, minArgs, argCount)
|
err = fmt.Errorf("%s(): too few params -- expected %d or more, got %d", funcName, minArgs, argCount)
|
||||||
} else {
|
} else {
|
||||||
@ -17,39 +17,39 @@ func errTooFewParams(funcName string, minArgs, maxArgs, argCount int) (err error
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func errTooMuchParams(funcName string, maxArgs, argCount int) (err error) {
|
func ErrTooMuchParams(funcName string, maxArgs, argCount int) (err error) {
|
||||||
err = fmt.Errorf("%s(): too much params -- expected %d, got %d", funcName, maxArgs, argCount)
|
err = fmt.Errorf("%s(): too much params -- expected %d, got %d", funcName, maxArgs, argCount)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- General errors
|
// --- General errors
|
||||||
|
|
||||||
func errCantConvert(funcName string, value any, kind string) error {
|
func ErrCantConvert(funcName string, value any, kind string) error {
|
||||||
return fmt.Errorf("%s(): can't convert %s to %s", funcName, TypeName(value), kind)
|
return fmt.Errorf("%s(): can't convert %s to %s", funcName, TypeName(value), kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
func errExpectedGot(funcName string, kind string, value any) error {
|
func ErrExpectedGot(funcName string, kind string, value any) error {
|
||||||
return fmt.Errorf("%s() expected %s, got %s (%v)", funcName, kind, TypeName(value), value)
|
return fmt.Errorf("%s(): expected %s, got %s (%v)", funcName, kind, TypeName(value), value)
|
||||||
}
|
}
|
||||||
|
|
||||||
func errFuncDivisionByZero(funcName string) error {
|
func ErrFuncDivisionByZero(funcName string) error {
|
||||||
return fmt.Errorf("%s(): division by zero", funcName)
|
return fmt.Errorf("%s(): division by zero", funcName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func errDivisionByZero() error {
|
func ErrDivisionByZero() error {
|
||||||
return fmt.Errorf("division by zero")
|
return fmt.Errorf("division by zero")
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Parameter errors
|
// --- Parameter errors
|
||||||
|
|
||||||
func errMissingRequiredParameter(funcName, paramName string) error {
|
func ErrMissingRequiredParameter(funcName, paramName string) error {
|
||||||
return fmt.Errorf("%s() missing required parameter %q", funcName, paramName)
|
return fmt.Errorf("%s(): missing required parameter %q", funcName, paramName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func errInvalidParameterValue(funcName, paramName string, paramValue any) error {
|
func ErrInvalidParameterValue(funcName, paramName string, paramValue any) error {
|
||||||
return fmt.Errorf("%s() invalid value %s (%v) for parameter %q", funcName, TypeName(paramValue), paramValue, paramName)
|
return fmt.Errorf("%s(): invalid value %s (%v) for parameter %q", funcName, TypeName(paramValue), paramValue, paramName)
|
||||||
}
|
}
|
||||||
|
|
||||||
func errWrongParamType(funcName, paramName, paramType string, paramValue any) error {
|
func ErrWrongParamType(funcName, paramName, paramType string, paramValue any) error {
|
||||||
return fmt.Errorf("%s() the %q parameter must be a %s, got a %s (%v)", funcName, paramName, paramType, TypeName(paramValue), paramValue)
|
return fmt.Errorf("%s(): the %q parameter must be a %s, got a %s (%v)", funcName, paramName, paramType, TypeName(paramValue), paramValue)
|
||||||
}
|
}
|
||||||
|
72
dict-type.go
72
dict-type.go
@ -32,42 +32,52 @@ func newDict(dictAny map[any]*term) (dict *DictType) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *DictType) toMultiLine(sb *strings.Builder, indent int) {
|
func (dict *DictType) toMultiLine(sb *strings.Builder, opt FmtOpt) {
|
||||||
sb.WriteString(strings.Repeat("\t", indent))
|
indent := GetFormatIndent(opt)
|
||||||
sb.WriteString("{\n")
|
flags := GetFormatFlags(opt)
|
||||||
|
//sb.WriteString(strings.Repeat(" ", indent))
|
||||||
|
sb.WriteByte('{')
|
||||||
|
|
||||||
first := true
|
if len(*dict) > 0 {
|
||||||
for name, value := range *dict {
|
innerOpt := MakeFormatOptions(flags, indent+1)
|
||||||
if first {
|
nest := strings.Repeat(" ", indent+1)
|
||||||
first = false
|
sb.WriteByte('\n')
|
||||||
} else {
|
|
||||||
sb.WriteByte(',')
|
|
||||||
sb.WriteByte('\n')
|
|
||||||
}
|
|
||||||
|
|
||||||
sb.WriteString(strings.Repeat("\t", indent+1))
|
first := true
|
||||||
if key, ok := name.(string); ok {
|
for name, value := range *dict {
|
||||||
sb.WriteString(string('"') + key + string('"'))
|
if first {
|
||||||
} else {
|
first = false
|
||||||
sb.WriteString(fmt.Sprintf("%v", name))
|
} else {
|
||||||
}
|
sb.WriteByte(',')
|
||||||
sb.WriteString(": ")
|
sb.WriteByte('\n')
|
||||||
if f, ok := value.(Formatter); ok {
|
}
|
||||||
sb.WriteString(f.ToString(MultiLine))
|
|
||||||
} else if _, ok = value.(Functor); ok {
|
sb.WriteString(nest)
|
||||||
sb.WriteString("func(){}")
|
if key, ok := name.(string); ok {
|
||||||
} else {
|
sb.WriteString(string('"') + key + string('"'))
|
||||||
sb.WriteString(fmt.Sprintf("%v", value))
|
} else {
|
||||||
|
sb.WriteString(fmt.Sprintf("%v", name))
|
||||||
|
}
|
||||||
|
sb.WriteString(": ")
|
||||||
|
if f, ok := value.(Formatter); ok {
|
||||||
|
sb.WriteString(f.ToString(innerOpt))
|
||||||
|
} else if _, ok = value.(Functor); ok {
|
||||||
|
sb.WriteString("func(){}")
|
||||||
|
} else {
|
||||||
|
sb.WriteString(fmt.Sprintf("%v", value))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
sb.WriteByte('\n')
|
||||||
|
sb.WriteString(strings.Repeat(" ", indent))
|
||||||
}
|
}
|
||||||
sb.WriteString(strings.Repeat("\t", indent))
|
sb.WriteString("}")
|
||||||
sb.WriteString("\n}")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dict *DictType) ToString(opt FmtOpt) string {
|
func (dict *DictType) ToString(opt FmtOpt) string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
if opt&MultiLine != 0 {
|
flags := GetFormatFlags(opt)
|
||||||
dict.toMultiLine(&sb, 0)
|
if flags&MultiLine != 0 {
|
||||||
|
dict.toMultiLine(&sb, opt)
|
||||||
} else {
|
} else {
|
||||||
sb.WriteByte('{')
|
sb.WriteByte('{')
|
||||||
first := true
|
first := true
|
||||||
@ -133,3 +143,9 @@ func (dict *DictType) setItem(key any, value any) (err error) {
|
|||||||
(*dict)[key] = value
|
(*dict)[key] = value
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////
|
||||||
|
|
||||||
|
type DictFormat interface {
|
||||||
|
ToDict() *DictType
|
||||||
|
}
|
||||||
|
14
formatter.go
14
formatter.go
@ -6,7 +6,7 @@ package expr
|
|||||||
|
|
||||||
import "fmt"
|
import "fmt"
|
||||||
|
|
||||||
type FmtOpt uint16
|
type FmtOpt uint32 // lower 16 bits hold a bit-mask, higher 16 bits hold an indentation number
|
||||||
|
|
||||||
const (
|
const (
|
||||||
TTY FmtOpt = 1 << iota
|
TTY FmtOpt = 1 << iota
|
||||||
@ -30,6 +30,18 @@ func TruncateString(s string) (trunc string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MakeFormatOptions(flags FmtOpt, indent int) FmtOpt {
|
||||||
|
return FmtOpt(indent<<16) | flags
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFormatFlags(opt FmtOpt) FmtOpt {
|
||||||
|
return opt & 0xFFFF
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetFormatIndent(opt FmtOpt) int {
|
||||||
|
return int(opt >> 16)
|
||||||
|
}
|
||||||
|
|
||||||
type Formatter interface {
|
type Formatter interface {
|
||||||
ToString(options FmtOpt) string
|
ToString(options FmtOpt) string
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ func makeGeneratingFraction(s string) (f *FractionType, err error) {
|
|||||||
}
|
}
|
||||||
for _, c := range dec[0:lsd] {
|
for _, c := range dec[0:lsd] {
|
||||||
if c < '0' || c > '9' {
|
if c < '0' || c > '9' {
|
||||||
return nil, errExpectedGot("fract", "digit", c)
|
return nil, ErrExpectedGot("fract", "digit", c)
|
||||||
}
|
}
|
||||||
num = num*10 + int64(c-'0')
|
num = num*10 + int64(c-'0')
|
||||||
den = den * 10
|
den = den * 10
|
||||||
@ -81,7 +81,7 @@ func makeGeneratingFraction(s string) (f *FractionType, err error) {
|
|||||||
mul := int64(1)
|
mul := int64(1)
|
||||||
for _, c := range subParts[0] {
|
for _, c := range subParts[0] {
|
||||||
if c < '0' || c > '9' {
|
if c < '0' || c > '9' {
|
||||||
return nil, errExpectedGot("fract", "digit", c)
|
return nil, ErrExpectedGot("fract", "digit", c)
|
||||||
}
|
}
|
||||||
num = num*10 + int64(c-'0')
|
num = num*10 + int64(c-'0')
|
||||||
sub = sub*10 + int64(c-'0')
|
sub = sub*10 + int64(c-'0')
|
||||||
@ -94,7 +94,7 @@ func makeGeneratingFraction(s string) (f *FractionType, err error) {
|
|||||||
p := subParts[1][0 : len(subParts[1])-1]
|
p := subParts[1][0 : len(subParts[1])-1]
|
||||||
for _, c := range p {
|
for _, c := range p {
|
||||||
if c < '0' || c > '9' {
|
if c < '0' || c > '9' {
|
||||||
return nil, errExpectedGot("fract", "digit", c)
|
return nil, ErrExpectedGot("fract", "digit", c)
|
||||||
}
|
}
|
||||||
num = num*10 + int64(c-'0')
|
num = num*10 + int64(c-'0')
|
||||||
den = den*10 + 9
|
den = den*10 + 9
|
||||||
@ -212,7 +212,7 @@ func anyToFract(v any) (f *FractionType, err error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if f == nil {
|
if f == nil {
|
||||||
err = errExpectedGot("fract", TypeFraction, v)
|
err = ErrExpectedGot("fract", TypeFraction, v)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ func (functor *baseFunctor) ToString(opt FmtOpt) (s string) {
|
|||||||
if functor.info != nil {
|
if functor.info != nil {
|
||||||
s = functor.info.ToString(opt)
|
s = functor.info.ToString(opt)
|
||||||
} else {
|
} else {
|
||||||
s = "func() {<body>}"
|
s = "func() {}"
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
@ -180,7 +180,7 @@ func (info *funcInfo) ToString(opt FmtOpt) string {
|
|||||||
} else {
|
} else {
|
||||||
sb.WriteString(TypeAny)
|
sb.WriteString(TypeAny)
|
||||||
}
|
}
|
||||||
sb.WriteString(" {<body>}")
|
sb.WriteString(" {}")
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,21 +26,21 @@ func NewListIterator(list *ListType, args []any) (it *ListIterator) {
|
|||||||
}
|
}
|
||||||
it = &ListIterator{a: list, count: 0, index: -1, start: 0, stop: listLen - 1, step: 1}
|
it = &ListIterator{a: list, count: 0, index: -1, start: 0, stop: listLen - 1, step: 1}
|
||||||
if argc >= 1 {
|
if argc >= 1 {
|
||||||
if i, err := toInt(args[0], "start index"); err == nil {
|
if i, err := ToInt(args[0], "start index"); err == nil {
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
i = listLen + i
|
i = listLen + i
|
||||||
}
|
}
|
||||||
it.start = i
|
it.start = i
|
||||||
}
|
}
|
||||||
if argc >= 2 {
|
if argc >= 2 {
|
||||||
if i, err := toInt(args[1], "stop index"); err == nil {
|
if i, err := ToInt(args[1], "stop index"); err == nil {
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
i = listLen + i
|
i = listLen + i
|
||||||
}
|
}
|
||||||
it.stop = i
|
it.stop = i
|
||||||
}
|
}
|
||||||
if argc >= 3 {
|
if argc >= 3 {
|
||||||
if i, err := toInt(args[2], "step"); err == nil {
|
if i, err := ToInt(args[2], "step"); err == nil {
|
||||||
if i < 0 {
|
if i < 0 {
|
||||||
i = -i
|
i = -i
|
||||||
}
|
}
|
||||||
|
23
list-type.go
23
list-type.go
@ -52,16 +52,24 @@ func ListFromStrings(stringList []string) (list *ListType) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (ls *ListType) ToString(opt FmtOpt) (s string) {
|
func (ls *ListType) ToString(opt FmtOpt) (s string) {
|
||||||
|
indent := GetFormatIndent(opt)
|
||||||
|
flags := GetFormatFlags(opt)
|
||||||
|
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
sb.WriteByte('[')
|
sb.WriteByte('[')
|
||||||
if len(*ls) > 0 {
|
if len(*ls) > 0 {
|
||||||
if opt&MultiLine != 0 {
|
innerOpt := MakeFormatOptions(flags, indent+1)
|
||||||
sb.WriteString("\n ")
|
nest := strings.Repeat(" ", indent+1)
|
||||||
|
|
||||||
|
if flags&MultiLine != 0 {
|
||||||
|
sb.WriteByte('\n')
|
||||||
|
sb.WriteString(nest)
|
||||||
}
|
}
|
||||||
for i, item := range []any(*ls) {
|
for i, item := range []any(*ls) {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
if opt&MultiLine != 0 {
|
if flags&MultiLine != 0 {
|
||||||
sb.WriteString(",\n ")
|
sb.WriteString(",\n")
|
||||||
|
sb.WriteString(nest)
|
||||||
} else {
|
} else {
|
||||||
sb.WriteString(", ")
|
sb.WriteString(", ")
|
||||||
}
|
}
|
||||||
@ -70,17 +78,20 @@ func (ls *ListType) ToString(opt FmtOpt) (s string) {
|
|||||||
sb.WriteByte('"')
|
sb.WriteByte('"')
|
||||||
sb.WriteString(s)
|
sb.WriteString(s)
|
||||||
sb.WriteByte('"')
|
sb.WriteByte('"')
|
||||||
|
} else if formatter, ok := item.(Formatter); ok {
|
||||||
|
sb.WriteString(formatter.ToString(innerOpt))
|
||||||
} else {
|
} else {
|
||||||
sb.WriteString(fmt.Sprintf("%v", item))
|
sb.WriteString(fmt.Sprintf("%v", item))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if opt&MultiLine != 0 {
|
if flags&MultiLine != 0 {
|
||||||
sb.WriteByte('\n')
|
sb.WriteByte('\n')
|
||||||
|
sb.WriteString(strings.Repeat(" ", indent))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.WriteByte(']')
|
sb.WriteByte(']')
|
||||||
s = sb.String()
|
s = sb.String()
|
||||||
if opt&Truncate != 0 && len(s) > TruncateSize {
|
if flags&Truncate != 0 && len(s) > TruncateSize {
|
||||||
s = TruncateString(s)
|
s = TruncateString(s)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
@ -26,7 +26,7 @@ func checkFunctionCall(ctx ExprContext, name string, varParams *[]any) (err erro
|
|||||||
if info, exists, owner := GetFuncInfo(ctx, name); exists {
|
if info, exists, owner := GetFuncInfo(ctx, name); exists {
|
||||||
passedCount := len(*varParams)
|
passedCount := len(*varParams)
|
||||||
if info.MinArgs() > passedCount {
|
if info.MinArgs() > passedCount {
|
||||||
err = errTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
|
err = ErrTooFewParams(name, info.MinArgs(), info.MaxArgs(), passedCount)
|
||||||
}
|
}
|
||||||
for i, p := range info.Params() {
|
for i, p := range info.Params() {
|
||||||
if i >= passedCount {
|
if i >= passedCount {
|
||||||
@ -37,7 +37,7 @@ func checkFunctionCall(ctx ExprContext, name string, varParams *[]any) (err erro
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(*varParams) {
|
if err == nil && info.MaxArgs() >= 0 && info.MaxArgs() < len(*varParams) {
|
||||||
err = errTooMuchParams(name, info.MaxArgs(), len(*varParams))
|
err = ErrTooMuchParams(name, info.MaxArgs(), len(*varParams))
|
||||||
}
|
}
|
||||||
if err == nil && owner != ctx {
|
if err == nil && owner != ctx {
|
||||||
ctx.RegisterFuncInfo(info)
|
ctx.RegisterFuncInfo(info)
|
||||||
|
@ -25,7 +25,7 @@ func evalNot(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if b, ok := toBool(rightValue); ok {
|
if b, ok := ToBool(rightValue); ok {
|
||||||
v = !b
|
v = !b
|
||||||
} else {
|
} else {
|
||||||
err = self.errIncompatibleType(rightValue)
|
err = self.errIncompatibleType(rightValue)
|
||||||
@ -65,8 +65,8 @@ func evalAndWithoutShortcut(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
leftBool, lok = toBool(leftValue)
|
leftBool, lok = ToBool(leftValue)
|
||||||
rightBool, rok = toBool(rightValue)
|
rightBool, rok = ToBool(rightValue)
|
||||||
|
|
||||||
if lok && rok {
|
if lok && rok {
|
||||||
v = leftBool && rightBool
|
v = leftBool && rightBool
|
||||||
@ -87,13 +87,13 @@ func evalAndWithShortcut(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if leftBool, lok := toBool(leftValue); !lok {
|
if leftBool, lok := ToBool(leftValue); !lok {
|
||||||
err = fmt.Errorf("got %T as left operand type of 'and' operator, it must be bool", leftBool)
|
err = fmt.Errorf("got %T as left operand type of 'and' operator, it must be bool", leftBool)
|
||||||
return
|
return
|
||||||
} else if !leftBool {
|
} else if !leftBool {
|
||||||
v = false
|
v = false
|
||||||
} else if rightValue, err = self.children[1].compute(ctx); err == nil {
|
} else if rightValue, err = self.children[1].compute(ctx); err == nil {
|
||||||
if rightBool, rok := toBool(rightValue); rok {
|
if rightBool, rok := ToBool(rightValue); rok {
|
||||||
v = rightBool
|
v = rightBool
|
||||||
} else {
|
} else {
|
||||||
err = self.errIncompatibleTypes(leftValue, rightValue)
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||||
@ -134,8 +134,8 @@ func evalOrWithoutShortcut(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
leftBool, lok = toBool(leftValue)
|
leftBool, lok = ToBool(leftValue)
|
||||||
rightBool, rok = toBool(rightValue)
|
rightBool, rok = ToBool(rightValue)
|
||||||
|
|
||||||
if lok && rok {
|
if lok && rok {
|
||||||
v = leftBool || rightBool
|
v = leftBool || rightBool
|
||||||
@ -156,13 +156,13 @@ func evalOrWithShortcut(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if leftBool, lok := toBool(leftValue); !lok {
|
if leftBool, lok := ToBool(leftValue); !lok {
|
||||||
err = fmt.Errorf("got %T as left operand type of 'or' operator, it must be bool", leftBool)
|
err = fmt.Errorf("got %T as left operand type of 'or' operator, it must be bool", leftBool)
|
||||||
return
|
return
|
||||||
} else if leftBool {
|
} else if leftBool {
|
||||||
v = true
|
v = true
|
||||||
} else if rightValue, err = self.children[1].compute(ctx); err == nil {
|
} else if rightValue, err = self.children[1].compute(ctx); err == nil {
|
||||||
if rightBool, rok := toBool(rightValue); rok {
|
if rightBool, rok := ToBool(rightValue); rok {
|
||||||
v = rightBool
|
v = rightBool
|
||||||
} else {
|
} else {
|
||||||
err = self.errIncompatibleTypes(leftValue, rightValue)
|
err = self.errIncompatibleTypes(leftValue, rightValue)
|
||||||
|
@ -31,7 +31,9 @@ func evalContextValue(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if sourceCtx != nil {
|
if sourceCtx != nil {
|
||||||
if formatter, ok := sourceCtx.(Formatter); ok {
|
if formatter, ok := sourceCtx.(DictFormat); ok {
|
||||||
|
v = formatter.ToDict()
|
||||||
|
} else if formatter, ok := sourceCtx.(Formatter); ok {
|
||||||
v = formatter.ToString(0)
|
v = formatter.ToString(0)
|
||||||
} else {
|
} else {
|
||||||
// keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' })
|
// keys := sourceCtx.EnumVars(func(name string) bool { return name[0] != '_' })
|
||||||
|
@ -23,7 +23,7 @@ func verifyKey(indexTerm *term, indexList *ListType) (index any, err error) {
|
|||||||
func verifyIndex(indexTerm *term, indexList *ListType, maxValue int) (index int, err error) {
|
func verifyIndex(indexTerm *term, indexList *ListType, maxValue int) (index int, err error) {
|
||||||
var v int
|
var v int
|
||||||
|
|
||||||
if v, err = toInt((*indexList)[0], "index expression"); err == nil {
|
if v, err = ToInt((*indexList)[0], "index expression"); err == nil {
|
||||||
if v < 0 && v >= -maxValue {
|
if v < 0 && v >= -maxValue {
|
||||||
v = maxValue + v
|
v = maxValue + v
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ func evalLength(ctx ExprContext, self *term) (v any, err error) {
|
|||||||
} else if it, ok := childValue.(Iterator); ok {
|
} else if it, ok := childValue.(Iterator); ok {
|
||||||
if extIt, ok := childValue.(ExtIterator); ok && extIt.HasOperation(countName) {
|
if extIt, ok := childValue.(ExtIterator); ok && extIt.HasOperation(countName) {
|
||||||
count, _ := extIt.CallOperation(countName, nil)
|
count, _ := extIt.CallOperation(countName, nil)
|
||||||
v, _ = toInt(count, "")
|
v, _ = ToInt(count, "")
|
||||||
} else {
|
} else {
|
||||||
v = int64(it.Index() + 1)
|
v = int64(it.Index() + 1)
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ func newNotEqualTerm(tk *Token) (inst *term) {
|
|||||||
|
|
||||||
func evalNotEqual(ctx ExprContext, self *term) (v any, err error) {
|
func evalNotEqual(ctx ExprContext, self *term) (v any, err error) {
|
||||||
if v, err = evalEqual(ctx, self); err == nil {
|
if v, err = evalEqual(ctx, self); err == nil {
|
||||||
b, _ := toBool(v)
|
b, _ := ToBool(v)
|
||||||
v = !b
|
v = !b
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
13
scanner.go
13
scanner.go
@ -178,13 +178,18 @@ func (self *scanner) fetchNextToken() (tk *Token) {
|
|||||||
tk = self.makeToken(SymDot, ch)
|
tk = self.makeToken(SymDot, ch)
|
||||||
}
|
}
|
||||||
case '\'':
|
case '\'':
|
||||||
tk = self.makeToken(SymQuote, ch)
|
if escape {
|
||||||
|
tk = self.makeToken(SymQuote, ch)
|
||||||
|
escape = false
|
||||||
|
} else {
|
||||||
|
tk = self.fetchString(ch)
|
||||||
|
}
|
||||||
case '"':
|
case '"':
|
||||||
if escape {
|
if escape {
|
||||||
tk = self.makeToken(SymDoubleQuote, ch)
|
tk = self.makeToken(SymDoubleQuote, ch)
|
||||||
escape = false
|
escape = false
|
||||||
} else {
|
} else {
|
||||||
tk = self.fetchString()
|
tk = self.fetchString(ch)
|
||||||
}
|
}
|
||||||
case '`':
|
case '`':
|
||||||
tk = self.makeToken(SymBackTick, ch)
|
tk = self.makeToken(SymBackTick, ch)
|
||||||
@ -533,7 +538,7 @@ func (self *scanner) fetchUntil(sym Symbol, allowEos bool, endings ...byte) (tk
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *scanner) fetchString() (tk *Token) {
|
func (self *scanner) fetchString(termCh byte) (tk *Token) {
|
||||||
var err error
|
var err error
|
||||||
var ch, prev byte
|
var ch, prev byte
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
@ -554,7 +559,7 @@ func (self *scanner) fetchString() (tk *Token) {
|
|||||||
sb.WriteByte(ch)
|
sb.WriteByte(ch)
|
||||||
}
|
}
|
||||||
prev = 0
|
prev = 0
|
||||||
} else if ch == '"' {
|
} else if ch == termCh {
|
||||||
break
|
break
|
||||||
} else {
|
} else {
|
||||||
prev = ch
|
prev = ch
|
||||||
|
@ -7,7 +7,7 @@ package expr
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"slices"
|
"slices"
|
||||||
"strings"
|
// "strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SimpleStore struct {
|
type SimpleStore struct {
|
||||||
@ -50,7 +50,7 @@ func (ctx *SimpleStore) Merge(src ExprContext) {
|
|||||||
ctx.funcStore[name], _ = src.GetFuncInfo(name)
|
ctx.funcStore[name], _ = src.GetFuncInfo(name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
func varsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
|
func varsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
|
||||||
sb.WriteString("vars: {\n")
|
sb.WriteString("vars: {\n")
|
||||||
first := true
|
first := true
|
||||||
@ -77,7 +77,7 @@ func varsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.WriteString(strings.Repeat("\t", indent))
|
sb.WriteString(strings.Repeat("\t", indent))
|
||||||
sb.WriteString("\n}\n")
|
sb.WriteString("\n}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func varsCtxToString(ctx ExprContext, indent int) string {
|
func varsCtxToString(ctx ExprContext, indent int) string {
|
||||||
@ -106,15 +106,59 @@ func funcsCtxToBuilder(sb *strings.Builder, ctx ExprContext, indent int) {
|
|||||||
sb.WriteString(fmt.Sprintf("%v", value))
|
sb.WriteString(fmt.Sprintf("%v", value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sb.WriteString("\n}\n")
|
sb.WriteString("\n}")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ctx *SimpleStore) ToString(opt FmtOpt) string {
|
func (ctx *SimpleStore) ToString(opt FmtOpt) string {
|
||||||
var sb strings.Builder
|
var sb strings.Builder
|
||||||
varsCtxToBuilder(&sb, ctx, 0)
|
varsCtxToBuilder(&sb, ctx, 0)
|
||||||
|
sb.WriteByte('\n')
|
||||||
funcsCtxToBuilder(&sb, ctx, 0)
|
funcsCtxToBuilder(&sb, ctx, 0)
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
func (ctx *SimpleStore) ToString(opt FmtOpt) string {
|
||||||
|
dict := ctx.ToDict()
|
||||||
|
return dict.ToString(opt)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *SimpleStore) varsToDict(dict *DictType) *DictType {
|
||||||
|
names := ctx.EnumVars(nil)
|
||||||
|
slices.Sort(names)
|
||||||
|
for _, name := range ctx.EnumVars(nil) {
|
||||||
|
value, _ := ctx.GetVar(name)
|
||||||
|
if f, ok := value.(Formatter); ok {
|
||||||
|
(*dict)[name] = f.ToString(0)
|
||||||
|
} else if _, ok = value.(Functor); ok {
|
||||||
|
(*dict)[name] = "func(){}"
|
||||||
|
} else {
|
||||||
|
(*dict)[name] = fmt.Sprintf("%v", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dict
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *SimpleStore) funcsToDict(dict *DictType) *DictType {
|
||||||
|
names := ctx.EnumFuncs(func(name string) bool { return true })
|
||||||
|
slices.Sort(names)
|
||||||
|
for _, name := range names {
|
||||||
|
value, _ := ctx.GetFuncInfo(name)
|
||||||
|
if formatter, ok := value.(Formatter); ok {
|
||||||
|
(*dict)[name] = formatter.ToString(0)
|
||||||
|
} else {
|
||||||
|
(*dict)[name] = fmt.Sprintf("%v", value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dict
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ctx *SimpleStore) ToDict() (dict *DictType) {
|
||||||
|
dict = MakeDict()
|
||||||
|
(*dict)["variables"] = ctx.varsToDict(MakeDict())
|
||||||
|
(*dict)["functions"] = ctx.funcsToDict(MakeDict())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (ctx *SimpleStore) GetVar(varName string) (v any, exists bool) {
|
func (ctx *SimpleStore) GetVar(varName string) (v any, exists bool) {
|
||||||
v, exists = ctx.varStore[varName]
|
v, exists = ctx.varStore[varName]
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
|
|
||||||
// t_func-base_test.go
|
// t_builtin-base_test.go
|
||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestFuncBase(t *testing.T) {
|
func TestFuncBase(t *testing.T) {
|
||||||
section := "Func-Base"
|
section := "Builtin-Base"
|
||||||
|
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`isNil(nil)`, true, nil},
|
/* 1 */ {`isNil(nil)`, true, nil},
|
24
t_builtin-import_test.go
Normal file
24
t_builtin-import_test.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// t_builtin-import_test.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFuncImport(t *testing.T) {
|
||||||
|
section := "Builtin-Import"
|
||||||
|
inputs := []inputType{
|
||||||
|
/* 1 */ {`builtin "import"; import("./test-resources/test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil},
|
||||||
|
/* 2 */ {`builtin "import"; import("test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil},
|
||||||
|
/* 3 */ {`builtin "import"; importAll("./test-resources/test-funcs.expr"); six()`, int64(6), nil},
|
||||||
|
/* 4 */ {`builtin "import"; import("./test-resources/sample-export-all.expr"); six()`, int64(6), nil},
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Setenv("EXPR_PATH", "test-resources")
|
||||||
|
|
||||||
|
// parserTestSpec(t, section, inputs, 69)
|
||||||
|
parserTest(t, section, inputs)
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
|
|
||||||
// t_func-math-arith_test.go
|
// t_builtin-math-arith_test.go
|
||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestFuncMathArith(t *testing.T) {
|
func TestFuncMathArith(t *testing.T) {
|
||||||
section := "Func-Math-Arith"
|
section := "Builtin-Math-Arith"
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`builtin "math.arith"; add(1,2)`, int64(3), nil},
|
/* 1 */ {`builtin "math.arith"; add(1,2)`, int64(3), nil},
|
||||||
/* 2 */ {`builtin "math.arith"; add(1,2,3)`, int64(6), nil},
|
/* 2 */ {`builtin "math.arith"; add(1,2,3)`, int64(6), nil},
|
@ -1,7 +1,7 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
|
|
||||||
// t_func-os_test.go
|
// t_builtin-os-file_test.go
|
||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@ -10,7 +10,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestFuncOs(t *testing.T) {
|
func TestFuncOs(t *testing.T) {
|
||||||
section := "Func-OS"
|
section := "Builtin-OS-File"
|
||||||
inputs := []inputType{
|
inputs := []inputType{
|
||||||
/* 1 */ {`builtin "os.file"`, int64(1), nil},
|
/* 1 */ {`builtin "os.file"`, int64(1), nil},
|
||||||
/* 2 */ {`builtin "os.file"; handle=fileOpen("/etc/hosts"); fileClose(handle)`, true, nil},
|
/* 2 */ {`builtin "os.file"; handle=fileOpen("/etc/hosts"); fileClose(handle)`, true, nil},
|
69
t_builtin-string_test.go
Normal file
69
t_builtin-string_test.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
||||||
|
// All rights reserved.
|
||||||
|
|
||||||
|
// t_builtin-string_test.go
|
||||||
|
package expr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestFuncString(t *testing.T) {
|
||||||
|
section := "Builtin-String"
|
||||||
|
|
||||||
|
inputs := []inputType{
|
||||||
|
/* 1 */ {`builtin "string"; strJoin("-", "one", "two", "three")`, "one-two-three", nil},
|
||||||
|
/* 2 */ {`builtin "string"; strJoin("-", ["one", "two", "three"])`, "one-two-three", nil},
|
||||||
|
/* 3 */ {`builtin "string"; ls= ["one", "two", "three"]; strJoin("-", ls)`, "one-two-three", nil},
|
||||||
|
/* 4 */ {`builtin "string"; ls= ["one", "two", "three"]; strJoin(1, ls)`, nil, errors.New(`strJoin(): the "separator" parameter must be a string, got a integer (1)`)},
|
||||||
|
/* 5 */ {`builtin "string"; ls= ["one", 2, "three"]; strJoin("-", ls)`, nil, errors.New(`strJoin(): expected string, got integer (2)`)},
|
||||||
|
/* 6 */ {`builtin "string"; "<"+strTrim(" bye bye ")+">"`, "<bye bye>", nil},
|
||||||
|
/* 7 */ {`builtin "string"; strSub("0123456789", 1,2)`, "12", nil},
|
||||||
|
/* 8 */ {`builtin "string"; strSub("0123456789", -3,2)`, "78", nil},
|
||||||
|
/* 9 */ {`builtin "string"; strSub("0123456789", -3)`, "789", nil},
|
||||||
|
/* 10 */ {`builtin "string"; strSub("0123456789")`, "0123456789", nil},
|
||||||
|
/* 11 */ {`builtin "string"; strStartsWith("0123456789", "xyz", "012")`, true, nil},
|
||||||
|
/* 12 */ {`builtin "string"; strStartsWith("0123456789", "xyz", "0125")`, false, nil},
|
||||||
|
/* 13 */ {`builtin "string"; strStartsWith("0123456789")`, nil, errors.New(`strStartsWith(): too few params -- expected 2 or more, got 1`)},
|
||||||
|
/* 14 */ {`builtin "string"; strEndsWith("0123456789", "xyz", "789")`, true, nil},
|
||||||
|
/* 15 */ {`builtin "string"; strEndsWith("0123456789", "xyz", "0125")`, false, nil},
|
||||||
|
/* 16 */ {`builtin "string"; strEndsWith("0123456789")`, nil, errors.New(`strEndsWith(): too few params -- expected 2 or more, got 1`)},
|
||||||
|
/* 17 */ {`builtin "string"; strSplit("one-two-three", "-")`, newListA("one", "two", "three"), nil},
|
||||||
|
/* 18 */ {`builtin "string"; strJoin("-", [1, "two", "three"])`, nil, errors.New(`strJoin(): expected string, got integer (1)`)},
|
||||||
|
/* 19 */ {`builtin "string"; strJoin()`, nil, errors.New(`strJoin(): too few params -- expected 1 or more, got 0`)},
|
||||||
|
|
||||||
|
/* 69 */ /*{`builtin "string"; $$global`, `vars: {
|
||||||
|
}
|
||||||
|
funcs: {
|
||||||
|
add(any=0 ...) -> number,
|
||||||
|
dec(any) -> decimal,
|
||||||
|
endsWithStr(source, suffix) -> boolean,
|
||||||
|
fract(any, denominator=1) -> fraction,
|
||||||
|
import( ...) -> any,
|
||||||
|
importAll( ...) -> any,
|
||||||
|
int(any) -> integer,
|
||||||
|
isBool(any) -> boolean,
|
||||||
|
isDec(any) -> boolean,
|
||||||
|
isDict(any) -> boolean,
|
||||||
|
isFloat(any) -> boolean,
|
||||||
|
isFract(any) -> boolean,
|
||||||
|
isInt(any) -> boolean,
|
||||||
|
isList(any) -> boolean,
|
||||||
|
isNil(any) -> boolean,
|
||||||
|
isString(any) -> boolean,
|
||||||
|
joinStr(separator, item="" ...) -> string,
|
||||||
|
mul(any=1 ...) -> number,
|
||||||
|
splitStr(source, separator="", count=-1) -> list of string,
|
||||||
|
startsWithStr(source, prefix) -> boolean,
|
||||||
|
subStr(source, start=0, count=-1) -> string,
|
||||||
|
trimStr(source) -> string
|
||||||
|
}
|
||||||
|
`, nil},*/
|
||||||
|
}
|
||||||
|
|
||||||
|
//t.Setenv("EXPR_PATH", ".")
|
||||||
|
|
||||||
|
// parserTestSpec(t, section, inputs, 19)
|
||||||
|
parserTest(t, section, inputs)
|
||||||
|
}
|
@ -110,7 +110,7 @@ func TestDictToStringMultiLine(t *testing.T) {
|
|||||||
var good bool
|
var good bool
|
||||||
section := "dict-ToString-ML"
|
section := "dict-ToString-ML"
|
||||||
want := `{
|
want := `{
|
||||||
"first": 1
|
"first": 1
|
||||||
}`
|
}`
|
||||||
args := map[any]*term{
|
args := map[any]*term{
|
||||||
"first": newLiteralTerm(NewValueToken(0, 0, SymInteger, "1", 1)),
|
"first": newLiteralTerm(NewValueToken(0, 0, SymInteger, "1", 1)),
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// t_func-import_test.go
|
|
||||||
package expr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFuncImport(t *testing.T) {
|
|
||||||
section := "Func-Import"
|
|
||||||
inputs := []inputType{
|
|
||||||
/* 1 */ {`builtin "import"; import("./test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil},
|
|
||||||
/* 2 */ {`builtin "import"; import("test-funcs.expr"); (double(3+a) + 1) * two()`, int64(34), nil},
|
|
||||||
/* 3 */ {`builtin "import"; importAll("./test-funcs.expr"); six()`, int64(6), nil},
|
|
||||||
/* 4 */ {`builtin "import"; import("./sample-export-all.expr"); six()`, int64(6), nil},
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Setenv("EXPR_PATH", ".")
|
|
||||||
|
|
||||||
// parserTestSpec(t, section, inputs, 69)
|
|
||||||
parserTest(t, section, inputs)
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
// Copyright (c) 2024 Celestino Amoroso (celestino.amoroso@gmail.com).
|
|
||||||
// All rights reserved.
|
|
||||||
|
|
||||||
// t_func-string_test.go
|
|
||||||
package expr
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestFuncString(t *testing.T) {
|
|
||||||
section := "Func-String"
|
|
||||||
|
|
||||||
inputs := []inputType{
|
|
||||||
/* 1 */ {`builtin "string"; joinStr("-", "one", "two", "three")`, "one-two-three", nil},
|
|
||||||
/* 2 */ {`builtin "string"; joinStr("-", ["one", "two", "three"])`, "one-two-three", nil},
|
|
||||||
/* 3 */ {`builtin "string"; ls= ["one", "two", "three"]; joinStr("-", ls)`, "one-two-three", nil},
|
|
||||||
/* 4 */ {`builtin "string"; ls= ["one", "two", "three"]; joinStr(1, ls)`, nil, errors.New(`joinStr() the "separator" parameter must be a string, got a integer (1)`)},
|
|
||||||
/* 5 */ {`builtin "string"; ls= ["one", 2, "three"]; joinStr("-", ls)`, nil, errors.New(`joinStr() expected string, got integer (2)`)},
|
|
||||||
/* 6 */ {`builtin "string"; "<"+trimStr(" bye bye ")+">"`, "<bye bye>", nil},
|
|
||||||
/* 7 */ {`builtin "string"; subStr("0123456789", 1,2)`, "12", nil},
|
|
||||||
/* 8 */ {`builtin "string"; subStr("0123456789", -3,2)`, "78", nil},
|
|
||||||
/* 9 */ {`builtin "string"; subStr("0123456789", -3)`, "789", nil},
|
|
||||||
/* 10 */ {`builtin "string"; subStr("0123456789")`, "0123456789", nil},
|
|
||||||
/* 11 */ {`builtin "string"; startsWithStr("0123456789", "xyz", "012")`, true, nil},
|
|
||||||
/* 12 */ {`builtin "string"; startsWithStr("0123456789", "xyz", "0125")`, false, nil},
|
|
||||||
/* 13 */ {`builtin "string"; startsWithStr("0123456789")`, nil, errors.New(`startsWithStr(): too few params -- expected 2 or more, got 1`)},
|
|
||||||
/* 14 */ {`builtin "string"; endsWithStr("0123456789", "xyz", "789")`, true, nil},
|
|
||||||
/* 15 */ {`builtin "string"; endsWithStr("0123456789", "xyz", "0125")`, false, nil},
|
|
||||||
/* 16 */ {`builtin "string"; endsWithStr("0123456789")`, nil, errors.New(`endsWithStr(): too few params -- expected 2 or more, got 1`)},
|
|
||||||
/* 17 */ {`builtin "string"; splitStr("one-two-three", "-")`, newListA("one", "two", "three"), nil},
|
|
||||||
/* 18 */ {`builtin "string"; joinStr("-", [1, "two", "three"])`, nil, errors.New(`joinStr() expected string, got integer (1)`)},
|
|
||||||
/* 19 */ {`builtin "string"; joinStr()`, nil, errors.New(`joinStr(): too few params -- expected 1 or more, got 0`)},
|
|
||||||
|
|
||||||
/* 69 */ /*{`builtin "string"; $$global`, `vars: {
|
|
||||||
}
|
|
||||||
funcs: {
|
|
||||||
add(any=0 ...) -> number,
|
|
||||||
dec(any) -> decimal,
|
|
||||||
endsWithStr(source, suffix) -> boolean,
|
|
||||||
fract(any, denominator=1) -> fraction,
|
|
||||||
import( ...) -> any,
|
|
||||||
importAll( ...) -> any,
|
|
||||||
int(any) -> integer,
|
|
||||||
isBool(any) -> boolean,
|
|
||||||
isDec(any) -> boolean,
|
|
||||||
isDict(any) -> boolean,
|
|
||||||
isFloat(any) -> boolean,
|
|
||||||
isFract(any) -> boolean,
|
|
||||||
isInt(any) -> boolean,
|
|
||||||
isList(any) -> boolean,
|
|
||||||
isNil(any) -> boolean,
|
|
||||||
isString(any) -> boolean,
|
|
||||||
joinStr(separator, item="" ...) -> string,
|
|
||||||
mul(any=1 ...) -> number,
|
|
||||||
splitStr(source, separator="", count=-1) -> list of string,
|
|
||||||
startsWithStr(source, prefix) -> boolean,
|
|
||||||
subStr(source, start=0, count=-1) -> string,
|
|
||||||
trimStr(source) -> string
|
|
||||||
}
|
|
||||||
`, nil},*/
|
|
||||||
}
|
|
||||||
|
|
||||||
//t.Setenv("EXPR_PATH", ".")
|
|
||||||
|
|
||||||
// parserTestSpec(t, section, inputs, 19)
|
|
||||||
parserTest(t, section, inputs)
|
|
||||||
}
|
|
@ -44,7 +44,7 @@ func dummy(ctx ExprContext, name string, args []any) (result any, err error) {
|
|||||||
|
|
||||||
func TestFunctionToStringSimple(t *testing.T) {
|
func TestFunctionToStringSimple(t *testing.T) {
|
||||||
source := NewGolangFunctor(dummy)
|
source := NewGolangFunctor(dummy)
|
||||||
want := "func() {<body>}"
|
want := "func() {}"
|
||||||
got := source.ToString(0)
|
got := source.ToString(0)
|
||||||
if got != want {
|
if got != want {
|
||||||
t.Errorf(`(func() -> result = %v [%T], want = %v [%T]`, got, got, want, want)
|
t.Errorf(`(func() -> result = %v [%T], want = %v [%T]`, got, got, want, want)
|
||||||
|
@ -45,7 +45,7 @@ func TestScanner(t *testing.T) {
|
|||||||
/* 22 */ {"@", SymAt, nil, nil},
|
/* 22 */ {"@", SymAt, nil, nil},
|
||||||
/* 23 */ {`#`, SymHash, nil, nil},
|
/* 23 */ {`#`, SymHash, nil, nil},
|
||||||
/* 24 */ {`%`, SymPercent, nil, nil},
|
/* 24 */ {`%`, SymPercent, nil, nil},
|
||||||
/* 25 */ {`'`, SymQuote, nil, nil},
|
/* 25 */ {`\'`, SymQuote, nil, nil},
|
||||||
/* 26 */ {`\"`, SymDoubleQuote, nil, nil},
|
/* 26 */ {`\"`, SymDoubleQuote, nil, nil},
|
||||||
/* 27 */ {`_`, SymUndescore, nil, nil},
|
/* 27 */ {`_`, SymUndescore, nil, nil},
|
||||||
/* 28 */ {`<>`, SymLessGreater, nil, nil},
|
/* 28 */ {`<>`, SymLessGreater, nil, nil},
|
||||||
|
@ -63,7 +63,7 @@ func TestIsString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count++
|
count++
|
||||||
b, ok := toBool(true)
|
b, ok := ToBool(true)
|
||||||
if !(ok && b) {
|
if !(ok && b) {
|
||||||
t.Errorf("%d: toBool(true) b=%v, ok=%v -> result = false, want true", count, b, ok)
|
t.Errorf("%d: toBool(true) b=%v, ok=%v -> result = false, want true", count, b, ok)
|
||||||
failed++
|
failed++
|
||||||
@ -72,7 +72,7 @@ func TestIsString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count++
|
count++
|
||||||
b, ok = toBool("abc")
|
b, ok = ToBool("abc")
|
||||||
if !(ok && b) {
|
if !(ok && b) {
|
||||||
t.Errorf("%d: toBool(\"abc\") b=%v, ok=%v -> result = false, want true", count, b, ok)
|
t.Errorf("%d: toBool(\"abc\") b=%v, ok=%v -> result = false, want true", count, b, ok)
|
||||||
failed++
|
failed++
|
||||||
@ -81,7 +81,7 @@ func TestIsString(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
count++
|
count++
|
||||||
b, ok = toBool([]int{})
|
b, ok = ToBool([]int{})
|
||||||
if ok {
|
if ok {
|
||||||
t.Errorf("%d: toBool([]) b=%v, ok=%v -> result = true, want false", count, b, ok)
|
t.Errorf("%d: toBool([]) b=%v, ok=%v -> result = true, want false", count, b, ok)
|
||||||
failed++
|
failed++
|
||||||
@ -97,7 +97,7 @@ func TestToIntOk(t *testing.T) {
|
|||||||
wantValue := int(64)
|
wantValue := int(64)
|
||||||
wantErr := error(nil)
|
wantErr := error(nil)
|
||||||
|
|
||||||
gotValue, gotErr := toInt(source, "test")
|
gotValue, gotErr := ToInt(source, "test")
|
||||||
|
|
||||||
if gotErr != nil || gotValue != wantValue {
|
if gotErr != nil || gotValue != wantValue {
|
||||||
t.Errorf("toInt(%v, \"test\") gotValue=%v, gotErr=%v -> wantValue=%v, wantErr=%v",
|
t.Errorf("toInt(%v, \"test\") gotValue=%v, gotErr=%v -> wantValue=%v, wantErr=%v",
|
||||||
@ -110,7 +110,7 @@ func TestToIntErr(t *testing.T) {
|
|||||||
wantValue := 0
|
wantValue := 0
|
||||||
wantErr := errors.New(`test expected integer, got uint64 (64)`)
|
wantErr := errors.New(`test expected integer, got uint64 (64)`)
|
||||||
|
|
||||||
gotValue, gotErr := toInt(source, "test")
|
gotValue, gotErr := ToInt(source, "test")
|
||||||
|
|
||||||
if gotErr.Error() != wantErr.Error() || gotValue != wantValue {
|
if gotErr.Error() != wantErr.Error() || gotValue != wantValue {
|
||||||
t.Errorf("toInt(%v, \"test\") gotValue=%v, gotErr=%v -> wantValue=%v, wantErr=%v",
|
t.Errorf("toInt(%v, \"test\") gotValue=%v, gotErr=%v -> wantValue=%v, wantErr=%v",
|
||||||
|
4
utils.go
4
utils.go
@ -86,7 +86,7 @@ func numAsFloat(v any) (f float64) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func toBool(v any) (b bool, ok bool) {
|
func ToBool(v any) (b bool, ok bool) {
|
||||||
ok = true
|
ok = true
|
||||||
switch x := v.(type) {
|
switch x := v.(type) {
|
||||||
case string:
|
case string:
|
||||||
@ -201,7 +201,7 @@ func CloneFilteredMap[K comparable, V any](source map[K]V, filter func(key K) (a
|
|||||||
return CopyFilteredMap(dest, source, filter)
|
return CopyFilteredMap(dest, source, filter)
|
||||||
}
|
}
|
||||||
|
|
||||||
func toInt(value any, description string) (i int, err error) {
|
func ToInt(value any, description string) (i int, err error) {
|
||||||
if valueInt64, ok := value.(int64); ok {
|
if valueInt64, ok := value.(int64); ok {
|
||||||
i = int(valueInt64)
|
i = int(valueInt64)
|
||||||
} else if valueInt, ok := value.(int); ok {
|
} else if valueInt, ok := value.(int); ok {
|
||||||
|
Loading…
Reference in New Issue
Block a user