98 lines
1.9 KiB
Odin
98 lines
1.9 KiB
Odin
package main
|
|
|
|
import "core:strings"
|
|
|
|
TokenType :: enum {
|
|
Text,
|
|
Italics,
|
|
Bold,
|
|
BreakLine,
|
|
Header,
|
|
Paragraph,
|
|
Root,
|
|
Blockquote,
|
|
}
|
|
|
|
TokenValue :: union {
|
|
string,
|
|
int,
|
|
}
|
|
|
|
Token :: struct {
|
|
type: TokenType,
|
|
value: TokenValue,
|
|
children: [dynamic]^Token,
|
|
parent: ^Token,
|
|
}
|
|
|
|
push_token :: proc(parent: ^Token, type: TokenType, value: TokenValue = nil) -> ^Token {
|
|
token := new(Token)
|
|
token^ = Token{type, value, nil, parent}
|
|
append(&parent.children, token)
|
|
return token
|
|
}
|
|
|
|
parse_header :: proc(line: string) -> (int, string) {
|
|
if len(line) == 0 {
|
|
return 0, line
|
|
}
|
|
|
|
lvl := 0
|
|
for lvl < len(line) && line[lvl] == '!' {
|
|
lvl += 1
|
|
}
|
|
if lvl == 0 || lvl >= len(line) || line[lvl] != ' ' {
|
|
return 0, line
|
|
}
|
|
return lvl, line[lvl + 1:]
|
|
}
|
|
|
|
parse :: proc(lines: []string, allocator := context.allocator) -> Token {
|
|
root := Token{TokenType.Root, nil, nil, nil}
|
|
current_token := &root
|
|
|
|
for untrimmed_line, line_index in lines {
|
|
line := strings.trim_space(untrimmed_line)
|
|
|
|
if len(line) == 0 {
|
|
if line_index != len(lines) - 1 {
|
|
current_token = push_token(&root, TokenType.Paragraph, nil)
|
|
continue
|
|
} else {
|
|
continue
|
|
}
|
|
}
|
|
|
|
header_level, text := parse_header(line)
|
|
if header_level > 0 {
|
|
current_token = push_token(&root, TokenType.Header, header_level)
|
|
push_token(current_token, TokenType.Text, text)
|
|
current_token = &root
|
|
continue
|
|
}
|
|
|
|
if strings.has_prefix(text, "> ") {
|
|
if current_token.type != TokenType.Blockquote {
|
|
current_token = push_token(&root, TokenType.Blockquote, nil)
|
|
}
|
|
push_token(current_token, TokenType.Text, text[2:])
|
|
continue
|
|
}
|
|
|
|
// LAST-CASE SCENARIO: NORMAL TEXT
|
|
|
|
if current_token.parent == nil {
|
|
current_token = push_token(&root, TokenType.Paragraph, nil)
|
|
}
|
|
|
|
#partial switch current_token.parent.type {
|
|
case TokenType.Blockquote:
|
|
current_token = current_token.parent
|
|
}
|
|
|
|
push_token(current_token, TokenType.Text, line)
|
|
}
|
|
|
|
return root
|
|
}
|