internal/shader: Implement basic constants

Updates #1192
This commit is contained in:
Hajime Hoshi 2021-04-08 23:55:35 +09:00
parent 0246a6407e
commit 59a80cf953
6 changed files with 82 additions and 10 deletions

View File

@ -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{
{

View File

@ -17,6 +17,7 @@ package shader
import (
"fmt"
"go/ast"
gconstant "go/constant"
"go/token"
"strings"
@ -32,7 +33,7 @@ type variable struct {
type constant struct {
name string
typ shaderir.Type
init ast.Expr
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],
value: es[0].Const,
})
}
return cs
return cs, true
}
func (cs *compileState) parseFuncParams(block *block, d *ast.FuncDecl) (in, out []variable) {

View File

@ -0,0 +1,6 @@
void F0(out vec2 l0);
void F0(out vec2 l0) {
l0 = vec2(3.5000000000e+00);
return;
}

8
internal/shader/testdata/const.go vendored Normal file
View File

@ -0,0 +1,8 @@
package main
const a = 1
const b = 2 + 0.5
func Foo() vec2 {
return vec2(a + b)
}

View File

@ -0,0 +1,6 @@
void F0(out vec2 l0);
void F0(out vec2 l0) {
l0 = vec2(3.5000000000e+00);
return;
}

7
internal/shader/testdata/const2.go vendored Normal file
View File

@ -0,0 +1,7 @@
package main
func Foo() vec2 {
const a = 1
const b = a + 2 + 0.5
return vec2(b)
}