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
 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}