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}