aboutsummaryrefslogtreecommitdiff
path: root/mardown/ast_modifier.go
blob: b9e53a1fbfb15d370feaf11362404724e7007e75 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
package mardown

import (
	"errors"
	"fmt"
	"html/template"
)

var (
	ErrInternalError         = errors.New("internal error")
	ErrInvalidModifier       = errors.Join(ErrInvalidParagraph, errors.New("invalid modifier organization"))
	ErrInvalidTypeInModifier = errors.Join(ErrInvalidParagraph, errors.New("invalid type in modifier"))
)

type modifierTag string

const (
	boldTag modifierTag = "b"
	emTag   modifierTag = "em"
	codeTag modifierTag = "code"
)

type astModifier struct {
	symbols string
	tag     modifierTag
	content []block
	parent  *astModifier
}

func (a *astModifier) Eval() (template.HTML, error) {
	var content template.HTML
	for _, c := range a.content {
		ct, err := c.Eval()
		if err != nil {
			return "", err
		}
		content += ct
	}
	return template.HTML(fmt.Sprintf("<%s>%s</%s>", a.tag, content, a.tag)), nil
}

func modifier(lxs *lexers) (*astModifier, error) {
	current := lxs.Current().Value
	mod := modifierDetect(current)
	modInside := mod
	if len(mod.content) > 0 {
		var ok bool
		modInside, ok = mod.content[0].(*astModifier)
		if modInside.content != nil && !ok {
			return nil, ErrInternalError
		}
		// getting the last modifier
		for len(modInside.content) > 0 {
			modInside, ok = modInside.content[0].(*astModifier)
			if modInside.content != nil && !ok {
				return nil, ErrInternalError
			}
		}
	}
	n := len(modInside.symbols)
	var s string
	for lxs.Next() {
		switch lxs.Current().Type {
		case lexerLiteral:
			s += lxs.Current().Value
		case lexerModifier:
			if len(lxs.Current().Value) < n {
				return nil, ErrInvalidModifier
			}
			if lxs.Current().Value[:n] != modInside.symbols {
				return nil, ErrInvalidModifier
			}
			modInside.content = append(modInside.content, astLiteral(s))
			s = ""
			modInside = modInside.parent
		default:
			return nil, ErrInvalidTypeInModifier
		}
	}
	return mod, nil
}

func modifierDetect(val string) *astModifier {
	mod := new(astModifier)
	if len(val) == 1 {
		mod.symbols = val
		if val == "`" {
			mod.tag = codeTag
		} else {
			mod.tag = emTag
		}
		return mod
	}
	if val[:2] == "**" || val[:2] == "__" {
		mod.symbols = val
		mod.tag = boldTag
	} else {
		mod = modifierDetect(val[:1])
		next := modifierDetect(val[1:])
		next.parent = mod
		mod.content = append(mod.content, next)
	}
	return mod
}