arnaucube
arnaucube/go-snarkPublic Self-hosted repository
go-snark/circuitcompiler/parser.go
circuitcompiler/parser.goRaw
 1package circuitcompiler
 2
 3import (
 4	"errors"
 5	"io"
 6)
 7
 8type Parser struct {
 9	s   *Scanner
10	buf struct {
11		tok Token  // last read token
12		lit string // last read literal
13		n   int    // buffer size (max=1)
14	}
15}
16
17type Constraint struct {
18	// v1 op v2 = out
19	Op      Token
20	V1      Token
21	V2      Token
22	Out     Token
23	Literal string
24}
25
26func NewParser(r io.Reader) *Parser {
27	return &Parser{s: NewScanner(r)}
28}
29
30func (p *Parser) scan() (tok Token, lit string) {
31	// if there is a token in the buffer return it
32	if p.buf.n != 0 {
33		p.buf.n = 0
34		return p.buf.tok, p.buf.lit
35	}
36	tok, lit = p.s.Scan()
37
38	p.buf.tok, p.buf.lit = tok, lit
39
40	return
41}
42
43func (p *Parser) unscan() {
44	p.buf.n = 1
45}
46
47func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) {
48	tok, lit = p.scan()
49	if tok == WS {
50		tok, lit = p.scan()
51	}
52	return
53}
54
55func (p *Parser) ParseLine() (*Constraint, error) {
56	/*
57		in this version,
58		line will be for example s3 = s1 * s4
59		this is:
60		val op val op val
61		ident op ident op ident
62	*/
63	c := &Constraint{}
64	var lit string
65	c.Out, lit = p.scanIgnoreWhitespace()
66	c.Literal += lit
67	_, lit = p.scanIgnoreWhitespace() // skip =
68	c.Literal += lit
69	c.V1, lit = p.scanIgnoreWhitespace()
70	c.Literal += lit
71	c.Op, lit = p.scanIgnoreWhitespace()
72	c.Literal += lit
73	c.V2, lit = p.scanIgnoreWhitespace()
74	c.Literal += lit
75	if c.Out == EOF {
76		return nil, errors.New("eof in parseline")
77	}
78	return c, nil
79}
80
81func (p *Parser) Parse() (*Circuit, error) {
82	circuit := &Circuit{}
83	for {
84		constraint, err := p.ParseLine()
85		if err != nil {
86			// return circuit, err
87			break
88		}
89		circuit.Constraints = append(circuit.Constraints, *constraint)
90	}
91	return circuit, nil
92}