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 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 fmt.Println(constraint)
164 if constraint.Literal == "func" {
165 // one constraint for each input
166 for _, in := range constraint.PrivateInputs {
167 newConstr := &Constraint{
168 Op: "in",
169 Out: in,
170 }
171 circuit.Constraints = append(circuit.Constraints, *newConstr)
172 nInputs++
173 }
174 for _, in := range constraint.PublicInputs {
175 newConstr := &Constraint{
176 Op: "in",
177 Out: in,
178 }
179 circuit.Constraints = append(circuit.Constraints, *newConstr)
180 nInputs++
181 }
182 circuit.PublicInputs = constraint.PublicInputs
183 circuit.PrivateInputs = constraint.PrivateInputs
184 continue
185 }
186 if constraint.Literal == "equals" {
187 // TODO
188 fmt.Println("circuit.Signals", circuit.Signals)
189 continue
190 }
191 circuit.Constraints = append(circuit.Constraints, *constraint)
192 isVal, _ := isValue(constraint.V1)
193 if !isVal {
194 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1)
195 }
196 isVal, _ = isValue(constraint.V2)
197 if !isVal {
198 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V2)
199 }
200 if constraint.Out == "out" {
201 // if Out is "out", put it after first value (one) and before the inputs
202 if !existInArray(circuit.Signals, constraint.Out) {
203 signalsCopy := copyArray(circuit.Signals)
204 var auxSignals []string
205 auxSignals = append(auxSignals, signalsCopy[0])
206 auxSignals = append(auxSignals, constraint.Out)
207 auxSignals = append(auxSignals, signalsCopy[1:]...)
208 circuit.Signals = auxSignals
209 circuit.PublicSignals = append(circuit.PublicSignals, constraint.Out)
210 circuit.NPublic++
211 }
212 } else {
213 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.Out)
214 }
215 }
216 circuit.NVars = len(circuit.Signals)
217 circuit.NSignals = len(circuit.Signals)
218 return circuit, nil
219}
220func copyArray(in []string) []string { // tmp
221 var out []string
222 for _, e := range in {
223 out = append(out, e)
224 }
225 return out
226}