shader: Implement variable initialization in multiple-value context

This commit is contained in:
Hajime Hoshi 2020-06-07 23:23:58 +09:00
parent 1ca5dd16b2
commit 84fb951729
2 changed files with 87 additions and 25 deletions

View File

@ -257,17 +257,20 @@ func (cs *compileState) parseDecl(b *block, d ast.Decl) {
} }
continue continue
} }
for i, v := range vs {
b.vars = append(b.vars, v) base := len(b.vars)
if inits[i] != nil { b.vars = append(b.vars, vs...)
if len(inits) > 0 {
for i := range vs {
b.ir.Stmts = append(b.ir.Stmts, shaderir.Stmt{ b.ir.Stmts = append(b.ir.Stmts, shaderir.Stmt{
Type: shaderir.Assign, Type: shaderir.Assign,
Exprs: []shaderir.Expr{ Exprs: []shaderir.Expr{
{ {
Type: shaderir.LocalVariable, Type: shaderir.LocalVariable,
Index: len(b.vars) - 1, Index: base + i,
}, },
*inits[i], inits[i],
}, },
}) })
} }
@ -305,18 +308,38 @@ func (cs *compileState) parseDecl(b *block, d ast.Decl) {
} }
} }
func (s *compileState) parseVariable(block *block, vs *ast.ValueSpec) ([]variable, []*shaderir.Expr, []shaderir.Stmt) { func (s *compileState) parseVariable(block *block, vs *ast.ValueSpec) ([]variable, []shaderir.Expr, []shaderir.Stmt) {
if len(vs.Names) != len(vs.Values) && len(vs.Values) != 1 && len(vs.Values) != 0 {
s.addError(vs.Pos(), fmt.Sprintf("the numbers of lhs and rhs don't match"))
return nil, nil, nil
}
var t shaderir.Type var t shaderir.Type
if vs.Type != nil { if vs.Type != nil {
t = s.parseType(vs.Type) t = s.parseType(vs.Type)
} }
var vars []variable var (
var inits []*shaderir.Expr vars []variable
var stmts []shaderir.Stmt inits []shaderir.Expr
stmts []shaderir.Stmt
)
for i, n := range vs.Names { for i, n := range vs.Names {
var init ast.Expr var init ast.Expr
if len(vs.Values) > 0 { switch len(vs.Values) {
case 0:
case 1:
init = vs.Values[0]
if t.Main == shaderir.None {
ts := s.detectType(block, init)
if len(ts) != len(vs.Names) {
s.addError(vs.Pos(), fmt.Sprintf("the numbers of lhs and rhs don't match"))
continue
}
t = ts[i]
}
default:
init = vs.Values[i] init = vs.Values[i]
if t.Main == shaderir.None { if t.Main == shaderir.None {
ts := s.detectType(block, init) ts := s.detectType(block, init)
@ -326,20 +349,25 @@ func (s *compileState) parseVariable(block *block, vs *ast.ValueSpec) ([]variabl
t = ts[0] t = ts[0]
} }
} }
name := n.Name name := n.Name
vars = append(vars, variable{ vars = append(vars, variable{
name: name, name: name,
typ: t, typ: t,
}) })
var expr *shaderir.Expr if len(vs.Values) > 1 || (len(vs.Values) == 1 && len(inits) == 0) {
if init != nil { es, ss := s.parseExpr(block, init)
e, ss := s.parseExpr(block, init) inits = append(inits, es...)
expr = &e[0]
stmts = append(stmts, ss...) stmts = append(stmts, ss...)
} }
inits = append(inits, expr)
} }
if len(inits) > 0 && len(vars) != len(inits) {
s.addError(vs.Pos(), fmt.Sprintf("single-value context and multiple-value context cannot be mixed"))
return nil, nil, nil
}
return vars, inits, stmts return vars, inits, stmts
} }
@ -755,6 +783,11 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) ([]shaderir.Expr,
} }
if t := f.ir.Return; t.Main != shaderir.None { if t := f.ir.Return; t.Main != shaderir.None {
if len(outParams) == 0 {
cs.addError(e.Pos(), fmt.Sprintf("a function returning value cannot have out-params so far: %s", e.Fun))
return nil, nil
}
idx := len(block.vars) idx := len(block.vars)
block.vars = append(block.vars, variable{ block.vars = append(block.vars, variable{
typ: t, typ: t,
@ -797,18 +830,18 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) ([]shaderir.Expr,
}, },
}) })
// TODO: What about the other params? if len(outParams) == 0 {
if len(outParams) > 0 { // TODO: Is this an error?
return []shaderir.Expr{
{
Type: shaderir.LocalVariable,
Index: outParams[0],
},
}, stmts
} }
// TODO: Is an empty expression work? var exprs []shaderir.Expr
return nil, stmts for _, p := range outParams {
exprs = append(exprs, shaderir.Expr{
Type: shaderir.LocalVariable,
Index: p,
})
}
return exprs, stmts
case *ast.Ident: case *ast.Ident:
if i, ok := block.findLocalVariable(e.Name); ok { if i, ok := block.findLocalVariable(e.Name); ok {
return []shaderir.Expr{ return []shaderir.Expr{

View File

@ -205,6 +205,35 @@ func Bar(x vec2) vec2 {
void F1(in vec2 l0, out vec2 l1) { void F1(in vec2 l0, out vec2 l1) {
l1 = l0; l1 = l0;
return; return;
}`,
},
{
Name: "call multiple out params",
Src: `package main
func Foo(x vec2) vec2 {
var xx, yx float = Bar(x.x, x.y)
return vec2(xx, yx)
}
func Bar(x float) (float, float) {
return x, x
}`,
VS: `void F0(in vec2 l0, out vec2 l1) {
float l2 = 0.0;
float l3 = 0.0;
float l4 = 0.0;
float l5 = 0.0;
F1((l0).x, (l0).y, l2, l3);
l4 = l2;
l5 = l3;
l1 = vec2(l4, l5);
return;
}
void F1(in float l0, out float l1, out float l2) {
l1 = l0;
l2 = l0;
return;
}`, }`,
}, },
{ {