go-snark/circuitcompiler/parser.go
circuitcompiler/parser.goRaw
1package circuitcompiler
2
3import (
4 "errors"
5 "io"
6 "regexp"
7 "strings"
8)
9
10type Parser struct {
11 s *Scanner
12 buf struct {
13 tok Token // last read token
14 lit string // last read literal
15 n int // buffer size (max=1)
16 }
17}
18
19type Constraint struct {
20 // v1 op v2 = out
21 Op Token
22 V1 string
23 V2 string
24 Out string
25 Literal string
26
27 Inputs []string // in func delcaration case
28}
29
30func NewParser(r io.Reader) *Parser {
31 return &Parser{s: NewScanner(r)}
32}
33
34func (p *Parser) scan() (tok Token, lit string) {
35 // if there is a token in the buffer return it
36 if p.buf.n != 0 {
37 p.buf.n = 0
38 return p.buf.tok, p.buf.lit
39 }
40 tok, lit = p.s.Scan()
41
42 p.buf.tok, p.buf.lit = tok, lit
43
44 return
45}
46
47func (p *Parser) unscan() {
48 p.buf.n = 1
49}
50
51func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) {
52 tok, lit = p.scan()
53 if tok == WS {
54 tok, lit = p.scan()
55 }
56 return
57}
58
59func (p *Parser) ParseLine() (*Constraint, error) {
60 /*
61 in this version,
62 line will be for example s3 = s1 * s4
63 this is:
64 val eq val op val
65 */
66 c := &Constraint{}
67 tok, lit := p.scanIgnoreWhitespace()
68 c.Out = lit
69 c.Literal += lit
70
71 if c.Literal == "func" {
72 // format: `func name(in):`
73 line, err := p.s.r.ReadString(':')
74 if err != nil {
75 return c, err
76 }
77 // read string inside ( )
78 rgx := regexp.MustCompile(`\((.*?)\)`)
79 insideParenthesis := rgx.FindStringSubmatch(line)
80 varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
81 c.Inputs = strings.Split(varsString, ",")
82 return c, nil
83 }
84
85 _, lit = p.scanIgnoreWhitespace() // skip =
86 c.Literal += lit
87
88 // v1
89 _, lit = p.scanIgnoreWhitespace()
90 c.V1 = lit
91 c.Literal += lit
92 // operator
93 c.Op, lit = p.scanIgnoreWhitespace()
94 c.Literal += lit
95 // v2
96 _, lit = p.scanIgnoreWhitespace()
97 c.V2 = lit
98 c.Literal += lit
99 if tok == EOF {
100 return nil, errors.New("eof in parseline")
101 }
102 return c, nil
103}
104
105func addToArrayIfNotExist(arr []string, elem string) []string {
106 for _, v := range arr {
107 if v == elem {
108 return arr
109 }
110 }
111 arr = append(arr, elem)
112 return arr
113}
114func (p *Parser) Parse() (*Circuit, error) {
115 circuit := &Circuit{}
116 circuit.Signals = append(circuit.Signals, "one")
117 for {
118 constraint, err := p.ParseLine()
119 if err != nil {
120 break
121 }
122 if constraint.Literal == "func" {
123 circuit.Inputs = constraint.Inputs
124 continue
125 }
126 circuit.Constraints = append(circuit.Constraints, *constraint)
127 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1)
128 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V2)
129 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.Out)
130 }
131 return circuit, nil
132}