arnaucube
arnaucube/go-snarkPublic Self-hosted repository
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
 45type Scanner struct {
 46	r *bufio.Reader
 47}
 48
 49func NewScanner(r io.Reader) *Scanner {
 50	return &Scanner{r: bufio.NewReader(r)}
 51}
 52
 53func (s *Scanner) read() rune {
 54	ch, _, err := s.r.ReadRune()
 55	if err != nil {
 56		return eof
 57	}
 58	return ch
 59}
 60
 61func (s *Scanner) unread() {
 62	_ = s.r.UnreadRune()
 63}
 64
 65func (s *Scanner) Scan() (tok Token, lit string) {
 66	ch := s.read()
 67
 68	if isWhitespace(ch) {
 69		// space
 70		s.unread()
 71		return s.scanWhitespace()
 72	} else if isLetter(ch) {
 73		// letter
 74		s.unread()
 75		return s.scanIndent()
 76	} else if isDigit(ch) {
 77		s.unread()
 78		return s.scanIndent()
 79	}
 80
 81	switch ch {
 82	case eof:
 83		return EOF, ""
 84	case '=':
 85		return EQ, "="
 86	case '+':
 87		return PLUS, "+"
 88	case '-':
 89		return MINUS, "-"
 90	case '*':
 91		return MULTIPLY, "*"
 92	case '/':
 93		return DIVIDE, "/"
 94	case '^':
 95		return EXP, "^"
 96	}
 97
 98	return ILLEGAL, string(ch)
 99}
100
101func (s *Scanner) scanWhitespace() (token Token, lit string) {
102	var buf bytes.Buffer
103	buf.WriteRune(s.read())
104
105	for {
106		if ch := s.read(); ch == eof {
107			break
108		} else if !isWhitespace(ch) {
109			s.unread()
110			break
111		} else {
112			_, _ = buf.WriteRune(ch)
113		}
114	}
115	return WS, buf.String()
116}
117
118func (s *Scanner) scanIndent() (tok Token, lit string) {
119	var buf bytes.Buffer
120	buf.WriteRune(s.read())
121
122	for {
123		if ch := s.read(); ch == eof {
124			break
125		} else if !isLetter(ch) && !isDigit(ch) {
126			s.unread()
127			break
128		} else {
129			_, _ = buf.WriteRune(ch)
130		}
131	}
132	switch buf.String() {
133	case "var":
134		return VAR, buf.String()
135	}
136
137	if len(buf.String()) == 1 {
138		return Token(rune(buf.String()[0])), buf.String()
139	}
140	if buf.String() == "out" {
141		return OUT, buf.String()
142	}
143	return IDENT, buf.String()
144}