package parser

import "../token"
import "core:strings"

ESCAPE_PLACEHOLDER_BASE :: 0xE000

is_escapable_char :: proc(b: byte) -> bool {
	switch b {
	case '\\',
	     '*',
	     '_',
	     '~',
	     '^',
	     '`',
	     '[',
	     ']',
	     '(',
	     ')',
	     '$',
	     '&',
	     '!',
	     '>',
	     '<',
	     '|',
	     '-',
	     '=',
	     '#',
	     '.':
		return true
	}
	return false
}

is_repeatable_token_char :: proc(b: byte) -> bool {
	switch b {
	case '*', '_', '~', '^', '<', '>', '-', '=', '&', '!', '.':
		return true
	}
	return false
}

escape_placeholder_rune :: proc(b: byte) -> rune {
	return rune(ESCAPE_PLACEHOLDER_BASE + int(b))
}

is_escape_placeholder :: proc(r: rune) -> bool {
	return r >= ESCAPE_PLACEHOLDER_BASE && r < ESCAPE_PLACEHOLDER_BASE + 256
}

escape_placeholder_to_byte :: proc(r: rune) -> byte {
	return byte(int(r) - ESCAPE_PLACEHOLDER_BASE)
}

unescape_backslashes :: proc(s: string, allocator := context.temp_allocator) -> string {
	if !strings.contains(s, "\\") {
		return s
	}

	b := strings.builder_make(allocator)
	i := 0
	for i < len(s) {
		if s[i] == '`' {
			close := strings.index_byte(s[i + 1:], '`')
			if close != -1 {
				end := i + 1 + close
				strings.write_string(&b, s[i:end + 1])
				i = end + 1
				continue
			}
		}
		if s[i] == '\\' && i + 1 < len(s) && is_escapable_char(s[i + 1]) {
			esc := s[i + 1]
			strings.write_rune(&b, escape_placeholder_rune(esc))
			i += 2
			if is_repeatable_token_char(esc) {
				for i < len(s) && s[i] == esc {
					strings.write_rune(&b, escape_placeholder_rune(esc))
					i += 1
				}
			}
		} else {
			strings.write_byte(&b, s[i])
			i += 1
		}
	}
	return strings.to_string(b)
}

decode_escapes :: proc(s: string, allocator := context.temp_allocator) -> string {
	has_placeholder := false
	for r in s {
		if is_escape_placeholder(r) {
			has_placeholder = true
			break
		}
	}
	if !has_placeholder {
		return s
	}

	b := strings.builder_make(allocator)
	for r in s {
		if is_escape_placeholder(r) {
			strings.write_byte(&b, escape_placeholder_to_byte(r))
		} else {
			strings.write_rune(&b, r)
		}
	}
	return strings.to_string(b)
}

decode_text_escapes :: proc(tok: ^token.Token) {
	if tok.type == .Text {
		if str, ok := tok.value.(string); ok {
			tok.value = decode_escapes(str)
		}
	}
	if tok.children != nil {
		for child in tok.children {
			decode_text_escapes(child)
		}
	}
}
