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
 19type Constraint struct {
 20	// v1 op v2 = out
 21	Op      Token
 22	V1      string
 23	V2      string
 24	Out     string
 25	Literal string
 26
 27	Inputs []string // in func delcaration case
 28}
 29
 30func NewParser(r io.Reader) *Parser {
 31	return &Parser{s: NewScanner(r)}
 32}
 33
 34func (p *Parser) scan() (tok Token, lit string) {
 35	// if there is a token in the buffer return it
 36	if p.buf.n != 0 {
 37		p.buf.n = 0
 38		return p.buf.tok, p.buf.lit
 39	}
 40	tok, lit = p.s.Scan()
 41
 42	p.buf.tok, p.buf.lit = tok, lit
 43
 44	return
 45}
 46
 47func (p *Parser) unscan() {
 48	p.buf.n = 1
 49}
 50
 51func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) {
 52	tok, lit = p.scan()
 53	if tok == WS {
 54		tok, lit = p.scan()
 55	}
 56	return
 57}
 58
 59func (p *Parser) ParseLine() (*Constraint, error) {
 60	/*
 61		in this version,
 62		line will be for example s3 = s1 * s4
 63		this is:
 64		val eq val op val
 65	*/
 66	c := &Constraint{}
 67	tok, lit := p.scanIgnoreWhitespace()
 68	c.Out = lit
 69	c.Literal += lit
 70
 71	if c.Literal == "func" {
 72		// format: `func name(in):`
 73		line, err := p.s.r.ReadString(':')
 74		if err != nil {
 75			return c, err
 76		}
 77		// read string inside ( )
 78		rgx := regexp.MustCompile(`\((.*?)\)`)
 79		insideParenthesis := rgx.FindStringSubmatch(line)
 80		varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
 81		c.Inputs = strings.Split(varsString, ",")
 82		return c, nil
 83	}
 84
 85	_, lit = p.scanIgnoreWhitespace() // skip =
 86	c.Literal += lit
 87
 88	// v1
 89	_, lit = p.scanIgnoreWhitespace()
 90	c.V1 = lit
 91	c.Literal += lit
 92	// operator
 93	c.Op, lit = p.scanIgnoreWhitespace()
 94	c.Literal += lit
 95	// v2
 96	_, lit = p.scanIgnoreWhitespace()
 97	c.V2 = lit
 98	c.Literal += lit
 99	if tok == EOF {
100		return nil, errors.New("eof in parseline")
101	}
102	return c, nil
103}
104
105func addToArrayIfNotExist(arr []string, elem string) []string {
106	for _, v := range arr {
107		if v == elem {
108			return arr
109		}
110	}
111	arr = append(arr, elem)
112	return arr
113}
114func (p *Parser) Parse() (*Circuit, error) {
115	circuit := &Circuit{}
116	circuit.Signals = append(circuit.Signals, "one")
117	for {
118		constraint, err := p.ParseLine()
119		if err != nil {
120			break
121		}
122		if constraint.Literal == "func" {
123			circuit.Inputs = constraint.Inputs
124			continue
125		}
126		circuit.Constraints = append(circuit.Constraints, *constraint)
127		circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1)
128		circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V2)
129		circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.Out)
130	}
131	return circuit, nil
132}