Go: use slices for Handler arguments
First step to replacing linked lists with something more Go-like.
This commit is contained in:
parent
1ae1b9bb98
commit
f4f03d1737
290
ell/ell.go
290
ell/ell.go
|
@ -545,7 +545,7 @@ func (p *Parser) Run() (result *V, err error) {
|
||||||
// --- Runtime -----------------------------------------------------------------
|
// --- Runtime -----------------------------------------------------------------
|
||||||
|
|
||||||
// Handler is a Go handler for an Ell function.
|
// Handler is a Go handler for an Ell function.
|
||||||
type Handler func(*Ell, *V, **V) bool
|
type Handler func(*Ell, []V, **V) bool
|
||||||
|
|
||||||
// Ell is an interpreter context.
|
// Ell is an interpreter context.
|
||||||
type Ell struct {
|
type Ell struct {
|
||||||
|
@ -666,7 +666,15 @@ func (ell *Ell) evalNative(name string, args *V, result **V) bool {
|
||||||
if !ell.evalArgs(args, &arguments) {
|
if !ell.evalArgs(args, &arguments) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return fn(ell, arguments, result)
|
// FIXME: Must change V.Head to a slice, too! This is just a provisional
|
||||||
|
// change to not have to do both at once! Lots of copying this way.
|
||||||
|
var sliced []V
|
||||||
|
for ; arguments != nil; arguments = arguments.Next {
|
||||||
|
singledOut := *arguments
|
||||||
|
singledOut.Next = nil
|
||||||
|
sliced = append(sliced, singledOut)
|
||||||
|
}
|
||||||
|
return fn(ell, sliced, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ell *Ell) evalResolved(body *V, args *V, result **V) bool {
|
func (ell *Ell) evalResolved(body *V, args *V, result **V) bool {
|
||||||
|
@ -807,40 +815,37 @@ func NewBoolean(b bool) *V {
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
||||||
func fnLocal(ell *Ell, args *V, result **V) bool {
|
func fnLocal(ell *Ell, args []V, result **V) bool {
|
||||||
names := args
|
if len(args) == 0 || args[0].Type != VTypeList {
|
||||||
if names == nil || names.Type != VTypeList {
|
|
||||||
return ell.Errorf("first argument must be a list")
|
return ell.Errorf("first argument must be a list")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Duplicates or non-strings don't really matter to us, user's problem.
|
// Duplicates or non-strings don't really matter to us, user's problem.
|
||||||
scope := &ell.scopes.Head
|
scope := &ell.scopes.Head
|
||||||
|
|
||||||
values := names.Next
|
values := args[1:]
|
||||||
for names = names.Head; names != nil; names = names.Next {
|
for name := args[0].Head; name != nil; name = name.Next {
|
||||||
scopePrepend(scope, string(names.String), values.Clone())
|
scopePrepend(scope, string(name.String), values[0].Clone())
|
||||||
if values != nil {
|
if len(values) > 0 {
|
||||||
values = values.Next
|
values = values[1:]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnSet(ell *Ell, args *V, result **V) bool {
|
func fnSet(ell *Ell, args []V, result **V) bool {
|
||||||
name := args
|
if len(args) == 0 || args[0].Type != VTypeString {
|
||||||
if name == nil || name.Type != VTypeString {
|
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
|
|
||||||
v := name.Next
|
if len(args) > 1 {
|
||||||
if v != nil {
|
*result = args[1].Clone()
|
||||||
*result = v.Clone()
|
ell.Set(args[0].String, *result)
|
||||||
ell.Set(string(name.String), v)
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// We return an empty list for a nil value.
|
// We return an empty list for a nil value.
|
||||||
if v = ell.Get(string(name.String)); v != nil {
|
if v := ell.Get(args[0].String); v != nil {
|
||||||
*result = v.Clone()
|
*result = v.Clone()
|
||||||
} else {
|
} else {
|
||||||
*result = NewList(nil)
|
*result = NewList(nil)
|
||||||
|
@ -848,47 +853,56 @@ func fnSet(ell *Ell, args *V, result **V) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnList(ell *Ell, args *V, result **V) bool {
|
func sliceToSeq(slice []V) (res *V) {
|
||||||
*result = NewList(args.CloneSeq())
|
out := &res
|
||||||
|
for _, v := range slice {
|
||||||
|
*out = v.Clone()
|
||||||
|
out = &(*out).Next
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func fnList(ell *Ell, args []V, result **V) bool {
|
||||||
|
*result = NewList(sliceToSeq(args))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnValues(ell *Ell, args *V, result **V) bool {
|
func fnValues(ell *Ell, args []V, result **V) bool {
|
||||||
*result = args.CloneSeq()
|
*result = sliceToSeq(args)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnIf(ell *Ell, args *V, result **V) bool {
|
func fnIf(ell *Ell, args []V, result **V) bool {
|
||||||
var cond, body, keyword *V
|
var cond, body, keyword int
|
||||||
for cond = args; ; cond = keyword.Next {
|
for cond = 0; ; cond = keyword + 1 {
|
||||||
if cond == nil {
|
if cond >= len(args) {
|
||||||
return ell.Errorf("missing condition")
|
return ell.Errorf("missing condition")
|
||||||
}
|
}
|
||||||
if body = cond.Next; body == nil {
|
if body = cond + 1; body >= len(args) {
|
||||||
return ell.Errorf("missing body")
|
return ell.Errorf("missing body")
|
||||||
}
|
}
|
||||||
|
|
||||||
var res *V
|
var res *V
|
||||||
if !EvalAny(ell, cond, nil, &res) {
|
if !EvalAny(ell, &args[cond], nil, &res) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if Truthy(res) {
|
if Truthy(res) {
|
||||||
return EvalAny(ell, body, nil, result)
|
return EvalAny(ell, &args[body], nil, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
if keyword = body.Next; keyword == nil {
|
if keyword = body + 1; keyword >= len(args) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if keyword.Type != VTypeString {
|
if args[keyword].Type != VTypeString {
|
||||||
return ell.Errorf("expected keyword, got list")
|
return ell.Errorf("expected keyword, got list")
|
||||||
}
|
}
|
||||||
|
|
||||||
switch kw := string(keyword.String); kw {
|
switch kw := args[keyword].String; kw {
|
||||||
case "else":
|
case "else":
|
||||||
if body = keyword.Next; body == nil {
|
if body = keyword + 1; body >= len(args) {
|
||||||
return ell.Errorf("missing body")
|
return ell.Errorf("missing body")
|
||||||
}
|
}
|
||||||
return EvalAny(ell, body, nil, result)
|
return EvalAny(ell, &args[body], nil, result)
|
||||||
case "elif":
|
case "elif":
|
||||||
default:
|
default:
|
||||||
return ell.Errorf("invalid keyword: %s", kw)
|
return ell.Errorf("invalid keyword: %s", kw)
|
||||||
|
@ -897,15 +911,16 @@ func fnIf(ell *Ell, args *V, result **V) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnMap(ell *Ell, args *V, result **V) bool {
|
func fnMap(ell *Ell, args []V, result **V) bool {
|
||||||
var body, values *V
|
if len(args) < 1 {
|
||||||
if body = args; body == nil {
|
|
||||||
return ell.Errorf("first argument must be a function")
|
return ell.Errorf("first argument must be a function")
|
||||||
}
|
}
|
||||||
if values = body.Next; values == nil || values.Type != VTypeList {
|
if len(args) < 2 || args[0].Type != VTypeList {
|
||||||
return ell.Errorf("second argument must be a list")
|
return ell.Errorf("second argument must be a list")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body, values := &args[0], &args[1]
|
||||||
|
|
||||||
var res *V
|
var res *V
|
||||||
out := &res
|
out := &res
|
||||||
|
|
||||||
|
@ -921,37 +936,37 @@ func fnMap(ell *Ell, args *V, result **V) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnPrint(ell *Ell, args *V, result **V) bool {
|
func fnPrint(ell *Ell, args []V, result **V) bool {
|
||||||
for ; args != nil; args = args.Next {
|
for _, arg := range args {
|
||||||
if args.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
PrintV(os.Stdout, args)
|
PrintV(os.Stdout, &arg)
|
||||||
} else if _, err := os.Stdout.WriteString(args.String); err != nil {
|
} else if _, err := os.Stdout.WriteString(arg.String); err != nil {
|
||||||
return ell.Errorf("write failed: %s", err)
|
return ell.Errorf("write failed: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnCat(ell *Ell, args *V, result **V) bool {
|
func fnCat(ell *Ell, args []V, result **V) bool {
|
||||||
buf := bytes.NewBuffer(nil)
|
buf := bytes.NewBuffer(nil)
|
||||||
for ; args != nil; args = args.Next {
|
for _, arg := range args {
|
||||||
if args.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
PrintV(buf, args)
|
PrintV(buf, &arg)
|
||||||
} else {
|
} else {
|
||||||
buf.WriteString(args.String)
|
buf.WriteString(arg.String)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*result = NewString(buf.String())
|
*result = NewString(buf.String())
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnSystem(ell *Ell, args *V, result **V) bool {
|
func fnSystem(ell *Ell, args []V, result **V) bool {
|
||||||
var argv []string
|
var argv []string
|
||||||
for ; args != nil; args = args.Next {
|
for _, arg := range args {
|
||||||
if args.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
return ell.Errorf("arguments must be strings")
|
return ell.Errorf("arguments must be strings")
|
||||||
}
|
}
|
||||||
argv = append(argv, string(args.String))
|
argv = append(argv, string(arg.String))
|
||||||
}
|
}
|
||||||
if len(argv) == 0 {
|
if len(argv) == 0 {
|
||||||
return ell.Errorf("command name required")
|
return ell.Errorf("command name required")
|
||||||
|
@ -973,13 +988,12 @@ func fnSystem(ell *Ell, args *V, result **V) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnParse(ell *Ell, args *V, result **V) bool {
|
func fnParse(ell *Ell, args []V, result **V) bool {
|
||||||
body := args
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
if body == nil || body.Type != VTypeString {
|
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := NewParser([]byte(body.String)).Run()
|
res, err := NewParser([]byte(args[0].String)).Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ell.Errorf("%s", err)
|
return ell.Errorf("%s", err)
|
||||||
}
|
}
|
||||||
|
@ -987,14 +1001,15 @@ func fnParse(ell *Ell, args *V, result **V) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnTry(ell *Ell, args *V, result **V) bool {
|
func fnTry(ell *Ell, args []V, result **V) bool {
|
||||||
var body, handler *V
|
var body, handler *V
|
||||||
if body = args; body == nil {
|
if len(args) < 1 {
|
||||||
return ell.Errorf("first argument must be a function")
|
return ell.Errorf("first argument must be a function")
|
||||||
}
|
}
|
||||||
if handler = body.Next; handler == nil {
|
if len(args) < 2 {
|
||||||
return ell.Errorf("second argument must be a function")
|
return ell.Errorf("second argument must be a function")
|
||||||
}
|
}
|
||||||
|
body, handler = &args[0], &args[1]
|
||||||
if EvalAny(ell, body, nil, result) {
|
if EvalAny(ell, body, nil, result) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -1006,112 +1021,111 @@ func fnTry(ell *Ell, args *V, result **V) bool {
|
||||||
return EvalAny(ell, handler, msg, result)
|
return EvalAny(ell, handler, msg, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnThrow(ell *Ell, args *V, result **V) bool {
|
func fnThrow(ell *Ell, args []V, result **V) bool {
|
||||||
message := args
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
if message == nil || message.Type != VTypeString {
|
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
return ell.Errorf("%s", message.String)
|
return ell.Errorf("%s", args[0].String)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnPlus(ell *Ell, args *V, result **V) bool {
|
func fnPlus(ell *Ell, args []V, result **V) bool {
|
||||||
res := 0.
|
res := 0.
|
||||||
for ; args != nil; args = args.Next {
|
for _, arg := range args {
|
||||||
if args.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
return ell.Errorf("arguments must be strings")
|
return ell.Errorf("arguments must be strings")
|
||||||
}
|
}
|
||||||
var arg float64
|
var value float64
|
||||||
if n, _ := fmt.Sscan(string(args.String), &arg); n < 1 {
|
if n, _ := fmt.Sscan(arg.String, &value); n < 1 {
|
||||||
return ell.Errorf("invalid number: %s", args.String)
|
return ell.Errorf("invalid number: %s", arg.String)
|
||||||
}
|
}
|
||||||
res += arg
|
res += value
|
||||||
}
|
}
|
||||||
*result = NewNumber(res)
|
*result = NewNumber(res)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnMinus(ell *Ell, args *V, result **V) bool {
|
func fnMinus(ell *Ell, args []V, result **V) bool {
|
||||||
if args == nil || args.Type != VTypeString {
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
|
|
||||||
var res float64
|
var res float64
|
||||||
if n, _ := fmt.Sscan(string(args.String), &res); n < 1 {
|
if n, _ := fmt.Sscan(args[0].String, &res); n < 1 {
|
||||||
return ell.Errorf("invalid number: %f", args.String)
|
return ell.Errorf("invalid number: %f", args[0].String)
|
||||||
}
|
}
|
||||||
if args = args.Next; args == nil {
|
if len(args) == 1 {
|
||||||
res = -res
|
res = -res
|
||||||
}
|
}
|
||||||
|
|
||||||
for ; args != nil; args = args.Next {
|
for _, arg := range args[1:] {
|
||||||
if args.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
return ell.Errorf("arguments must be strings")
|
return ell.Errorf("arguments must be strings")
|
||||||
}
|
}
|
||||||
var arg float64
|
var value float64
|
||||||
if n, _ := fmt.Sscan(string(args.String), &arg); n < 1 {
|
if n, _ := fmt.Sscan(arg.String, &value); n < 1 {
|
||||||
return ell.Errorf("invalid number: %f", args.String)
|
return ell.Errorf("invalid number: %f", arg.String)
|
||||||
}
|
}
|
||||||
res -= arg
|
res -= value
|
||||||
}
|
}
|
||||||
*result = NewNumber(res)
|
*result = NewNumber(res)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnMultiply(ell *Ell, args *V, result **V) bool {
|
func fnMultiply(ell *Ell, args []V, result **V) bool {
|
||||||
res := 1.
|
res := 1.
|
||||||
for ; args != nil; args = args.Next {
|
for _, arg := range args {
|
||||||
if args.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
return ell.Errorf("arguments must be strings")
|
return ell.Errorf("arguments must be strings")
|
||||||
}
|
}
|
||||||
var arg float64
|
var value float64
|
||||||
if n, _ := fmt.Sscan(string(args.String), &arg); n < 1 {
|
if n, _ := fmt.Sscan(arg.String, &value); n < 1 {
|
||||||
return ell.Errorf("invalid number: %s", args.String)
|
return ell.Errorf("invalid number: %s", arg.String)
|
||||||
}
|
}
|
||||||
res *= arg
|
res *= value
|
||||||
}
|
}
|
||||||
*result = NewNumber(res)
|
*result = NewNumber(res)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnDivide(ell *Ell, args *V, result **V) bool {
|
func fnDivide(ell *Ell, args []V, result **V) bool {
|
||||||
if args == nil || args.Type != VTypeString {
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
|
|
||||||
var res float64
|
var res float64
|
||||||
if n, _ := fmt.Sscan(string(args.String), &res); n < 1 {
|
if n, _ := fmt.Sscan(args[0].String, &res); n < 1 {
|
||||||
return ell.Errorf("invalid number: %f", args.String)
|
return ell.Errorf("invalid number: %f", args[0].String)
|
||||||
}
|
}
|
||||||
for args = args.Next; args != nil; args = args.Next {
|
for _, arg := range args[1:] {
|
||||||
if args.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
return ell.Errorf("arguments must be strings")
|
return ell.Errorf("arguments must be strings")
|
||||||
}
|
}
|
||||||
var arg float64
|
var value float64
|
||||||
if n, _ := fmt.Sscan(string(args.String), &arg); n < 1 {
|
if n, _ := fmt.Sscan(arg.String, &value); n < 1 {
|
||||||
return ell.Errorf("invalid number: %f", args.String)
|
return ell.Errorf("invalid number: %f", arg.String)
|
||||||
}
|
}
|
||||||
res /= arg
|
res /= value
|
||||||
}
|
}
|
||||||
*result = NewNumber(res)
|
*result = NewNumber(res)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnNot(ell *Ell, args *V, result **V) bool {
|
func fnNot(ell *Ell, args []V, result **V) bool {
|
||||||
if args == nil {
|
if len(args) < 1 {
|
||||||
return ell.Errorf("missing argument")
|
return ell.Errorf("missing argument")
|
||||||
}
|
}
|
||||||
*result = NewBoolean(!Truthy(args))
|
*result = NewBoolean(!Truthy(&args[0]))
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnAnd(ell *Ell, args *V, result **V) bool {
|
func fnAnd(ell *Ell, args []V, result **V) bool {
|
||||||
if args == nil {
|
if args == nil {
|
||||||
*result = NewBoolean(true)
|
*result = NewBoolean(true)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
for ; args != nil; args = args.Next {
|
for _, arg := range args {
|
||||||
*result = nil
|
*result = nil
|
||||||
if !EvalAny(ell, args, nil, result) {
|
if !EvalAny(ell, &arg, nil, result) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !Truthy(*result) {
|
if !Truthy(*result) {
|
||||||
|
@ -1122,9 +1136,9 @@ func fnAnd(ell *Ell, args *V, result **V) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnOr(ell *Ell, args *V, result **V) bool {
|
func fnOr(ell *Ell, args []V, result **V) bool {
|
||||||
for ; args != nil; args = args.Next {
|
for _, arg := range args {
|
||||||
if !EvalAny(ell, args, nil, result) {
|
if !EvalAny(ell, &arg, nil, result) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if Truthy(*result) {
|
if Truthy(*result) {
|
||||||
|
@ -1136,17 +1150,16 @@ func fnOr(ell *Ell, args *V, result **V) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnEq(ell *Ell, args *V, result **V) bool {
|
func fnEq(ell *Ell, args []V, result **V) bool {
|
||||||
etalon := args
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
if etalon == nil || etalon.Type != VTypeString {
|
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
res := true
|
etalon, res := args[0].String, true
|
||||||
for args = etalon.Next; args != nil; args = args.Next {
|
for _, arg := range args[1:] {
|
||||||
if args.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
return ell.Errorf("arguments must be strings")
|
return ell.Errorf("arguments must be strings")
|
||||||
}
|
}
|
||||||
if res = string(etalon.String) == string(args.String); !res {
|
if res = etalon == arg.String; !res {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1154,41 +1167,39 @@ func fnEq(ell *Ell, args *V, result **V) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnLt(ell *Ell, args *V, result **V) bool {
|
func fnLt(ell *Ell, args []V, result **V) bool {
|
||||||
etalon := args
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
if etalon == nil || etalon.Type != VTypeString {
|
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
res := true
|
etalon, res := args[0].String, true
|
||||||
for args = etalon.Next; args != nil; args = args.Next {
|
for _, arg := range args[1:] {
|
||||||
if args.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
return ell.Errorf("arguments must be strings")
|
return ell.Errorf("arguments must be strings")
|
||||||
}
|
}
|
||||||
if res = string(etalon.String) < string(args.String); !res {
|
if res = etalon < arg.String; !res {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
etalon = args
|
etalon = arg.String
|
||||||
}
|
}
|
||||||
*result = NewBoolean(res)
|
*result = NewBoolean(res)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnEquals(ell *Ell, args *V, result **V) bool {
|
func fnEquals(ell *Ell, args []V, result **V) bool {
|
||||||
etalon := args
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
if etalon == nil || etalon.Type != VTypeString {
|
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
var first, second float64
|
var first, second float64
|
||||||
if n, _ := fmt.Sscan(string(etalon.String), &first); n < 1 {
|
if n, _ := fmt.Sscan(args[0].String, &first); n < 1 {
|
||||||
return ell.Errorf("invalid number: %f", etalon.String)
|
return ell.Errorf("invalid number: %f", args[0].String)
|
||||||
}
|
}
|
||||||
res := true
|
res := true
|
||||||
for args = etalon.Next; args != nil; args = args.Next {
|
for _, arg := range args[1:] {
|
||||||
if args.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
return ell.Errorf("arguments must be strings")
|
return ell.Errorf("arguments must be strings")
|
||||||
}
|
}
|
||||||
if n, _ := fmt.Sscan(string(args.String), &second); n < 1 {
|
if n, _ := fmt.Sscan(arg.String, &second); n < 1 {
|
||||||
return ell.Errorf("invalid number: %f", args.String)
|
return ell.Errorf("invalid number: %f", arg.String)
|
||||||
}
|
}
|
||||||
if res = first == second; !res {
|
if res = first == second; !res {
|
||||||
break
|
break
|
||||||
|
@ -1199,22 +1210,21 @@ func fnEquals(ell *Ell, args *V, result **V) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func fnLess(ell *Ell, args *V, result **V) bool {
|
func fnLess(ell *Ell, args []V, result **V) bool {
|
||||||
etalon := args
|
if len(args) < 1 || args[0].Type != VTypeString {
|
||||||
if etalon == nil || etalon.Type != VTypeString {
|
|
||||||
return ell.Errorf("first argument must be string")
|
return ell.Errorf("first argument must be string")
|
||||||
}
|
}
|
||||||
var first, second float64
|
var first, second float64
|
||||||
if n, _ := fmt.Sscan(string(etalon.String), &first); n < 1 {
|
if n, _ := fmt.Sscan(args[0].String, &first); n < 1 {
|
||||||
return ell.Errorf("invalid number: %f", etalon.String)
|
return ell.Errorf("invalid number: %f", args[0].String)
|
||||||
}
|
}
|
||||||
res := true
|
res := true
|
||||||
for args = etalon.Next; args != nil; args = args.Next {
|
for _, arg := range args[1:] {
|
||||||
if args.Type != VTypeString {
|
if arg.Type != VTypeString {
|
||||||
return ell.Errorf("arguments must be strings")
|
return ell.Errorf("arguments must be strings")
|
||||||
}
|
}
|
||||||
if n, _ := fmt.Sscan(string(args.String), &second); n < 1 {
|
if n, _ := fmt.Sscan(arg.String, &second); n < 1 {
|
||||||
return ell.Errorf("invalid number: %f", args.String)
|
return ell.Errorf("invalid number: %f", arg.String)
|
||||||
}
|
}
|
||||||
if res = first < second; !res {
|
if res = first < second; !res {
|
||||||
break
|
break
|
||||||
|
|
Loading…
Reference in New Issue