Skip to content

Commit

Permalink
Merge 7c0dfe6 into a22808e
Browse files Browse the repository at this point in the history
  • Loading branch information
sysread committed Dec 16, 2019
2 parents a22808e + 7c0dfe6 commit b7ed023
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 12 deletions.
1 change: 1 addition & 0 deletions evaluator/evaluator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -879,6 +879,7 @@ c")`, []string{"a", "b", "c"}},
{`[1, 2].keys()`, []int{0, 1}},
{`[1, 2].join("-")`, "1-2"},
{`["a", "b"].join("-")`, "a-b"},
{`["a", "b"].join()`, "ab"},
{`"a".any("b")`, false},
{`"a".any("a")`, true},
{`"a".prefix("b")`, false},
Expand Down
93 changes: 81 additions & 12 deletions evaluator/functions.go
Original file line number Diff line number Diff line change
Expand Up @@ -374,20 +374,74 @@ func validateArgs(tok token.Token, name string, args []object.Object, size int,
return nil
}

func validateVarArgs(tok token.Token, name string, args []object.Object, required int, types [][][]string) object.Object {
if len(args) < required {
return newError(tok, "wrong number of arguments to %s(...): got=%d, min=%d, max=%d", name, len(args), required, len(types))
// spec is an array of {
// { // signature: func(num|str, arr)
// { NUMBER_OBJ, STRING_OBJ }, // type options for arg 0
// { ARRAY_OBJ}, // type options for arg 1
// },
// { // signature: func(num|str)
// { NUMBER_OBJ, STRING_OBJ }, // type options for arg 0
// },
// }
func validateVarArgs(tok token.Token, name string, args []object.Object, specs [][][]string) (object.Object, int) {
required := -1
max := 0

for _, spec := range specs {
// find the min number of arguments required
if required == -1 || len(spec) < required {
required = len(spec)
}

// find the max number of arguments supported
if len(spec) > max {
max = len(spec)
}
}

for i, set := range types {
for _, t := range set {
if !util.Contains(t, string(args[i].Type())) {
return newError(tok, "argument %d to %s(...) is not supported (got: %s, allowed: %s)", i, name, args[i].Inspect(), strings.Join(t, ", "))
if len(args) < required || len(args) > max {
return newError(tok, "wrong number of arguments to %s(...): got=%d, min=%d, max=%d", name, len(args), required, max), -1
}

for which, spec := range specs {
// does the number of args match this spec?
if len(args) != len(spec) {
continue
}

// do the caller's args match this spec?
match := true
for i, types := range spec {
if i < len(args) && !util.Contains(types, string(args[i].Type())) {
match = false
break
}
}

// found a match; return the index of the matched spec
if match {
return nil, which
}
}

return nil
// no signature specs matched
return newError(tok, usageVarArgs(name, specs)), -1
}

func usageVarArgs(name string, specs [][][]string) string {
signatures := []string{}

for _, spec := range specs {
args := []string{}

for _, types := range spec {
args = append(args, strings.Join(types, " | "))
}

signatures = append(signatures, fmt.Sprintf("%s(%s)", name, strings.Join(args, ", ")))
}

return strings.Join(signatures, "\n")
}

// len(var:"hello")
Expand Down Expand Up @@ -722,14 +776,20 @@ func stdinNextFn() (object.Object, object.Object) {

// env(variable:"PWD") or env(string:"KEY", string:"VAL")
func envFn(tok token.Token, env *object.Environment, args ...object.Object) object.Object {
err := validateVarArgs(tok, "env", args, 1, [][][]string{{{object.STRING_OBJ}, {object.STRING_OBJ}}})
err, spec := validateVarArgs(tok, "env", args, [][][]string{
{{object.STRING_OBJ}, {object.STRING_OBJ}},
{{object.STRING_OBJ}},
})

fmt.Printf("matched %d\n", spec)

if err != nil {
return err
}

key := args[0].(*object.String)

if len(args) > 1 {
if spec == 0 {
val := args[1].(*object.String)
os.Setenv(key.Value, val.Value)
}
Expand Down Expand Up @@ -1572,11 +1632,20 @@ func itemsFn(tok token.Token, env *object.Environment, args ...object.Object) ob
}

func joinFn(tok token.Token, env *object.Environment, args ...object.Object) object.Object {
err := validateArgs(tok, "join", args, 2, [][]string{{object.ARRAY_OBJ}, {object.STRING_OBJ}})
err, spec := validateVarArgs(tok, "join", args, [][][]string{
{{object.ARRAY_OBJ}, {object.STRING_OBJ}},
{{object.ARRAY_OBJ}},
})

if err != nil {
return err
}

glue := ""
if spec == 0 {
glue = args[1].(*object.String).Value
}

arr := args[0].(*object.Array)
length := len(arr.Elements)
newElements := make([]string, length, length)
Expand All @@ -1585,7 +1654,7 @@ func joinFn(tok token.Token, env *object.Environment, args ...object.Object) obj
newElements[k] = v.Inspect()
}

return &object.String{Token: tok, Value: strings.Join(newElements, args[1].(*object.String).Value)}
return &object.String{Token: tok, Value: strings.Join(newElements, glue)}
}

func sleepFn(tok token.Token, env *object.Environment, args ...object.Object) object.Object {
Expand Down

0 comments on commit b7ed023

Please sign in to comment.