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