go-snark/circuitcompiler/lexer.go
circuitcompiler/lexer.goRaw
1package circuitcompiler
2
3import (
4 "bufio"
5 "bytes"
6 "io"
7)
8
9type OperatorSymbol int
10type Token int
11
12const (
13 ILLEGAL Token = iota
14 WS
15 EOF
16
17 IDENT // val
18
19 VAR // var
20 CONST // const value
21
22 EQ // =
23 PLUS // +
24 MINUS // -
25 MULTIPLY // *
26 DIVIDE // /
27 EXP // ^
28
29 OUT
30)
31
32var eof = rune(0)
33
34func isWhitespace(ch rune) bool {
35 return ch == ' ' || ch == '\t' || ch == '\n'
36}
37
38func isLetter(ch rune) bool {
39 return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')
40}
41func isDigit(ch rune) bool {
42 return (ch >= '0' && ch <= '9')
43}
44
45// Scanner holds the bufio.Reader
46type Scanner struct {
47 r *bufio.Reader
48}
49
50// NewScanner creates a new Scanner with the given io.Reader
51func NewScanner(r io.Reader) *Scanner {
52 return &Scanner{r: bufio.NewReader(r)}
53}
54
55func (s *Scanner) read() rune {
56 ch, _, err := s.r.ReadRune()
57 if err != nil {
58 return eof
59 }
60 return ch
61}
62
63func (s *Scanner) unread() {
64 _ = s.r.UnreadRune()
65}
66
67// Scan returns the Token and literal string of the current value
68func (s *Scanner) scan() (tok Token, lit string) {
69 ch := s.read()
70
71 if isWhitespace(ch) {
72 // space
73 s.unread()
74 return s.scanWhitespace()
75 } else if isLetter(ch) {
76 // letter
77 s.unread()
78 return s.scanIndent()
79 } else if isDigit(ch) {
80 s.unread()
81 return s.scanIndent()
82 }
83
84 switch ch {
85 case eof:
86 return EOF, ""
87 case '=':
88 return EQ, "="
89 case '+':
90 return PLUS, "+"
91 case '-':
92 return MINUS, "-"
93 case '*':
94 return MULTIPLY, "*"
95 case '/':
96 return DIVIDE, "/"
97 case '^':
98 return EXP, "^"
99 }
100
101 return ILLEGAL, string(ch)
102}
103
104func (s *Scanner) scanWhitespace() (token Token, lit string) {
105 var buf bytes.Buffer
106 buf.WriteRune(s.read())
107
108 for {
109 if ch := s.read(); ch == eof {
110 break
111 } else if !isWhitespace(ch) {
112 s.unread()
113 break
114 } else {
115 _, _ = buf.WriteRune(ch)
116 }
117 }
118 return WS, buf.String()
119}
120
121func (s *Scanner) scanIndent() (tok Token, lit string) {
122 var buf bytes.Buffer
123 buf.WriteRune(s.read())
124
125 for {
126 if ch := s.read(); ch == eof {
127 break
128 } else if !isLetter(ch) && !isDigit(ch) {
129 s.unread()
130 break
131 } else {
132 _, _ = buf.WriteRune(ch)
133 }
134 }
135 switch buf.String() {
136 case "var":
137 return VAR, buf.String()
138 }
139
140 if len(buf.String()) == 1 {
141 return Token(rune(buf.String()[0])), buf.String()
142 }
143 if buf.String() == "out" {
144 return OUT, buf.String()
145 }
146 return IDENT, buf.String()
147}