╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ gen_parser_oracle.zig ────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
545 // IdentCont <- IdentStart / [0-9] 546 fn parseIdentifier(p: *Parser) !?Node.Index { 547 const start = p.i; 548 switch (p.next() orelse return null) { 549 'a'...'z', 'A'...'Z', '_' => {}, 550 else => return null, 551 } 552 while (p.peek()) |cont| { 553 switch (cont) { 554 'a'...'z', 'A'...'Z', '_', '0'...'9' => p.i += 1, 555 else => break, 556 } 557 } 558 const id = p.source[start..p.i]; 559 _ = p.eatSpacing(); 560 return try p.addNode(.{ .id = id }); 561 } 562 563 // Literal <- ['] < ( !['] Char )* > ['] Spacing 564 // / ["] < ( !["] Char )* > ["] Spacing 565 fn parseLiteral(p: *Parser) !?Node.Index { 566 const quote: u8 = if (p.eat('\'')) '\'' else if (p.eat('"')) '"' else return null; 567 const off = p.strings.items.len; 568 while (!p.eat(quote)) { 569 const byte = p.parseChar() orelse return null; 570 try p.strings.append(p.gpa, byte); 571 } 572 _ = p.eatSpacing(); 573 return try p.addNode(.{ .literal = .{ 574 .off = @intCast(off), 575 .len = @intCast(p.strings.items.len - off), 576 } }); 577 } 578 579 // Class <- '[' < ( !']' Range )* > ']' Spacing 580 fn parseClass(p: *Parser) !?Node.Index { 581 var scratch: std.ArrayList(Node.Index) = .empty; 582 defer scratch.deinit(p.gpa); 583 if (!p.eat('[')) return null; 584 while (!p.eat(']')) { 585 const range = try p.parseRange() orelse return null; 586 try scratch.append(p.gpa, range); 587 } 588 _ = p.eatSpacing(); 589 const ranges = try p.addExtra(scratch.items); 590 return try p.addNode(.{ .class = ranges }); 591 } 592 593 // Range <- Char '-' Char / Char 594 fn parseRange(p: *Parser) !?Node.Index { 595 const start = p.parseChar() orelse return null; 596 const end = blk: { 597 if (p.eat('-')) { 598 break :blk p.parseChar() orelse return null; 599 } 600 break :blk start; 601 }; 602 return try p.addNode(.{ .range = .{ 603 .start = start, 604 .end = end, 605 } }); 606 } 607 608 // Char <- '\\' [abefnrtv'"\[\]\\] 609 // / '\\' [0-3][0-7][0-7] 610 // / '\\' [0-7][0-7]? 611 // / '\\' '-' 612 // / !'\\' . 613 fn parseChar(p: *Parser) ?u8 { 614 if (p.eat('\\')) { 615 const c = p.next() orelse return null; 616 return switch (c) { 617 // Only the escape sequences actually used in the Zig grammar are implemented 618 'n' => '\n', 619 'r' => '\r', 620 't' => '\t', 621 '\'' => '\'', 622 '"' => '"', 623 '[' => '[', 624 ']' => ']', 625 '\\' => '\\', 626 '-' => '-', 627 '0'...'7' => { 628 // octal 629 if (c <= '3') { 630 const c2 = p.next() orelse return null; 631 if (c2 < '0' or c2 > '7') return null; 632 const c3 = p.next() orelse return null; 633 if (c3 < '0' or c3 > '7') return null; 634 return (c - '0') * 8 * 8 + (c2 - '0') * 8 + (c3 - '0'); 635 } else { 636 if (p.peek()) |c2| { 637 if (c2 >= '0' and c2 <= '7') { 638 p.i += 1; 639 return (c - '0') * 8 + (c2 - '0'); 640 } 641 } 642 return (c - '0'); 643 } 644 }, 645 else => null, 646 }; 647 } else { 648 return p.next(); 649 } 650 } 651 652 // LEFTARROW <- '<-' Spacing 653 fn eatLeftArrow(p: *Parser) bool { 654 return p.eat('<') and p.eat('-') and p.eatSpacing(); 655 } 656 657 // SLASH <- '/' Spacing 658 fn eatSlash(p: *Parser) bool { 659 return p.eat('/') and p.eatSpacing(); 660 } 661 662 // AND <- '&' Spacing 663 fn eatAnd(p: *Parser) bool { 664 return p.eat('&') and p.eatSpacing(); 665 } 666 667 // NOT <- '!' Spacing 668 fn eatNot(p: *Parser) bool { 669 return p.eat('!') and p.eatSpacing(); 670 } 671 672 // QUERY <- '?' Spacing 673 fn eatQuery(p: *Parser) bool { 674 return p.eat('?') and p.eatSpacing(); 675 } 676 677 // STAR <- '*' Spacing 678 fn eatStar(p: *Parser) bool { 679 return p.eat('*') and p.eatSpacing(); 680 } 681 682 // PLUS <- '+' Spacing 683 fn eatPlus(p: *Parser) bool { 684 return p.eat('+') and p.eatSpacing(); 685 } 686 687 // OPEN <- '(' Spacing 688 fn eatOpen(p: *Parser) bool { 689 return p.eat('(') and p.eatSpacing(); 690 } 691 692 // CLOSE <- ')' Spacing 693 fn eatClose(p: *Parser) bool { 694 return p.eat(')') and p.eatSpacing(); 695 } 696 697 // DOT <- '.' Spacing 698 fn eatDot(p: *Parser) bool { 699 return p.eat('.') and p.eatSpacing(); 700 } 701 702 // Spacing <- ( Space / Comment )* 703 fn eatSpacing(p: *Parser) bool { 704 while (p.eatSpace() or p.eatComment()) {} 705 return true; 706 } 707 708 // Comment <- '#' ( !EndOfLine . )* EndOfLine 709 fn eatComment(p: *Parser) bool { 710 if (!p.eat('#')) return false; 711 while (!p.eatEndOfLine()) p.i += 1; 712 return true; 713 } 714 715 // Space <- ' ' / '\t' / EndOfLine 716 fn eatSpace(p: *Parser) bool { 717 return p.eat(' ') or p.eat('\t') or p.eatEndOfLine(); 718 } 719 720 // EndOfLine <- '\r\n' / '\n' / '\r' 721 fn eatEndOfLine(p: *Parser) bool { 722 return p.eat('\r') | p.eat('\n'); 723 } 724 725 fn peek(p: *Parser) ?u8 { 726 if (p.i < p.source.len) { 727 return p.source[p.i]; 728 } 729 return null; 730 } 731 732 fn next(p: *Parser) ?u8 { 733 if (p.i < p.source.len) { 734 defer p.i += 1; 735 return p.source[p.i]; 736 } 737 return null; 738 } 739 740 fn eat(p: *Parser, byte: u8) bool { 741 if (p.i < p.source.len and p.source[p.i] == byte) { 742 p.i += 1; 743 return true; 744 } 745 return false; 746 } 747 748 fn addNode(p: *Parser, node: Node) !Node.Index { 749 try p.nodes.append(p.gpa, node); 750 return @fromBackingInt(@intCast(p.nodes.items.len - 1)); 751 } 752 753 fn addExtra(p: *Parser, nodes: []const Node.Index) !Node.Slice { 754 const off = p.extra.items.len; 755 try p.extra.appendSlice(p.gpa, nodes); 756 return .{ .off = @intCast(off), .len = @intCast(p.extra.items.len - off) }; 757 } 758 759 const Pos = struct { 760 i: u32, 761 nodes_len: u32, 762 extra_len: u32, 763 strings_len: u32, 764 }; 765 766 fn savePos(p: *const Parser) Pos { 767 return .{ 768 .i = p.i, 769 .nodes_len = @intCast(p.nodes.items.len), 770 .extra_len = @intCast(p.extra.items.len), 771 .strings_len = @intCast(p.strings.items.len), 772 }; 773 } 774 775 fn restorePos(p: *Parser, pos: Pos) void { 776 assert(p.i >= pos.i); 777 p.i = pos.i; 778 p.nodes.shrinkRetainingCapacity(pos.nodes_len); 779 p.extra.shrinkRetainingCapacity(pos.extra_len); 780 p.strings.shrinkRetainingCapacity(pos.strings_len); 781 } 782 783 fn getExtra(p: *const Parser, s: Node.Slice) []const Node.Index { 784 return p.extra.items[s.off..][0..s.len]; 785 } 786 }; 787