]> git.lizzy.rs Git - micro.git/blob - runtime/syntax/syntax_converter.go
Add autoretab
[micro.git] / runtime / syntax / syntax_converter.go
1 //+build ignore
2
3 package main
4
5 import (
6         "fmt"
7         "io/ioutil"
8         "os"
9         "regexp"
10         "strings"
11 )
12
13 type SingleRule struct {
14         color string
15         regex string
16 }
17
18 type MultiRule struct {
19         color string
20         start string
21         end   string
22 }
23
24 // JoinRule takes a syntax rule (which can be multiple regular expressions)
25 // and joins it into one regular expression by ORing everything together
26 func JoinRule(rule string) string {
27         split := strings.Split(rule, `" "`)
28         joined := strings.Join(split, "|")
29         return joined
30 }
31
32 func parseFile(text, filename string) (filetype, syntax, header string, rules []interface{}) {
33         lines := strings.Split(text, "\n")
34
35         // Regex for parsing syntax statements
36         syntaxParser := regexp.MustCompile(`syntax "(.*?)"\s+"(.*)"+`)
37         // Regex for parsing header statements
38         headerParser := regexp.MustCompile(`header "(.*)"`)
39
40         // Regex for parsing standard syntax rules
41         ruleParser := regexp.MustCompile(`color (.*?)\s+(?:\((.+?)?\)\s+)?"(.*)"`)
42         // Regex for parsing syntax rules with start="..." end="..."
43         ruleStartEndParser := regexp.MustCompile(`color (.*?)\s+(?:\((.+?)?\)\s+)?start="(.*)"\s+end="(.*)"`)
44
45         for lineNum, line := range lines {
46                 line = strings.TrimSpace(line)
47                 if line == "" {
48                         continue
49                 }
50                 if strings.HasPrefix(line, "#") {
51                         continue
52                 }
53                 if strings.HasPrefix(line, "syntax") {
54                         syntaxMatches := syntaxParser.FindSubmatch([]byte(line))
55                         if len(syntaxMatches) == 3 {
56                                 filetype = string(syntaxMatches[1])
57                                 syntax = JoinRule(string(syntaxMatches[2]))
58                         } else {
59                                 fmt.Println(filename, lineNum, "Syntax statement is not valid: "+line)
60                                 continue
61                         }
62                 }
63                 if strings.HasPrefix(line, "header") {
64                         // Header statement
65                         headerMatches := headerParser.FindSubmatch([]byte(line))
66                         if len(headerMatches) == 2 {
67                                 header = JoinRule(string(headerMatches[1]))
68                         } else {
69                                 fmt.Println(filename, lineNum, "Header statement is not valid: "+line)
70                                 continue
71                         }
72                 }
73
74                 // Syntax rule, but it could be standard or start-end
75                 if ruleParser.MatchString(line) {
76                         // Standard syntax rule
77                         // Parse the line
78                         submatch := ruleParser.FindSubmatch([]byte(line))
79                         var color string
80                         var regexStr string
81                         var flags string
82                         if len(submatch) == 4 {
83                                 // If len is 4 then the user specified some additional flags to use
84                                 color = string(submatch[1])
85                                 flags = string(submatch[2])
86                                 if flags != "" {
87                                         regexStr = "(?" + flags + ")" + JoinRule(string(submatch[3]))
88                                 } else {
89                                         regexStr = JoinRule(string(submatch[3]))
90                                 }
91                         } else if len(submatch) == 3 {
92                                 // If len is 3, no additional flags were given
93                                 color = string(submatch[1])
94                                 regexStr = JoinRule(string(submatch[2]))
95                         } else {
96                                 // If len is not 3 or 4 there is a problem
97                                 fmt.Println(filename, lineNum, "Invalid statement: "+line)
98                                 continue
99                         }
100
101                         rules = append(rules, SingleRule{color, regexStr})
102                 } else if ruleStartEndParser.MatchString(line) {
103                         // Start-end syntax rule
104                         submatch := ruleStartEndParser.FindSubmatch([]byte(line))
105                         var color string
106                         var start string
107                         var end string
108                         // Use m and s flags by default
109                         if len(submatch) == 5 {
110                                 // If len is 5 the user provided some additional flags
111                                 color = string(submatch[1])
112                                 start = string(submatch[3])
113                                 end = string(submatch[4])
114                         } else if len(submatch) == 4 {
115                                 // If len is 4 the user did not provide additional flags
116                                 color = string(submatch[1])
117                                 start = string(submatch[2])
118                                 end = string(submatch[3])
119                         } else {
120                                 // If len is not 4 or 5 there is a problem
121                                 fmt.Println(filename, lineNum, "Invalid statement: "+line)
122                                 continue
123                         }
124
125                         // rules[color] = "(?" + flags + ")" + "(" + start + ").*?(" + end + ")"
126                         rules = append(rules, MultiRule{color, start, end})
127                 }
128         }
129
130         return
131 }
132
133 func generateFile(filetype, syntax, header string, rules []interface{}) string {
134         output := ""
135
136         output += fmt.Sprintf("filetype: %s\n\n", filetype)
137         output += fmt.Sprintf("detect: \n    filename: \"%s\"\n", strings.Replace(strings.Replace(syntax, "\\", "\\\\", -1), "\"", "\\\"", -1))
138
139         if header != "" {
140                 output += fmt.Sprintf("    header: \"%s\"\n", strings.Replace(strings.Replace(header, "\\", "\\\\", -1), "\"", "\\\"", -1))
141         }
142
143         output += "\nrules:\n"
144
145         for _, r := range rules {
146                 if rule, ok := r.(SingleRule); ok {
147                         output += fmt.Sprintf("    - %s: \"%s\"\n", rule.color, strings.Replace(strings.Replace(rule.regex, "\\", "\\\\", -1), "\"", "\\\"", -1))
148                 } else if rule, ok := r.(MultiRule); ok {
149                         output += fmt.Sprintf("    - %s:\n", rule.color)
150                         output += fmt.Sprintf("        start: \"%s\"\n", strings.Replace(strings.Replace(rule.start, "\\", "\\\\", -1), "\"", "\\\"", -1))
151                         output += fmt.Sprintf("        end: \"%s\"\n", strings.Replace(strings.Replace(rule.end, "\\", "\\\\", -1), "\"", "\\\"", -1))
152                         output += fmt.Sprintf("        rules: []\n\n")
153                 }
154         }
155
156         return output
157 }
158
159 func main() {
160         if len(os.Args) < 2 {
161                 fmt.Println("no args")
162                 return
163         }
164
165         data, _ := ioutil.ReadFile(os.Args[1])
166         fmt.Print(generateFile(parseFile(string(data), os.Args[1])))
167 }