-
Notifications
You must be signed in to change notification settings - Fork 0
/
parse.go
121 lines (105 loc) · 2.65 KB
/
parse.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
package lsystem
import (
"strconv"
"strings"
)
func ParseRule(str string) []WeightedRule {
groups := strings.Split(strings.ReplaceAll(str, "\n", ""), ";")
var weightedTokens []WeightedRule
for _, group := range groups {
if strings.TrimSpace(group) == "" {
continue
}
tokens := strings.Fields(group)
weight, err := strconv.ParseFloat(tokens[0], 64)
if err != nil {
continue
}
// expect *Token to indicate a catalyst requirement on [1]
if len(tokens) > 1 && tokens[1][0] == '*' {
weightedTokens = append(weightedTokens, WeightedRule{
Probability: weight,
Catalyst: Token(tokens[1][1:]),
Tokens: symbolsToTokens(tokens[2:]),
})
continue
}
weightedTokens = append(weightedTokens, WeightedRule{
Probability: weight,
Tokens: symbolsToTokens(tokens[1:]),
})
}
return weightedTokens
}
func ParseRules(rulesMap map[Token]string) (TokenSet, TokenSet, map[Token]ProductionRule) {
vars := make(TokenSet)
consts := make(TokenSet)
parsedRules := make(map[Token]ProductionRule)
indexToken := func(token Token) {
if isVariable(token) {
vars.Add(token)
} else {
consts.Add(token)
}
}
for key, value := range rulesMap {
indexToken(key)
parsedRules[key] = NewProductionRule(key, ParseRule(value))
for _, wt := range parsedRules[key].Weights {
indexToken(wt.Catalyst)
for _, token := range wt.Tokens {
indexToken(token)
}
}
}
return vars, consts, parsedRules
}
func ParseState(state string) []Token {
return symbolsToTokens(strings.Fields(state))
}
func tryParseStatefulVariable(t Token) (variable string, num uint8, ok bool) {
var sb strings.Builder
cumulativeNumber := 0
if t[len(t)-1] < '0' || t[len(t)-1] > '9' {
return "", 0, false
}
for _, r := range t {
if r >= '0' && r <= '9' {
cumulativeNumber = cumulativeNumber*10 + int(r-'0')
continue
}
if cumulativeNumber == 0 {
sb.WriteRune(r)
continue
}
}
if cumulativeNumber == 0 {
return "", 0, false
}
if cumulativeNumber > 255 {
cumulativeNumber = 255
}
num = uint8(cumulativeNumber)
return sb.String(), num, true
}
func symbolsToTokens(symbols []string) []Token {
var tokens []Token
for _, symbol := range symbols {
tokens = append(tokens, Token(symbol))
}
return tokens
}
func isCapitalized(t Token) bool {
// empty string for missing catalyst (nil token)
if len(t) == 0 {
return false
}
firstLetter := string(t)[0]
return firstLetter >= 'A' && firstLetter <= 'Z'
}
func isVariable(t Token) bool {
// empty string for missing catalyst (nil token)
endsWithUnderscore := len(t) >= 1
endsWithUnderscore = endsWithUnderscore && t[len(t)-1] == '_'
return isCapitalized(t) && !endsWithUnderscore
}