161 lines
5.8 KiB
C++
161 lines
5.8 KiB
C++
/*
|
|
* lang_lua.hpp
|
|
* Lua highlighting
|
|
* Shared by the MontaukOS text editor (GUI) and edit.elf (CLI)
|
|
* Copyright (c) 2026 Daniel Hammer
|
|
*/
|
|
|
|
// Included by <syntax/syntax.hpp>; not standalone.
|
|
|
|
#pragma once
|
|
|
|
// ============================================================================
|
|
// Keyword / builtin classification
|
|
// ============================================================================
|
|
|
|
inline SynToken syn_classify_lua_word(const char* buf, int len) {
|
|
static const char* keywords[] = {
|
|
"and", "break", "do", "else", "elseif", "end", "false",
|
|
"for", "function", "goto", "if", "in", "local", "nil",
|
|
"not", "or", "repeat", "return", "then", "true",
|
|
"until", "while",
|
|
};
|
|
static const char* builtins[] = {
|
|
"_ENV", "_G", "_VERSION",
|
|
"assert", "collectgarbage", "coroutine", "debug", "dofile",
|
|
"error", "getmetatable", "io", "ipairs", "load", "loadfile",
|
|
"math", "next", "os", "package", "pairs", "pcall",
|
|
"print", "rawequal", "rawget", "rawlen", "rawset", "require",
|
|
"select", "setmetatable", "string", "table", "tonumber",
|
|
"tostring", "type", "utf8", "warn", "xpcall",
|
|
};
|
|
for (int i = 0; i < (int)(sizeof(keywords) / sizeof(keywords[0])); i++) {
|
|
if (syn_streq(buf, len, keywords[i])) return SYN_KEYWORD;
|
|
}
|
|
for (int i = 0; i < (int)(sizeof(builtins) / sizeof(builtins[0])); i++) {
|
|
if (syn_streq(buf, len, builtins[i])) return SYN_TYPE;
|
|
}
|
|
return SYN_NORMAL;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Lua long bracket matching
|
|
// ============================================================================
|
|
|
|
inline bool syn_match_lua_long_bracket_open(const char* line, int len, int i,
|
|
int& eqs, int& span) {
|
|
if (i >= len || line[i] != '[') return false;
|
|
int j = i + 1;
|
|
while (j < len && line[j] == '=') j++;
|
|
if (j < len && line[j] == '[') {
|
|
eqs = j - i - 1;
|
|
span = j - i + 1;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
inline bool syn_match_lua_long_bracket_close(const char* line, int len, int i,
|
|
int eqs, int& span) {
|
|
if (i >= len || line[i] != ']') return false;
|
|
int j = i + 1;
|
|
for (int k = 0; k < eqs; k++) {
|
|
if (j >= len || line[j] != '=') return false;
|
|
j++;
|
|
}
|
|
if (j < len && line[j] == ']') {
|
|
span = j - i + 1;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Per-line highlighter
|
|
// ============================================================================
|
|
|
|
inline void syn_highlight_line_lua(const char* line, int len, SynToken* out, int out_len,
|
|
SynState& state) {
|
|
int i = 0;
|
|
while (i < len) {
|
|
if (state.long_token != SYN_NORMAL) {
|
|
int span = 0;
|
|
if (syn_match_lua_long_bracket_close(line, len, i, state.long_bracket_eqs, span)) {
|
|
syn_fill_tokens(out, out_len, i, i + span, state.long_token);
|
|
i += span;
|
|
state.long_token = SYN_NORMAL;
|
|
state.long_bracket_eqs = -1;
|
|
continue;
|
|
}
|
|
syn_set_token(out, out_len, i, state.long_token);
|
|
i++;
|
|
continue;
|
|
}
|
|
char c = line[i];
|
|
if (c == '-' && i + 1 < len && line[i + 1] == '-') {
|
|
int eqs = 0;
|
|
int span = 0;
|
|
if (i + 2 < len && syn_match_lua_long_bracket_open(line, len, i + 2, eqs, span)) {
|
|
syn_fill_tokens(out, out_len, i, i + 2 + span, SYN_COMMENT);
|
|
i += 2 + span;
|
|
state.long_token = SYN_COMMENT;
|
|
state.long_bracket_eqs = eqs;
|
|
continue;
|
|
}
|
|
syn_fill_tokens(out, out_len, i, len, SYN_COMMENT);
|
|
break;
|
|
}
|
|
if (c == '"' || c == '\'') {
|
|
char quote = c;
|
|
syn_set_token(out, out_len, i, SYN_STRING);
|
|
i++;
|
|
while (i < len) {
|
|
if (line[i] == '\\' && i + 1 < len) {
|
|
syn_set_token(out, out_len, i, SYN_STRING);
|
|
syn_set_token(out, out_len, i + 1, SYN_STRING);
|
|
i += 2;
|
|
continue;
|
|
}
|
|
syn_set_token(out, out_len, i, SYN_STRING);
|
|
if (line[i] == quote) {
|
|
i++;
|
|
break;
|
|
}
|
|
i++;
|
|
}
|
|
continue;
|
|
}
|
|
int eqs = 0;
|
|
int span = 0;
|
|
if (syn_match_lua_long_bracket_open(line, len, i, eqs, span)) {
|
|
syn_fill_tokens(out, out_len, i, i + span, SYN_STRING);
|
|
i += span;
|
|
state.long_token = SYN_STRING;
|
|
state.long_bracket_eqs = eqs;
|
|
continue;
|
|
}
|
|
if (syn_is_digit(c) || (c == '.' && i + 1 < len && syn_is_digit(line[i + 1]))) {
|
|
syn_consume_number(line, len, i, out, out_len, 0);
|
|
continue;
|
|
}
|
|
if (syn_is_alpha(c)) {
|
|
int start = i;
|
|
while (i < len && syn_is_alnum(line[i])) i++;
|
|
SynToken tok = syn_classify_word(SYN_LANG_LUA, line + start, i - start);
|
|
syn_fill_tokens(out, out_len, start, i, tok);
|
|
continue;
|
|
}
|
|
if (c == '+' || c == '-' || c == '*' || c == '/' || c == '%' ||
|
|
c == '^' || c == '#' || c == '=' || c == '<' || c == '>' ||
|
|
c == '~' || c == ':' || c == '.' || c == ',' || c == ';' ||
|
|
c == '(' || c == ')' || c == '{' || c == '}' ||
|
|
c == '[' || c == ']') {
|
|
syn_set_token(out, out_len, i, SYN_OPERATOR);
|
|
i++;
|
|
continue;
|
|
}
|
|
syn_set_token(out, out_len, i, SYN_NORMAL);
|
|
i++;
|
|
}
|
|
}
|