shader: Let parseExpr return multiple values

This commit is contained in:
Hajime Hoshi 2020-06-08 00:51:20 +09:00
parent bee79e3b67
commit 1ca5dd16b2

View File

@ -335,7 +335,7 @@ func (s *compileState) parseVariable(block *block, vs *ast.ValueSpec) ([]variabl
var expr *shaderir.Expr var expr *shaderir.Expr
if init != nil { if init != nil {
e, ss := s.parseExpr(block, init) e, ss := s.parseExpr(block, init)
expr = &e expr = &e[0]
stmts = append(stmts, ss...) stmts = append(stmts, ss...)
} }
inits = append(inits, expr) inits = append(inits, expr)
@ -531,9 +531,10 @@ func (cs *compileState) parseBlock(outer *block, b *ast.BlockStmt, inParams, out
lhs, stmts := cs.parseExpr(block, l.Lhs[i]) lhs, stmts := cs.parseExpr(block, l.Lhs[i])
block.ir.Stmts = append(block.ir.Stmts, stmts...) block.ir.Stmts = append(block.ir.Stmts, stmts...)
// TODO: Treat multiple expressions
block.ir.Stmts = append(block.ir.Stmts, shaderir.Stmt{ block.ir.Stmts = append(block.ir.Stmts, shaderir.Stmt{
Type: shaderir.Assign, Type: shaderir.Assign,
Exprs: []shaderir.Expr{lhs, rhs}, Exprs: []shaderir.Expr{lhs[0], rhs[0]},
}) })
} }
case token.ASSIGN: case token.ASSIGN:
@ -545,9 +546,10 @@ func (cs *compileState) parseBlock(outer *block, b *ast.BlockStmt, inParams, out
lhs, stmts := cs.parseExpr(block, l.Lhs[i]) lhs, stmts := cs.parseExpr(block, l.Lhs[i])
block.ir.Stmts = append(block.ir.Stmts, stmts...) block.ir.Stmts = append(block.ir.Stmts, stmts...)
// TODO: Treat multiple expressions
block.ir.Stmts = append(block.ir.Stmts, shaderir.Stmt{ block.ir.Stmts = append(block.ir.Stmts, shaderir.Stmt{
Type: shaderir.Assign, Type: shaderir.Assign,
Exprs: []shaderir.Expr{lhs, rhs}, Exprs: []shaderir.Expr{lhs[0], rhs[0]},
}) })
} }
} }
@ -563,8 +565,15 @@ func (cs *compileState) parseBlock(outer *block, b *ast.BlockStmt, inParams, out
cs.parseDecl(block, l.Decl) cs.parseDecl(block, l.Decl)
case *ast.ReturnStmt: case *ast.ReturnStmt:
for i, r := range l.Results { for i, r := range l.Results {
e, stmts := cs.parseExpr(block, r) exprs, stmts := cs.parseExpr(block, r)
block.ir.Stmts = append(block.ir.Stmts, stmts...) block.ir.Stmts = append(block.ir.Stmts, stmts...)
if len(exprs) == 0 {
continue
}
if len(exprs) > 1 {
cs.addError(r.Pos(), "multiple-context with return is not implemented yet")
continue
}
block.ir.Stmts = append(block.ir.Stmts, shaderir.Stmt{ block.ir.Stmts = append(block.ir.Stmts, shaderir.Stmt{
Type: shaderir.Assign, Type: shaderir.Assign,
Exprs: []shaderir.Expr{ Exprs: []shaderir.Expr{
@ -572,7 +581,7 @@ func (cs *compileState) parseBlock(outer *block, b *ast.BlockStmt, inParams, out
Type: shaderir.LocalVariable, Type: shaderir.LocalVariable,
Index: len(inParams) + i, Index: len(inParams) + i,
}, },
e, exprs[0],
}, },
}) })
} }
@ -585,7 +594,7 @@ func (cs *compileState) parseBlock(outer *block, b *ast.BlockStmt, inParams, out
return block return block
} }
func (cs *compileState) parseExpr(block *block, expr ast.Expr) (shaderir.Expr, []shaderir.Stmt) { func (cs *compileState) parseExpr(block *block, expr ast.Expr) ([]shaderir.Expr, []shaderir.Stmt) {
switch e := expr.(type) { switch e := expr.(type) {
case *ast.BasicLit: case *ast.BasicLit:
switch e.Kind { switch e.Kind {
@ -593,21 +602,25 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) (shaderir.Expr, [
v, err := strconv.ParseInt(e.Value, 10, 32) v, err := strconv.ParseInt(e.Value, 10, 32)
if err != nil { if err != nil {
cs.addError(e.Pos(), fmt.Sprintf("unexpected literal: %s", e.Value)) cs.addError(e.Pos(), fmt.Sprintf("unexpected literal: %s", e.Value))
return shaderir.Expr{}, nil return nil, nil
} }
return shaderir.Expr{ return []shaderir.Expr{
{
Type: shaderir.IntExpr, Type: shaderir.IntExpr,
Int: int32(v), Int: int32(v),
},
}, nil }, nil
case token.FLOAT: case token.FLOAT:
v, err := strconv.ParseFloat(e.Value, 32) v, err := strconv.ParseFloat(e.Value, 32)
if err != nil { if err != nil {
cs.addError(e.Pos(), fmt.Sprintf("unexpected literal: %s", e.Value)) cs.addError(e.Pos(), fmt.Sprintf("unexpected literal: %s", e.Value))
return shaderir.Expr{}, nil return nil, nil
} }
return shaderir.Expr{ return []shaderir.Expr{
{
Type: shaderir.FloatExpr, Type: shaderir.FloatExpr,
Float: float32(v), Float: float32(v),
},
}, nil }, nil
default: default:
cs.addError(e.Pos(), fmt.Sprintf("literal not implemented: %#v", e)) cs.addError(e.Pos(), fmt.Sprintf("literal not implemented: %#v", e))
@ -655,21 +668,32 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) (shaderir.Expr, [
op = shaderir.OrOr op = shaderir.OrOr
default: default:
cs.addError(e.Pos(), fmt.Sprintf("unexpected operator: %s", e.Op)) cs.addError(e.Pos(), fmt.Sprintf("unexpected operator: %s", e.Op))
return shaderir.Expr{}, nil return nil, nil
} }
var stmts []shaderir.Stmt var stmts []shaderir.Stmt
// Prase RHS first for the order of the statements. // Prase RHS first for the order of the statements.
rhs, ss := cs.parseExpr(block, e.Y) rhs, ss := cs.parseExpr(block, e.Y)
stmts = append(stmts, ss...) if len(rhs) != 1 {
lhs, ss := cs.parseExpr(block, e.X) cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a binary operator: %s", e.Y))
return nil, nil
}
stmts = append(stmts, ss...) stmts = append(stmts, ss...)
return shaderir.Expr{ lhs, ss := cs.parseExpr(block, e.X)
if len(lhs) != 1 {
cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a binary operator: %s", e.X))
return nil, nil
}
stmts = append(stmts, ss...)
return []shaderir.Expr{
{
Type: shaderir.Binary, Type: shaderir.Binary,
Op: op, Op: op,
Exprs: []shaderir.Expr{lhs, rhs}, Exprs: []shaderir.Expr{lhs[0], rhs[0]},
},
}, stmts }, stmts
case *ast.CallExpr: case *ast.CallExpr:
var ( var (
@ -680,30 +704,42 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) (shaderir.Expr, [
// Parse the argument first for the order of the statements. // Parse the argument first for the order of the statements.
for _, a := range e.Args { for _, a := range e.Args {
e, ss := cs.parseExpr(block, a) es, ss := cs.parseExpr(block, a)
if len(es) > 1 && len(e.Args) > 1 {
cs.addError(e.Pos(), fmt.Sprintf("single-value context and multiple-value context cannot be mixed: %s", e.Fun))
return nil, nil
}
// TODO: Convert integer literals to float literals if necessary. // TODO: Convert integer literals to float literals if necessary.
args = append(args, e) args = append(args, es...)
stmts = append(stmts, ss...) stmts = append(stmts, ss...)
} }
// TODO: When len(ss) is not 0? // TODO: When len(ss) is not 0?
expr, ss := cs.parseExpr(block, e.Fun) es, ss := cs.parseExpr(block, e.Fun)
callee = expr if len(es) != 1 {
cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a callee: %s", e.Fun))
return nil, nil
}
callee = es[0]
stmts = append(stmts, ss...) stmts = append(stmts, ss...)
// For built-in functions, we can call this in this position. Return an expression for the function // For built-in functions, we can call this in this position. Return an expression for the function
// call. // call.
if expr.Type == shaderir.BuiltinFuncExpr { if callee.Type == shaderir.BuiltinFuncExpr {
return shaderir.Expr{ return []shaderir.Expr{
{
Type: shaderir.Call, Type: shaderir.Call,
Exprs: append([]shaderir.Expr{callee}, args...), Exprs: append([]shaderir.Expr{callee}, args...),
},
}, stmts }, stmts
} }
if expr.Type != shaderir.FunctionExpr { if callee.Type != shaderir.FunctionExpr {
cs.addError(e.Pos(), fmt.Sprintf("function callee must be a funciton name but %s", e.Fun)) cs.addError(e.Pos(), fmt.Sprintf("function callee must be a funciton name but %s", e.Fun))
return nil, nil
} }
f := cs.funcs[expr.Index]
f := cs.funcs[callee.Index]
var outParams []int var outParams []int
for _, p := range f.ir.OutParams { for _, p := range f.ir.OutParams {
@ -741,9 +777,11 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) (shaderir.Expr, [
// The actual expression here is just a local variable that includes the result of the // The actual expression here is just a local variable that includes the result of the
// function call. // function call.
return shaderir.Expr{ return []shaderir.Expr{
{
Type: shaderir.LocalVariable, Type: shaderir.LocalVariable,
Index: idx, Index: idx,
},
}, stmts }, stmts
} }
@ -761,51 +799,67 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) (shaderir.Expr, [
// TODO: What about the other params? // TODO: What about the other params?
if len(outParams) > 0 { if len(outParams) > 0 {
return shaderir.Expr{ return []shaderir.Expr{
{
Type: shaderir.LocalVariable, Type: shaderir.LocalVariable,
Index: outParams[0], Index: outParams[0],
},
}, stmts }, stmts
} }
// TODO: Is an empty expression work? // TODO: Is an empty expression work?
return shaderir.Expr{}, stmts return nil, 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{
{
Type: shaderir.LocalVariable, Type: shaderir.LocalVariable,
Index: i, Index: i,
},
}, nil }, nil
} }
if i, ok := cs.findFunction(e.Name); ok { if i, ok := cs.findFunction(e.Name); ok {
return shaderir.Expr{ return []shaderir.Expr{
{
Type: shaderir.FunctionExpr, Type: shaderir.FunctionExpr,
Index: i, Index: i,
},
}, nil }, nil
} }
if i, ok := cs.findUniformVariable(e.Name); ok { if i, ok := cs.findUniformVariable(e.Name); ok {
return shaderir.Expr{ return []shaderir.Expr{
{
Type: shaderir.UniformVariable, Type: shaderir.UniformVariable,
Index: i, Index: i,
},
}, nil }, nil
} }
if f, ok := shaderir.ParseBuiltinFunc(e.Name); ok { if f, ok := shaderir.ParseBuiltinFunc(e.Name); ok {
return shaderir.Expr{ return []shaderir.Expr{
{
Type: shaderir.BuiltinFuncExpr, Type: shaderir.BuiltinFuncExpr,
BuiltinFunc: f, BuiltinFunc: f,
},
}, nil }, nil
} }
cs.addError(e.Pos(), fmt.Sprintf("unexpected identifier: %s", e.Name)) cs.addError(e.Pos(), fmt.Sprintf("unexpected identifier: %s", e.Name))
case *ast.SelectorExpr: case *ast.SelectorExpr:
expr, stmts := cs.parseExpr(block, e.X) exprs, stmts := cs.parseExpr(block, e.X)
return shaderir.Expr{ if len(exprs) != 1 {
cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a selector: %s", e.X))
return nil, nil
}
return []shaderir.Expr{
{
Type: shaderir.FieldSelector, Type: shaderir.FieldSelector,
Exprs: []shaderir.Expr{ Exprs: []shaderir.Expr{
expr, exprs[0],
{ {
Type: shaderir.SwizzlingExpr, Type: shaderir.SwizzlingExpr,
Swizzling: e.Sel.Name, Swizzling: e.Sel.Name,
}, },
}, },
},
}, stmts }, stmts
case *ast.UnaryExpr: case *ast.UnaryExpr:
var op shaderir.Op var op shaderir.Op
@ -818,16 +872,22 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr) (shaderir.Expr, [
op = shaderir.NotOp op = shaderir.NotOp
default: default:
cs.addError(e.Pos(), fmt.Sprintf("unexpected operator: %s", e.Op)) cs.addError(e.Pos(), fmt.Sprintf("unexpected operator: %s", e.Op))
return shaderir.Expr{}, nil return nil, nil
} }
expr, stmts := cs.parseExpr(block, e.X) exprs, stmts := cs.parseExpr(block, e.X)
return shaderir.Expr{ if len(exprs) != 1 {
cs.addError(e.Pos(), fmt.Sprintf("multiple-value context is not available at a unary operator: %s", e.X))
return nil, nil
}
return []shaderir.Expr{
{
Type: shaderir.Unary, Type: shaderir.Unary,
Op: op, Op: op,
Exprs: []shaderir.Expr{expr}, Exprs: exprs,
},
}, stmts }, stmts
default: default:
cs.addError(e.Pos(), fmt.Sprintf("expression not implemented: %#v", e)) cs.addError(e.Pos(), fmt.Sprintf("expression not implemented: %#v", e))
} }
return shaderir.Expr{}, nil return nil, nil
} }