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
 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}