| 17 | } |
| 18 | |
| 19 | func (*CodeBlockParser) Match(tokens []*tokenizer.Token) (int, bool) { |
| 20 | if len(tokens) < 9 { |
| 21 | return 0, false |
| 22 | } |
| 23 | |
| 24 | if tokens[0].Type != tokenizer.Backtick || tokens[1].Type != tokenizer.Backtick || tokens[2].Type != tokenizer.Backtick { |
| 25 | return 0, false |
| 26 | } |
| 27 | if tokens[3].Type != tokenizer.Newline && tokens[4].Type != tokenizer.Newline { |
| 28 | return 0, false |
| 29 | } |
| 30 | cursor := 4 |
| 31 | if tokens[3].Type != tokenizer.Newline { |
| 32 | cursor = 5 |
| 33 | } |
| 34 | |
| 35 | matched := false |
| 36 | for ; cursor < len(tokens)-3; cursor++ { |
| 37 | if tokens[cursor].Type == tokenizer.Newline && tokens[cursor+1].Type == tokenizer.Backtick && tokens[cursor+2].Type == tokenizer.Backtick && tokens[cursor+3].Type == tokenizer.Backtick { |
| 38 | if cursor+3 == len(tokens)-1 { |
| 39 | cursor += 4 |
| 40 | matched = true |
| 41 | break |
| 42 | } else if tokens[cursor+4].Type == tokenizer.Newline { |
| 43 | cursor += 5 |
| 44 | matched = true |
| 45 | break |
| 46 | } |
| 47 | } |
| 48 | } |
| 49 | if !matched { |
| 50 | return 0, false |
| 51 | } |
| 52 | |
| 53 | return cursor, true |
| 54 | } |
| 55 | |
| 56 | func (p *CodeBlockParser) Parse(tokens []*tokenizer.Token) (ast.Node, error) { |
| 57 | size, ok := p.Match(tokens) |