Files
TypoML/src/parser.odin
T
2026-07-14 00:29:38 +02:00

123 lines
2.8 KiB
Odin

package main
import "core:fmt"
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,
}
current_token: ^Token
replace_text :: proc(text: string, start: int, len_: int, repl: string) -> string {
builder := strings.builder_make(context.temp_allocator)
strings.write_string(&builder, text[:start])
strings.write_string(&builder, repl)
strings.write_string(&builder, text[start + len_:])
return strings.to_string(builder)
}
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 {
if current_token.parent != nil {
current_token = current_token.parent
}
append(
&current_token.children,
Token{TokenType.Paragraph, nil, nil, current_token},
)
current_token = &current_token.children[len(current_token.children) - 1]
continue
} else {
continue
}
}
header_level, text := parse_header(line)
if header_level > 0 {
if current_token.parent != nil {
current_token = current_token.parent
}
append(
&current_token.children,
Token{TokenType.Header, header_level, nil, current_token},
)
current_token = &current_token.children[len(current_token.children) - 1]
append(&current_token.children, Token{TokenType.Text, text, nil, current_token})
current_token = current_token.parent
continue
}
if text[0:2] == "> " {
if current_token.type != TokenType.Blockquote {
append(
&current_token.children,
Token{TokenType.Blockquote, nil, nil, current_token},
)
current_token = &current_token.children[len(current_token.children) - 1]
}
append(&current_token.children, Token{TokenType.Text, text[2:], nil, current_token})
continue
}
// LAST-CASE SCENARIO: NORMAL TEXT
if current_token.parent == nil {
append(&current_token.children, Token{TokenType.Paragraph, nil, nil, current_token})
current_token = &current_token.children[len(current_token.children) - 1]
}
#partial switch current_token.parent.type {
case TokenType.Blockquote:
current_token = current_token.parent
}
append(&current_token.children, Token{TokenType.Text, line, nil, current_token})
}
return root
}