Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit f15ff61

Browse files
cmaglieFederico Fissore
authored andcommittedDec 10, 2015
Refactoring: ctags parser now uses a CTag structure
Signed-off-by: Cristian Maglie <[email protected]>
1 parent 90ba6d5 commit f15ff61

File tree

8 files changed

+300
-271
lines changed

8 files changed

+300
-271
lines changed
 

‎src/arduino.cc/builder/collect_ctags_from_sketch_files.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,10 @@ func (s *CollectCTagsFromSketchFiles) Run(context map[string]interface{}) error
4242
sketch := context[constants.CTX_SKETCH].(*types.Sketch)
4343
sketchFileNames := collectSketchFileNamesFrom(sketch)
4444

45-
ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]map[string]string)
46-
ctagsOfSketch := []map[string]string{}
45+
ctags := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*CTag)
46+
ctagsOfSketch := []*CTag{}
4747
for _, ctag := range ctags {
48-
if utils.SliceContains(sketchFileNames, strings.Replace(ctag[FIELD_FILENAME], "\\\\", "\\", -1)) {
48+
if utils.SliceContains(sketchFileNames, strings.Replace(ctag.Filename, "\\\\", "\\", -1)) {
4949
ctagsOfSketch = append(ctagsOfSketch, ctag)
5050
}
5151
}

‎src/arduino.cc/builder/compare_prototypes_from_source_and_preproc_source.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,10 @@ import (
3636
type ComparePrototypesFromSourceAndPreprocSource struct{}
3737

3838
func (s *ComparePrototypesFromSourceAndPreprocSource) Run(context map[string]interface{}) error {
39-
ctagsOfSource := context[constants.CTX_CTAGS_OF_SOURCE].([]map[string]string)
40-
ctagsOfPreprocSource := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]map[string]string)
39+
ctagsOfSource := context[constants.CTX_CTAGS_OF_SOURCE].([]*CTag)
40+
ctagsOfPreprocSource := context[constants.CTX_CTAGS_OF_PREPROC_SOURCE].([]*CTag)
4141

42-
actualCTags := []map[string]string{}
42+
actualCTags := []*CTag{}
4343
for _, ctagOfPreprocSource := range ctagsOfPreprocSource {
4444
if sliceContainsCTag(ctagsOfSource, ctagOfPreprocSource) {
4545
actualCTags = append(actualCTags, ctagOfPreprocSource)
@@ -51,9 +51,9 @@ func (s *ComparePrototypesFromSourceAndPreprocSource) Run(context map[string]int
5151
return nil
5252
}
5353

54-
func sliceContainsCTag(slice []map[string]string, target map[string]string) bool {
54+
func sliceContainsCTag(slice []*CTag, target *CTag) bool {
5555
for _, value := range slice {
56-
if value[FIELD_FUNCTION_NAME] == target[FIELD_FUNCTION_NAME] {
56+
if value.FunctionName == target.FunctionName {
5757
return true
5858
}
5959
}

‎src/arduino.cc/builder/ctags_parser.go

Lines changed: 103 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -39,44 +39,52 @@ import (
3939
"strings"
4040
)
4141

42-
const FIELD_KIND = "kind"
43-
const FIELD_LINE = "line"
44-
const FIELD_SIGNATURE = "signature"
45-
const FIELD_RETURNTYPE = "returntype"
46-
const FIELD_CODE = "code"
47-
const FIELD_CLASS = "class"
48-
const FIELD_STRUCT = "struct"
49-
const FIELD_NAMESPACE = "namespace"
50-
const FIELD_FILENAME = "filename"
51-
const FIELD_SKIP = "skipMe"
52-
const FIELD_FUNCTION_NAME = "functionName"
53-
5442
const KIND_PROTOTYPE = "prototype"
5543
const KIND_FUNCTION = "function"
56-
const KIND_PROTOTYPE_MODIFIERS = "prototype_modifiers"
44+
45+
//const KIND_PROTOTYPE_MODIFIERS = "prototype_modifiers"
5746

5847
const TEMPLATE = "template"
5948
const STATIC = "static"
60-
const TRUE = "true"
6149

62-
var FIELDS = map[string]bool{"kind": true, "line": true, "typeref": true, "signature": true, "returntype": true, "class": true, "struct": true, "namespace": true}
63-
var KNOWN_TAG_KINDS = map[string]bool{"prototype": true, "function": true}
64-
var FIELDS_MARKING_UNHANDLED_TAGS = []string{FIELD_CLASS, FIELD_STRUCT, FIELD_NAMESPACE}
50+
var KNOWN_TAG_KINDS = map[string]bool{
51+
"prototype": true,
52+
"function": true,
53+
}
6554

6655
type CTagsParser struct{}
6756

57+
type CTag struct {
58+
FunctionName string
59+
Kind string
60+
Line int
61+
Signature string
62+
Returntype string
63+
Code string
64+
Class string
65+
Struct string
66+
Namespace string
67+
Filename string
68+
Typeref string
69+
SkipMe bool
70+
71+
Prototype string
72+
Function string
73+
PrototypeModifiers string
74+
}
75+
6876
func (s *CTagsParser) Run(context map[string]interface{}) error {
6977
rows := strings.Split(context[constants.CTX_CTAGS_OUTPUT].(string), "\n")
7078

7179
rows = removeEmpty(rows)
7280

73-
var tags []map[string]string
81+
var tags []*CTag
7482
for _, row := range rows {
7583
tags = append(tags, parseTag(row))
7684
}
7785

7886
skipTagsWhere(tags, tagIsUnknown, context)
79-
skipTagsWithField(tags, FIELDS_MARKING_UNHANDLED_TAGS, context)
87+
skipTagsWhere(tags, tagIsUnhandled, context)
8088
skipTagsWhere(tags, signatureContainsDefaultArg, context)
8189
addPrototypes(tags)
8290
removeDefinedProtypes(tags, context)
@@ -88,90 +96,90 @@ func (s *CTagsParser) Run(context map[string]interface{}) error {
8896
return nil
8997
}
9098

91-
func addPrototypes(tags []map[string]string) {
99+
func addPrototypes(tags []*CTag) {
92100
for _, tag := range tags {
93-
if tag[FIELD_SKIP] != TRUE {
94-
addPrototype(tag)
101+
if !tag.SkipMe {
102+
tag.AddPrototype()
95103
}
96104
}
97105
}
98106

99-
func addPrototype(tag map[string]string) {
100-
if strings.Index(tag[FIELD_RETURNTYPE], TEMPLATE) == 0 || strings.Index(tag[FIELD_CODE], TEMPLATE) == 0 {
101-
code := tag[FIELD_CODE]
107+
func (tag *CTag) AddPrototype() {
108+
if strings.Index(tag.Returntype, TEMPLATE) == 0 || strings.Index(tag.Code, TEMPLATE) == 0 {
109+
code := tag.Code
102110
if strings.Contains(code, "{") {
103111
code = code[:strings.Index(code, "{")]
104112
} else {
105113
code = code[:strings.LastIndex(code, ")")+1]
106114
}
107-
tag[KIND_PROTOTYPE] = code + ";"
115+
tag.Prototype = code + ";"
108116
return
109117
}
110118

111-
tag[KIND_PROTOTYPE] = tag[FIELD_RETURNTYPE] + " " + tag[FIELD_FUNCTION_NAME] + tag[FIELD_SIGNATURE] + ";"
119+
tag.Prototype = tag.Returntype + " " + tag.FunctionName + tag.Signature + ";"
112120

113-
tag[KIND_PROTOTYPE_MODIFIERS] = ""
114-
if strings.Index(tag[FIELD_CODE], STATIC+" ") != -1 {
115-
tag[KIND_PROTOTYPE_MODIFIERS] = tag[KIND_PROTOTYPE_MODIFIERS] + " " + STATIC
121+
tag.PrototypeModifiers = ""
122+
if strings.Index(tag.Code, STATIC+" ") != -1 {
123+
tag.PrototypeModifiers = tag.PrototypeModifiers + " " + STATIC
116124
}
117-
tag[KIND_PROTOTYPE_MODIFIERS] = strings.TrimSpace(tag[KIND_PROTOTYPE_MODIFIERS])
125+
tag.PrototypeModifiers = strings.TrimSpace(tag.PrototypeModifiers)
118126
}
119127

120-
func removeDefinedProtypes(tags []map[string]string, context map[string]interface{}) {
128+
func removeDefinedProtypes(tags []*CTag, context map[string]interface{}) {
121129
definedPrototypes := make(map[string]bool)
122130
for _, tag := range tags {
123-
if tag[FIELD_KIND] == KIND_PROTOTYPE {
124-
definedPrototypes[tag[KIND_PROTOTYPE]] = true
131+
if tag.Kind == KIND_PROTOTYPE {
132+
definedPrototypes[tag.Prototype] = true
125133
}
126134
}
127135

128136
for _, tag := range tags {
129-
if definedPrototypes[tag[KIND_PROTOTYPE]] {
137+
if definedPrototypes[tag.Prototype] {
130138
if utils.DebugLevel(context) >= 10 {
131-
utils.Logger(context).Fprintln(os.Stderr, constants.MSG_SKIPPING_TAG_ALREADY_DEFINED, tag[FIELD_FUNCTION_NAME])
139+
utils.Logger(context).Fprintln(os.Stderr, constants.MSG_SKIPPING_TAG_ALREADY_DEFINED, tag.FunctionName)
132140
}
133-
tag[FIELD_SKIP] = TRUE
141+
tag.SkipMe = true
134142
}
135143
}
136144
}
137145

138-
func removeDuplicate(tags []map[string]string) {
146+
func removeDuplicate(tags []*CTag) {
139147
definedPrototypes := make(map[string]bool)
140148

141149
for _, tag := range tags {
142-
if !definedPrototypes[tag[KIND_PROTOTYPE]] {
143-
definedPrototypes[tag[KIND_PROTOTYPE]] = true
150+
if !definedPrototypes[tag.Prototype] {
151+
definedPrototypes[tag.Prototype] = true
144152
} else {
145-
tag[FIELD_SKIP] = TRUE
153+
tag.SkipMe = true
146154
}
147155
}
148156
}
149157

150-
type skipFuncType func(tag map[string]string) bool
158+
type skipFuncType func(tag *CTag) bool
151159

152-
func skipTagsWhere(tags []map[string]string, skipFunc skipFuncType, context map[string]interface{}) {
160+
func skipTagsWhere(tags []*CTag, skipFunc skipFuncType, context map[string]interface{}) {
153161
for _, tag := range tags {
154-
if tag[FIELD_SKIP] != TRUE {
162+
if !tag.SkipMe {
155163
skip := skipFunc(tag)
156164
if skip && utils.DebugLevel(context) >= 10 {
157-
utils.Logger(context).Fprintln(os.Stderr, constants.MSG_SKIPPING_TAG_WITH_REASON, tag[FIELD_FUNCTION_NAME], runtime.FuncForPC(reflect.ValueOf(skipFunc).Pointer()).Name())
165+
utils.Logger(context).Fprintln(os.Stderr, constants.MSG_SKIPPING_TAG_WITH_REASON, tag.FunctionName, runtime.FuncForPC(reflect.ValueOf(skipFunc).Pointer()).Name())
158166
}
159-
tag[FIELD_SKIP] = strconv.FormatBool(skip)
167+
tag.SkipMe = skip
160168
}
161169
}
162170
}
163171

164-
func signatureContainsDefaultArg(tag map[string]string) bool {
165-
return strings.Contains(tag[FIELD_SIGNATURE], "=")
172+
func signatureContainsDefaultArg(tag *CTag) bool {
173+
return strings.Contains(tag.Signature, "=")
166174
}
167175

168-
func prototypeAndCodeDontMatch(tag map[string]string) bool {
169-
if tag[FIELD_SKIP] == TRUE {
176+
func prototypeAndCodeDontMatch(tag *CTag) bool {
177+
if tag.SkipMe {
170178
return true
171179
}
172180

173-
code := removeSpacesAndTabs(tag[FIELD_CODE])
174-
prototype := removeSpacesAndTabs(tag[KIND_PROTOTYPE])
181+
code := removeSpacesAndTabs(tag.Code)
182+
prototype := removeSpacesAndTabs(tag.Prototype)
175183
prototype = removeTralingSemicolon(prototype)
176184

177185
return strings.Index(code, prototype) == -1
@@ -187,41 +195,66 @@ func removeSpacesAndTabs(s string) string {
187195
return s
188196
}
189197

190-
func skipTagsWithField(tags []map[string]string, fields []string, context map[string]interface{}) {
191-
for _, tag := range tags {
192-
if field, skip := utils.TagHasAtLeastOneField(tag, fields); skip {
193-
if utils.DebugLevel(context) >= 10 {
194-
utils.Logger(context).Fprintln(os.Stderr, constants.MSG_SKIPPING_TAG_BECAUSE_HAS_FIELD, field)
195-
}
196-
tag[FIELD_SKIP] = TRUE
197-
}
198+
func tagIsUnhandled(tag *CTag) bool {
199+
return !tag.IsHandled()
200+
}
201+
202+
func (tag *CTag) IsHandled() bool {
203+
if tag.Class != "" {
204+
return false
205+
}
206+
if tag.Struct != "" {
207+
return false
208+
}
209+
if tag.Namespace != "" {
210+
return false
198211
}
212+
return true
199213
}
200214

201-
func tagIsUnknown(tag map[string]string) bool {
202-
return !KNOWN_TAG_KINDS[tag[FIELD_KIND]]
215+
func tagIsUnknown(tag *CTag) bool {
216+
return !KNOWN_TAG_KINDS[tag.Kind]
203217
}
204218

205-
func parseTag(row string) map[string]string {
206-
tag := make(map[string]string)
219+
func parseTag(row string) *CTag {
220+
tag := &CTag{}
207221
parts := strings.Split(row, "\t")
208222

209-
tag[FIELD_FUNCTION_NAME] = parts[0]
210-
tag[FIELD_FILENAME] = parts[1]
223+
tag.FunctionName = parts[0]
224+
tag.Filename = parts[1]
211225

212226
parts = parts[2:]
213227

214228
for _, part := range parts {
215229
if strings.Contains(part, ":") {
216-
field := part[:strings.Index(part, ":")]
217-
if FIELDS[field] {
218-
tag[field] = strings.TrimSpace(part[strings.Index(part, ":")+1:])
230+
colon := strings.Index(part, ":")
231+
field := part[:colon]
232+
value := strings.TrimSpace(part[colon+1:])
233+
switch field {
234+
case "kind":
235+
tag.Kind = value
236+
case "line":
237+
val, _ := strconv.Atoi(value)
238+
// TODO: Check err from strconv.Atoi
239+
tag.Line = val
240+
case "typeref":
241+
tag.Typeref = value
242+
case "signature":
243+
tag.Signature = value
244+
case "returntype":
245+
tag.Returntype = value
246+
case "class":
247+
tag.Class = value
248+
case "struct":
249+
tag.Struct = value
250+
case "namespace":
251+
tag.Namespace = value
219252
}
220253
}
221254
}
222255

223256
if strings.Contains(row, "/^") && strings.Contains(row, "$/;") {
224-
tag[FIELD_CODE] = row[strings.Index(row, "/^")+2 : strings.Index(row, "$/;")]
257+
tag.Code = row[strings.Index(row, "/^")+2 : strings.Index(row, "$/;")]
225258
}
226259

227260
return tag

‎src/arduino.cc/builder/ctags_to_prototypes.go

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,13 @@ import (
3333
"arduino.cc/builder/constants"
3434
"arduino.cc/builder/types"
3535
"arduino.cc/builder/utils"
36-
"strconv"
3736
"strings"
3837
)
3938

4039
type CTagsToPrototypes struct{}
4140

4241
func (s *CTagsToPrototypes) Run(context map[string]interface{}) error {
43-
tags := context[constants.CTX_COLLECTED_CTAGS].([]map[string]string)
42+
tags := context[constants.CTX_COLLECTED_CTAGS].([]*CTag)
4443

4544
lineWhereToInsertPrototypes, err := findLineWhereToInsertPrototypes(tags)
4645
if err != nil {
@@ -56,7 +55,7 @@ func (s *CTagsToPrototypes) Run(context map[string]interface{}) error {
5655
return nil
5756
}
5857

59-
func findLineWhereToInsertPrototypes(tags []map[string]string) (int, error) {
58+
func findLineWhereToInsertPrototypes(tags []*CTag) (int, error) {
6059
firstFunctionLine, err := firstFunctionAtLine(tags)
6160
if err != nil {
6261
return -1, utils.WrapError(err)
@@ -78,50 +77,56 @@ func findLineWhereToInsertPrototypes(tags []map[string]string) (int, error) {
7877
}
7978
}
8079

81-
func firstFunctionPointerUsedAsArgument(tags []map[string]string) (int, error) {
80+
func firstFunctionPointerUsedAsArgument(tags []*CTag) (int, error) {
8281
functionNames := collectFunctionNames(tags)
8382
for _, tag := range tags {
8483
if functionNameUsedAsFunctionPointerIn(tag, functionNames) {
85-
return strconv.Atoi(tag[FIELD_LINE])
84+
return tag.Line, nil
8685
}
8786
}
8887
return -1, nil
8988
}
9089

91-
func functionNameUsedAsFunctionPointerIn(tag map[string]string, functionNames []string) bool {
90+
func functionNameUsedAsFunctionPointerIn(tag *CTag, functionNames []string) bool {
9291
for _, functionName := range functionNames {
93-
if strings.Index(tag[FIELD_CODE], "&"+functionName) != -1 {
92+
if strings.Index(tag.Code, "&"+functionName) != -1 {
9493
return true
9594
}
9695
}
9796
return false
9897
}
9998

100-
func collectFunctionNames(tags []map[string]string) []string {
99+
func collectFunctionNames(tags []*CTag) []string {
101100
names := []string{}
102101
for _, tag := range tags {
103-
if tag[FIELD_KIND] == KIND_FUNCTION {
104-
names = append(names, tag[FIELD_FUNCTION_NAME])
102+
if tag.Kind == KIND_FUNCTION {
103+
names = append(names, tag.FunctionName)
105104
}
106105
}
107106
return names
108107
}
109108

110-
func firstFunctionAtLine(tags []map[string]string) (int, error) {
109+
func firstFunctionAtLine(tags []*CTag) (int, error) {
111110
for _, tag := range tags {
112-
_, tagHasAtLeastOneField := utils.TagHasAtLeastOneField(tag, FIELDS_MARKING_UNHANDLED_TAGS)
113-
if !tagIsUnknown(tag) && !tagHasAtLeastOneField && tag[FIELD_KIND] == KIND_FUNCTION {
114-
return strconv.Atoi(tag[FIELD_LINE])
111+
if !tagIsUnknown(tag) && tag.IsHandled() && tag.Kind == KIND_FUNCTION {
112+
return tag.Line, nil
115113
}
116114
}
117115
return -1, nil
118116
}
119117

120-
func toPrototypes(tags []map[string]string) []*types.Prototype {
118+
func toPrototypes(tags []*CTag) []*types.Prototype {
121119
prototypes := []*types.Prototype{}
122120
for _, tag := range tags {
123-
if tag[FIELD_SKIP] != TRUE {
124-
prototype := &types.Prototype{FunctionName: tag[FIELD_FUNCTION_NAME], File: tag[FIELD_FILENAME], Prototype: tag[KIND_PROTOTYPE], Modifiers: tag[KIND_PROTOTYPE_MODIFIERS], Line: tag[FIELD_LINE], Fields: tag}
121+
if !tag.SkipMe {
122+
prototype := &types.Prototype{
123+
FunctionName: tag.FunctionName,
124+
File: tag.Filename,
125+
Prototype: tag.Prototype,
126+
Modifiers: tag.PrototypeModifiers,
127+
Line: tag.Line,
128+
//Fields: tag,
129+
}
125130
prototypes = append(prototypes, prototype)
126131
}
127132
}

‎src/arduino.cc/builder/prototypes_adder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ func composePrototypeSection(line int, prototypes []*types.Prototype) string {
7878
func joinPrototypes(prototypes []*types.Prototype) string {
7979
prototypesSlice := []string{}
8080
for _, proto := range prototypes {
81-
prototypesSlice = append(prototypesSlice, "#line "+proto.Line+" \""+proto.File+"\"")
81+
prototypesSlice = append(prototypesSlice, "#line "+strconv.Itoa(proto.Line)+" \""+proto.File+"\"")
8282
prototypeParts := []string{}
8383
if proto.Modifiers != "" {
8484
prototypeParts = append(prototypeParts, proto.Modifiers)

‎src/arduino.cc/builder/test/ctags_parser_test.go

Lines changed: 163 additions & 163 deletions
Large diffs are not rendered by default.

‎src/arduino.cc/builder/types/types.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ package types
3131

3232
import (
3333
"arduino.cc/builder/constants"
34+
"strconv"
3435
)
3536

3637
type SketchFile struct {
@@ -157,12 +158,11 @@ type Prototype struct {
157158
File string
158159
Prototype string
159160
Modifiers string
160-
Line string
161-
Fields map[string]string
161+
Line int
162162
}
163163

164164
func (proto *Prototype) String() string {
165-
return proto.Modifiers + " " + proto.Prototype + " @ " + proto.Line
165+
return proto.Modifiers + " " + proto.Prototype + " @ " + strconv.Itoa(proto.Line)
166166
}
167167

168168
type SourceFolder struct {

‎src/arduino.cc/builder/utils/utils.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -456,15 +456,6 @@ func TouchFile(targetFilePath string) error {
456456
return WriteFileBytes(targetFilePath, []byte{})
457457
}
458458

459-
func TagHasAtLeastOneField(tag map[string]string, fields []string) (string, bool) {
460-
for _, field := range fields {
461-
if tag[field] != constants.EMPTY_STRING {
462-
return field, true
463-
}
464-
}
465-
return "", false
466-
}
467-
468459
func NULLFile() string {
469460
if runtime.GOOS == "windows" {
470461
return "nul"

0 commit comments

Comments
 (0)
Please sign in to comment.