shader: Add token positions to the error message

This commit is contained in:
Hajime Hoshi 2020-05-09 16:47:07 +09:00
parent c8045210ac
commit 00b32a663e

View File

@ -40,6 +40,8 @@ type variable struct {
} }
type Shader struct { type Shader struct {
fs *token.FileSet
// position is the field name of VertexOut that represents a vertex position (gl_Position in GLSL). // position is the field name of VertexOut that represents a vertex position (gl_Position in GLSL).
position variable position variable
@ -64,12 +66,15 @@ func (p *ParseError) Error() string {
} }
func NewShader(src []byte) (*Shader, error) { func NewShader(src []byte) (*Shader, error) {
f, err := parser.ParseFile(token.NewFileSet(), "", src, parser.AllErrors) fs := token.NewFileSet()
f, err := parser.ParseFile(fs, "", src, parser.AllErrors)
if err != nil { if err != nil {
return nil, err return nil, err
} }
s := &Shader{} s := &Shader{
fs: fs,
}
s.parse(f) s.parse(f)
if len(s.errs) > 0 { if len(s.errs) > 0 {
@ -90,9 +95,9 @@ func NewShader(src []byte) (*Shader, error) {
return s, nil return s, nil
} }
func (s *Shader) addError(str string) { func (s *Shader) addError(pos token.Pos, str string) {
// TODO: Add token positions. p := s.fs.Position(pos)
s.errs = append(s.errs, str) s.errs = append(s.errs, fmt.Sprintf("%s: %s", p, str))
} }
func (s *Shader) parse(f *ast.File) { func (s *Shader) parse(f *ast.File) {
@ -114,13 +119,13 @@ func (s *Shader) parse(f *ast.File) {
func (sh *Shader) parseVaryingStruct(obj *ast.Object) { func (sh *Shader) parseVaryingStruct(obj *ast.Object) {
name := obj.Name name := obj.Name
if obj.Kind != ast.Typ { if obj.Kind != ast.Typ {
sh.addError(fmt.Sprintf("%s must be a type but %s", name, obj.Kind)) sh.addError(obj.Pos(), fmt.Sprintf("%s must be a type but %s", name, obj.Kind))
return return
} }
t := obj.Decl.(*ast.TypeSpec).Type t := obj.Decl.(*ast.TypeSpec).Type
s, ok := t.(*ast.StructType) s, ok := t.(*ast.StructType)
if !ok { if !ok {
sh.addError(fmt.Sprintf("%s must be a struct but not", name)) sh.addError(t.Pos(), fmt.Sprintf("%s must be a struct but not", name))
return return
} }
@ -129,24 +134,24 @@ func (sh *Shader) parseVaryingStruct(obj *ast.Object) {
tag := f.Tag.Value tag := f.Tag.Value
m := kageTagRe.FindStringSubmatch(tag) m := kageTagRe.FindStringSubmatch(tag)
if m == nil { if m == nil {
sh.addError(fmt.Sprintf("invalid struct tag: %s", tag)) sh.addError(f.Tag.Pos(), fmt.Sprintf("invalid struct tag: %s", tag))
continue continue
} }
if m[1] != "position" { if m[1] != "position" {
sh.addError(fmt.Sprintf("struct tag value must be position in %s but %s", varyingStructName, m[1])) sh.addError(f.Tag.Pos(), fmt.Sprintf("struct tag value must be position in %s but %s", varyingStructName, m[1]))
continue continue
} }
if len(f.Names) != 1 { if len(f.Names) != 1 {
sh.addError(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, err := parseType(f.Type)
if err != nil { if err != nil {
sh.addError(err.Error()) sh.addError(f.Type.Pos(), err.Error())
continue continue
} }
if t != typVec4 { if t != typVec4 {
sh.addError(fmt.Sprintf("position must be vec4 but %s", t)) sh.addError(f.Type.Pos(), fmt.Sprintf("position must be vec4 but %s", t))
continue continue
} }
sh.position = variable{ sh.position = variable{
@ -157,11 +162,11 @@ func (sh *Shader) parseVaryingStruct(obj *ast.Object) {
} }
t, err := parseType(f.Type) t, err := parseType(f.Type)
if err != nil { if err != nil {
sh.addError(err.Error()) sh.addError(f.Type.Pos(), err.Error())
continue continue
} }
if !t.numeric() { if !t.numeric() {
sh.addError(fmt.Sprintf("members in %s must be numeric but %s", varyingStructName, t)) sh.addError(f.Type.Pos(), fmt.Sprintf("members in %s must be numeric but %s", varyingStructName, t))
continue continue
} }
for _, n := range f.Names { for _, n := range f.Names {
@ -176,12 +181,12 @@ func (sh *Shader) parseVaryingStruct(obj *ast.Object) {
func (s *Shader) parsePackageLevelVariable(name string, obj *ast.Object) { func (s *Shader) parsePackageLevelVariable(name string, obj *ast.Object) {
v, ok := obj.Decl.(*ast.ValueSpec) v, ok := obj.Decl.(*ast.ValueSpec)
if !ok { if !ok {
s.addError("value spec expected") s.addError(obj.Pos(), "value spec expected")
return return
} }
t, err := parseType(v.Type) t, err := parseType(v.Type)
if err != nil { if err != nil {
s.addError(err.Error()) s.addError(v.Type.Pos(), err.Error())
return return
} }
val := variable{ val := variable{
@ -199,12 +204,12 @@ func (s *Shader) parsePackageLevelVariable(name string, obj *ast.Object) {
func (s *Shader) parsePackageLevelConstant(name string, obj *ast.Object) { func (s *Shader) parsePackageLevelConstant(name string, obj *ast.Object) {
vs, ok := obj.Decl.(*ast.ValueSpec) vs, ok := obj.Decl.(*ast.ValueSpec)
if !ok { if !ok {
s.addError("value spec expected") s.addError(obj.Pos(), "value spec expected")
return return
} }
t, err := parseType(vs.Type) t, err := parseType(vs.Type)
if err != nil { if err != nil {
s.addError(err.Error()) s.addError(vs.Pos(), err.Error())
return return
} }
for i, v := range vs.Values { for i, v := range vs.Values {
@ -216,7 +221,7 @@ func (s *Shader) parsePackageLevelConstant(name string, obj *ast.Object) {
switch v := v.(type) { switch v := v.(type) {
case *ast.BasicLit: case *ast.BasicLit:
if v.Kind != token.INT && v.Kind != token.FLOAT { if v.Kind != token.INT && v.Kind != token.FLOAT {
s.addError(fmt.Sprintf("literal must be int or float but %s", v.Kind)) s.addError(v.Pos(), fmt.Sprintf("literal must be int or float but %s", v.Kind))
return return
} }
init = v.Value // TODO: This should be math/big.Int or Float. init = v.Value // TODO: This should be math/big.Int or Float.