diff --git a/internal/shader/expr.go b/internal/shader/expr.go index 0db0e7dbd..8b9389201 100644 --- a/internal/shader/expr.go +++ b/internal/shader/expr.go @@ -390,6 +390,14 @@ func (cs *compileState) parseExpr(block *block, expr ast.Expr, markLocalVariable }, }, []shaderir.Type{t}, nil, true } + if c, ok := block.findConstant(e.Name); ok { + return []shaderir.Expr{ + { + Type: shaderir.NumberExpr, + Const: c.value, + }, + }, []shaderir.Type{c.typ}, nil, true + } if i, ok := cs.findFunction(e.Name); ok { return []shaderir.Expr{ { diff --git a/internal/shader/shader.go b/internal/shader/shader.go index 24d7cb586..f997894d7 100644 --- a/internal/shader/shader.go +++ b/internal/shader/shader.go @@ -17,6 +17,7 @@ package shader import ( "fmt" "go/ast" + gconstant "go/constant" "go/token" "strings" @@ -30,9 +31,9 @@ type variable struct { } type constant struct { - name string - typ shaderir.Type - init ast.Expr + name string + typ shaderir.Type + value gconstant.Value } type function struct { @@ -154,6 +155,23 @@ func (b *block) findLocalVariableByIndex(idx int) (shaderir.Type, bool) { return shaderir.Type{}, false } +func (b *block) findConstant(name string) (constant, bool) { + if name == "" || name == "_" { + panic("shader: constant name must be non-empty and non-underscore") + } + + for _, c := range b.consts { + if c.name == name { + return c, true + } + } + if b.outer != nil { + return b.outer.findConstant(name) + } + + return constant{}, false +} + type ParseError struct { errs []string } @@ -304,7 +322,10 @@ func (cs *compileState) parseDecl(b *block, d ast.Decl) ([]shaderir.Stmt, bool) case token.CONST: for _, s := range d.Specs { s := s.(*ast.ValueSpec) - cs := cs.parseConstant(b, s) + cs, ok := cs.parseConstant(b, s) + if !ok { + return nil, false + } b.consts = append(b.consts, cs...) } case token.VAR: @@ -528,25 +549,41 @@ func (s *compileState) parseVariable(block *block, vs *ast.ValueSpec) ([]variabl return vars, inits, stmts, true } -func (s *compileState) parseConstant(block *block, vs *ast.ValueSpec) []constant { +func (s *compileState) parseConstant(block *block, vs *ast.ValueSpec) ([]constant, bool) { var t shaderir.Type if vs.Type != nil { var ok bool t, ok = s.parseType(block, vs.Type) if !ok { - return nil + return nil, false } } var cs []constant for i, n := range vs.Names { + es, _, ss, ok := s.parseExpr(block, vs.Values[i], false) + if !ok { + return nil, false + } + if len(ss) > 0 { + s.addError(vs.Pos(), fmt.Sprintf("invalid constant expression: %s", n)) + return nil, false + } + if len(es) != 1 { + s.addError(vs.Pos(), fmt.Sprintf("invalid constant expression: %s", n)) + return nil, false + } + if es[0].Type != shaderir.NumberExpr { + s.addError(vs.Pos(), fmt.Sprintf("constant expresion must be a number but not: %s", n)) + return nil, false + } cs = append(cs, constant{ - name: n.Name, - typ: t, - init: vs.Values[i], + name: n.Name, + typ: t, + value: es[0].Const, }) } - return cs + return cs, true } func (cs *compileState) parseFuncParams(block *block, d *ast.FuncDecl) (in, out []variable) { diff --git a/internal/shader/testdata/const.expected.vs b/internal/shader/testdata/const.expected.vs new file mode 100644 index 000000000..d6ea47afe --- /dev/null +++ b/internal/shader/testdata/const.expected.vs @@ -0,0 +1,6 @@ +void F0(out vec2 l0); + +void F0(out vec2 l0) { + l0 = vec2(3.5000000000e+00); + return; +} diff --git a/internal/shader/testdata/const.go b/internal/shader/testdata/const.go new file mode 100644 index 000000000..3862124a8 --- /dev/null +++ b/internal/shader/testdata/const.go @@ -0,0 +1,8 @@ +package main + +const a = 1 +const b = 2 + 0.5 + +func Foo() vec2 { + return vec2(a + b) +} diff --git a/internal/shader/testdata/const2.expected.vs b/internal/shader/testdata/const2.expected.vs new file mode 100644 index 000000000..d6ea47afe --- /dev/null +++ b/internal/shader/testdata/const2.expected.vs @@ -0,0 +1,6 @@ +void F0(out vec2 l0); + +void F0(out vec2 l0) { + l0 = vec2(3.5000000000e+00); + return; +} diff --git a/internal/shader/testdata/const2.go b/internal/shader/testdata/const2.go new file mode 100644 index 000000000..289de2f66 --- /dev/null +++ b/internal/shader/testdata/const2.go @@ -0,0 +1,7 @@ +package main + +func Foo() vec2 { + const a = 1 + const b = a + 2 + 0.5 + return vec2(b) +}