shader: Check at least one variable on left side of :=

Updates #1330
This commit is contained in:
Hajime Hoshi 2020-09-03 01:15:37 +09:00
parent 5f446a4c09
commit f5829b2cf3
5 changed files with 87 additions and 4 deletions

View File

@ -369,6 +369,13 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) ([]shaderir.Expr,
}, },
}, []shaderir.Type{{Main: shaderir.Bool}}, nil, true }, []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 { if i, t, ok := block.findLocalVariable(e.Name); ok {
return []shaderir.Expr{ return []shaderir.Expr{
{ {

View File

@ -104,6 +104,10 @@ func (b *block) totalLocalVariableNum() int {
} }
func (b *block) findLocalVariable(name string) (int, shaderir.Type, bool) { 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 idx := 0
for outer := b.outer; outer != nil; outer = outer.outer { for outer := b.outer; outer != nil; outer = outer.outer {
idx += len(outer.vars) idx += len(outer.vars)

View File

@ -444,6 +444,7 @@ func (cs *compileState) assign(block *block, pos token.Pos, lhs, rhs []ast.Expr,
var stmts []shaderir.Stmt var stmts []shaderir.Stmt
var rhsExprs []shaderir.Expr var rhsExprs []shaderir.Expr
var rhsTypes []shaderir.Type var rhsTypes []shaderir.Type
allblank := true
for i, e := range lhs { for i, e := range lhs {
if len(lhs) == len(rhs) { 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 return nil, false
} }
} }
v := variable{
name: name,
}
ts, ok := cs.functionReturnTypes(block, rhs[i]) ts, ok := cs.functionReturnTypes(block, rhs[i])
if !ok { if !ok {
ts = origts 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")) cs.addError(pos, fmt.Sprintf("single-value context and multiple-value context cannot be mixed"))
return nil, false return nil, false
} }
v := variable{
name: name,
}
if len(ts) == 1 { if len(ts) == 1 {
v.typ = ts[0] 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...) stmts = append(stmts, ss...)
if l[0].Type == shaderir.Blank {
continue
}
allblank = false
if r[0].Type == shaderir.NumberExpr { if r[0].Type == shaderir.NumberExpr {
t, ok := block.findLocalVariableByIndex(l[0].Index) t, ok := block.findLocalVariableByIndex(l[0].Index)
if !ok { if !ok {
@ -572,11 +579,22 @@ func (cs *compileState) assign(block *block, pos token.Pos, lhs, rhs []ast.Expr,
} }
stmts = append(stmts, ss...) stmts = append(stmts, ss...)
if l[0].Type == shaderir.Blank {
continue
}
allblank = false
stmts = append(stmts, shaderir.Stmt{ stmts = append(stmts, shaderir.Stmt{
Type: shaderir.Assign, Type: shaderir.Assign,
Exprs: []shaderir.Expr{l[0], rhsExprs[i]}, 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 return stmts, true
} }

View File

@ -111,7 +111,8 @@ type Expr struct {
type ExprType int type ExprType int
const ( const (
NumberExpr ExprType = iota Blank ExprType = iota
NumberExpr
UniformVariable UniformVariable
TextureVariable TextureVariable
LocalVariable LocalVariable

View File

@ -181,3 +181,56 @@ func TestShaderNoMain(t *testing.T) {
t.Errorf("error must be non-nil but was nil") 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)
}
}