shader: Parse block variables

This commit is contained in:
Hajime Hoshi 2020-05-09 23:38:52 +09:00
parent e848eacedf
commit 5e6be91eac
4 changed files with 128 additions and 31 deletions

42
internal/shader/block.go Normal file
View File

@ -0,0 +1,42 @@
// Copyright 2020 The Ebiten Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shader
import (
"fmt"
"go/token"
"strings"
)
type block struct {
vars []variable
stmts []stmt
pos token.Pos
}
func (b *block) dump(indent int) []string {
idt := strings.Repeat("\t", indent)
var lines []string
for _, v := range b.vars {
lines = append(lines, fmt.Sprintf("%svar %s %s", idt, v.name, v.typ))
}
return lines
}
type stmt struct {
}

View File

@ -43,6 +43,7 @@ type function struct {
name string
args []variable
rets []variable
body *block
}
type Shader struct {
@ -89,6 +90,9 @@ func NewShader(src []byte) (*Shader, error) {
return nil, &ParseError{s.errs}
}
// TODO: Resolve identifiers?
// TODO: Resolve constants
sort.Slice(s.varyings, func(a, b int) bool {
return s.varyings[a].name < s.varyings[b].name
})
@ -129,7 +133,14 @@ func (sh *Shader) parse(f *ast.File) {
case token.VAR:
for _, s := range d.Specs {
s := s.(*ast.ValueSpec)
sh.parseTopLevelVariable(s)
vs := sh.parseVariable(s)
for _, v := range vs {
if 'A' <= v.name[0] && v.name[0] <= 'Z' {
sh.uniforms = append(sh.uniforms, v)
} else {
sh.globals = append(sh.globals, v)
}
}
}
case token.IMPORT:
sh.addError(d.Pos(), "import is forbidden")
@ -200,25 +211,26 @@ func (sh *Shader) parseVaryingStruct(t *ast.TypeSpec) {
}
}
func (s *Shader) parseTopLevelVariable(vs *ast.ValueSpec) {
t, err := parseType(vs.Type)
if err != nil {
s.addError(vs.Type.Pos(), err.Error())
return
func (s *Shader) parseVariable(vs *ast.ValueSpec) []variable {
var t typ
if vs.Type != nil {
var err error
t, err = parseType(vs.Type)
if err != nil {
s.addError(vs.Type.Pos(), err.Error())
return nil
}
}
var vars []variable
for _, n := range vs.Names {
name := n.Name
val := variable{
vars = append(vars, variable{
name: name,
typ: t,
}
// TODO: Parse initial value.
if 'A' <= name[0] && name[0] <= 'Z' {
s.uniforms = append(s.uniforms, val)
} else {
s.globals = append(s.globals, val)
}
})
}
return vars
}
func (s *Shader) parseTopLevelConstant(vs *ast.ValueSpec) {
@ -302,10 +314,51 @@ func (sh *Shader) parseFunc(d *ast.FuncDecl) {
name: d.Name.Name,
args: args,
rets: rets,
body: sh.parseBlock(d.Body),
}
sh.funcs = append(sh.funcs, f)
}
func (sh *Shader) parseBlock(b *ast.BlockStmt) *block {
block := &block{}
for _, l := range b.List {
switch l := l.(type) {
case *ast.AssignStmt:
if l.Tok == token.DEFINE {
for _, s := range l.Lhs {
ident := s.(*ast.Ident)
block.vars = append(block.vars, variable{
name: ident.Name,
})
}
} else {
// TODO
}
case *ast.DeclStmt:
switch d := l.Decl.(type) {
case *ast.GenDecl:
switch d.Tok {
case token.VAR:
for _, s := range d.Specs {
s := s.(*ast.ValueSpec)
vs := sh.parseVariable(s)
block.vars = append(block.vars, vs...)
}
}
}
case *ast.ReturnStmt:
default:
}
}
sort.Slice(block.vars, func(a, b int) bool {
return block.vars[a].name < block.vars[b].name
})
return block
}
// Dump dumps the shader state in an intermediate language.
func (s *Shader) Dump() string {
var lines []string
@ -348,7 +401,10 @@ func (s *Shader) Dump() string {
if len(rets) > 0 {
l += " (" + strings.Join(rets, ", ") + ")"
}
l += " {"
lines = append(lines, l)
lines = append(lines, f.body.dump(1)...)
lines = append(lines, "}")
}
return strings.Join(lines, "\n") + "\n"

View File

@ -44,7 +44,11 @@ var (
const C1 float = 1
const C2, C3 float = 2, 3
func foo(a, b vec2) vec4 {
func F1(a, b vec2) vec4 {
var c0 vec2 = a
var c1 = b
c2 := vec4{c0, c1}
return c2
}
`,
Dump: `var Position varying vec4 // position
@ -58,7 +62,11 @@ const C1 float = 1
const C2 float = 2
const C3 float = 3
var qux vec4
func foo(a vec2, b vec2) (_ vec4)
func F1(a vec2, b vec2) (_ vec4) {
var c0 vec2
var c1 (none)
var c2 (none)
}
`,
},
}

View File

@ -24,8 +24,7 @@ type typ int
// TODO: What about array types?
const (
typBool typ = iota
typInt
typNone typ = iota
typFloat
typVec2
typVec3
@ -40,10 +39,6 @@ func parseType(expr ast.Expr) (typ, error) {
switch t := expr.(type) {
case *ast.Ident:
switch t.Name {
case "bool":
return typBool, nil
case "int":
return typInt, nil
case "float":
return typFloat, nil
case "vec2":
@ -68,10 +63,8 @@ func parseType(expr ast.Expr) (typ, error) {
func (t typ) String() string {
switch t {
case typBool:
return "bool"
case typInt:
return "int"
case typNone:
return "(none)"
case typFloat:
return "float"
case typVec2:
@ -94,15 +87,13 @@ func (t typ) String() string {
}
func (t typ) numeric() bool {
return t != typSampler2d
return t != typNone && t != typSampler2d
}
func (t typ) glslString() string {
switch t {
case typBool:
return "bool"
case typInt:
return "int"
case typNone:
return "?(none)"
case typFloat:
return "float"
case typVec2: