Source file src/cmd/compile/internal/syntax/testing.go
1 // Copyright 2020 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // This file implements testing support. 6 7 package syntax 8 9 import ( 10 "io" 11 "regexp" 12 "strings" 13 ) 14 15 // CommentsDo parses the given source and calls the provided handler for each 16 // comment or error. If the text provided to handler starts with a '/' it is 17 // the comment text; otherwise it is the error message. 18 func CommentsDo(src io.Reader, handler func(line, col uint, text string)) { 19 var s scanner 20 s.init(src, handler, comments) 21 for s.tok != _EOF { 22 s.next() 23 } 24 } 25 26 // ERROR comments must start with text `ERROR "msg"` or `ERROR msg`. 27 // Space around "msg" or msg is ignored. 28 var errRx = regexp.MustCompile(`^ *ERROR *"?([^"]*)"?`) 29 30 // ErrorMap collects all comments with comment text of the form 31 // `ERROR "msg"` or `ERROR msg` from the given src and returns them 32 // as []Error lists in a map indexed by line number. The position 33 // for each Error is the position of the token immediately preceding 34 // the comment, the Error message is the message msg extracted from 35 // the comment, with all errors that are on the same line collected 36 // in a slice, in source order. If there is no preceding token (the 37 // `ERROR` comment appears in the beginning of the file), then the 38 // recorded position is unknown (line, col = 0, 0). If there are no 39 // ERROR comments, the result is nil. 40 func ErrorMap(src io.Reader) (errmap map[uint][]Error) { 41 // position of previous token 42 var base *PosBase 43 var prev struct{ line, col uint } 44 45 var s scanner 46 s.init(src, func(_, _ uint, text string) { 47 if text[0] != '/' { 48 return // error, ignore 49 } 50 if text[1] == '*' { 51 text = text[:len(text)-2] // strip trailing */ 52 } 53 if s := errRx.FindStringSubmatch(text[2:]); len(s) == 2 { 54 pos := MakePos(base, prev.line, prev.col) 55 err := Error{pos, strings.TrimSpace(s[1])} 56 if errmap == nil { 57 errmap = make(map[uint][]Error) 58 } 59 errmap[prev.line] = append(errmap[prev.line], err) 60 } 61 }, comments) 62 63 for s.tok != _EOF { 64 s.next() 65 if s.tok == _Semi && s.lit != "semicolon" { 66 continue // ignore automatically inserted semicolons 67 } 68 prev.line, prev.col = s.line, s.col 69 } 70 71 return 72 } 73