Skip to content

Commit

Permalink
Add count builtin
Browse files Browse the repository at this point in the history
  • Loading branch information
antonmedv committed Feb 25, 2020
1 parent 17ab719 commit 0ea1051
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 1 deletion.
23 changes: 22 additions & 1 deletion checker/checker.go
Expand Up @@ -492,10 +492,31 @@ func (v *visitor) BuiltinNode(node *ast.BuiltinNode) reflect.Type {
return reflect.ArrayOf(0, closure.Out(0))

}
panic(v.error(node.Arguments[1], "closure should return bool"))
panic(v.error(node.Arguments[1], "closure should has one input and one output param"))
}
panic(v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection))

case "count":
collection := v.visit(node.Arguments[0])
if !isArray(collection) {
panic(v.error(node.Arguments[0], "builtin %v takes only array (got %v)", node.Name, collection))
}

v.collections = append(v.collections, collection)
closure := v.visit(node.Arguments[1])
v.collections = v.collections[:len(v.collections)-1]

if isFunc(closure) &&
closure.NumOut() == 1 &&
closure.NumIn() == 1 && isInterface(closure.In(0)) {
if !isBool(closure.Out(0)) {
panic(v.error(node.Arguments[1], "closure should return boolean (got %v)", closure.Out(0).String()))
}

return integerType
}
panic(v.error(node.Arguments[1], "closure should has one input and one output param"))

default:
panic(v.error(node, "unknown builtin %v", node.Name))
}
Expand Down
12 changes: 12 additions & 0 deletions checker/checker_test.go
Expand Up @@ -157,6 +157,7 @@ func TestCheck(t *testing.T) {
`"a" < "b"`,
"Variadic('', 1, 2) + Variadic('')",
"Foo.Variadic('', 1, 2) + Foo.Variadic('')",
"count(1..30, {# % 3 == 0}) > 0",
}
for _, test := range typeTests {
var err error
Expand Down Expand Up @@ -439,6 +440,16 @@ Foo.Variadic('', '')
cannot use string as argument (type int) to call Variadic (1:18)
| Foo.Variadic('', '')
| .................^
count(1, {#})
builtin count takes only array (got int) (1:7)
| count(1, {#})
| ......^
count(ArrayOfInt, {#})
closure should return boolean (got int) (1:19)
| count(ArrayOfInt, {#})
| ..................^
`

func TestCheck_error(t *testing.T) {
Expand Down Expand Up @@ -569,6 +580,7 @@ type mockEnv2 struct {
Map map[string]*foo
Any interface{}
ArrayOfAny []interface{}
ArrayOfInt []int
ManOfAny map[string]interface{}
Fn func(bool, int, string, interface{}) string
Bool bool
Expand Down
15 changes: 15 additions & 0 deletions compiler/compiler.go
Expand Up @@ -531,6 +531,21 @@ func (c *compiler) BuiltinNode(node *ast.BuiltinNode) {
c.emit(OpEnd)
c.emit(OpArray)

case "count":
count := c.makeConstant("count")
c.compile(node.Arguments[0])
c.emit(OpBegin)
c.emitPush(0)
c.emit(OpStore, count...)
c.emitLoop(func() {
c.compile(node.Arguments[1])
c.emitCond(func() {
c.emit(OpInc, count...)
})
})
c.emit(OpLoad, count...)
c.emit(OpEnd)

default:
panic(fmt.Sprintf("unknown builtin %v", node.Name))
}
Expand Down
4 changes: 4 additions & 0 deletions expr_test.go
Expand Up @@ -687,6 +687,10 @@ func TestExpr(t *testing.T) {
`one([1,1,0,1], {# == 0}) and not one([1,0,0,1], {# == 0})`,
true,
},
{
`count(1..30, {# % 3 == 0})`,
10,
},
{
`Now.After(BirthDay)`,
true,
Expand Down
1 change: 1 addition & 0 deletions parser/parser.go
Expand Up @@ -70,6 +70,7 @@ var builtins = map[string]builtin{
"one": {2},
"filter": {2},
"map": {2},
"count": {2},
}

type parser struct {
Expand Down

0 comments on commit 0ea1051

Please sign in to comment.