From fc0604805a898cfb4bb0629562c8a8b8ef4324d4 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 9 May 2020 04:21:45 +0900 Subject: [PATCH] shader: Parse constants --- internal/shader/shader.go | 76 ++++++++++++++++++++++++++++------ internal/shader/shader_test.go | 6 +++ 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/internal/shader/shader.go b/internal/shader/shader.go index bec8e363a..7f0ae0fd8 100644 --- a/internal/shader/shader.go +++ b/internal/shader/shader.go @@ -32,23 +32,25 @@ var ( kageTagRe = regexp.MustCompile("^`" + `kage:\"(.+)\"` + "`$") ) -type nameAndType struct { - name string - typ typ +type variable struct { + name string + typ typ + constant bool + init string } type Shader struct { // position is the field name of VertexOut that represents a vertex position (gl_Position in GLSL). - position nameAndType + position variable // varyings is a collection of varying variables. - varyings []nameAndType + varyings []variable // uniforms is a collection of uniform variables. - uniforms []nameAndType + uniforms []variable // globals is a collection of global variables. - globals []nameAndType + globals []variable errs []string } @@ -100,6 +102,8 @@ func (s *Shader) parse(f *ast.File) { s.parseVaryingStruct(obj) default: switch obj.Kind { + case ast.Con: + s.parsePackageLevelConstant(name, obj) case ast.Var: s.parsePackageLevelVariable(name, obj) } @@ -145,7 +149,7 @@ func (sh *Shader) parseVaryingStruct(obj *ast.Object) { sh.addError(fmt.Sprintf("position must be vec4 but %s", t)) continue } - sh.position = nameAndType{ + sh.position = variable{ name: f.Names[0].Name, typ: t, } @@ -161,7 +165,7 @@ func (sh *Shader) parseVaryingStruct(obj *ast.Object) { continue } for _, n := range f.Names { - sh.varyings = append(sh.varyings, nameAndType{ + sh.varyings = append(sh.varyings, variable{ name: n.Name, typ: t, }) @@ -180,14 +184,52 @@ func (s *Shader) parsePackageLevelVariable(name string, obj *ast.Object) { s.addError(err.Error()) return } - nt := nameAndType{ + val := variable{ name: name, typ: t, } + // TODO: Parse initial value. if 'A' <= name[0] && name[0] <= 'Z' { - s.uniforms = append(s.uniforms, nt) + s.uniforms = append(s.uniforms, val) } else { - s.globals = append(s.globals, nt) + s.globals = append(s.globals, val) + } +} + +func (s *Shader) parsePackageLevelConstant(name string, obj *ast.Object) { + vs, ok := obj.Decl.(*ast.ValueSpec) + if !ok { + s.addError("value spec expected") + return + } + t, err := parseType(vs.Type) + if err != nil { + s.addError(err.Error()) + return + } + for i, v := range vs.Values { + if vs.Names[i].Name != name { + continue + } + + var init string + switch v := v.(type) { + case *ast.BasicLit: + if v.Kind != token.INT && v.Kind != token.FLOAT { + s.addError(fmt.Sprintf("literal must be int or float but %s", v.Kind)) + return + } + init = v.Value // TODO: This should be math/big.Int or Float. + default: + // TODO: Parse the expression. + } + val := variable{ + name: name, + typ: t, // TODO: Treat consts without types + constant: true, + init: init, + } + s.globals = append(s.globals, val) } } @@ -205,7 +247,15 @@ func (s *Shader) Dump() string { } for _, g := range s.globals { - lines = append(lines, fmt.Sprintf("var %s %s", g.name, g.typ)) + prefix := "var" + if g.constant { + prefix = "const" + } + init := "" + if g.init != "" { + init = " = " + g.init + } + lines = append(lines, fmt.Sprintf("%s %s %s%s", prefix, g.name, g.typ, init)) } return strings.Join(lines, "\n") + "\n" diff --git a/internal/shader/shader_test.go b/internal/shader/shader_test.go index 75e7b3cde..598ecdd29 100644 --- a/internal/shader/shader_test.go +++ b/internal/shader/shader_test.go @@ -40,6 +40,9 @@ var ( Baz, Quux vec3 qux vec4 ) + +const C1 float = 1 +const C2, C3 float = 2, 3 `, Dump: `var Position varying vec4 // position var Color varying vec4 @@ -48,6 +51,9 @@ var Bar uniform vec2 var Baz uniform vec3 var Foo uniform float var Quux uniform vec3 +const C1 float = 1 +const C2 float = 2 +const C3 float = 3 var qux vec4 `, },