-
Notifications
You must be signed in to change notification settings - Fork 0
/
io.go
136 lines (117 loc) · 3.51 KB
/
io.go
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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package io
import (
"os"
"path/filepath"
"regexp"
"strings"
)
const (
newLine = "\n"
emptyString = ""
)
/*
FileAccessor is an interface for reading code lines of source file and creating new files
*/
type FileAccessor interface {
ReadCodeAsLines(name string) ([]string, []int)
ReadCode(name string) string
CreateFileFromLines(name string, lines []string)
CreateFileFromContent(name string, content string)
FindPaths(root, pattern string) ([]string, error)
}
/*
DefaultFileAccessor is the base implementation of FileAccessor
*/
type DefaultFileAccessor struct {
FileReader
FileWriter
}
/*
ReadCodeAsLines reads the code lines from a source file into a string array.
It will ignore all of the empty lines and the comments.
It will give back the line numbers in the files in an int array, what will help later the parser to locate the error,
if a there is an invalid code which can not be translated to binary.
*/
func (sr *DefaultFileAccessor) ReadCodeAsLines(name string) ([]string, []int) {
bytes, err := sr.Read(name)
panicIfError(err)
codeSrc := stripComments(string(bytes))
lines := strings.Split(codeSrc, newLine)
return scanRawLines(lines)
}
/*
ReadCode reads the code lines from a source file into a string array.
It will ignore all of the empty lines and the comments.
It will give back the line numbers in the files in an int array, what will help later the parser to locate the error,
if a there is an invalid code which can not be translated to binary.
*/
func (sr *DefaultFileAccessor) ReadCode(name string) string {
codeAsLines, _ := sr.ReadCodeAsLines(name)
return join(codeAsLines)
}
/*
CreateFileFromLines creates a file with the given name and extension and lines as content
*/
func (sr *DefaultFileAccessor) CreateFileFromLines(name string, lines []string) {
joinedLines := join(lines)
err := sr.Write(name, []byte(joinedLines))
panicIfError(err)
}
/*
CreateFileFromContent creates a file with the given name and extension with content
*/
func (sr *DefaultFileAccessor) CreateFileFromContent(name string, content string) {
err := sr.Write(name, []byte(content))
panicIfError(err)
}
/*
FindPaths returns all file paths from the given root path, if it is a file path, it will return it as a slice
*/
func (sr *DefaultFileAccessor) FindPaths(root, pattern string) ([]string, error) {
var filePaths []string
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if matched, err := filepath.Match(pattern, filepath.Base(path)); err != nil {
return err
} else if matched {
filePaths = append(filePaths, path)
}
return nil
})
if err != nil {
return nil, err
}
return filePaths, nil
}
func scanRawLines(lines []string) ([]string, []int) {
lineCount := 0
var codeLines []string
var codeLineNumbers []int
for _, line := range lines {
lineCount++
instruction := getInstructionPart(line)
if instruction != "" {
codeLines = append(codeLines, instruction)
codeLineNumbers = append(codeLineNumbers, lineCount)
}
}
return codeLines, codeLineNumbers
}
func getInstructionPart(line string) string {
return strings.TrimSpace(line)
}
func stripComments(src string) string {
multiLineComments := regexp.MustCompile("(?s)/\\*.*?\\*/")
singleLineComments := regexp.MustCompile("//.*")
return singleLineComments.ReplaceAllString(multiLineComments.ReplaceAllString(src, emptyString), emptyString)
}
func join(lines []string) string {
return strings.Join(lines, newLine) + newLine
}
func panicIfError(e error) {
if e != nil {
panic(e)
}
}