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 fmt.Println("params", params)
105 // TODO
106 c.V1 = params[0]
107 c.V2 = params[1]
108 return c, nil
109 }
110 // if c.Literal == "out" {
111 // // TODO
112 // return c, nil
113 // }
114
115 _, lit = p.scanIgnoreWhitespace() // skip =
116 c.Literal += lit
117
118 // v1
119 _, lit = p.scanIgnoreWhitespace()
120 c.V1 = lit
121 c.Literal += lit
122 // operator
123 _, lit = p.scanIgnoreWhitespace()
124 c.Op = lit
125 c.Literal += lit
126 // v2
127 _, lit = p.scanIgnoreWhitespace()
128 c.V2 = lit
129 c.Literal += lit
130 if tok == EOF {
131 return nil, errors.New("eof in parseline")
132 }
133 return c, nil
134}
135
136func existInArray(arr []string, elem string) bool {
137 for _, v := range arr {
138 if v == elem {
139 return true
140 }
141 }
142 return false
143}
144
145func addToArrayIfNotExist(arr []string, elem string) []string {
146 for _, v := range arr {
147 if v == elem {
148 return arr
149 }
150 }
151 arr = append(arr, elem)
152 return arr
153}
154
155// Parse parses the lines and returns the compiled Circuit
156func (p *Parser) Parse() (*Circuit, error) {
157 circuit := &Circuit{}
158 circuit.Signals = append(circuit.Signals, "one")
159 nInputs := 0
160 for {
161 constraint, err := p.parseLine()
162 if err != nil {
163 break
164 }
165 fmt.Println(constraint)
166 if constraint.Literal == "func" {
167 // one constraint for each input
168 for _, in := range constraint.PublicInputs {
169 newConstr := &Constraint{
170 Op: "in",
171 Out: in,
172 }
173 circuit.Constraints = append(circuit.Constraints, *newConstr)
174 nInputs++
175 circuit.Signals = addToArrayIfNotExist(circuit.Signals, in)
176 circuit.NPublic++
177 }
178 for _, in := range constraint.PrivateInputs {
179 newConstr := &Constraint{
180 Op: "in",
181 Out: in,
182 }
183 circuit.Constraints = append(circuit.Constraints, *newConstr)
184 nInputs++
185 circuit.Signals = addToArrayIfNotExist(circuit.Signals, in)
186 }
187 circuit.PublicInputs = constraint.PublicInputs
188 circuit.PrivateInputs = constraint.PrivateInputs
189 continue
190 }
191 if constraint.Literal == "equals" {
192 // TODO
193 fmt.Println("circuit.Signals", circuit.Signals)
194 constr1 := &Constraint{
195 Op: "*",
196 V1: constraint.V2,
197 V2: "1",
198 Out: constraint.V1,
199 Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V1 + "==" + constraint.V2 + " * 1",
200 }
201 circuit.Constraints = append(circuit.Constraints, *constr1)
202 constr2 := &Constraint{
203 Op: "*",
204 V1: constraint.V1,
205 V2: "1",
206 Out: constraint.V2,
207 Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V2 + "==" + constraint.V1 + " * 1",
208 }
209 circuit.Constraints = append(circuit.Constraints, *constr2)
210 continue
211 }
212 circuit.Constraints = append(circuit.Constraints, *constraint)
213 isVal, _ := isValue(constraint.V1)
214 if !isVal {
215 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1)
216 }
217 isVal, _ = isValue(constraint.V2)
218 if !isVal {
219 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V2)
220 }
221
222 // if constraint.Out == "out" {
223 // if Out is "out", put it after first value (one) and before the inputs
224 // if constraint.Out == circuit.PublicInputs[0] {
225 // if existInArray(circuit.PublicInputs, constraint.Out) {
226 // // if Out is a public signal, put it after first value (one) and before the private inputs
227 // if !existInArray(circuit.Signals, constraint.Out) {
228 // // if already don't exists in signal array
229 // signalsCopy := copyArray(circuit.Signals)
230 // var auxSignals []string
231 // auxSignals = append(auxSignals, signalsCopy[0])
232 // auxSignals = append(auxSignals, constraint.Out)
233 // auxSignals = append(auxSignals, signalsCopy[1:]...)
234 // circuit.Signals = auxSignals
235 // // circuit.PublicInputs = append(circuit.PublicInputs, constraint.Out)
236 // circuit.NPublic++
237 // }
238 // } else {
239 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.Out)
240 // }
241 }
242 circuit.NVars = len(circuit.Signals)
243 circuit.NSignals = len(circuit.Signals)
244 return circuit, nil
245}
246func copyArray(in []string) []string { // tmp
247 var out []string
248 for _, e := range in {
249 out = append(out, e)
250 }
251 return out
252}