arnaucube
arnaucube/go-snarkPublic Self-hosted repository
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 the inputs
151			if !existInArray(circuit.Signals, constraint.Out) {
152				signalsCopy := copyArray(circuit.Signals)
153				var auxSignals []string
154				auxSignals = append(auxSignals, signalsCopy[0:nInputs+1]...)
155				auxSignals = append(auxSignals, constraint.Out)
156				auxSignals = append(auxSignals, signalsCopy[nInputs+1:]...)
157				circuit.Signals = auxSignals
158			}
159		} else {
160			circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.Out)
161		}
162	}
163	circuit.NVars = len(circuit.Signals)
164	circuit.NSignals = len(circuit.Signals)
165	circuit.NPublic = 0
166	return circuit, nil
167}
168func copyArray(in []string) []string { // tmp
169	var out []string
170	for _, e := range in {
171		out = append(out, e)
172	}
173	return out
174}