1
2 package parser
3
4 import (
5 "fmt"
6 "strings"
7 "sync"
8
9 "github.com/yuin/goldmark/ast"
10 "github.com/yuin/goldmark/text"
11 "github.com/yuin/goldmark/util"
12 )
13
14
15 type Reference interface {
16
17 String() string
18
19
20 Label() []byte
21
22
23 Destination() []byte
24
25
26 Title() []byte
27 }
28
29 type reference struct {
30 label []byte
31 destination []byte
32 title []byte
33 }
34
35
36 func NewReference(label, destination, title []byte) Reference {
37 return &reference{label, destination, title}
38 }
39
40 func (r *reference) Label() []byte {
41 return r.label
42 }
43
44 func (r *reference) Destination() []byte {
45 return r.destination
46 }
47
48 func (r *reference) Title() []byte {
49 return r.title
50 }
51
52 func (r *reference) String() string {
53 return fmt.Sprintf("Reference{Label:%s, Destination:%s, Title:%s}", r.label, r.destination, r.title)
54 }
55
56
57 type IDs interface {
58
59 Generate(value []byte, kind ast.NodeKind) []byte
60
61
62 Put(value []byte)
63 }
64
65 type ids struct {
66 values map[string]bool
67 }
68
69 func newIDs() IDs {
70 return &ids{
71 values: map[string]bool{},
72 }
73 }
74
75 func (s *ids) Generate(value []byte, kind ast.NodeKind) []byte {
76 value = util.TrimLeftSpace(value)
77 value = util.TrimRightSpace(value)
78 result := []byte{}
79 for i := 0; i < len(value); {
80 v := value[i]
81 l := util.UTF8Len(v)
82 i += int(l)
83 if l != 1 {
84 continue
85 }
86 if util.IsAlphaNumeric(v) {
87 if 'A' <= v && v <= 'Z' {
88 v += 'a' - 'A'
89 }
90 result = append(result, v)
91 } else if util.IsSpace(v) || v == '-' || v == '_' {
92 result = append(result, '-')
93 }
94 }
95 if len(result) == 0 {
96 if kind == ast.KindHeading {
97 result = []byte("heading")
98 } else {
99 result = []byte("id")
100 }
101 }
102 if _, ok := s.values[util.BytesToReadOnlyString(result)]; !ok {
103 s.values[util.BytesToReadOnlyString(result)] = true
104 return result
105 }
106 for i := 1; ; i++ {
107 newResult := fmt.Sprintf("%s-%d", result, i)
108 if _, ok := s.values[newResult]; !ok {
109 s.values[newResult] = true
110 return []byte(newResult)
111 }
112
113 }
114 }
115
116 func (s *ids) Put(value []byte) {
117 s.values[util.BytesToReadOnlyString(value)] = true
118 }
119
120
121 type ContextKey int
122
123
124 var ContextKeyMax ContextKey
125
126
127 func NewContextKey() ContextKey {
128 ContextKeyMax++
129 return ContextKeyMax
130 }
131
132
133
134 type Context interface {
135
136 String() string
137
138
139 Get(ContextKey) interface{}
140
141
142 ComputeIfAbsent(ContextKey, func() interface{}) interface{}
143
144
145 Set(ContextKey, interface{})
146
147
148 AddReference(Reference)
149
150
151
152 Reference(label string) (Reference, bool)
153
154
155 References() []Reference
156
157
158 IDs() IDs
159
160
161
162
163 BlockOffset() int
164
165
166
167 SetBlockOffset(int)
168
169
170
171
172 BlockIndent() int
173
174
175
176 SetBlockIndent(int)
177
178
179 FirstDelimiter() *Delimiter
180
181
182 LastDelimiter() *Delimiter
183
184
185
186 PushDelimiter(delimiter *Delimiter)
187
188
189 RemoveDelimiter(d *Delimiter)
190
191
192 ClearDelimiters(bottom ast.Node)
193
194
195 OpenedBlocks() []Block
196
197
198 SetOpenedBlocks([]Block)
199
200
201 LastOpenedBlock() Block
202
203
204 IsInLinkLabel() bool
205 }
206
207
208 type ContextConfig struct {
209 IDs IDs
210 }
211
212
213 type ContextOption func(*ContextConfig)
214
215
216 func WithIDs(ids IDs) ContextOption {
217 return func(c *ContextConfig) {
218 c.IDs = ids
219 }
220 }
221
222 type parseContext struct {
223 store []interface{}
224 ids IDs
225 refs map[string]Reference
226 blockOffset int
227 blockIndent int
228 delimiters *Delimiter
229 lastDelimiter *Delimiter
230 openedBlocks []Block
231 }
232
233
234 func NewContext(options ...ContextOption) Context {
235 cfg := &ContextConfig{
236 IDs: newIDs(),
237 }
238 for _, option := range options {
239 option(cfg)
240 }
241
242 return &parseContext{
243 store: make([]interface{}, ContextKeyMax+1),
244 refs: map[string]Reference{},
245 ids: cfg.IDs,
246 blockOffset: -1,
247 blockIndent: -1,
248 delimiters: nil,
249 lastDelimiter: nil,
250 openedBlocks: []Block{},
251 }
252 }
253
254 func (p *parseContext) Get(key ContextKey) interface{} {
255 return p.store[key]
256 }
257
258 func (p *parseContext) ComputeIfAbsent(key ContextKey, f func() interface{}) interface{} {
259 v := p.store[key]
260 if v == nil {
261 v = f()
262 p.store[key] = v
263 }
264 return v
265 }
266
267 func (p *parseContext) Set(key ContextKey, value interface{}) {
268 p.store[key] = value
269 }
270
271 func (p *parseContext) IDs() IDs {
272 return p.ids
273 }
274
275 func (p *parseContext) BlockOffset() int {
276 return p.blockOffset
277 }
278
279 func (p *parseContext) SetBlockOffset(v int) {
280 p.blockOffset = v
281 }
282
283 func (p *parseContext) BlockIndent() int {
284 return p.blockIndent
285 }
286
287 func (p *parseContext) SetBlockIndent(v int) {
288 p.blockIndent = v
289 }
290
291 func (p *parseContext) LastDelimiter() *Delimiter {
292 return p.lastDelimiter
293 }
294
295 func (p *parseContext) FirstDelimiter() *Delimiter {
296 return p.delimiters
297 }
298
299 func (p *parseContext) PushDelimiter(d *Delimiter) {
300 if p.delimiters == nil {
301 p.delimiters = d
302 p.lastDelimiter = d
303 } else {
304 l := p.lastDelimiter
305 p.lastDelimiter = d
306 l.NextDelimiter = d
307 d.PreviousDelimiter = l
308 }
309 }
310
311 func (p *parseContext) RemoveDelimiter(d *Delimiter) {
312 if d.PreviousDelimiter == nil {
313 p.delimiters = d.NextDelimiter
314 } else {
315 d.PreviousDelimiter.NextDelimiter = d.NextDelimiter
316 if d.NextDelimiter != nil {
317 d.NextDelimiter.PreviousDelimiter = d.PreviousDelimiter
318 }
319 }
320 if d.NextDelimiter == nil {
321 p.lastDelimiter = d.PreviousDelimiter
322 }
323 if p.delimiters != nil {
324 p.delimiters.PreviousDelimiter = nil
325 }
326 if p.lastDelimiter != nil {
327 p.lastDelimiter.NextDelimiter = nil
328 }
329 d.NextDelimiter = nil
330 d.PreviousDelimiter = nil
331 if d.Length != 0 {
332 ast.MergeOrReplaceTextSegment(d.Parent(), d, d.Segment)
333 } else {
334 d.Parent().RemoveChild(d.Parent(), d)
335 }
336 }
337
338 func (p *parseContext) ClearDelimiters(bottom ast.Node) {
339 if p.lastDelimiter == nil {
340 return
341 }
342 var c ast.Node
343 for c = p.lastDelimiter; c != nil && c != bottom; {
344 prev := c.PreviousSibling()
345 if d, ok := c.(*Delimiter); ok {
346 p.RemoveDelimiter(d)
347 }
348 c = prev
349 }
350 }
351
352 func (p *parseContext) AddReference(ref Reference) {
353 key := util.ToLinkReference(ref.Label())
354 if _, ok := p.refs[key]; !ok {
355 p.refs[key] = ref
356 }
357 }
358
359 func (p *parseContext) Reference(label string) (Reference, bool) {
360 v, ok := p.refs[label]
361 return v, ok
362 }
363
364 func (p *parseContext) References() []Reference {
365 ret := make([]Reference, 0, len(p.refs))
366 for _, v := range p.refs {
367 ret = append(ret, v)
368 }
369 return ret
370 }
371
372 func (p *parseContext) String() string {
373 refs := []string{}
374 for _, r := range p.refs {
375 refs = append(refs, r.String())
376 }
377
378 return fmt.Sprintf("Context{Store:%#v, Refs:%s}", p.store, strings.Join(refs, ","))
379 }
380
381 func (p *parseContext) OpenedBlocks() []Block {
382 return p.openedBlocks
383 }
384
385 func (p *parseContext) SetOpenedBlocks(v []Block) {
386 p.openedBlocks = v
387 }
388
389 func (p *parseContext) LastOpenedBlock() Block {
390 if l := len(p.openedBlocks); l != 0 {
391 return p.openedBlocks[l-1]
392 }
393 return Block{}
394 }
395
396 func (p *parseContext) IsInLinkLabel() bool {
397 tlist := p.Get(linkLabelStateKey)
398 return tlist != nil
399 }
400
401
402
403 type State int
404
405 const (
406 none State = 1 << iota
407
408
409 Continue
410
411
412 Close
413
414
415 HasChildren
416
417
418 NoChildren
419
420
421
422
423 RequireParagraph
424 )
425
426
427 type Config struct {
428 Options map[OptionName]interface{}
429 BlockParsers util.PrioritizedSlice
430 InlineParsers util.PrioritizedSlice
431 ParagraphTransformers util.PrioritizedSlice
432 ASTTransformers util.PrioritizedSlice
433 EscapedSpace bool
434 }
435
436
437 func NewConfig() *Config {
438 return &Config{
439 Options: map[OptionName]interface{}{},
440 BlockParsers: util.PrioritizedSlice{},
441 InlineParsers: util.PrioritizedSlice{},
442 ParagraphTransformers: util.PrioritizedSlice{},
443 ASTTransformers: util.PrioritizedSlice{},
444 }
445 }
446
447
448 type Option interface {
449 SetParserOption(*Config)
450 }
451
452
453 type OptionName string
454
455
456 const optAttribute OptionName = "Attribute"
457
458 type withAttribute struct {
459 }
460
461 func (o *withAttribute) SetParserOption(c *Config) {
462 c.Options[optAttribute] = true
463 }
464
465
466 func WithAttribute() Option {
467 return &withAttribute{}
468 }
469
470
471 type Parser interface {
472
473 Parse(reader text.Reader, opts ...ParseOption) ast.Node
474
475
476 AddOptions(...Option)
477 }
478
479
480 type SetOptioner interface {
481
482
483
484 SetOption(name OptionName, value interface{})
485 }
486
487
488
489 type BlockParser interface {
490
491
492
493 Trigger() []byte
494
495
496
497
498
499
500
501
502
503
504 Open(parent ast.Node, reader text.Reader, pc Context) (ast.Node, State)
505
506
507
508
509
510
511
512
513
514
515
516 Continue(node ast.Node, reader text.Reader, pc Context) State
517
518
519 Close(node ast.Node, reader text.Reader, pc Context)
520
521
522
523 CanInterruptParagraph() bool
524
525
526
527 CanAcceptIndentedLine() bool
528 }
529
530
531 type InlineParser interface {
532
533
534
535
536
537 Trigger() []byte
538
539
540
541
542
543
544 Parse(parent ast.Node, block text.Reader, pc Context) ast.Node
545 }
546
547
548
549 type CloseBlocker interface {
550
551 CloseBlock(parent ast.Node, block text.Reader, pc Context)
552 }
553
554
555
556 type ParagraphTransformer interface {
557
558 Transform(node *ast.Paragraph, reader text.Reader, pc Context)
559 }
560
561
562 type ASTTransformer interface {
563
564 Transform(node *ast.Document, reader text.Reader, pc Context)
565 }
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580 func DefaultBlockParsers() []util.PrioritizedValue {
581 return []util.PrioritizedValue{
582 util.Prioritized(NewSetextHeadingParser(), 100),
583 util.Prioritized(NewThematicBreakParser(), 200),
584 util.Prioritized(NewListParser(), 300),
585 util.Prioritized(NewListItemParser(), 400),
586 util.Prioritized(NewCodeBlockParser(), 500),
587 util.Prioritized(NewATXHeadingParser(), 600),
588 util.Prioritized(NewFencedCodeBlockParser(), 700),
589 util.Prioritized(NewBlockquoteParser(), 800),
590 util.Prioritized(NewHTMLBlockParser(), 900),
591 util.Prioritized(NewParagraphParser(), 1000),
592 }
593 }
594
595
596
597
598
599
600
601
602
603 func DefaultInlineParsers() []util.PrioritizedValue {
604 return []util.PrioritizedValue{
605 util.Prioritized(NewCodeSpanParser(), 100),
606 util.Prioritized(NewLinkParser(), 200),
607 util.Prioritized(NewAutoLinkParser(), 300),
608 util.Prioritized(NewRawHTMLParser(), 400),
609 util.Prioritized(NewEmphasisParser(), 500),
610 }
611 }
612
613
614
615
616
617 func DefaultParagraphTransformers() []util.PrioritizedValue {
618 return []util.PrioritizedValue{
619 util.Prioritized(LinkReferenceParagraphTransformer, 100),
620 }
621 }
622
623
624 type Block struct {
625
626 Node ast.Node
627
628 Parser BlockParser
629 }
630
631 type parser struct {
632 options map[OptionName]interface{}
633 blockParsers [256][]BlockParser
634 freeBlockParsers []BlockParser
635 inlineParsers [256][]InlineParser
636 closeBlockers []CloseBlocker
637 paragraphTransformers []ParagraphTransformer
638 astTransformers []ASTTransformer
639 escapedSpace bool
640 config *Config
641 initSync sync.Once
642 }
643
644 type withBlockParsers struct {
645 value []util.PrioritizedValue
646 }
647
648 func (o *withBlockParsers) SetParserOption(c *Config) {
649 c.BlockParsers = append(c.BlockParsers, o.value...)
650 }
651
652
653
654 func WithBlockParsers(bs ...util.PrioritizedValue) Option {
655 return &withBlockParsers{bs}
656 }
657
658 type withInlineParsers struct {
659 value []util.PrioritizedValue
660 }
661
662 func (o *withInlineParsers) SetParserOption(c *Config) {
663 c.InlineParsers = append(c.InlineParsers, o.value...)
664 }
665
666
667
668 func WithInlineParsers(bs ...util.PrioritizedValue) Option {
669 return &withInlineParsers{bs}
670 }
671
672 type withParagraphTransformers struct {
673 value []util.PrioritizedValue
674 }
675
676 func (o *withParagraphTransformers) SetParserOption(c *Config) {
677 c.ParagraphTransformers = append(c.ParagraphTransformers, o.value...)
678 }
679
680
681
682 func WithParagraphTransformers(ps ...util.PrioritizedValue) Option {
683 return &withParagraphTransformers{ps}
684 }
685
686 type withASTTransformers struct {
687 value []util.PrioritizedValue
688 }
689
690 func (o *withASTTransformers) SetParserOption(c *Config) {
691 c.ASTTransformers = append(c.ASTTransformers, o.value...)
692 }
693
694
695
696 func WithASTTransformers(ps ...util.PrioritizedValue) Option {
697 return &withASTTransformers{ps}
698 }
699
700 type withEscapedSpace struct {
701 }
702
703 func (o *withEscapedSpace) SetParserOption(c *Config) {
704 c.EscapedSpace = true
705 }
706
707
708 func WithEscapedSpace() Option {
709 return &withEscapedSpace{}
710 }
711
712 type withOption struct {
713 name OptionName
714 value interface{}
715 }
716
717 func (o *withOption) SetParserOption(c *Config) {
718 c.Options[o.name] = o.value
719 }
720
721
722
723 func WithOption(name OptionName, value interface{}) Option {
724 return &withOption{name, value}
725 }
726
727
728 func NewParser(options ...Option) Parser {
729 config := NewConfig()
730 for _, opt := range options {
731 opt.SetParserOption(config)
732 }
733
734 p := &parser{
735 options: map[OptionName]interface{}{},
736 config: config,
737 }
738
739 return p
740 }
741
742 func (p *parser) AddOptions(opts ...Option) {
743 for _, opt := range opts {
744 opt.SetParserOption(p.config)
745 }
746 }
747
748 func (p *parser) addBlockParser(v util.PrioritizedValue, options map[OptionName]interface{}) {
749 bp, ok := v.Value.(BlockParser)
750 if !ok {
751 panic(fmt.Sprintf("%v is not a BlockParser", v.Value))
752 }
753 tcs := bp.Trigger()
754 so, ok := v.Value.(SetOptioner)
755 if ok {
756 for oname, ovalue := range options {
757 so.SetOption(oname, ovalue)
758 }
759 }
760 if tcs == nil {
761 p.freeBlockParsers = append(p.freeBlockParsers, bp)
762 } else {
763 for _, tc := range tcs {
764 if p.blockParsers[tc] == nil {
765 p.blockParsers[tc] = []BlockParser{}
766 }
767 p.blockParsers[tc] = append(p.blockParsers[tc], bp)
768 }
769 }
770 }
771
772 func (p *parser) addInlineParser(v util.PrioritizedValue, options map[OptionName]interface{}) {
773 ip, ok := v.Value.(InlineParser)
774 if !ok {
775 panic(fmt.Sprintf("%v is not a InlineParser", v.Value))
776 }
777 tcs := ip.Trigger()
778 so, ok := v.Value.(SetOptioner)
779 if ok {
780 for oname, ovalue := range options {
781 so.SetOption(oname, ovalue)
782 }
783 }
784 if cb, ok := ip.(CloseBlocker); ok {
785 p.closeBlockers = append(p.closeBlockers, cb)
786 }
787 for _, tc := range tcs {
788 if p.inlineParsers[tc] == nil {
789 p.inlineParsers[tc] = []InlineParser{}
790 }
791 p.inlineParsers[tc] = append(p.inlineParsers[tc], ip)
792 }
793 }
794
795 func (p *parser) addParagraphTransformer(v util.PrioritizedValue, options map[OptionName]interface{}) {
796 pt, ok := v.Value.(ParagraphTransformer)
797 if !ok {
798 panic(fmt.Sprintf("%v is not a ParagraphTransformer", v.Value))
799 }
800 so, ok := v.Value.(SetOptioner)
801 if ok {
802 for oname, ovalue := range options {
803 so.SetOption(oname, ovalue)
804 }
805 }
806 p.paragraphTransformers = append(p.paragraphTransformers, pt)
807 }
808
809 func (p *parser) addASTTransformer(v util.PrioritizedValue, options map[OptionName]interface{}) {
810 at, ok := v.Value.(ASTTransformer)
811 if !ok {
812 panic(fmt.Sprintf("%v is not a ASTTransformer", v.Value))
813 }
814 so, ok := v.Value.(SetOptioner)
815 if ok {
816 for oname, ovalue := range options {
817 so.SetOption(oname, ovalue)
818 }
819 }
820 p.astTransformers = append(p.astTransformers, at)
821 }
822
823
824 type ParseConfig struct {
825 Context Context
826 }
827
828
829 type ParseOption func(c *ParseConfig)
830
831
832
833 func WithContext(context Context) ParseOption {
834 return func(c *ParseConfig) {
835 c.Context = context
836 }
837 }
838
839 func (p *parser) Parse(reader text.Reader, opts ...ParseOption) ast.Node {
840 p.initSync.Do(func() {
841 p.config.BlockParsers.Sort()
842 for _, v := range p.config.BlockParsers {
843 p.addBlockParser(v, p.config.Options)
844 }
845 for i := range p.blockParsers {
846 if p.blockParsers[i] != nil {
847 p.blockParsers[i] = append(p.blockParsers[i], p.freeBlockParsers...)
848 }
849 }
850
851 p.config.InlineParsers.Sort()
852 for _, v := range p.config.InlineParsers {
853 p.addInlineParser(v, p.config.Options)
854 }
855 p.config.ParagraphTransformers.Sort()
856 for _, v := range p.config.ParagraphTransformers {
857 p.addParagraphTransformer(v, p.config.Options)
858 }
859 p.config.ASTTransformers.Sort()
860 for _, v := range p.config.ASTTransformers {
861 p.addASTTransformer(v, p.config.Options)
862 }
863 p.escapedSpace = p.config.EscapedSpace
864 p.config = nil
865 })
866 c := &ParseConfig{}
867 for _, opt := range opts {
868 opt(c)
869 }
870 if c.Context == nil {
871 c.Context = NewContext()
872 }
873 pc := c.Context
874 root := ast.NewDocument()
875 p.parseBlocks(root, reader, pc)
876
877 blockReader := text.NewBlockReader(reader.Source(), nil)
878 p.walkBlock(root, func(node ast.Node) {
879 p.parseBlock(blockReader, node, pc)
880 })
881 for _, at := range p.astTransformers {
882 at.Transform(root, reader, pc)
883 }
884
885 return root
886 }
887
888 func (p *parser) transformParagraph(node *ast.Paragraph, reader text.Reader, pc Context) bool {
889 for _, pt := range p.paragraphTransformers {
890 pt.Transform(node, reader, pc)
891 if node.Parent() == nil {
892 return true
893 }
894 }
895 return false
896 }
897
898 func (p *parser) closeBlocks(from, to int, reader text.Reader, pc Context) {
899 blocks := pc.OpenedBlocks()
900 for i := from; i >= to; i-- {
901 node := blocks[i].Node
902 paragraph, ok := node.(*ast.Paragraph)
903 if ok && node.Parent() != nil {
904 p.transformParagraph(paragraph, reader, pc)
905 }
906 if node.Parent() != nil {
907 blocks[i].Parser.Close(blocks[i].Node, reader, pc)
908 }
909 }
910 if from == len(blocks)-1 {
911 blocks = blocks[0:to]
912 } else {
913 blocks = append(blocks[0:to], blocks[from+1:]...)
914 }
915 pc.SetOpenedBlocks(blocks)
916 }
917
918 type blockOpenResult int
919
920 const (
921 paragraphContinuation blockOpenResult = iota + 1
922 newBlocksOpened
923 noBlocksOpened
924 )
925
926 func (p *parser) openBlocks(parent ast.Node, blankLine bool, reader text.Reader, pc Context) blockOpenResult {
927 result := blockOpenResult(noBlocksOpened)
928 continuable := false
929 lastBlock := pc.LastOpenedBlock()
930 if lastBlock.Node != nil {
931 continuable = ast.IsParagraph(lastBlock.Node)
932 }
933 retry:
934 var bps []BlockParser
935 line, _ := reader.PeekLine()
936 w, pos := util.IndentWidth(line, reader.LineOffset())
937 if w >= len(line) {
938 pc.SetBlockOffset(-1)
939 pc.SetBlockIndent(-1)
940 } else {
941 pc.SetBlockOffset(pos)
942 pc.SetBlockIndent(w)
943 }
944 if line == nil || line[0] == '\n' {
945 goto continuable
946 }
947 bps = p.freeBlockParsers
948 if pos < len(line) {
949 bps = p.blockParsers[line[pos]]
950 if bps == nil {
951 bps = p.freeBlockParsers
952 }
953 }
954 if bps == nil {
955 goto continuable
956 }
957
958 for _, bp := range bps {
959 if continuable && result == noBlocksOpened && !bp.CanInterruptParagraph() {
960 continue
961 }
962 if w > 3 && !bp.CanAcceptIndentedLine() {
963 continue
964 }
965 lastBlock = pc.LastOpenedBlock()
966 last := lastBlock.Node
967 node, state := bp.Open(parent, reader, pc)
968 if node != nil {
969
970
971
972
973
974
975
976
977
978
979
980
981
982 if state&RequireParagraph != 0 {
983 if last == parent.LastChild() {
984
985
986 lastBlock.Parser.Close(last, reader, pc)
987 blocks := pc.OpenedBlocks()
988 pc.SetOpenedBlocks(blocks[0 : len(blocks)-1])
989 if p.transformParagraph(last.(*ast.Paragraph), reader, pc) {
990
991
992 continuable = false
993 goto retry
994 }
995 }
996 }
997 node.SetBlankPreviousLines(blankLine)
998 if last != nil && last.Parent() == nil {
999 lastPos := len(pc.OpenedBlocks()) - 1
1000 p.closeBlocks(lastPos, lastPos, reader, pc)
1001 }
1002 parent.AppendChild(parent, node)
1003 result = newBlocksOpened
1004 be := Block{node, bp}
1005 pc.SetOpenedBlocks(append(pc.OpenedBlocks(), be))
1006 if state&HasChildren != 0 {
1007 parent = node
1008 goto retry
1009 }
1010 break
1011 }
1012 }
1013
1014 continuable:
1015 if result == noBlocksOpened && continuable {
1016 state := lastBlock.Parser.Continue(lastBlock.Node, reader, pc)
1017 if state&Continue != 0 {
1018 result = paragraphContinuation
1019 }
1020 }
1021 return result
1022 }
1023
1024 type lineStat struct {
1025 lineNum int
1026 level int
1027 isBlank bool
1028 }
1029
1030 func isBlankLine(lineNum, level int, stats []lineStat) bool {
1031 ret := true
1032 for i := len(stats) - 1 - level; i >= 0; i-- {
1033 ret = false
1034 s := stats[i]
1035 if s.lineNum == lineNum {
1036 if s.level < level && s.isBlank {
1037 return true
1038 } else if s.level == level {
1039 return s.isBlank
1040 }
1041 }
1042 if s.lineNum < lineNum {
1043 return ret
1044 }
1045 }
1046 return ret
1047 }
1048
1049 func (p *parser) parseBlocks(parent ast.Node, reader text.Reader, pc Context) {
1050 pc.SetOpenedBlocks([]Block{})
1051 blankLines := make([]lineStat, 0, 128)
1052 isBlank := false
1053 for {
1054 _, lines, ok := reader.SkipBlankLines()
1055 if !ok {
1056 return
1057 }
1058 lineNum, _ := reader.Position()
1059 if lines != 0 {
1060 blankLines = blankLines[0:0]
1061 l := len(pc.OpenedBlocks())
1062 for i := 0; i < l; i++ {
1063 blankLines = append(blankLines, lineStat{lineNum - 1, i, lines != 0})
1064 }
1065 }
1066 isBlank = isBlankLine(lineNum-1, 0, blankLines)
1067
1068 if p.openBlocks(parent, isBlank, reader, pc) != newBlocksOpened {
1069 return
1070 }
1071 reader.AdvanceLine()
1072 for {
1073 openedBlocks := pc.OpenedBlocks()
1074 l := len(openedBlocks)
1075 if l == 0 {
1076 break
1077 }
1078 lastIndex := l - 1
1079 for i := 0; i < l; i++ {
1080 be := openedBlocks[i]
1081 line, _ := reader.PeekLine()
1082 if line == nil {
1083 p.closeBlocks(lastIndex, 0, reader, pc)
1084 reader.AdvanceLine()
1085 return
1086 }
1087 lineNum, _ := reader.Position()
1088 blankLines = append(blankLines, lineStat{lineNum, i, util.IsBlank(line)})
1089
1090
1091 if !ast.IsParagraph(be.Node) {
1092 state := be.Parser.Continue(be.Node, reader, pc)
1093 if state&Continue != 0 {
1094
1095
1096 if state&HasChildren != 0 && i == lastIndex {
1097 isBlank = isBlankLine(lineNum-1, i, blankLines)
1098 p.openBlocks(be.Node, isBlank, reader, pc)
1099 break
1100 }
1101 continue
1102 }
1103 }
1104
1105 isBlank = isBlankLine(lineNum-1, i, blankLines)
1106 thisParent := parent
1107 if i != 0 {
1108 thisParent = openedBlocks[i-1].Node
1109 }
1110 lastNode := openedBlocks[lastIndex].Node
1111 result := p.openBlocks(thisParent, isBlank, reader, pc)
1112 if result != paragraphContinuation {
1113
1114
1115 if openedBlocks[lastIndex].Node != lastNode {
1116 lastIndex--
1117 }
1118 p.closeBlocks(lastIndex, i, reader, pc)
1119 }
1120 break
1121 }
1122
1123 reader.AdvanceLine()
1124 }
1125 }
1126 }
1127
1128 func (p *parser) walkBlock(block ast.Node, cb func(node ast.Node)) {
1129 for c := block.FirstChild(); c != nil; c = c.NextSibling() {
1130 p.walkBlock(c, cb)
1131 }
1132 cb(block)
1133 }
1134
1135 const (
1136 lineBreakHard uint8 = 1 << iota
1137 lineBreakSoft
1138 lineBreakVisible
1139 )
1140
1141 func (p *parser) parseBlock(block text.BlockReader, parent ast.Node, pc Context) {
1142 if parent.IsRaw() {
1143 return
1144 }
1145 escaped := false
1146 source := block.Source()
1147 block.Reset(parent.Lines())
1148 for {
1149 retry:
1150 line, _ := block.PeekLine()
1151 if line == nil {
1152 break
1153 }
1154 lineLength := len(line)
1155 var lineBreakFlags uint8 = 0
1156 hasNewLine := line[lineLength-1] == '\n'
1157 if ((lineLength >= 3 && line[lineLength-2] == '\\' && line[lineLength-3] != '\\') || (lineLength == 2 && line[lineLength-2] == '\\')) && hasNewLine {
1158 lineLength -= 2
1159 lineBreakFlags |= lineBreakHard | lineBreakVisible
1160 } else if ((lineLength >= 4 && line[lineLength-3] == '\\' && line[lineLength-2] == '\r' && line[lineLength-4] != '\\') || (lineLength == 3 && line[lineLength-3] == '\\' && line[lineLength-2] == '\r')) && hasNewLine {
1161 lineLength -= 3
1162 lineBreakFlags |= lineBreakHard | lineBreakVisible
1163 } else if lineLength >= 3 && line[lineLength-3] == ' ' && line[lineLength-2] == ' ' && hasNewLine {
1164 lineLength -= 3
1165 lineBreakFlags |= lineBreakHard
1166 } else if lineLength >= 4 && line[lineLength-4] == ' ' && line[lineLength-3] == ' ' && line[lineLength-2] == '\r' && hasNewLine {
1167 lineLength -= 4
1168 lineBreakFlags |= lineBreakHard
1169 } else if hasNewLine {
1170
1171
1172
1173 lineBreakFlags |= lineBreakSoft
1174 }
1175
1176 l, startPosition := block.Position()
1177 n := 0
1178 for i := 0; i < lineLength; i++ {
1179 c := line[i]
1180 if c == '\n' {
1181 break
1182 }
1183 isSpace := util.IsSpace(c) && c != '\r' && c != '\n'
1184 isPunct := util.IsPunct(c)
1185 if (isPunct && !escaped) || isSpace && !(escaped && p.escapedSpace) || i == 0 {
1186 parserChar := c
1187 if isSpace || (i == 0 && !isPunct) {
1188 parserChar = ' '
1189 }
1190 ips := p.inlineParsers[parserChar]
1191 if ips != nil {
1192 block.Advance(n)
1193 n = 0
1194 savedLine, savedPosition := block.Position()
1195 if i != 0 {
1196 _, currentPosition := block.Position()
1197 ast.MergeOrAppendTextSegment(parent, startPosition.Between(currentPosition))
1198 _, startPosition = block.Position()
1199 }
1200 var inlineNode ast.Node
1201 for _, ip := range ips {
1202 inlineNode = ip.Parse(parent, block, pc)
1203 if inlineNode != nil {
1204 break
1205 }
1206 block.SetPosition(savedLine, savedPosition)
1207 }
1208 if inlineNode != nil {
1209 parent.AppendChild(parent, inlineNode)
1210 goto retry
1211 }
1212 }
1213 }
1214 if escaped {
1215 escaped = false
1216 n++
1217 continue
1218 }
1219
1220 if c == '\\' {
1221 escaped = true
1222 n++
1223 continue
1224 }
1225
1226 escaped = false
1227 n++
1228 }
1229 if n != 0 {
1230 block.Advance(n)
1231 }
1232 currentL, currentPosition := block.Position()
1233 if l != currentL {
1234 continue
1235 }
1236 diff := startPosition.Between(currentPosition)
1237 var text *ast.Text
1238 if lineBreakFlags&(lineBreakHard|lineBreakVisible) == lineBreakHard|lineBreakVisible {
1239 text = ast.NewTextSegment(diff)
1240 } else {
1241 text = ast.NewTextSegment(diff.TrimRightSpace(source))
1242 }
1243 text.SetSoftLineBreak(lineBreakFlags&lineBreakSoft != 0)
1244 text.SetHardLineBreak(lineBreakFlags&lineBreakHard != 0)
1245 parent.AppendChild(parent, text)
1246 block.AdvanceLine()
1247 }
1248
1249 ProcessDelimiters(nil, pc)
1250 for _, ip := range p.closeBlockers {
1251 ip.CloseBlock(parent, block, pc)
1252 }
1253 }
1254
View as plain text