aboutsummaryrefslogtreecommitdiff
path: root/adapter_go.go
blob: 1b39e0bb106e9eb430c9ae3cd891841bd7fae783 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
package main

import (
	"bytes"
	"github.com/Fuwn/iku/engine"
	"go/format"
	"go/parser"
	"go/token"
)

type GoAdapter struct{}

func (a *GoAdapter) Analyze(source []byte) ([]byte, []engine.LineEvent, error) {
	formattedSource, err := format.Source(source)

	if err != nil {
		return nil, nil, err
	}

	tokenFileSet := token.NewFileSet()
	parsedFile, err := parser.ParseFile(tokenFileSet, "", formattedSource, parser.ParseComments)

	if err != nil {
		return nil, nil, err
	}

	formatter := &Formatter{}
	lineInformationMap := formatter.buildLineInfo(tokenFileSet, parsedFile)
	sourceByteLines := bytes.Split(formattedSource, []byte("\n"))
	events := make([]engine.LineEvent, len(sourceByteLines))
	insideRawString := false

	for lineIndex, currentLineBytes := range sourceByteLines {
		currentLine := string(currentLineBytes)
		backtickCount := countRawStringDelimiters(currentLine)
		wasInsideRawString := insideRawString

		if backtickCount%2 == 1 {
			insideRawString = !insideRawString
		}

		event := engine.NewLineEvent(currentLine)

		if wasInsideRawString {
			event.InRawString = true
			events[lineIndex] = event

			continue
		}

		if event.IsBlank {
			events[lineIndex] = event

			continue
		}

		lineNumber := lineIndex + 1
		currentInformation := lineInformationMap[lineNumber]

		if currentInformation != nil {
			event.HasASTInfo = true
			event.StatementType = currentInformation.statementType
			event.IsTopLevel = currentInformation.isTopLevel
			event.IsScoped = currentInformation.isScoped
			event.IsStartLine = currentInformation.isStartLine
		}

		event.IsClosingBrace = isClosingBrace(currentLine)
		event.IsOpeningBrace = isOpeningBrace(currentLine)
		event.IsCaseLabel = isCaseLabel(currentLine)
		event.IsCommentOnly = isCommentOnly(currentLine)
		event.IsPackageDecl = isPackageLine(event.TrimmedContent)
		events[lineIndex] = event
	}

	return formattedSource, events, nil
}

func MapCommentMode(mode CommentMode) engine.CommentMode {
	switch mode {
	case CommentsFollow:
		return engine.CommentsFollow
	case CommentsPrecede:
		return engine.CommentsPrecede
	case CommentsStandalone:
		return engine.CommentsStandalone
	default:
		return engine.CommentsFollow
	}
}