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
}
if e.Name == "_" {
return []shaderir.Expr{
{
Type: shaderir.Blank,
},
}, nil, nil, true
}
if i, t, ok := block.findLocalVariable(e.Name); ok {
return []shaderir.Expr{
{

View File

@ -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)

View File

@ -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
}

View File

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

View File

@ -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)
}
}