diff --git a/internal/shader/expr.go b/internal/shader/expr.go index 31774f9cb..93c2408f3 100644 --- a/internal/shader/expr.go +++ b/internal/shader/expr.go @@ -346,7 +346,15 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr, markLocalVariable }, }, []shaderir.Type{{Main: shaderir.Int}}, stmts, true case shaderir.IntF: - if args[0].Type == shaderir.NumberExpr && canTruncateToInteger(args[0].Const) { + if len(args) != 1 { + cs.addError(e.Pos(), fmt.Sprintf("number of %s's arguments must be 1 but %d", callee.BuiltinFunc, len(args))) + return nil, nil, nil, false + } + if args[0].Type == shaderir.NumberExpr { + if !canTruncateToInteger(args[0].Const) { + cs.addError(e.Pos(), fmt.Sprintf("cannot convert %s to type int", args[0].Const.String())) + return nil, nil, nil, false + } return []shaderir.Expr{ { Type: shaderir.NumberExpr, @@ -356,14 +364,20 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr, markLocalVariable }, []shaderir.Type{{Main: shaderir.Int}}, stmts, true } case shaderir.FloatF: + if len(args) != 1 { + cs.addError(e.Pos(), fmt.Sprintf("number of %s's arguments must be 1 but %d", callee.BuiltinFunc, len(args))) + return nil, nil, nil, false + } if args[0].Type == shaderir.NumberExpr { - return []shaderir.Expr{ - { - Type: shaderir.NumberExpr, - Const: gconstant.ToFloat(args[0].Const), - ConstType: shaderir.ConstTypeFloat, - }, - }, []shaderir.Type{{Main: shaderir.Float}}, stmts, true + if args[0].Const.Kind() == gconstant.Int || args[0].Const.Kind() == gconstant.Float { + return []shaderir.Expr{ + { + Type: shaderir.NumberExpr, + Const: gconstant.ToFloat(args[0].Const), + ConstType: shaderir.ConstTypeFloat, + }, + }, []shaderir.Type{{Main: shaderir.Float}}, stmts, true + } } case shaderir.Atan: if len(args) != 1 { @@ -379,13 +393,22 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr, markLocalVariable var t shaderir.Type switch callee.BuiltinFunc { case shaderir.BoolF: - // TODO: Check arg types. + if err := checkArgsForBoolBuiltinFunc(args, argts); err != nil { + cs.addError(e.Pos(), err.Error()) + return nil, nil, nil, false + } t = shaderir.Type{Main: shaderir.Bool} case shaderir.IntF: - // TODO: Check arg types. + if err := checkArgsForIntBuiltinFunc(args, argts); err != nil { + cs.addError(e.Pos(), err.Error()) + return nil, nil, nil, false + } t = shaderir.Type{Main: shaderir.Int} case shaderir.FloatF: - // TODO: Check arg types. + if err := checkArgsForFloatBuiltinFunc(args, argts); err != nil { + cs.addError(e.Pos(), err.Error()) + return nil, nil, nil, false + } t = shaderir.Type{Main: shaderir.Float} case shaderir.Vec2F: if err := checkArgsForVec2BuiltinFunc(args, argts); err != nil { diff --git a/internal/shader/syntax_test.go b/internal/shader/syntax_test.go index 42037ab6d..a8741bbec 100644 --- a/internal/shader/syntax_test.go +++ b/internal/shader/syntax_test.go @@ -1358,6 +1358,33 @@ func TestSyntaxBuiltinFuncType(t *testing.T) { stmt string err bool }{ + {stmt: "a := bool(false); _ = a", err: false}, + {stmt: "i := false; a := bool(i); _ = a", err: false}, + {stmt: "a := bool(1); _ = a", err: true}, + {stmt: "a := bool(1.0); _ = a", err: true}, + {stmt: "a := bool(); _ = a", err: true}, + {stmt: "a := bool(false, true); _ = a", err: true}, + + {stmt: "a := int(1); _ = a", err: false}, + {stmt: "a := int(1.0); _ = a", err: false}, + {stmt: "i := 1; a := int(i); _ = a", err: false}, + {stmt: "i := 1.0; a := int(i); _ = a", err: false}, + {stmt: "i := 1.1; a := int(i); _ = a", err: false}, + {stmt: "a := int(1.1); _ = a", err: true}, + {stmt: "a := int(false); _ = a", err: true}, + {stmt: "a := int(); _ = a", err: true}, + {stmt: "a := int(1, 2); _ = a", err: true}, + + {stmt: "a := float(1); _ = a", err: false}, + {stmt: "a := float(1.0); _ = a", err: false}, + {stmt: "a := float(1.1); _ = a", err: false}, + {stmt: "i := 1; a := float(i); _ = a", err: false}, + {stmt: "i := 1.0; a := float(i); _ = a", err: false}, + {stmt: "i := 1.1; a := float(i); _ = a", err: false}, + {stmt: "a := float(false); _ = a", err: true}, + {stmt: "a := float(); _ = a", err: true}, + {stmt: "a := float(1, 2); _ = a", err: true}, + {stmt: "a := vec2(1); _ = a", err: false}, {stmt: "a := vec2(1.0); _ = a", err: false}, {stmt: "i := 1; a := vec2(i); _ = a", err: false}, diff --git a/internal/shader/type.go b/internal/shader/type.go index 28ac89c71..e32a61237 100644 --- a/internal/shader/type.go +++ b/internal/shader/type.go @@ -119,6 +119,54 @@ func canBeFloatImplicitly(expr shaderir.Expr, t shaderir.Type) bool { return false } +func checkArgsForBoolBuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) error { + if len(args) != len(argts) { + return fmt.Errorf("the number of arguments and types doesn't match: %d vs %d", len(args), len(argts)) + } + + if len(args) != 1 { + return fmt.Errorf("number of bool's arguments must be 1 but %d", len(args)) + } + if argts[0].Main == shaderir.Bool { + return nil + } + if args[0].Const != nil && args[0].Const.Kind() == gconstant.Bool { + return nil + } + return fmt.Errorf("invalid arguments for bool: (%s)", argts[0].String()) +} + +func checkArgsForIntBuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) error { + if len(args) != len(argts) { + return fmt.Errorf("the number of arguments and types doesn't match: %d vs %d", len(args), len(argts)) + } + + if len(args) != 1 { + return fmt.Errorf("number of int's arguments must be 1 but %d", len(args)) + } + if argts[0].Main == shaderir.Int || argts[0].Main == shaderir.Float { + return nil + } + if args[0].Const != nil && canTruncateToInteger(args[0].Const) { + return nil + } + return fmt.Errorf("invalid arguments for int: (%s)", argts[0].String()) +} + +func checkArgsForFloatBuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) error { + if len(args) != len(argts) { + return fmt.Errorf("the number of arguments and types doesn't match: %d vs %d", len(args), len(argts)) + } + + if len(args) != 1 { + return fmt.Errorf("number of float's arguments must be 1 but %d", len(args)) + } + if canBeFloatImplicitly(args[0], argts[0]) { + return nil + } + return fmt.Errorf("invalid arguments for float: (%s)", argts[0].String()) +} + func checkArgsForVec2BuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) error { if len(args) != len(argts) { return fmt.Errorf("the number of arguments and types doesn't match: %d vs %d", len(args), len(argts)) @@ -137,7 +185,7 @@ func checkArgsForVec2BuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) er return nil } default: - return fmt.Errorf("too many arguments for vec2") + return fmt.Errorf("invalid number of arguments for vec2") } var str []string @@ -172,7 +220,7 @@ func checkArgsForVec3BuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) er return nil } default: - return fmt.Errorf("too many arguments for vec3") + return fmt.Errorf("invalid number of arguments for vec3") } var str []string @@ -220,7 +268,7 @@ func checkArgsForVec4BuiltinFunc(args []shaderir.Expr, argts []shaderir.Type) er return nil } default: - return fmt.Errorf("too many arguments for vec4") + return fmt.Errorf("invalid number of arguments for vec4") } var str []string