go-snark/circuitcompiler/parser.go
circuitcompiler/parser.goRaw
1package circuitcompiler
2
3import (
4 "errors"
5 "io"
6 "regexp"
7 "strings"
8)
9
10// Parser data structure holds the Scanner and the Parsing functions
11type Parser struct {
12 s *Scanner
13 buf struct {
14 tok Token // last read token
15 lit string // last read literal
16 n int // buffer size (max=1)
17 }
18}
19
20// NewParser creates a new parser from a io.Reader
21func NewParser(r io.Reader) *Parser {
22 return &Parser{s: NewScanner(r)}
23}
24
25func (p *Parser) scan() (tok Token, lit string) {
26 // if there is a token in the buffer return it
27 if p.buf.n != 0 {
28 p.buf.n = 0
29 return p.buf.tok, p.buf.lit
30 }
31 tok, lit = p.s.scan()
32
33 p.buf.tok, p.buf.lit = tok, lit
34
35 return
36}
37
38func (p *Parser) unscan() {
39 p.buf.n = 1
40}
41
42func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) {
43 tok, lit = p.scan()
44 if tok == WS {
45 tok, lit = p.scan()
46 }
47 return
48}
49
50// parseLine parses the current line
51func (p *Parser) parseLine() (*Constraint, error) {
52 /*
53 in this version,
54 line will be for example s3 = s1 * s4
55 this is:
56 val eq val op val
57 */
58 c := &Constraint{}
59 tok, lit := p.scanIgnoreWhitespace()
60 c.Out = lit
61 c.Literal += lit
62
63 if c.Literal == "func" {
64 // format: `func name(in):`
65 line, err := p.s.r.ReadString(':')
66 if err != nil {
67 return c, err
68 }
69 // read string inside ( )
70 rgx := regexp.MustCompile(`\((.*?)\)`)
71 insideParenthesis := rgx.FindStringSubmatch(line)
72 varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
73 c.Inputs = strings.Split(varsString, ",")
74 return c, nil
75 }
76
77 _, lit = p.scanIgnoreWhitespace() // skip =
78 c.Literal += lit
79
80 // v1
81 _, lit = p.scanIgnoreWhitespace()
82 c.V1 = lit
83 c.Literal += lit
84 // operator
85 _, lit = p.scanIgnoreWhitespace()
86 c.Op = lit
87 c.Literal += lit
88 // v2
89 _, lit = p.scanIgnoreWhitespace()
90 c.V2 = lit
91 c.Literal += lit
92 if tok == EOF {
93 return nil, errors.New("eof in parseline")
94 }
95 return c, nil
96}
97
98func existInArray(arr []string, elem string) bool {
99 for _, v := range arr {
100 if v == elem {
101 return true
102 }
103 }
104 return false
105}
106
107func addToArrayIfNotExist(arr []string, elem string) []string {
108 for _, v := range arr {
109 if v == elem {
110 return arr
111 }
112 }
113 arr = append(arr, elem)
114 return arr
115}
116
117// Parse parses the lines and returns the compiled Circuit
118func (p *Parser) Parse() (*Circuit, error) {
119 circuit := &Circuit{}
120 circuit.Signals = append(circuit.Signals, "one")
121 nInputs := 0
122 for {
123 constraint, err := p.parseLine()
124 if err != nil {
125 break
126 }
127 if constraint.Literal == "func" {
128 // one constraint for each input
129 for _, in := range constraint.Inputs {
130 newConstr := &Constraint{
131 Op: "in",
132 Out: in,
133 }
134 circuit.Constraints = append(circuit.Constraints, *newConstr)
135 nInputs++
136 }
137 circuit.Inputs = constraint.Inputs
138 continue
139 }
140 circuit.Constraints = append(circuit.Constraints, *constraint)
141 isVal, _ := isValue(constraint.V1)
142 if !isVal {
143 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1)
144 }
145 isVal, _ = isValue(constraint.V2)
146 if !isVal {
147 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V2)
148 }
149 if constraint.Out == "out" {
150 // if Out is "out", put it after first value (one) and before the inputs
151 if !existInArray(circuit.Signals, constraint.Out) {
152 signalsCopy := copyArray(circuit.Signals)
153 var auxSignals []string
154 auxSignals = append(auxSignals, signalsCopy[0])
155 auxSignals = append(auxSignals, constraint.Out)
156 auxSignals = append(auxSignals, signalsCopy[1:]...)
157 circuit.Signals = auxSignals
158 circuit.PublicSignals = append(circuit.PublicSignals, constraint.Out)
159 circuit.NPublic++
160 }
161 } else {
162 circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.Out)
163 }
164 }
165 circuit.NVars = len(circuit.Signals)
166 circuit.NSignals = len(circuit.Signals)
167 return circuit, nil
168}
169func copyArray(in []string) []string { // tmp
170 var out []string
171 for _, e := range in {
172 out = append(out, e)
173 }
174 return out
175}