shader: Parse assignments

This commit is contained in:
Hajime Hoshi 2020-05-10 02:01:28 +09:00
parent 1a7da0bc63
commit 9430b6be37
4 changed files with 85 additions and 89 deletions

View File

@ -16,6 +16,7 @@ package shader
import ( import (
"fmt" "fmt"
"go/ast"
"go/token" "go/token"
"strings" "strings"
) )
@ -35,13 +36,13 @@ func (b *block) dump(indent int) []string {
for _, v := range b.vars { for _, v := range b.vars {
init := "" init := ""
if v.init != "" { if v.init != nil {
init = " = " + v.init init = " = " + dumpExpr(v.init)
} }
lines = append(lines, fmt.Sprintf("%svar %s %s%s", idt, v.name, v.typ, init)) lines = append(lines, fmt.Sprintf("%svar %s %s%s", idt, v.name, v.typ, init))
} }
for _, c := range b.consts { for _, c := range b.consts {
lines = append(lines, fmt.Sprintf("%sconst %s %s = %s", idt, c.name, c.typ, c.init)) lines = append(lines, fmt.Sprintf("%sconst %s %s = %s", idt, c.name, c.typ, dumpExpr(c.init)))
} }
for _, f := range b.funcs { for _, f := range b.funcs {
var args []string var args []string
@ -77,12 +78,13 @@ type stmtType int
const ( const (
stmtNone stmtType = iota stmtNone stmtType = iota
stmtAssign
stmtReturn stmtReturn
) )
type stmt struct { type stmt struct {
stmtType stmtType stmtType stmtType
exprs []expr exprs []ast.Expr
} }
func (s *stmt) dump(indent int) []string { func (s *stmt) dump(indent int) []string {
@ -92,12 +94,14 @@ func (s *stmt) dump(indent int) []string {
switch s.stmtType { switch s.stmtType {
case stmtNone: case stmtNone:
lines = append(lines, "%s(none)", idt) lines = append(lines, "%s(none)", idt)
case stmtAssign:
lines = append(lines, fmt.Sprintf("%s%s = %s", idt, dumpExpr(s.exprs[0]), dumpExpr(s.exprs[1])))
case stmtReturn: case stmtReturn:
var expr string var expr string
if len(s.exprs) > 0 { if len(s.exprs) > 0 {
var strs []string var strs []string
for _, e := range s.exprs { for _, e := range s.exprs {
strs = append(strs, e.dump()) strs = append(strs, dumpExpr(e))
} }
expr = " " + strings.Join(strs, ", ") expr = " " + strings.Join(strs, ", ")
} }
@ -109,25 +113,22 @@ func (s *stmt) dump(indent int) []string {
return lines return lines
} }
type exprType int func dumpExpr(e ast.Expr) string {
switch e := e.(type) {
const ( case *ast.BasicLit:
exprNone exprType = iota return e.Value
exprIdent case *ast.CompositeLit:
) t := parseType(e.Type)
var vals []string
type expr struct { for _, e := range e.Elts {
exprType exprType vals = append(vals, dumpExpr(e))
value string }
} return fmt.Sprintf("%s{%s}", t, strings.Join(vals, ", "))
case *ast.Ident:
func (e *expr) dump() string { return e.Name
switch e.exprType { case *ast.SelectorExpr:
case exprNone: return fmt.Sprintf("%s.%s", dumpExpr(e.X), dumpExpr(e.Sel))
return "(none)"
case exprIdent:
return e.value
default: default:
return fmt.Sprintf("(unkown expr: %d)", e.exprType) return fmt.Sprintf("(unkown expr: %#v)", e)
} }
} }

View File

@ -35,13 +35,13 @@ var (
type variable struct { type variable struct {
name string name string
typ typ typ typ
init string init ast.Expr
} }
type constant struct { type constant struct {
name string name string
typ typ typ typ
init string init ast.Expr
} }
type function struct { type function struct {
@ -194,9 +194,9 @@ func (sh *Shader) parseVaryingStruct(t *ast.TypeSpec) {
sh.addError(f.Pos(), fmt.Sprintf("position members must be one")) sh.addError(f.Pos(), fmt.Sprintf("position members must be one"))
continue continue
} }
t, err := parseType(f.Type) t := parseType(f.Type)
if err != nil { if t == typNone {
sh.addError(f.Type.Pos(), err.Error()) sh.addError(f.Type.Pos(), fmt.Sprintf("unexpected type: %s", f.Type))
continue continue
} }
if t != typVec4 { if t != typVec4 {
@ -209,9 +209,9 @@ func (sh *Shader) parseVaryingStruct(t *ast.TypeSpec) {
} }
continue continue
} }
t, err := parseType(f.Type) t := parseType(f.Type)
if err != nil { if t == typNone {
sh.addError(f.Type.Pos(), err.Error()) sh.addError(f.Type.Pos(), fmt.Sprintf("unexpected type: %s", f.Type))
continue continue
} }
if !t.numeric() { if !t.numeric() {
@ -230,20 +230,24 @@ func (sh *Shader) parseVaryingStruct(t *ast.TypeSpec) {
func (s *Shader) parseVariable(vs *ast.ValueSpec) []variable { func (s *Shader) parseVariable(vs *ast.ValueSpec) []variable {
var t typ var t typ
if vs.Type != nil { if vs.Type != nil {
var err error t = parseType(vs.Type)
t, err = parseType(vs.Type) if t == typNone {
if err != nil { s.addError(vs.Type.Pos(), fmt.Sprintf("unexpected type: %s", vs.Type))
s.addError(vs.Type.Pos(), err.Error())
return nil return nil
} }
} }
var vars []variable var vars []variable
for _, n := range vs.Names { for i, n := range vs.Names {
var init ast.Expr
if len(vs.Values) > 0 {
init = vs.Values[i]
}
name := n.Name name := n.Name
vars = append(vars, variable{ vars = append(vars, variable{
name: name, name: name,
typ: t, typ: t,
init: init,
}) })
} }
return vars return vars
@ -252,32 +256,19 @@ func (s *Shader) parseVariable(vs *ast.ValueSpec) []variable {
func (s *Shader) parseConstant(vs *ast.ValueSpec) []constant { func (s *Shader) parseConstant(vs *ast.ValueSpec) []constant {
var t typ var t typ
if vs.Type != nil { if vs.Type != nil {
var err error t = parseType(vs.Type)
t, err = parseType(vs.Type) if t == typNone {
if err != nil { s.addError(vs.Type.Pos(), fmt.Sprintf("unexpected type: %s", vs.Type))
s.addError(vs.Type.Pos(), err.Error())
return nil return nil
} }
} }
var cs []constant var cs []constant
for i, n := range vs.Names { for i, n := range vs.Names {
v := vs.Values[i]
var init string
switch v := v.(type) {
case *ast.BasicLit:
if v.Kind != token.INT && v.Kind != token.FLOAT {
s.addError(v.Pos(), fmt.Sprintf("literal must be int or float but %s", v.Kind))
return cs
}
init = v.Value // TODO: This should be go/constant.Value
default:
// TODO: Parse the expression.
}
cs = append(cs, constant{ cs = append(cs, constant{
name: n.Name, name: n.Name,
typ: t, typ: t,
init: init, init: vs.Values[i],
}) })
} }
return cs return cs
@ -295,9 +286,9 @@ func (sh *Shader) parseFunc(d *ast.FuncDecl) function {
var args []variable var args []variable
for _, f := range d.Type.Params.List { for _, f := range d.Type.Params.List {
t, err := parseType(f.Type) t := parseType(f.Type)
if err != nil { if t == typNone {
sh.addError(f.Type.Pos(), err.Error()) sh.addError(f.Type.Pos(), fmt.Sprintf("unexpected type: %s", f.Type))
continue continue
} }
for _, n := range f.Names { for _, n := range f.Names {
@ -310,9 +301,9 @@ func (sh *Shader) parseFunc(d *ast.FuncDecl) function {
var rets []variable var rets []variable
for _, f := range d.Type.Results.List { for _, f := range d.Type.Results.List {
t, err := parseType(f.Type) t := parseType(f.Type)
if err != nil { if t == typNone {
sh.addError(f.Type.Pos(), err.Error()) sh.addError(f.Type.Pos(), fmt.Sprintf("unexpected type: %s", f.Type))
continue continue
} }
if len(f.Names) == 0 { if len(f.Names) == 0 {
@ -344,22 +335,35 @@ func (sh *Shader) parseBlock(b *ast.BlockStmt) *block {
for _, l := range b.List { for _, l := range b.List {
switch l := l.(type) { switch l := l.(type) {
case *ast.AssignStmt: case *ast.AssignStmt:
if l.Tok == token.DEFINE { switch l.Tok {
case token.DEFINE:
for _, s := range l.Lhs { for _, s := range l.Lhs {
ident := s.(*ast.Ident) ident := s.(*ast.Ident)
block.vars = append(block.vars, variable{ block.vars = append(block.vars, variable{
name: ident.Name, name: ident.Name,
}) })
} }
} else { for i := range l.Rhs {
// TODO block.stmts = append(block.stmts, stmt{
stmtType: stmtAssign,
exprs: []ast.Expr{l.Lhs[i], l.Rhs[i]},
})
}
case token.ASSIGN:
// TODO: What about the statement `a,b = b,a?`
for i := range l.Rhs {
block.stmts = append(block.stmts, stmt{
stmtType: stmtAssign,
exprs: []ast.Expr{l.Lhs[i], l.Rhs[i]},
})
}
} }
case *ast.DeclStmt: case *ast.DeclStmt:
sh.parseDecl(block, l.Decl) sh.parseDecl(block, l.Decl)
case *ast.ReturnStmt: case *ast.ReturnStmt:
var exprs []expr var exprs []ast.Expr
for _, r := range l.Results { for _, r := range l.Results {
exprs = append(exprs, sh.parseExpr(r)) exprs = append(exprs, r)
} }
block.stmts = append(block.stmts, stmt{ block.stmts = append(block.stmts, stmt{
stmtType: stmtReturn, stmtType: stmtReturn,
@ -379,17 +383,6 @@ func (sh *Shader) parseBlock(b *ast.BlockStmt) *block {
return block return block
} }
func (sh *Shader) parseExpr(e ast.Expr) expr {
switch e := e.(type) {
case *ast.Ident:
return expr{
exprType: exprIdent,
value: e.Name,
}
}
return expr{}
}
// Dump dumps the shader state in an intermediate language. // Dump dumps the shader state in an intermediate language.
func (s *Shader) Dump() string { func (s *Shader) Dump() string {
var lines []string var lines []string

View File

@ -64,10 +64,12 @@ const C1 float = 1
const C2 float = 2 const C2 float = 2
const C3 float = 3 const C3 float = 3
func F1(a vec2, b vec2) (_ vec4) { func F1(a vec2, b vec2) (_ vec4) {
var c0 vec2 var c0 vec2 = a
var c1 (none) var c1 (none) = b
var c2 (none) var c2 (none) = 1.0
var c3 (none) var c3 (none)
c1.x = c2.x
c3 = vec4{c0, c1}
return c2 return c2
} }
`, `,

View File

@ -35,30 +35,30 @@ const (
typSampler2d typSampler2d
) )
func parseType(expr ast.Expr) (typ, error) { func parseType(expr ast.Expr) typ {
switch t := expr.(type) { switch t := expr.(type) {
case *ast.Ident: case *ast.Ident:
switch t.Name { switch t.Name {
case "float": case "float":
return typFloat, nil return typFloat
case "vec2": case "vec2":
return typVec2, nil return typVec2
case "vec3": case "vec3":
return typVec3, nil return typVec3
case "vec4": case "vec4":
return typVec4, nil return typVec4
case "mat2": case "mat2":
return typMat2, nil return typMat2
case "mat3": case "mat3":
return typMat3, nil return typMat3
case "mat4": case "mat4":
return typMat4, nil return typMat4
case "sampler2d": case "sampler2d":
return typSampler2d, nil return typSampler2d
} }
// TODO: Parse array types // TODO: Parse array types
} }
return 0, fmt.Errorf("invalid type: %s", expr) return typNone
} }
func (t typ) String() string { func (t typ) String() string {