github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/equity/compiler/parse.go (about) 1 package compiler 2 3 import ( 4 "bytes" 5 "encoding/hex" 6 "fmt" 7 "strconv" 8 "unicode" 9 ) 10 11 // We have some function naming conventions. 12 // 13 // For terminals: 14 // scanX takes buf and position, returns new position (and maybe a value) 15 // peekX takes *parser, returns bool or string 16 // consumeX takes *parser and maybe a required literal, maybe returns value 17 // also updates the parser position 18 // 19 // For nonterminals: 20 // parseX takes *parser, returns AST node, updates parser position 21 22 type parser struct { 23 buf []byte 24 pos int 25 } 26 27 func (p *parser) errorf(format string, args ...interface{}) { 28 panic(parserErr{buf: p.buf, offset: p.pos, format: format, args: args}) 29 } 30 31 // parse is the main entry point to the parser 32 func parse(buf []byte) (contracts []*Contract, err error) { 33 defer func() { 34 if val := recover(); val != nil { 35 if e, ok := val.(parserErr); ok { 36 err = e 37 } else { 38 panic(val) 39 } 40 } 41 }() 42 p := &parser{buf: buf} 43 contracts = parseContracts(p) 44 return 45 } 46 47 // parse functions 48 49 func parseContracts(p *parser) []*Contract { 50 var result []*Contract 51 if pos := scanKeyword(p.buf, p.pos, "contract"); pos < 0 { 52 p.errorf("expected contract") 53 } 54 55 for peekKeyword(p) == "contract" { 56 contract := parseContract(p) 57 result = append(result, contract) 58 } 59 return result 60 } 61 62 // contract name(p1, p2: t1, p3: t2) locks value { ... } 63 func parseContract(p *parser) *Contract { 64 consumeKeyword(p, "contract") 65 name := consumeIdentifier(p) 66 params := parseParams(p) 67 // locks amount of asset 68 consumeKeyword(p, "locks") 69 value := ValueInfo{} 70 value.Amount = consumeIdentifier(p) 71 consumeKeyword(p, "of") 72 value.Asset = consumeIdentifier(p) 73 consumeTok(p, "{") 74 clauses := parseClauses(p) 75 consumeTok(p, "}") 76 return &Contract{Name: name, Params: params, Clauses: clauses, Value: value} 77 } 78 79 // (p1, p2: t1, p3: t2) 80 func parseParams(p *parser) []*Param { 81 var params []*Param 82 consumeTok(p, "(") 83 first := true 84 for !peekTok(p, ")") { 85 if first { 86 first = false 87 } else { 88 consumeTok(p, ",") 89 } 90 pt := parseParamsType(p) 91 params = append(params, pt...) 92 } 93 consumeTok(p, ")") 94 return params 95 } 96 97 func parseClauses(p *parser) []*Clause { 98 var clauses []*Clause 99 for !peekTok(p, "}") { 100 c := parseClause(p) 101 clauses = append(clauses, c) 102 } 103 return clauses 104 } 105 106 func parseParamsType(p *parser) []*Param { 107 firstName := consumeIdentifier(p) 108 params := []*Param{&Param{Name: firstName}} 109 for peekTok(p, ",") { 110 consumeTok(p, ",") 111 name := consumeIdentifier(p) 112 params = append(params, &Param{Name: name}) 113 } 114 consumeTok(p, ":") 115 typ := consumeIdentifier(p) 116 for _, parm := range params { 117 if tdesc, ok := types[typ]; ok { 118 parm.Type = tdesc 119 } else { 120 p.errorf("unknown type %s", typ) 121 } 122 } 123 return params 124 } 125 126 func parseClause(p *parser) *Clause { 127 var c Clause 128 consumeKeyword(p, "clause") 129 c.Name = consumeIdentifier(p) 130 c.Params = parseParams(p) 131 consumeTok(p, "{") 132 c.statements = parseStatements(p) 133 consumeTok(p, "}") 134 return &c 135 } 136 137 func parseStatements(p *parser) []statement { 138 var statements []statement 139 for !peekTok(p, "}") { 140 s := parseStatement(p) 141 statements = append(statements, s) 142 } 143 return statements 144 } 145 146 func parseStatement(p *parser) statement { 147 switch peekKeyword(p) { 148 case "if": 149 return parseIfStmt(p) 150 case "define": 151 return parseDefineStmt(p) 152 case "assign": 153 return parseAssignStmt(p) 154 case "verify": 155 return parseVerifyStmt(p) 156 case "lock": 157 return parseLockStmt(p) 158 case "unlock": 159 return parseUnlockStmt(p) 160 } 161 panic(parseErr(p.buf, p.pos, "unknown keyword \"%s\"", peekKeyword(p))) 162 } 163 164 func parseIfStmt(p *parser) *ifStatement { 165 consumeKeyword(p, "if") 166 condition := parseExpr(p) 167 body := &IfStatmentBody{} 168 consumeTok(p, "{") 169 body.trueBody = parseStatements(p) 170 consumeTok(p, "}") 171 if peekKeyword(p) == "else" { 172 consumeKeyword(p, "else") 173 consumeTok(p, "{") 174 body.falseBody = parseStatements(p) 175 consumeTok(p, "}") 176 } 177 return &ifStatement{condition: condition, body: body} 178 } 179 180 func parseDefineStmt(p *parser) *defineStatement { 181 defineStat := &defineStatement{} 182 consumeKeyword(p, "define") 183 param := &Param{} 184 param.Name = consumeIdentifier(p) 185 consumeTok(p, ":") 186 variableType := consumeIdentifier(p) 187 if tdesc, ok := types[variableType]; ok { 188 param.Type = tdesc 189 } else { 190 p.errorf("unknown type %s", variableType) 191 } 192 defineStat.variable = param 193 if peekTok(p, "=") { 194 consumeTok(p, "=") 195 defineStat.expr = parseExpr(p) 196 } 197 return defineStat 198 } 199 200 func parseAssignStmt(p *parser) *assignStatement { 201 consumeKeyword(p, "assign") 202 varName := consumeIdentifier(p) 203 consumeTok(p, "=") 204 expr := parseExpr(p) 205 return &assignStatement{variable: &Param{Name: varName}, expr: expr} 206 } 207 208 func parseVerifyStmt(p *parser) *verifyStatement { 209 consumeKeyword(p, "verify") 210 expr := parseExpr(p) 211 return &verifyStatement{expr: expr} 212 } 213 214 func parseLockStmt(p *parser) *lockStatement { 215 consumeKeyword(p, "lock") 216 lockedAmount := parseExpr(p) 217 consumeKeyword(p, "of") 218 lockedAsset := parseExpr(p) 219 consumeKeyword(p, "with") 220 program := parseExpr(p) 221 return &lockStatement{lockedAmount: lockedAmount, lockedAsset: lockedAsset, program: program} 222 } 223 224 func parseUnlockStmt(p *parser) *unlockStatement { 225 consumeKeyword(p, "unlock") 226 unlockedAmount := parseExpr(p) 227 consumeKeyword(p, "of") 228 unlockedAsset := parseExpr(p) 229 return &unlockStatement{unlockedAmount: unlockedAmount, unlockedAsset: unlockedAsset} 230 } 231 232 func parseExpr(p *parser) expression { 233 // Uses the precedence-climbing algorithm 234 // <https://en.wikipedia.org/wiki/Operator-precedence_parser#Precedence_climbing_method> 235 expr := parseUnaryExpr(p) 236 expr2, pos := parseExprCont(p, expr, 0) 237 if pos < 0 { 238 p.errorf("expected expression") 239 } 240 p.pos = pos 241 return expr2 242 } 243 244 func parseUnaryExpr(p *parser) expression { 245 op, pos := scanUnaryOp(p.buf, p.pos) 246 if pos < 0 { 247 return parseExpr2(p) 248 } 249 p.pos = pos 250 expr := parseUnaryExpr(p) 251 return &unaryExpr{op: op, expr: expr} 252 } 253 254 func parseExprCont(p *parser, lhs expression, minPrecedence int) (expression, int) { 255 for { 256 op, pos := scanBinaryOp(p.buf, p.pos) 257 if pos < 0 || op.precedence < minPrecedence { 258 break 259 } 260 p.pos = pos 261 262 rhs := parseUnaryExpr(p) 263 264 for { 265 op2, pos2 := scanBinaryOp(p.buf, p.pos) 266 if pos2 < 0 || op2.precedence <= op.precedence { 267 break 268 } 269 rhs, p.pos = parseExprCont(p, rhs, op2.precedence) 270 if p.pos < 0 { 271 return nil, -1 // or is this an error? 272 } 273 } 274 lhs = &binaryExpr{left: lhs, right: rhs, op: op} 275 } 276 return lhs, p.pos 277 } 278 279 func parseExpr2(p *parser) expression { 280 if expr, pos := scanLiteralExpr(p.buf, p.pos); pos >= 0 { 281 p.pos = pos 282 return expr 283 } 284 return parseExpr3(p) 285 } 286 287 func parseExpr3(p *parser) expression { 288 e := parseExpr4(p) 289 if peekTok(p, "(") { 290 args := parseArgs(p) 291 return &callExpr{fn: e, args: args} 292 } 293 return e 294 } 295 296 func parseExpr4(p *parser) expression { 297 if peekTok(p, "(") { 298 consumeTok(p, "(") 299 e := parseExpr(p) 300 consumeTok(p, ")") 301 return e 302 } 303 if peekTok(p, "[") { 304 var elts []expression 305 consumeTok(p, "[") 306 first := true 307 for !peekTok(p, "]") { 308 if first { 309 first = false 310 } else { 311 consumeTok(p, ",") 312 } 313 e := parseExpr(p) 314 elts = append(elts, e) 315 } 316 consumeTok(p, "]") 317 return listExpr(elts) 318 } 319 name := consumeIdentifier(p) 320 return varRef(name) 321 } 322 323 func parseArgs(p *parser) []expression { 324 var exprs []expression 325 consumeTok(p, "(") 326 first := true 327 for !peekTok(p, ")") { 328 if first { 329 first = false 330 } else { 331 consumeTok(p, ",") 332 } 333 e := parseExpr(p) 334 exprs = append(exprs, e) 335 } 336 consumeTok(p, ")") 337 return exprs 338 } 339 340 // peek functions 341 342 func peekKeyword(p *parser) string { 343 name, _ := scanIdentifier(p.buf, p.pos) 344 return name 345 } 346 347 func peekTok(p *parser, token string) bool { 348 pos := scanTok(p.buf, p.pos, token) 349 return pos >= 0 350 } 351 352 // consume functions 353 354 var keywords = []string{ 355 "contract", "clause", "verify", "locks", "of", 356 "lock", "with", "unlock", "if", "else", 357 "define", "assign", "true", "false", 358 } 359 360 func consumeKeyword(p *parser, keyword string) { 361 pos := scanKeyword(p.buf, p.pos, keyword) 362 if pos < 0 { 363 p.errorf("expected keyword %s", keyword) 364 } 365 p.pos = pos 366 } 367 368 func consumeIdentifier(p *parser) string { 369 name, pos := scanIdentifier(p.buf, p.pos) 370 if pos < 0 { 371 p.errorf("expected identifier") 372 } 373 p.pos = pos 374 return name 375 } 376 377 func consumeTok(p *parser, token string) { 378 pos := scanTok(p.buf, p.pos, token) 379 if pos < 0 { 380 p.errorf("expected %s token", token) 381 } 382 p.pos = pos 383 } 384 385 // scan functions 386 387 func scanUnaryOp(buf []byte, offset int) (*unaryOp, int) { 388 // Maximum munch. Make sure "-3" scans as ("-3"), not ("-", "3"). 389 if _, pos := scanIntLiteral(buf, offset); pos >= 0 { 390 return nil, -1 391 } 392 for _, op := range unaryOps { 393 newOffset := scanTok(buf, offset, op.op) 394 if newOffset >= 0 { 395 return &op, newOffset 396 } 397 } 398 return nil, -1 399 } 400 401 func scanBinaryOp(buf []byte, offset int) (*binaryOp, int) { 402 offset = skipWsAndComments(buf, offset) 403 var ( 404 found *binaryOp 405 newOffset = -1 406 ) 407 for i, op := range binaryOps { 408 offset2 := scanTok(buf, offset, op.op) 409 if offset2 >= 0 { 410 if found == nil || len(op.op) > len(found.op) { 411 found = &binaryOps[i] 412 newOffset = offset2 413 } 414 } 415 } 416 return found, newOffset 417 } 418 419 // TODO(bobg): boolean literals? 420 func scanLiteralExpr(buf []byte, offset int) (expression, int) { 421 offset = skipWsAndComments(buf, offset) 422 intliteral, newOffset := scanIntLiteral(buf, offset) 423 if newOffset >= 0 { 424 return intliteral, newOffset 425 } 426 strliteral, newOffset := scanStrLiteral(buf, offset) 427 if newOffset >= 0 { 428 return strliteral, newOffset 429 } 430 bytesliteral, newOffset := scanBytesLiteral(buf, offset) // 0x6c249a... 431 if newOffset >= 0 { 432 return bytesliteral, newOffset 433 } 434 booleanLiteral, newOffset := scanBoolLiteral(buf, offset) // true or false 435 if newOffset >= 0 { 436 return booleanLiteral, newOffset 437 } 438 return nil, -1 439 } 440 441 func scanIdentifier(buf []byte, offset int) (string, int) { 442 offset = skipWsAndComments(buf, offset) 443 i := offset 444 for ; i < len(buf) && isIDChar(buf[i], i == offset); i++ { 445 } 446 if i == offset { 447 return "", -1 448 } 449 return string(buf[offset:i]), i 450 } 451 452 func scanTok(buf []byte, offset int, s string) int { 453 offset = skipWsAndComments(buf, offset) 454 prefix := []byte(s) 455 if bytes.HasPrefix(buf[offset:], prefix) { 456 return offset + len(prefix) 457 } 458 return -1 459 } 460 461 func scanKeyword(buf []byte, offset int, keyword string) int { 462 id, newOffset := scanIdentifier(buf, offset) 463 if newOffset < 0 { 464 return -1 465 } 466 if id != keyword { 467 return -1 468 } 469 return newOffset 470 } 471 472 func scanIntLiteral(buf []byte, offset int) (integerLiteral, int) { 473 offset = skipWsAndComments(buf, offset) 474 start := offset 475 if offset < len(buf) && buf[offset] == '-' { 476 offset++ 477 } 478 i := offset 479 for ; i < len(buf) && unicode.IsDigit(rune(buf[i])); i++ { 480 // the literal is BytesLiteral when it starts with 0x/0X 481 if buf[i] == '0' && i < len(buf)-1 && (buf[i+1] == 'x' || buf[i+1] == 'X') { 482 return 0, -1 483 } 484 } 485 if i > offset { 486 n, err := strconv.ParseInt(string(buf[start:i]), 10, 64) 487 if err != nil { 488 return 0, -1 489 } 490 return integerLiteral(n), i 491 } 492 return 0, -1 493 } 494 495 func scanStrLiteral(buf []byte, offset int) (bytesLiteral, int) { 496 offset = skipWsAndComments(buf, offset) 497 if offset >= len(buf) || buf[offset] != '\'' { 498 return bytesLiteral{}, -1 499 } 500 var byteBuf bytesLiteral 501 for i := offset + 1; i < len(buf); i++ { 502 if buf[i] == '\'' { 503 return byteBuf, i + 1 504 } 505 if buf[i] == '\\' && i < len(buf)-1 { 506 if c, ok := scanEscape(buf[i+1]); ok { 507 byteBuf = append(byteBuf, c) 508 i++ 509 continue 510 } 511 } 512 byteBuf = append(byteBuf, buf[i]) 513 } 514 panic(parseErr(buf, offset, "unterminated string literal")) 515 } 516 517 func scanBytesLiteral(buf []byte, offset int) (bytesLiteral, int) { 518 offset = skipWsAndComments(buf, offset) 519 if offset+4 >= len(buf) { 520 return nil, -1 521 } 522 if buf[offset] != '0' || (buf[offset+1] != 'x' && buf[offset+1] != 'X') { 523 return nil, -1 524 } 525 if !isHexDigit(buf[offset+2]) || !isHexDigit(buf[offset+3]) { 526 return nil, -1 527 } 528 i := offset + 4 529 for ; i < len(buf); i += 2 { 530 if i == len(buf)-1 { 531 panic(parseErr(buf, offset, "odd number of digits in hex literal")) 532 } 533 if !isHexDigit(buf[i]) { 534 break 535 } 536 if !isHexDigit(buf[i+1]) { 537 panic(parseErr(buf, offset, "odd number of digits in hex literal")) 538 } 539 } 540 decoded := make([]byte, hex.DecodedLen(i-(offset+2))) 541 _, err := hex.Decode(decoded, buf[offset+2:i]) 542 if err != nil { 543 return bytesLiteral{}, -1 544 } 545 return bytesLiteral(decoded), i 546 } 547 548 func scanBoolLiteral(buf []byte, offset int) (booleanLiteral, int) { 549 offset = skipWsAndComments(buf, offset) 550 if offset >= len(buf) { 551 return false, -1 552 } 553 554 newOffset := scanKeyword(buf, offset, "true") 555 if newOffset < 0 { 556 if newOffset = scanKeyword(buf, offset, "false"); newOffset < 0 { 557 return false, -1 558 } 559 return false, newOffset 560 } 561 return true, newOffset 562 } 563 564 func skipWsAndComments(buf []byte, offset int) int { 565 var inComment bool 566 for ; offset < len(buf); offset++ { 567 c := buf[offset] 568 if inComment { 569 if c == '\n' { 570 inComment = false 571 } 572 } else { 573 if c == '/' && offset < len(buf)-1 && buf[offset+1] == '/' { 574 inComment = true 575 offset++ // skip two chars instead of one 576 } else if !unicode.IsSpace(rune(c)) { 577 break 578 } 579 } 580 } 581 return offset 582 } 583 584 func isHexDigit(b byte) bool { 585 return (b >= '0' && b <= '9') || (b >= 'a' && b <= 'f') || (b >= 'A' && b <= 'F') 586 } 587 588 func isIDChar(c byte, initial bool) bool { 589 if c >= 'a' && c <= 'z' { 590 return true 591 } 592 if c >= 'A' && c <= 'Z' { 593 return true 594 } 595 if c == '_' { 596 return true 597 } 598 if initial { 599 return false 600 } 601 return unicode.IsDigit(rune(c)) 602 } 603 604 type parserErr struct { 605 buf []byte 606 offset int 607 format string 608 args []interface{} 609 } 610 611 func parseErr(buf []byte, offset int, format string, args ...interface{}) error { 612 return parserErr{buf: buf, offset: offset, format: format, args: args} 613 } 614 615 func (p parserErr) Error() string { 616 // Lines start at 1, columns start at 0, like nature intended. 617 line := 1 618 col := 0 619 for i := 0; i < p.offset; i++ { 620 if p.buf[i] == '\n' { 621 line++ 622 col = 0 623 } else { 624 col++ 625 } 626 } 627 args := []interface{}{line, col} 628 args = append(args, p.args...) 629 return fmt.Sprintf("line %d, col %d: "+p.format, args...) 630 } 631 632 func scanEscape(c byte) (byte, bool) { 633 escapeFlag := true 634 switch c { 635 case '\'', '"', '\\': 636 case 'b': 637 c = '\b' 638 case 'f': 639 c = '\f' 640 case 'n': 641 c = '\n' 642 case 'r': 643 c = '\r' 644 case 't': 645 c = '\t' 646 case 'v': 647 c = '\v' 648 default: 649 escapeFlag = false 650 } 651 return c, escapeFlag 652 }