go-snark/circuitcompiler/parser.go
circuitcompiler/parser.goRaw
1package circuitcompiler
2
3import (
4 "errors"
5 "fmt"
6 "io"
7 "os"
8 "regexp"
9 "strings"
10)
11
12// Parser data structure holds the Scanner and the Parsing functions
13type Parser struct {
14 s *Scanner
15 buf struct {
16 tok Token // last read token
17 lit string // last read literal
18 n int // buffer size (max=1)
19 }
20}
21
22// NewParser creates a new parser from a io.Reader
23func NewParser(r io.Reader) *Parser {
24 return &Parser{s: NewScanner(r)}
25}
26
27func (p *Parser) scan() (tok Token, lit string) {
28 // if there is a token in the buffer return it
29 if p.buf.n != 0 {
30 p.buf.n = 0
31 return p.buf.tok, p.buf.lit
32 }
33 tok, lit = p.s.scan()
34
35 p.buf.tok, p.buf.lit = tok, lit
36
37 return
38}
39
40func (p *Parser) unscan() {
41 p.buf.n = 1
42}
43
44func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) {
45 tok, lit = p.scan()
46 if tok == WS {
47 tok, lit = p.scan()
48 }
49 return
50}
51
52// parseLine parses the current line
53func (p *Parser) parseLine() (*Constraint, error) {
54 /*
55 in this version,
56 line will be for example s3 = s1 * s4
57 this is:
58 val eq val op val
59 */
60 c := &Constraint{}
61 tok, lit := p.scanIgnoreWhitespace()
62 c.Out = lit
63 c.Literal += lit
64
65 if c.Literal == "func" {
66 // format: `func name(in):`
67 line, err := p.s.r.ReadString(':')
68 if err != nil {
69 return c, err
70 }
71 // read string inside ( )
72 rgx := regexp.MustCompile(`\((.*?)\)`)
73 insideParenthesis := rgx.FindStringSubmatch(line)
74 varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
75 allInputs := strings.Split(varsString, ",")
76
77 // from allInputs, get the private and the public separated
78 for _, in := range allInputs {
79 if strings.Contains(in, "private") {
80 input := strings.Replace(in, "private", "", -1)
81 c.PrivateInputs = append(c.PrivateInputs, input)
82 } else if strings.Contains(in, "public") {
83 input := strings.Replace(in, "public", "", -1)
84 c.PublicInputs = append(c.PublicInputs, input)
85 } else {
86 // TODO give more info about the circuit code error
87 fmt.Println("error on declaration of public and private inputs")
88 os.Exit(0)
89 }
90 }
91 return c, nil
92 }
93 if c.Literal == "equals" {
94 // format: `equals(a, b)`
95 line, err := p.s.r.ReadString(')')
96 if err != nil {
97 return c, err
98 }
99 // read string inside ( )
100 rgx := regexp.MustCompile(`\((.*?)\)`)
101 insideParenthesis := rgx.FindStringSubmatch(line)
102 varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
103 params := strings.Split(varsString, ",")
104 c.V1 = params[0]
105 c.V2 = params[1]
106 return c, nil
107 }
108 // if c.Literal == "out" {
109 // // TODO
110 // return c, nil
111 // }
112
113 _, lit = p.scanIgnoreWhitespace() // skip =
114 c.Literal += lit
115
116 // v1
117 _, lit = p.scanIgnoreWhitespace()
118 c.V1 = lit
119 c.Literal += lit
120 // operator
121 _, lit = p.scanIgnoreWhitespace()
122 c.Op = lit
123 c.Literal += lit
124 // v2
125 _, lit = p.scanIgnoreWhitespace()
126 c.V2 = lit
127 c.Literal += lit
128 if tok == EOF {
129 return nil, errors.New("eof in parseline")
130 }
131 return c, nil
132}
133
134func existInArray(arr []string, elem string) bool {
135 for _, v := range arr {
136 if v == elem {
137 return true
138 }
139 }
140 return false
141}
142
143func addToArrayIfNotExist(arr []string, elem string) []string {
144 for _, v := range arr {
145 if v == elem {
146 return arr
147 }
148 }
149 arr = append(arr, elem)
150 return arr
151}
152
153// Parse parses the lines and returns the compiled Circuit
154func (p *Parser) Parse() (*Circuit, error) {
155 circuit := &Circuit{}
156 circuit.Signals = append(circuit.Signals, "one")
157 nInputs := 0
158 for {
159 constraint, err := p.parseLine()
160 if err != nil {
161 break
162 }
163 if constraint.Literal == "func" {
164 // one constraint for each input
165 for _, in := range constraint.PublicInputs {
166 newConstr := &Constraint{
167 Op: "in",
168 Out: in,
169 }
170 circuit.Constraints = append(circuit.Constraints, *newConstr)
171 nInputs++
172 circuit.Signals = addToArrayIfNotExist(circuit.Signals, in)
173 circuit.NPublic++
174 }
175 for _, in := range constraint.PrivateInputs {
176 newConstr := &Constraint{
177 Op: "in",
178 Out: in,
179 }
180 circuit.Constraints = append(circuit.Constraints, *newConstr)
181 nInputs++
182 circuit.Signals = addToArrayIfNotExist(circuit.Signals, in)
183 }
184 circuit.PublicInputs = constraint.PublicInputs
185 circuit.PrivateInputs = constraint.PrivateInputs
186 continue
187 }
188 if constraint.Literal == "equals" {
189 constr1 := &Constraint{
190 Op: "*",
191 V1: constraint.V2,
192 V2: "1",
193 Out: constraint.V1,
194 Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V1 + "==" + constraint.V2 + " * 1",
195 }
196 circuit.Constraints = append(circuit.Constraints, *constr1)
197 constr2 := &Constraint{
198 Op: "*",
199 V1: constraint.V1,
200 V2: "1",
201 Out: constraint.V2,
202 Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V2 + "==" + constraint.V1 + " * 1",
203 }
204 circuit.Constraints = append(circuit.Constraints, *constr2)
205 continue
206 }
207 circuit.Constraints = append(circuit.Constraints, *constraint)
208 isVal, _ := isValue(constraint.V1)
209 if !isVal {
210 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1)
211 }
212 isVal, _ = isValue(constraint.V2)
213 if !isVal {
214 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V2)
215 }
216
217 // if constraint.Out == "out" {
218 // if Out is "out", put it after first value (one) and before the inputs
219 // if constraint.Out == circuit.PublicInputs[0] {
220 // if existInArray(circuit.PublicInputs, constraint.Out) {
221 // // if Out is a public signal, put it after first value (one) and before the private inputs
222 // if !existInArray(circuit.Signals, constraint.Out) {
223 // // if already don't exists in signal array
224 // signalsCopy := copyArray(circuit.Signals)
225 // var auxSignals []string
226 // auxSignals = append(auxSignals, signalsCopy[0])
227 // auxSignals = append(auxSignals, constraint.Out)
228 // auxSignals = append(auxSignals, signalsCopy[1:]...)
229 // circuit.Signals = auxSignals
230 // // circuit.PublicInputs = append(circuit.PublicInputs, constraint.Out)
231 // circuit.NPublic++
232 // }
233 // } else {
234 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.Out)
235 // }
236 }
237 circuit.NVars = len(circuit.Signals)
238 circuit.NSignals = len(circuit.Signals)
239 return circuit, nil
240}
241func copyArray(in []string) []string { // tmp
242 var out []string
243 for _, e := range in {
244 out = append(out, e)
245 }
246 return out
247}