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.

354 lines
9.7 KiB

  1. package circuitcompiler
  2. import (
  3. "bufio"
  4. "errors"
  5. "fmt"
  6. "io"
  7. "os"
  8. "regexp"
  9. "strconv"
  10. "strings"
  11. )
  12. // Parser data structure holds the Scanner and the Parsing functions
  13. type Parser struct {
  14. s *Scanner
  15. buf struct {
  16. tok Token // last read token
  17. lit string // last read literal
  18. n int // buffer size (max=1)
  19. }
  20. }
  21. // NewParser creates a new parser from a io.Reader
  22. func NewParser(r io.Reader) *Parser {
  23. return &Parser{s: NewScanner(r)}
  24. }
  25. func (p *Parser) scan() (tok Token, lit string) {
  26. // if there is a token in the buffer return it
  27. if p.buf.n != 0 {
  28. p.buf.n = 0
  29. return p.buf.tok, p.buf.lit
  30. }
  31. tok, lit = p.s.scan()
  32. p.buf.tok, p.buf.lit = tok, lit
  33. return
  34. }
  35. func (p *Parser) unscan() {
  36. p.buf.n = 1
  37. }
  38. func (p *Parser) scanIgnoreWhitespace() (tok Token, lit string) {
  39. tok, lit = p.scan()
  40. if tok == WS {
  41. tok, lit = p.scan()
  42. }
  43. return
  44. }
  45. // parseLine parses the current line
  46. func (p *Parser) parseLine() (*Constraint, error) {
  47. /*
  48. in this version,
  49. line will be for example s3 = s1 * s4
  50. this is:
  51. val eq val op val
  52. */
  53. c := &Constraint{}
  54. tok, lit := p.scanIgnoreWhitespace()
  55. c.Out = lit
  56. c.Literal += lit
  57. if c.Literal == "func" {
  58. // format: `func name(in):`
  59. line, err := p.s.r.ReadString(':')
  60. if err != nil {
  61. return c, err
  62. }
  63. // get func name
  64. fName := strings.Split(line, "(")[0]
  65. fName = strings.Replace(fName, " ", "", -1)
  66. fName = strings.Replace(fName, " ", "", -1)
  67. c.V1 = fName // so, the name of the func will be in c.V1
  68. // read string inside ( )
  69. rgx := regexp.MustCompile(`\((.*?)\)`)
  70. insideParenthesis := rgx.FindStringSubmatch(line)
  71. varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
  72. allInputs := strings.Split(varsString, ",")
  73. // from allInputs, get the private and the public separated
  74. for _, in := range allInputs {
  75. if strings.Contains(in, "private") {
  76. input := strings.Replace(in, "private", "", -1)
  77. c.PrivateInputs = append(c.PrivateInputs, input)
  78. } else if strings.Contains(in, "public") {
  79. input := strings.Replace(in, "public", "", -1)
  80. c.PublicInputs = append(c.PublicInputs, input)
  81. } else {
  82. // TODO give more info about the circuit code error
  83. fmt.Println("error on declaration of public and private inputs")
  84. os.Exit(0)
  85. }
  86. }
  87. return c, nil
  88. }
  89. if c.Literal == "equals" {
  90. // format: `equals(a, b)`
  91. line, err := p.s.r.ReadString(')')
  92. if err != nil {
  93. return c, err
  94. }
  95. // read string inside ( )
  96. rgx := regexp.MustCompile(`\((.*?)\)`)
  97. insideParenthesis := rgx.FindStringSubmatch(line)
  98. varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
  99. params := strings.Split(varsString, ",")
  100. c.V1 = params[0]
  101. c.V2 = params[1]
  102. return c, nil
  103. }
  104. if c.Literal == "return" {
  105. _, varToReturn := p.scanIgnoreWhitespace()
  106. c.Out = varToReturn
  107. return c, nil
  108. }
  109. if c.Literal == "import" {
  110. line, err := p.s.r.ReadString('\n')
  111. if err != nil {
  112. return c, err
  113. }
  114. // read string inside " "
  115. path := strings.TrimLeft(strings.TrimRight(line, `"`), `"`)
  116. path = strings.Replace(path, `"`, "", -1)
  117. path = strings.Replace(path, " ", "", -1)
  118. path = strings.Replace(path, "\n", "", -1)
  119. c.Out = path
  120. return c, nil
  121. }
  122. _, lit = p.scanIgnoreWhitespace() // skip =
  123. c.Literal += lit
  124. // v1
  125. _, lit = p.scanIgnoreWhitespace()
  126. // check if lit is a name of a func that we have declared
  127. if _, ok := circuits[lit]; ok {
  128. // if inside, is calling a declared function
  129. c.Literal = "call"
  130. c.Op = lit // c.Op handles the name of the function called
  131. // put the inputs of the call into the c.PrivateInputs
  132. // format: `funcname(a, b)`
  133. line, err := p.s.r.ReadString(')')
  134. if err != nil {
  135. fmt.Println("ERR", err)
  136. return c, err
  137. }
  138. // read string inside ( )
  139. rgx := regexp.MustCompile(`\((.*?)\)`)
  140. insideParenthesis := rgx.FindStringSubmatch(line)
  141. varsString := strings.Replace(insideParenthesis[1], " ", "", -1)
  142. params := strings.Split(varsString, ",")
  143. c.PrivateInputs = params
  144. return c, nil
  145. }
  146. c.V1 = lit
  147. c.Literal += lit
  148. // operator
  149. _, lit = p.scanIgnoreWhitespace()
  150. if lit == "(" {
  151. panic(errors.New("using not declared function"))
  152. }
  153. c.Op = lit
  154. c.Literal += lit
  155. // v2
  156. _, lit = p.scanIgnoreWhitespace()
  157. c.V2 = lit
  158. c.Literal += lit
  159. if tok == EOF {
  160. return nil, errors.New("eof in parseline")
  161. }
  162. return c, nil
  163. }
  164. func existInArray(arr []string, elem string) bool {
  165. for _, v := range arr {
  166. if v == elem {
  167. return true
  168. }
  169. }
  170. return false
  171. }
  172. func addToArrayIfNotExist(arr []string, elem string) []string {
  173. for _, v := range arr {
  174. if v == elem {
  175. return arr
  176. }
  177. }
  178. arr = append(arr, elem)
  179. return arr
  180. }
  181. func subsIfInMap(original string, m map[string]string) string {
  182. if v, ok := m[original]; ok {
  183. return v
  184. }
  185. return original
  186. }
  187. var circuits map[string]*Circuit
  188. // Parse parses the lines and returns the compiled Circuit
  189. func (p *Parser) Parse() (*Circuit, error) {
  190. // funcsMap is a map holding the functions names and it's content as Circuit
  191. circuits = make(map[string]*Circuit)
  192. mainExist := false
  193. circuits["main"] = &Circuit{}
  194. callsCount := 0
  195. circuits["main"].Signals = append(circuits["main"].Signals, "one")
  196. nInputs := 0
  197. currCircuit := ""
  198. for {
  199. constraint, err := p.parseLine()
  200. if err != nil {
  201. break
  202. }
  203. if constraint.Literal == "func" {
  204. // the name of the func is in constraint.V1
  205. // check if the name of func is main
  206. if constraint.V1 != "main" {
  207. currCircuit = constraint.V1
  208. circuits[currCircuit] = &Circuit{}
  209. circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *constraint)
  210. continue
  211. }
  212. currCircuit = "main"
  213. mainExist = true
  214. // l, _ := json.Marshal(constraint)
  215. // fmt.Println(string(l))
  216. // one constraint for each input
  217. for _, in := range constraint.PublicInputs {
  218. newConstr := &Constraint{
  219. Op: "in",
  220. Out: in,
  221. }
  222. circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *newConstr)
  223. nInputs++
  224. circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, in)
  225. circuits[currCircuit].NPublic++
  226. }
  227. for _, in := range constraint.PrivateInputs {
  228. newConstr := &Constraint{
  229. Op: "in",
  230. Out: in,
  231. }
  232. circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *newConstr)
  233. nInputs++
  234. circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, in)
  235. }
  236. circuits[currCircuit].PublicInputs = constraint.PublicInputs
  237. circuits[currCircuit].PrivateInputs = constraint.PrivateInputs
  238. continue
  239. }
  240. if constraint.Literal == "equals" {
  241. constr1 := &Constraint{
  242. Op: "*",
  243. V1: constraint.V2,
  244. V2: "1",
  245. Out: constraint.V1,
  246. Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V1 + "==" + constraint.V2 + " * 1",
  247. }
  248. circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *constr1)
  249. constr2 := &Constraint{
  250. Op: "*",
  251. V1: constraint.V1,
  252. V2: "1",
  253. Out: constraint.V2,
  254. Literal: "equals(" + constraint.V1 + ", " + constraint.V2 + "): " + constraint.V2 + "==" + constraint.V1 + " * 1",
  255. }
  256. circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *constr2)
  257. continue
  258. }
  259. if constraint.Literal == "return" {
  260. currCircuit = ""
  261. continue
  262. }
  263. if constraint.Literal == "call" {
  264. callsCountStr := strconv.Itoa(callsCount)
  265. // for each of the constraints of the called circuit
  266. // add it into the current circuit
  267. signalMap := make(map[string]string)
  268. for i, s := range constraint.PrivateInputs {
  269. // signalMap[s] = circuits[constraint.Op].Constraints[0].PrivateInputs[i]
  270. signalMap[circuits[constraint.Op].Constraints[0].PrivateInputs[i]+callsCountStr] = s
  271. }
  272. // add out to map
  273. signalMap[circuits[constraint.Op].Constraints[len(circuits[constraint.Op].Constraints)-1].Out+callsCountStr] = constraint.Out
  274. for i := 1; i < len(circuits[constraint.Op].Constraints); i++ {
  275. c := circuits[constraint.Op].Constraints[i]
  276. // add constraint, puting unique names to vars
  277. nc := &Constraint{
  278. Op: c.Op,
  279. V1: subsIfInMap(c.V1+callsCountStr, signalMap),
  280. V2: subsIfInMap(c.V2+callsCountStr, signalMap),
  281. Out: subsIfInMap(c.Out+callsCountStr, signalMap),
  282. Literal: "",
  283. }
  284. nc.Literal = nc.Out + "=" + nc.V1 + nc.Op + nc.V2
  285. circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *nc)
  286. }
  287. for _, s := range circuits[constraint.Op].Signals {
  288. circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, subsIfInMap(s+callsCountStr, signalMap))
  289. }
  290. callsCount++
  291. continue
  292. }
  293. if constraint.Literal == "import" {
  294. circuitFile, err := os.Open(constraint.Out)
  295. if err != nil {
  296. panic(errors.New("imported path error: " + constraint.Out))
  297. }
  298. parser := NewParser(bufio.NewReader(circuitFile))
  299. _, err = parser.Parse() // this will add the imported file funcs into the `circuits` map
  300. continue
  301. }
  302. circuits[currCircuit].Constraints = append(circuits[currCircuit].Constraints, *constraint)
  303. isVal, _ := isValue(constraint.V1)
  304. if !isVal {
  305. circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, constraint.V1)
  306. }
  307. isVal, _ = isValue(constraint.V2)
  308. if !isVal {
  309. circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, constraint.V2)
  310. }
  311. circuits[currCircuit].Signals = addToArrayIfNotExist(circuits[currCircuit].Signals, constraint.Out)
  312. }
  313. circuits["main"].NVars = len(circuits["main"].Signals)
  314. circuits["main"].NSignals = len(circuits["main"].Signals)
  315. if mainExist == false {
  316. return circuits["main"], errors.New("No 'main' func declared")
  317. }
  318. return circuits["main"], nil
  319. }
  320. func copyArray(in []string) []string { // tmp
  321. var out []string
  322. for _, e := range in {
  323. out = append(out, e)
  324. }
  325. return out
  326. }