From 00b32a663e7f6d0141e1c8ec9e59afa849bcadec Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 9 May 2020 16:47:07 +0900 Subject: [PATCH] shader: Add token positions to the error message --- internal/shader/shader.go | 43 ++++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/internal/shader/shader.go b/internal/shader/shader.go index 8c7a80392..f7d705f54 100644 --- a/internal/shader/shader.go +++ b/internal/shader/shader.go @@ -40,6 +40,8 @@ type variable struct { } type Shader struct { + fs *token.FileSet + // position is the field name of VertexOut that represents a vertex position (gl_Position in GLSL). position variable @@ -64,12 +66,15 @@ func (p *ParseError) Error() string { } 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 { return nil, err } - s := &Shader{} + s := &Shader{ + fs: fs, + } s.parse(f) if len(s.errs) > 0 { @@ -90,9 +95,9 @@ func NewShader(src []byte) (*Shader, error) { return s, nil } -func (s *Shader) addError(str string) { - // TODO: Add token positions. - s.errs = append(s.errs, str) +func (s *Shader) addError(pos token.Pos, str string) { + p := s.fs.Position(pos) + s.errs = append(s.errs, fmt.Sprintf("%s: %s", p, str)) } 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) { name := obj.Name 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 } t := obj.Decl.(*ast.TypeSpec).Type s, ok := t.(*ast.StructType) 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 } @@ -129,24 +134,24 @@ func (sh *Shader) parseVaryingStruct(obj *ast.Object) { tag := f.Tag.Value m := kageTagRe.FindStringSubmatch(tag) 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 } 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 } 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 } t, err := parseType(f.Type) if err != nil { - sh.addError(err.Error()) + sh.addError(f.Type.Pos(), err.Error()) continue } 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 } sh.position = variable{ @@ -157,11 +162,11 @@ func (sh *Shader) parseVaryingStruct(obj *ast.Object) { } t, err := parseType(f.Type) if err != nil { - sh.addError(err.Error()) + sh.addError(f.Type.Pos(), err.Error()) continue } 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 } 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) { v, ok := obj.Decl.(*ast.ValueSpec) if !ok { - s.addError("value spec expected") + s.addError(obj.Pos(), "value spec expected") return } t, err := parseType(v.Type) if err != nil { - s.addError(err.Error()) + s.addError(v.Type.Pos(), err.Error()) return } val := variable{ @@ -199,12 +204,12 @@ func (s *Shader) parsePackageLevelVariable(name string, obj *ast.Object) { func (s *Shader) parsePackageLevelConstant(name string, obj *ast.Object) { vs, ok := obj.Decl.(*ast.ValueSpec) if !ok { - s.addError("value spec expected") + s.addError(obj.Pos(), "value spec expected") return } t, err := parseType(vs.Type) if err != nil { - s.addError(err.Error()) + s.addError(vs.Pos(), err.Error()) return } for i, v := range vs.Values { @@ -216,7 +221,7 @@ func (s *Shader) parsePackageLevelConstant(name string, obj *ast.Object) { 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)) + s.addError(v.Pos(), 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.