diff --git a/internal/shader/expr.go b/internal/shader/expr.go index c10c69226..5dc9a32dc 100644 --- a/internal/shader/expr.go +++ b/internal/shader/expr.go @@ -369,6 +369,13 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) ([]shaderir.Expr, }, }, []shaderir.Type{{Main: shaderir.Bool}}, nil, true } + if e.Name == "_" { + return []shaderir.Expr{ + { + Type: shaderir.Blank, + }, + }, nil, nil, true + } if i, t, ok := block.findLocalVariable(e.Name); ok { return []shaderir.Expr{ { diff --git a/internal/shader/shader.go b/internal/shader/shader.go index ccbf241e3..ee605229b 100644 --- a/internal/shader/shader.go +++ b/internal/shader/shader.go @@ -104,6 +104,10 @@ func (b *block) totalLocalVariableNum() int { } func (b *block) findLocalVariable(name string) (int, shaderir.Type, bool) { + if name == "" || name == "_" { + panic("shader: variable name must be non-empty and non-underscore") + } + idx := 0 for outer := b.outer; outer != nil; outer = outer.outer { idx += len(outer.vars) diff --git a/internal/shader/stmt.go b/internal/shader/stmt.go index 1d968e3e1..f19ce0662 100644 --- a/internal/shader/stmt.go +++ b/internal/shader/stmt.go @@ -444,6 +444,7 @@ func (cs *compileState) assign(block *block, pos token.Pos, lhs, rhs []ast.Expr, var stmts []shaderir.Stmt var rhsExprs []shaderir.Expr var rhsTypes []shaderir.Type + allblank := true for i, e := range lhs { if len(lhs) == len(rhs) { @@ -462,9 +463,6 @@ func (cs *compileState) assign(block *block, pos token.Pos, lhs, rhs []ast.Expr, return nil, false } } - v := variable{ - name: name, - } ts, ok := cs.functionReturnTypes(block, rhs[i]) if !ok { ts = origts @@ -473,6 +471,10 @@ func (cs *compileState) assign(block *block, pos token.Pos, lhs, rhs []ast.Expr, cs.addError(pos, fmt.Sprintf("single-value context and multiple-value context cannot be mixed")) return nil, false } + + v := variable{ + name: name, + } if len(ts) == 1 { v.typ = ts[0] } @@ -490,6 +492,11 @@ func (cs *compileState) assign(block *block, pos token.Pos, lhs, rhs []ast.Expr, } stmts = append(stmts, ss...) + if l[0].Type == shaderir.Blank { + continue + } + allblank = false + if r[0].Type == shaderir.NumberExpr { t, ok := block.findLocalVariableByIndex(l[0].Index) if !ok { @@ -572,11 +579,22 @@ func (cs *compileState) assign(block *block, pos token.Pos, lhs, rhs []ast.Expr, } stmts = append(stmts, ss...) + if l[0].Type == shaderir.Blank { + continue + } + allblank = false + stmts = append(stmts, shaderir.Stmt{ Type: shaderir.Assign, Exprs: []shaderir.Expr{l[0], rhsExprs[i]}, }) } } + + if define && allblank { + cs.addError(pos, fmt.Sprintf("no new variables on left side of :=")) + return nil, false + } + return stmts, true } diff --git a/internal/shaderir/program.go b/internal/shaderir/program.go index 633bfb529..18f9e23dd 100644 --- a/internal/shaderir/program.go +++ b/internal/shaderir/program.go @@ -111,7 +111,8 @@ type Expr struct { type ExprType int const ( - NumberExpr ExprType = iota + Blank ExprType = iota + NumberExpr UniformVariable TextureVariable LocalVariable diff --git a/shader_test.go b/shader_test.go index b3c0bab94..193a1abb5 100644 --- a/shader_test.go +++ b/shader_test.go @@ -181,3 +181,56 @@ func TestShaderNoMain(t *testing.T) { t.Errorf("error must be non-nil but was nil") } } + +func TestShaderNoNewVariables(t *testing.T) { + if _, err := NewShader([]byte(`package main + +func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + _ := 1 +} +`)); err == nil { + t.Errorf("error must be non-nil but was nil") + } + + if _, err := NewShader([]byte(`package main + +func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + _, _ := 1, 1 +} +`)); err == nil { + t.Errorf("error must be non-nil but was nil") + } + + if _, err := NewShader([]byte(`package main + +func Foo() (int, int) { + return 1, 1 +} + +func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + _, _ := Foo() +} +`)); err == nil { + t.Errorf("error must be non-nil but was nil") + } + + if _, err := NewShader([]byte(`package main + +func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + a, _ := 1, 1 + _ = a +} +`)); err != nil { + t.Errorf("error must be nil but non-nil: %v", err) + } + + if _, err := NewShader([]byte(`package main + +func Fragment(position vec4, texCoord vec2, color vec4) vec4 { + _, a := 1, 1 + _ = a +} +`)); err != nil { + t.Errorf("error must be nil but non-nil: %v", err) + } +}