arnaucube
arnaucube/go-snarkPublic Self-hosted repository
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}