-
Notifications
You must be signed in to change notification settings - Fork 0
/
parser.go
125 lines (104 loc) · 2.37 KB
/
parser.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
package parser
import (
"bytes"
"fmt"
"github.com/alecthomas/participle/v2"
"github.com/alecthomas/participle/v2/lexer"
"strconv"
)
type ATCommands struct {
AT string `@AT`
Commands []ATCommand `( @@ ( CommandSeparator @@ )* )?`
}
type ATCommand interface {
value()
}
type ATTestCommand struct {
CommandName string `@CommandName`
TestModifier string `@TestModifier`
}
func (v ATTestCommand) value() {}
type ATReadCommand struct {
CommandName string `@CommandName`
ReadModifier string `@ReadModifier`
}
func (v ATReadCommand) value() {}
type ATExecuteCommand struct {
CommandName string `@CommandName`
}
func (v ATExecuteCommand) value() {}
type ATSetCommand struct {
CommandName string `@CommandName`
SetModifier string `@SetModifier`
Values []String `(@@ (ValueSeparator @@)*)?`
}
func (v ATSetCommand) value() {}
type String struct {
Fragments []Fragment `@@*`
}
func (s String) String() string {
var v string
for _, fragment := range s.Fragments {
v += fragment.String()
}
return v
}
type Fragment struct {
Escaped string `( (@Escaped | @QuotedEscaped )`
Text string ` | (@Chars | @QuotedChars) )`
}
func (f Fragment) String() string {
if f.Escaped != "" {
s, err := strconv.Unquote(`"` + f.Escaped + `"`)
if err != nil {
panic(err)
}
return s
} else {
return f.Text
}
}
type Parser struct {
parser *participle.Parser[ATCommands]
}
func NewParser() (*Parser, error) {
parser, err := participle.Build[ATCommands](
participle.Lexer(atLexer),
participle.Union[ATCommand](
ATTestCommand{},
ATReadCommand{},
ATSetCommand{},
ATExecuteCommand{},
),
)
if err != nil {
return nil, err
}
return &Parser{
parser: parser,
}, nil
}
func (p *Parser) Parse(text string) (*ATCommands, error) {
return p.parser.ParseString("", text)
}
func (p *Parser) LexerSymbolMap() map[lexer.TokenType]string {
m := make(map[lexer.TokenType]string)
for symbol, tokenType := range p.parser.Lexer().Symbols() {
m[tokenType] = symbol
}
return m
}
func (p *Parser) Lex(text string) ([]lexer.Token, error) {
return p.parser.Lex("", bytes.NewReader([]byte(text)))
}
func (p *Parser) DumpTokens(text string) error {
tokens, err := p.Lex(text)
if err != nil {
return err
}
symbolMap := p.LexerSymbolMap()
for _, token := range tokens {
fmt.Printf("%s [%s] (%s)\n", token.Value, symbolMap[token.Type], token.Pos)
}
return nil
}