You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
3.8 KiB

  1. package circuitcompiler
  2. import (
  3. "errors"
  4. "io"
  5. "regexp"
  6. "strings"
  7. )
  8. // Parser data structure holds the Scanner and the Parsing functions
  9. type Parser struct {
  10. s *Scanner
  11. buf struct {
  12. tok Token // last read token
  13. lit string // last read literal
  14. n int // buffer size (max=1)
  15. }
  16. }
  17. // NewParser creates a new parser from a io.Reader
  18. func NewParser(r io.Reader) *Parser {
  19. return &Parser{s: NewScanner(r)}
  20. }
  21. func (p *Parser) scan() (tok Token, lit string) {
  22. // if there is a token in the buffer return it
  23. if p.buf.n != 0 {
  24. p.buf.n = 0
  25. return p.buf.tok, p.buf.lit
  26. }
  27. tok, lit = p.s.scan()
  28. p.buf.tok, p.buf.lit = tok, lit
  29. return
  30. }
  31. func (p *Parser) unscan() {
  32. p.buf.n = 1
  33. }
  34. func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) {
  35. tok, lit = p.scan()
  36. if tok == WS {
  37. tok, lit = p.scan()
  38. }
  39. return
  40. }
  41. // parseLine parses the current line
  42. func (p *Parser) parseLine() (*Constraint, error) {
  43. /*
  44. in this version,
  45. line will be for example s3 = s1 * s4
  46. this is:
  47. val eq val op val
  48. */
  49. c := &Constraint{}
  50. tok, lit := p.scanIgnoreWhitespace()
  51. c.Out = lit
  52. c.Literal += lit
  53. if c.Literal == "func" {
  54. // format: `func name(in):`
  55. line, err := p.s.r.ReadString(':')
  56. if err != nil {
  57. return c, err
  58. }
  59. // read string inside ( )
  60. rgx := regexp.MustCompile(`\((.*?)\)`)
  61. insideParenthesis := rgx.FindStringSubmatch(line)
  62. varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
  63. c.Inputs = strings.Split(varsString, ",")
  64. return c, nil
  65. }
  66. _, lit = p.scanIgnoreWhitespace() // skip =
  67. c.Literal += lit
  68. // v1
  69. _, lit = p.scanIgnoreWhitespace()
  70. c.V1 = lit
  71. c.Literal += lit
  72. // operator
  73. _, lit = p.scanIgnoreWhitespace()
  74. c.Op = lit
  75. c.Literal += lit
  76. // v2
  77. _, lit = p.scanIgnoreWhitespace()
  78. c.V2 = lit
  79. c.Literal += lit
  80. if tok == EOF {
  81. return nil, errors.New("eof in parseline")
  82. }
  83. return c, nil
  84. }
  85. func existInArray(arr []string, elem string) bool {
  86. for _, v := range arr {
  87. if v == elem {
  88. return true
  89. }
  90. }
  91. return false
  92. }
  93. func addToArrayIfNotExist(arr []string, elem string) []string {
  94. for _, v := range arr {
  95. if v == elem {
  96. return arr
  97. }
  98. }
  99. arr = append(arr, elem)
  100. return arr
  101. }
  102. // Parse parses the lines and returns the compiled Circuit
  103. func (p *Parser) Parse() (*Circuit, error) {
  104. circuit := &Circuit{}
  105. circuit.Signals = append(circuit.Signals, "one")
  106. nInputs := 0
  107. for {
  108. constraint, err := p.parseLine()
  109. if err != nil {
  110. break
  111. }
  112. if constraint.Literal == "func" {
  113. // one constraint for each input
  114. for _, in := range constraint.Inputs {
  115. newConstr := &Constraint{
  116. Op: "in",
  117. Out: in,
  118. }
  119. circuit.Constraints = append(circuit.Constraints, *newConstr)
  120. nInputs++
  121. }
  122. circuit.Inputs = constraint.Inputs
  123. continue
  124. }
  125. circuit.Constraints = append(circuit.Constraints, *constraint)
  126. isVal, _ := isValue(constraint.V1)
  127. if !isVal {
  128. circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V1)
  129. }
  130. isVal, _ = isValue(constraint.V2)
  131. if !isVal {
  132. circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.V2)
  133. }
  134. if constraint.Out == "out" {
  135. // if Out is "out", put it after the inputs
  136. if !existInArray(circuit.Signals, constraint.Out) {
  137. signalsCopy := copyArray(circuit.Signals)
  138. var auxSignals []string
  139. auxSignals = append(auxSignals, signalsCopy[0:nInputs+1]...)
  140. auxSignals = append(auxSignals, constraint.Out)
  141. auxSignals = append(auxSignals, signalsCopy[nInputs+1:]...)
  142. circuit.Signals = auxSignals
  143. }
  144. } else {
  145. circuit.Signals = addToArrayIfNotExist(circuit.Signals, constraint.Out)
  146. }
  147. }
  148. circuit.NVars = len(circuit.Signals)
  149. circuit.NSignals = len(circuit.Signals)
  150. circuit.NPublic = 0
  151. return circuit, nil
  152. }
  153. func copyArray(in []string) []string { // tmp
  154. var out []string
  155. for _, e := range in {
  156. out = append(out, e)
  157. }
  158. return out
  159. }