aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--lexers/LexLPeg.cxx661
1 files changed, 343 insertions, 318 deletions
diff --git a/lexers/LexLPeg.cxx b/lexers/LexLPeg.cxx
index 39bbc7ba7..e79a7f83d 100644
--- a/lexers/LexLPeg.cxx
+++ b/lexers/LexLPeg.cxx
@@ -32,50 +32,144 @@ extern "C" {
LUALIB_API int luaopen_lpeg(lua_State *L);
}
-#if _WIN32
-#define strcasecmp _stricmp
-#endif
-#define streq(s1, s2) (strcasecmp((s1), (s2)) == 0)
-
using namespace Scintilla;
-#define l_setmetatable(l, k, mtf) \
- if (luaL_newmetatable(l, k)) { \
- lua_pushcfunction(l, mtf), lua_setfield(l, -2, "__index"); \
- lua_pushcfunction(l, mtf), lua_setfield(l, -2, "__newindex"); \
- } \
- lua_setmetatable(l, -2);
-#define l_pushlexerp(l, mtf) do { \
- lua_newtable(l); \
- lua_pushvalue(l, 2), lua_setfield(l, -2, "property"); \
- l_setmetatable(l, "sci_lexerp", mtf); \
-} while(0)
-#define l_getlexerobj(l) \
- lua_getfield(l, LUA_REGISTRYINDEX, "sci_lexers"); \
- lua_pushlightuserdata(l, reinterpret_cast<void *>(this)); \
- lua_gettable(l, -2), lua_replace(l, -2);
-#define l_getlexerfield(l, k) \
- l_getlexerobj(l); \
- lua_getfield(l, -1, k), lua_replace(l, -2);
#if LUA_VERSION_NUM < 502
-#define l_openlib(f, s) \
- (lua_pushcfunction(L, f), lua_pushstring(L, s), lua_call(L, 1, 0))
-#define LUA_BASELIBNAME ""
+#define luaL_requiref(l, s, f, _) \
+ (lua_pushcfunction(l, f), lua_pushstring(l, s), lua_call(l, 1, 1))
#define lua_rawlen lua_objlen
#define LUA_OK 0
-#define lua_compare(l, a, b, _) lua_equal(l, a, b)
-#define LUA_OPEQ 0
-#else
-#define l_openlib(f, s) (luaL_requiref(L, s, f, 1), lua_pop(L, 1))
-#define LUA_BASELIBNAME "_G"
+#define lua_rawgetp(l, i, p) (lua_pushlightuserdata(l, p), lua_rawget(l, i))
+#define lua_rawsetp(l, i, p) \
+ (lua_pushlightuserdata(l, p), lua_insert(l, -2), lua_rawset(l, i))
#endif
-#define l_setfunction(l, f, k) (lua_pushcfunction(l, f), lua_setfield(l, -2, k))
-#define l_setconstant(l, c, k) (lua_pushinteger(l, c), lua_setfield(l, -2, k))
-
-#if CURSES
-#define A_COLORCHAR (A_COLOR | A_CHARTEXT)
+#if LUA_VERSION_NUM < 503
+#define lua_getfield(l, i, k) (lua_getfield(l, i, k), lua_type(l, -1))
+#define lua_rawget(l, i) (lua_rawget(l, i), lua_type(l, -1))
#endif
+/** lexer.property[key] metamethod. */
+static int lexer_property_index(lua_State *L) {
+ const char *property = lua_tostring(L, lua_upvalueindex(1));
+ lua_getfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+ lua_rawgetp(L, LUA_REGISTRYINDEX, lua_touserdata(L, -1));
+ lua_getfield(L, -1, "_PROPS");
+ auto props = static_cast<PropSetSimple *>(lua_touserdata(L, -1));
+ lua_getfield(L, -2, "_BUFFER");
+ auto buffer = static_cast<IDocument *>(lua_touserdata(L, -1));
+ if (strcmp(property, "fold_level") == 0) {
+ luaL_argcheck(L, buffer, 1, "must be lexing or folding");
+ lua_pushinteger(L, buffer->GetLevel(luaL_checkinteger(L, 2)));
+ } else if (strcmp(property, "indent_amount") == 0) {
+ luaL_argcheck(L, buffer, 1, "must be lexing or folding");
+ lua_pushinteger(L, buffer->GetLineIndentation(luaL_checkinteger(L, 2)));
+ } else if (strcmp(property, "property") == 0) {
+ lua_pushstring(L, props->Get(luaL_checkstring(L, 2)));
+ } else if (strcmp(property, "property_int") == 0) {
+ lua_pushstring(L, props->Get(luaL_checkstring(L, 2)));
+ lua_pushinteger(L, lua_tointeger(L, -1));
+ } else if (strcmp(property, "style_at") == 0) {
+ luaL_argcheck(L, buffer, 1, "must be lexing or folding");
+ int style = buffer->StyleAt(luaL_checkinteger(L, 2) - 1);
+ lua_getfield(L, 4, "_TOKENSTYLES");
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ if (luaL_checkinteger(L, -1) == style) break;
+ lua_pop(L, 1); // value
+ }
+ lua_pop(L, 1); // style_num, leaving name on top
+ } else if (strcmp(property, "line_state") == 0) {
+ luaL_argcheck(L, buffer, 1, "must be lexing or folding");
+ lua_pushinteger(L, buffer->GetLineState(luaL_checkinteger(L, 2)));
+ }
+ return 1;
+}
+
+/** lexer.property[key] = value metamethod. */
+static int lexer_property_newindex(lua_State *L) {
+ const char *property = lua_tostring(L, lua_upvalueindex(1));
+ luaL_argcheck(L, strcmp(property, "fold_level") != 0 &&
+ strcmp(property, "indent_amount") != 0 &&
+ strcmp(property, "property_int") != 0 &&
+ strcmp(property, "style_at") != 0 &&
+ strcmp(property, "line_from_position") != 0, 3,
+ "read-only property");
+ lua_getfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+ lua_rawgetp(L, LUA_REGISTRYINDEX, lua_touserdata(L, -1));
+ if (strcmp(property, "property") == 0) {
+ lua_getfield(L, -1, "_PROPS");
+ auto props = static_cast<PropSetSimple *>(lua_touserdata(L, -1));
+ props->Set(luaL_checkstring(L, 2), luaL_checkstring(L, 3), lua_rawlen(L, 2),
+ lua_rawlen(L, 3));
+ } else if (strcmp(property, "line_state") == 0) {
+ luaL_argcheck(L, lua_getfield(L, -1, "_BUFFER"), 1,
+ "must be lexing or folding");
+ auto buffer = static_cast<IDocument *>(lua_touserdata(L, -1));
+ buffer->SetLineState(luaL_checkinteger(L, 2), luaL_checkinteger(L, 3));
+ }
+ return 0;
+}
+
+/** The lexer's `line_from_position` Lua function. */
+static int line_from_position(lua_State *L) {
+ auto buffer = static_cast<IDocument *>(lua_touserdata(L,
+ lua_upvalueindex(1)));
+ lua_pushinteger(L, buffer->LineFromPosition(luaL_checkinteger(L, 1) - 1));
+ return 1;
+}
+
+/** lexer.property metamethod. */
+static int lexer_index(lua_State *L) {
+ const char *key = lua_tostring(L, 2);
+ if (strcmp(key, "fold_level") == 0 || strcmp(key, "indent_amount") == 0 ||
+ strcmp(key, "property") == 0 || strcmp(key, "property_int") == 0 ||
+ strcmp(key, "style_at") == 0 || strcmp(key, "line_state") == 0) {
+ lua_createtable(L, 0, 0);
+ lua_createtable(L, 0, 2);
+ lua_pushvalue(L, 2), lua_pushcclosure(L, lexer_property_index, 1);
+ lua_setfield(L, -2, "__index");
+ lua_pushvalue(L, 2), lua_pushcclosure(L, lexer_property_newindex, 1);
+ lua_setfield(L, -2, "__newindex");
+ lua_setmetatable(L, -2);
+ } else if (strcmp(key, "line_from_position") == 0) {
+ lua_getfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+ lua_rawgetp(L, LUA_REGISTRYINDEX, lua_touserdata(L, -1));
+ luaL_argcheck(L, lua_getfield(L, -1, "_BUFFER"), 2,
+ "must be lexing or folding");
+ lua_pushcclosure(L, line_from_position, 1);
+ } else lua_rawget(L, 1);
+ return 1;
+}
+
+/** lexer.property = value metamethod. */
+static int lexer_newindex(lua_State *L) {
+ const char *key = lua_tostring(L, 2);
+ luaL_argcheck(L, strcmp(key, "fold_level") != 0 &&
+ strcmp(key, "indent_amount") != 0 &&
+ strcmp(key, "property") != 0 &&
+ strcmp(key, "property_int") != 0 &&
+ strcmp(key, "style_at") != 0 &&
+ strcmp(key, "line_state") != 0 &&
+ strcmp(key, "line_from_position") != 0, 3,
+ "read-only property");
+ return (lua_rawset(L, 1), 0);
+}
+
+/**
+ * Replaces the string property key the top of the stack with its expanded
+ * value.
+ * Invokes `lexer.property_expanded[]` to perform the expansion.
+ * @param L The Lua State.
+ */
+static void expand_property(lua_State *L) {
+ //int orig_stack_top = lua_gettop(L);
+ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"), lua_getfield(L, -1, "lexer");
+ lua_getfield(L, -1, "property_expanded");
+ lua_pushvalue(L, -4), lua_gettable(L, -2), lua_replace(L, -5);
+ lua_pop(L, 3); // property_expanded, lexer, _LOADED
+ //assert(lua_gettop(L) == orig_stack_top);
+}
+
/** The LPeg Scintilla lexer. */
class LexerLPeg : public ILexer {
/**
@@ -85,8 +179,7 @@ class LexerLPeg : public ILexer {
*/
lua_State *L;
/**
- * The flag indicating whether or not an existing Lua state is owned by the
- * lexer.
+ * The flag indicating whether or not the Lua State is owned by the lexer.
*/
bool own_lua = true;
/**
@@ -119,117 +212,18 @@ class LexerLPeg : public ILexer {
* Logs the given error message or a Lua error message, prints it, and clears
* the stack.
* Error messages are logged to the "lexer.lpeg.error" property.
+ * @param L The Lua State.
* @param str The error message to log and print. If `nullptr`, logs and
* prints the Lua error message at the top of the stack.
*/
- static void l_error(lua_State *L, const char *str=nullptr) {
- lua_getfield(L, LUA_REGISTRYINDEX, "sci_props");
- PropSetSimple *props = static_cast<PropSetSimple *>(lua_touserdata(L, -1));
- lua_pop(L, 1); // props
+ void log_error(lua_State *L, const char *str = nullptr) {
const char *key = "lexer.lpeg.error";
const char *value = str ? str : lua_tostring(L, -1);
- props->Set(key, value, strlen(key), strlen(value));
- fprintf(stderr, "Lua Error: %s.\n", str ? str : lua_tostring(L, -1));
+ props.Set(key, value, strlen(key), strlen(value));
+ fprintf(stderr, "Lua Error: %s.\n", value);
lua_settop(L, 0);
}
- /** The lexer's `line_from_position` Lua function. */
- static int l_line_from_position(lua_State *L) {
- lua_getfield(L, LUA_REGISTRYINDEX, "sci_buffer");
- IDocument *buffer = static_cast<IDocument *>(lua_touserdata(L, -1));
- lua_pushinteger(L, buffer->LineFromPosition(luaL_checkinteger(L, 1) - 1));
- return 1;
- }
-
- /** The lexer's `__index` Lua metatable. */
- static int llexer_property(lua_State *L) {
- int newindex = (lua_gettop(L) == 3);
- luaL_getmetatable(L, "sci_lexer");
- lua_getmetatable(L, 1); // metatable can be either sci_lexer or sci_lexerp
- int is_lexer = lua_compare(L, -1, -2, LUA_OPEQ);
- lua_pop(L, 2); // metatable, metatable
-
- lua_getfield(L, LUA_REGISTRYINDEX, "sci_buffer");
- IDocument *buffer = static_cast<IDocument *>(lua_touserdata(L, -1));
- lua_getfield(L, LUA_REGISTRYINDEX, "sci_props");
- PropSetSimple *props = static_cast<PropSetSimple *>(lua_touserdata(L, -1));
- lua_pop(L, 2); // sci_props and sci_buffer
-
- if (is_lexer)
- lua_pushvalue(L, 2); // key is given
- else
- lua_getfield(L, 1, "property"); // indexible property
- const char *key = lua_tostring(L, -1);
- if (strcmp(key, "fold_level") == 0) {
- luaL_argcheck(L, !newindex, 3, "read-only property");
- if (is_lexer)
- l_pushlexerp(L, llexer_property);
- else
- lua_pushinteger(L, buffer->GetLevel(luaL_checkinteger(L, 2)));
- } else if (strcmp(key, "indent_amount") == 0) {
- luaL_argcheck(L, !newindex, 3, "read-only property");
- if (is_lexer)
- l_pushlexerp(L, llexer_property);
- else
- lua_pushinteger(L, buffer->GetLineIndentation(luaL_checkinteger(L, 2)));
- } else if (strcmp(key, "property") == 0) {
- luaL_argcheck(L, !is_lexer || !newindex, 3, "read-only property");
- if (is_lexer)
- l_pushlexerp(L, llexer_property);
- else if (!newindex)
- lua_pushstring(L, props->Get(luaL_checkstring(L, 2)));
- else
- props->Set(luaL_checkstring(L, 2), luaL_checkstring(L, 3),
- lua_rawlen(L, 2), lua_rawlen(L, 3));
- } else if (strcmp(key, "property_int") == 0) {
- luaL_argcheck(L, !newindex, 3, "read-only property");
- if (is_lexer)
- l_pushlexerp(L, llexer_property);
- else {
- lua_pushstring(L, props->Get(luaL_checkstring(L, 2)));
- lua_pushinteger(L, lua_tointeger(L, -1));
- }
- } else if (strcmp(key, "style_at") == 0) {
- luaL_argcheck(L, !newindex, 3, "read-only property");
- if (is_lexer)
- l_pushlexerp(L, llexer_property);
- else {
- int style = buffer->StyleAt(luaL_checkinteger(L, 2) - 1);
- lua_getfield(L, LUA_REGISTRYINDEX, "sci_lexer_obj");
- lua_getfield(L, -1, "_TOKENSTYLES"), lua_replace(L, -2);
- lua_pushnil(L);
- while (lua_next(L, -2)) {
- if (luaL_checkinteger(L, -1) == style) break;
- lua_pop(L, 1); // value
- }
- lua_pop(L, 1); // style_num
- }
- } else if (strcmp(key, "line_state") == 0) {
- luaL_argcheck(L, !is_lexer || !newindex, 3, "read-only property");
- if (is_lexer)
- l_pushlexerp(L, llexer_property);
- else if (!newindex)
- lua_pushinteger(L, buffer->GetLineState(luaL_checkinteger(L, 2)));
- else
- buffer->SetLineState(luaL_checkinteger(L, 2),
- luaL_checkinteger(L, 3));
- } else return !newindex ? (lua_rawget(L, 1), 1) : (lua_rawset(L, 1), 0);
- return 1;
- }
-
- /**
- * Expands value of the string property key at index *index* and pushes the
- * result onto the stack.
- * @param L The Lua State.
- * @param index The index the string property key.
- */
- void lL_getexpanded(lua_State *L, int index) {
- lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"), lua_getfield(L, -1, "lexer");
- lua_getfield(L, -1, "property_expanded");
- lua_pushvalue(L, (index > 0) ? index : index - 3), lua_gettable(L, -2);
- lua_replace(L, -4), lua_pop(L, 2); // property_expanded and lexer module
- }
-
/**
* Parses the given style string to set the properties for the given style
* number.
@@ -237,23 +231,23 @@ class LexerLPeg : public ILexer {
* @param style The style string containing properties to set.
*/
void SetStyle(int num, const char *style) {
- char *style_copy = static_cast<char *>(malloc(strlen(style) + 1));
- char *option = strcpy(style_copy, style), *next = nullptr, *p = nullptr;
- while (option) {
- if ((next = strchr(option, ','))) *next++ = '\0';
- if ((p = strchr(option, ':'))) *p++ = '\0';
- if (streq(option, "font") && p)
- SS(sci, SCI_STYLESETFONT, num, reinterpret_cast<sptr_t>(p));
- else if (streq(option, "size") && p)
- SS(sci, SCI_STYLESETSIZE, num, static_cast<int>(atoi(p)));
- else if (streq(option, "bold") || streq(option, "notbold") ||
- streq(option, "weight")) {
+ auto style_copy = static_cast<char *>(malloc(strlen(style) + 1));
+ char *key = strcpy(style_copy, style), *next = nullptr, *val = nullptr;
+ while (key) {
+ if ((next = strchr(key, ','))) *next++ = '\0';
+ if ((val = strchr(key, ':'))) *val++ = '\0';
+ if (strcmp(key, "font") == 0 && val)
+ SS(sci, SCI_STYLESETFONT, num, reinterpret_cast<sptr_t>(val));
+ else if (strcmp(key, "size") == 0 && val)
+ SS(sci, SCI_STYLESETSIZE, num, static_cast<int>(atoi(val)));
+ else if (strcmp(key, "bold") == 0 || strcmp(key, "notbold") == 0 ||
+ strcmp(key, "weight") == 0) {
#if !CURSES
int weight = SC_WEIGHT_NORMAL;
- if (*option == 'b')
+ if (*key == 'b')
weight = SC_WEIGHT_BOLD;
- else if (*option == 'w' && p)
- weight = atoi(p);
+ else if (*key == 'w' && val)
+ weight = atoi(val);
SS(sci, SCI_STYLESETWEIGHT, num, weight);
#else
// Scintilla curses requires font attributes to be stored in the "font
@@ -261,52 +255,58 @@ class LexerLPeg : public ILexer {
// First, clear any existing SC_WEIGHT_NORMAL, SC_WEIGHT_SEMIBOLD, or
// SC_WEIGHT_BOLD values stored in the lower 16 bits. Then set the
// appropriate curses attr.
- sptr_t weight = SS(sci, SCI_STYLEGETWEIGHT, num, 0) & ~A_COLORCHAR;
- int bold = *option == 'b' ||
- (*option == 'w' && p && atoi(p) > SC_WEIGHT_NORMAL);
+ sptr_t weight = SS(sci, SCI_STYLEGETWEIGHT, num, 0) & ~(A_COLOR |
+ A_CHARTEXT);
+ int bold = *key == 'b' ||
+ (*key == 'w' && val && atoi(val) > SC_WEIGHT_NORMAL);
SS(sci, SCI_STYLESETWEIGHT, num,
bold ? weight | A_BOLD : weight & ~A_BOLD);
#endif
- } else if (streq(option, "italics") || streq(option, "notitalics"))
- SS(sci, SCI_STYLESETITALIC, num, *option == 'i');
- else if (streq(option, "underlined") || streq(option, "notunderlined")) {
+ } else if (strcmp(key, "italics") == 0 || strcmp(key, "notitalics") == 0)
+ SS(sci, SCI_STYLESETITALIC, num, *key == 'i');
+ else if (strcmp(key, "underlined") == 0 ||
+ strcmp(key, "notunderlined") == 0) {
#if !CURSES
- SS(sci, SCI_STYLESETUNDERLINE, num, *option == 'u');
+ SS(sci, SCI_STYLESETUNDERLINE, num, *key == 'u');
#else
// Scintilla curses requires font attributes to be stored in the "font
// weight" style attribute.
// First, clear any existing SC_WEIGHT_NORMAL, SC_WEIGHT_SEMIBOLD, or
// SC_WEIGHT_BOLD values stored in the lower 16 bits. Then set the
// appropriate curses attr.
- sptr_t weight = SS(sci, SCI_STYLEGETWEIGHT, num, 0) & ~A_COLORCHAR;
+ sptr_t weight = SS(sci, SCI_STYLEGETWEIGHT, num, 0) & ~(A_COLOR |
+ A_CHARTEXT);
SS(sci, SCI_STYLESETWEIGHT, num,
- (*option == 'u') ? weight | A_UNDERLINE : weight & ~A_UNDERLINE);
+ (*key == 'u') ? weight | A_UNDERLINE : weight & ~A_UNDERLINE);
#endif
- } else if ((streq(option, "fore") || streq(option, "back")) && p) {
- int msg = (*option == 'f') ? SCI_STYLESETFORE : SCI_STYLESETBACK;
- int color = static_cast<int>(strtol(p, nullptr, 0));
- if (*p == '#') { // #RRGGBB format; Scintilla format is 0xBBGGRR
- color = static_cast<int>(strtol(p + 1, nullptr, 16));
+ } else if ((strcmp(key, "fore") == 0 || strcmp(key, "back") == 0) &&
+ val) {
+ int msg = (*key == 'f') ? SCI_STYLESETFORE : SCI_STYLESETBACK;
+ int color = static_cast<int>(strtol(val, nullptr, 0));
+ if (*val == '#') { // #RRGGBB format; Scintilla format is 0xBBGGRR
+ color = static_cast<int>(strtol(val + 1, nullptr, 16));
color = ((color & 0xFF0000) >> 16) | (color & 0xFF00) |
((color & 0xFF) << 16); // convert to 0xBBGGRR
}
SS(sci, msg, num, color);
- } else if (streq(option, "eolfilled") || streq(option, "noteolfilled"))
- SS(sci, SCI_STYLESETEOLFILLED, num, *option == 'e');
- else if (streq(option, "characterset") && p)
- SS(sci, SCI_STYLESETCHARACTERSET, num, static_cast<int>(atoi(p)));
- else if (streq(option, "case") && p) {
- if (*p == 'u')
+ } else if (strcmp(key, "eolfilled") == 0 ||
+ strcmp(key, "noteolfilled") == 0)
+ SS(sci, SCI_STYLESETEOLFILLED, num, *key == 'e');
+ else if (strcmp(key, "characterset") == 0 && val)
+ SS(sci, SCI_STYLESETCHARACTERSET, num, static_cast<int>(atoi(val)));
+ else if (strcmp(key, "case") == 0 && val) {
+ if (*val == 'u')
SS(sci, SCI_STYLESETCASE, num, SC_CASE_UPPER);
- else if (*p == 'l')
+ else if (*val == 'l')
SS(sci, SCI_STYLESETCASE, num, SC_CASE_LOWER);
- } else if (streq(option, "visible") || streq(option, "notvisible"))
- SS(sci, SCI_STYLESETVISIBLE, num, *option == 'v');
- else if (streq(option, "changeable") || streq(option, "notchangeable"))
- SS(sci, SCI_STYLESETCHANGEABLE, num, *option == 'c');
- else if (streq(option, "hotspot") || streq(option, "nothotspot"))
- SS(sci, SCI_STYLESETHOTSPOT, num, *option == 'h');
- option = next;
+ } else if (strcmp(key, "visible") == 0 || strcmp(key, "notvisible") == 0)
+ SS(sci, SCI_STYLESETVISIBLE, num, *key == 'v');
+ else if (strcmp(key, "changeable") == 0 ||
+ strcmp(key, "notchangeable") == 0)
+ SS(sci, SCI_STYLESETCHANGEABLE, num, *key == 'c');
+ else if (strcmp(key, "hotspot") == 0 || strcmp(key, "nothotspot") == 0)
+ SS(sci, SCI_STYLESETHOTSPOT, num, *key == 'h');
+ key = next;
}
free(style_copy);
}
@@ -316,9 +316,11 @@ class LexerLPeg : public ILexer {
* for all defined styles.
*/
bool SetStyles() {
+ //int orig_stack_top = lua_gettop(L);
// If the lexer defines additional styles, set their properties first (if
// the user has not already defined them).
- l_getlexerfield(L, "_EXTRASTYLES");
+ lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+ lua_getfield(L, -1, "_EXTRASTYLES");
lua_pushnil(L);
while (lua_next(L, -2)) {
if (lua_isstring(L, -2) && lua_isstring(L, -1)) {
@@ -332,30 +334,32 @@ class LexerLPeg : public ILexer {
}
lua_pop(L, 1); // _EXTRASTYLES
- l_getlexerfield(L, "_TOKENSTYLES");
if (!SS || !sci) {
- lua_pop(L, 1); // _TOKENSTYLES
+ lua_pop(L, 1); // lexer object
// Skip, but do not report an error since `reinit` would remain `false`
// and subsequent calls to `Lex()` and `Fold()` would repeatedly call this
// function and error.
+ //assert(lua_gettop(L) == orig_stack_top);
return true;
}
- lua_pushstring(L, "style.default"), lL_getexpanded(L, -1);
+ lua_pushstring(L, "style.default"), expand_property(L);
SetStyle(STYLE_DEFAULT, lua_tostring(L, -1));
- lua_pop(L, 2); // style and "style.default"
+ lua_pop(L, 1); // style
SS(sci, SCI_STYLECLEARALL, 0, 0); // set default styles
+ lua_getfield(L, -1, "_TOKENSTYLES");
lua_pushnil(L);
while (lua_next(L, -2)) {
if (lua_isstring(L, -2) && lua_isnumber(L, -1) &&
lua_tointeger(L, -1) != STYLE_DEFAULT) {
lua_pushstring(L, "style."), lua_pushvalue(L, -3), lua_concat(L, 2);
- lL_getexpanded(L, -1), lua_replace(L, -2);
+ expand_property(L);
SetStyle(lua_tointeger(L, -2), lua_tostring(L, -1));
lua_pop(L, 1); // style
}
lua_pop(L, 1); // value
}
- lua_pop(L, 1); // _TOKENSTYLES
+ lua_pop(L, 2); // _TOKENSTYLES, lexer object
+ //assert(lua_gettop(L) == orig_stack_top);
return true;
}
@@ -366,16 +370,19 @@ class LexerLPeg : public ILexer {
*/
const char *GetStyleName(int style) {
if (!L) return nullptr;
+ //int orig_stack_top = lua_gettop(L);
const char *name = nullptr;
- l_getlexerfield(L, "_TOKENSTYLES");
+ lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+ lua_getfield(L, -1, "_TOKENSTYLES");
lua_pushnil(L);
while (lua_next(L, -2))
if (lua_tointeger(L, -1) == style) {
- name = lua_tostring(L, -2);
+ name = lua_tostring(L, -2); // no need to copy; will remain in memory
lua_pop(L, 2); // value and key
break;
} else lua_pop(L, 1); // value
- lua_pop(L, 1); // _TOKENSTYLES
+ lua_pop(L, 2); // _TOKENSTYLES, lexer object
+ //assert(lua_gettop(L) == orig_stack_top);
return name;
}
@@ -389,13 +396,19 @@ class LexerLPeg : public ILexer {
props.GetExpanded("lexer.name", lexer);
props.GetExpanded("lexer.lpeg.color.theme", theme);
if (!*home || !*lexer || !L) return false;
+ //int orig_stack_top = lua_gettop(L);
- lua_pushlightuserdata(L, reinterpret_cast<void *>(&props));
- lua_setfield(L, LUA_REGISTRYINDEX, "sci_props");
+ // Designate the currently running LexerLPeg instance.
+ // This needs to be done prior to calling any Lua lexer code, particularly
+ // when `own_lua` is `false`, as there may be multiple LexerLPeg instances
+ // floating around, and the lexer module methods and metamethods need to
+ // know which instance to use.
+ lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
+ lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
// If necessary, load the lexer module and theme.
- lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"), lua_getfield(L, -1, "lexer");
- if (lua_isnil(L, -1)) {
+ lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
+ if (lua_getfield(L, -1, "lexer") == LUA_TNIL) {
lua_pop(L, 2); // nil and _LOADED
// Modify `package.path` to find lexers.
@@ -407,25 +420,18 @@ class LexerLPeg : public ILexer {
// Load the lexer module.
lua_getglobal(L, "require");
lua_pushstring(L, "lexer");
- if (lua_pcall(L, 1, 1, 0) != LUA_OK) return (l_error(L), false);
- l_setfunction(L, l_line_from_position, "line_from_position");
- l_setconstant(L, SC_FOLDLEVELBASE, "FOLD_BASE");
- l_setconstant(L, SC_FOLDLEVELWHITEFLAG, "FOLD_BLANK");
- l_setconstant(L, SC_FOLDLEVELHEADERFLAG, "FOLD_HEADER");
- l_setmetatable(L, "sci_lexer", llexer_property);
- if (*theme) {
- // Load the theme.
- if (!(strstr(theme, "/") || strstr(theme, "\\"))) { // theme name
- lua_pushstring(L, home);
- lua_pushstring(L, "/themes/");
- lua_pushstring(L, theme);
- lua_pushstring(L, ".lua");
- lua_concat(L, 4);
- } else lua_pushstring(L, theme); // path to theme
- if (luaL_loadfile(L, lua_tostring(L, -1)) != LUA_OK ||
- lua_pcall(L, 0, 0, 0) != LUA_OK) return (l_error(L), false);
- lua_pop(L, 1); // theme
+ if (lua_pcall(L, 1, 1, 0) != LUA_OK) return (log_error(L), false);
+ lua_pushinteger(L, SC_FOLDLEVELBASE);
+ lua_setfield(L, -2, "FOLD_BASE");
+ lua_pushinteger(L, SC_FOLDLEVELWHITEFLAG);
+ lua_setfield(L, -2, "FOLD_BLANK");
+ lua_pushinteger(L, SC_FOLDLEVELHEADERFLAG);
+ lua_setfield(L, -2, "FOLD_HEADER");
+ if (luaL_newmetatable(L, "sci_lexer")) {
+ lua_pushcfunction(L, lexer_index), lua_setfield(L, -2, "__index");
+ lua_pushcfunction(L, lexer_newindex), lua_setfield(L, -2, "__newindex");
}
+ lua_setmetatable(L, -2);
// Restore `package.path`.
lua_getglobal(L, "package");
@@ -435,21 +441,33 @@ class LexerLPeg : public ILexer {
} else lua_remove(L, -2); // _LOADED
// Load the language lexer.
- lua_getfield(L, -1, "load");
- if (lua_isfunction(L, -1)) {
- lua_pushstring(L, lexer), lua_pushnil(L), lua_pushboolean(L, 1);
- if (lua_pcall(L, 3, 1, 0) != LUA_OK) return (l_error(L), false);
- } else return (l_error(L, "'lexer.load' function not found"), false);
- lua_getfield(L, LUA_REGISTRYINDEX, "sci_lexers");
- lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
- lua_pushvalue(L, -3), lua_settable(L, -3), lua_pop(L, 1); // sci_lexers
- lua_pushvalue(L, -1), lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_obj");
+ if (lua_getfield(L, -1, "load") != LUA_TFUNCTION)
+ return (log_error(L, "'lexer.load' function not found"), false);
+ lua_pushstring(L, lexer), lua_pushnil(L), lua_pushboolean(L, 1);
+ if (lua_pcall(L, 3, 1, 0) != LUA_OK) return (log_error(L), false);
lua_remove(L, -2); // lexer module
+ lua_pushlightuserdata(L, reinterpret_cast<void *>(&props));
+ lua_setfield(L, -2, "_PROPS");
+ lua_rawsetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+
+ // Load the theme and set up styles.
+ if (*theme) {
+ if (!(strstr(theme, "/") || strstr(theme, "\\"))) { // theme name
+ lua_pushstring(L, home);
+ lua_pushstring(L, "/themes/");
+ lua_pushstring(L, theme);
+ lua_pushstring(L, ".lua");
+ lua_concat(L, 4);
+ } else lua_pushstring(L, theme); // path to theme
+ if (luaL_loadfile(L, lua_tostring(L, -1)) != LUA_OK ||
+ lua_pcall(L, 0, 0, 0) != LUA_OK) return (log_error(L), false);
+ lua_pop(L, 1); // theme
+ }
if (!SetStyles()) return false;
// If the lexer is a parent, it will have children in its _CHILDREN table.
- lua_getfield(L, -1, "_CHILDREN");
- if (lua_istable(L, -1)) {
+ lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+ if (lua_getfield(L, -1, "_CHILDREN") == LUA_TTABLE) {
multilang = true;
// Determine which styles are language whitespace styles
// ([lang]_whitespace). This is necessary for determining which language
@@ -460,10 +478,11 @@ class LexerLPeg : public ILexer {
ws[i] = strstr(style_name, "whitespace") ? true : false;
}
}
- lua_pop(L, 2); // _CHILDREN and lexer object
+ lua_pop(L, 2); // _CHILDREN, lexer object
reinit = false;
props.Set("lexer.lpeg.error", "", strlen("lexer.lpeg.error"), 0);
+ //assert(lua_gettop(L) == orig_stack_top);
return true;
}
@@ -489,14 +508,19 @@ public:
fprintf(stderr, "Lua failed to initialize.\n");
return;
}
- l_openlib(luaopen_base, LUA_BASELIBNAME);
- l_openlib(luaopen_table, LUA_TABLIBNAME);
- l_openlib(luaopen_string, LUA_STRLIBNAME);
#if LUA_VERSION_NUM < 502
- l_openlib(luaopen_io, LUA_IOLIBNAME); // for `package.searchpath()`
+ luaL_requiref(L, "", luaopen_base, 1), lua_pop(L, 1);
+#else
+ luaL_requiref(L, "_G", luaopen_base, 1), lua_pop(L, 1);
+#endif
+ luaL_requiref(L, LUA_TABLIBNAME, luaopen_table, 1), lua_pop(L, 1);
+ luaL_requiref(L, LUA_STRLIBNAME, luaopen_string, 1), lua_pop(L, 1);
+#if LUA_VERSION_NUM < 502
+ // `package.searchpath()` emulation requires io.
+ luaL_requiref(L, LUA_IOLIBNAME, luaopen_io, 1), lua_pop(L, 1);
#endif
- l_openlib(luaopen_package, LUA_LOADLIBNAME);
- l_openlib(luaopen_lpeg, "lpeg");
+ luaL_requiref(L, LUA_LOADLIBNAME, luaopen_package, 1), lua_pop(L, 1);
+ luaL_requiref(L, "lpeg", luaopen_lpeg, 1), lua_pop(L, 1);
#if _WIN32
lua_pushboolean(L, 1), lua_setglobal(L, "WIN32");
#endif
@@ -509,7 +533,6 @@ public:
#if CURSES
lua_pushboolean(L, 1), lua_setglobal(L, "CURSES");
#endif
- lua_newtable(L), lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexers");
}
/** Destructor. */
@@ -520,9 +543,8 @@ public:
if (own_lua && L)
lua_close(L);
else if (!own_lua) {
- lua_getfield(L, LUA_REGISTRYINDEX, "sci_lexers");
- lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
- lua_pushnil(L), lua_settable(L, -3), lua_pop(L, 1); // sci_lexers
+ lua_pushnil(L);
+ lua_rawsetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
}
delete this;
}
@@ -545,25 +567,25 @@ public:
styler.Flush();
return;
}
- lua_pushlightuserdata(L, reinterpret_cast<void *>(&props));
- lua_setfield(L, LUA_REGISTRYINDEX, "sci_props");
+ //int orig_stack_top = lua_gettop(L);
+ lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
+ lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+ lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
lua_pushlightuserdata(L, reinterpret_cast<void *>(buffer));
- lua_setfield(L, LUA_REGISTRYINDEX, "sci_buffer");
+ lua_setfield(L, -2, "_BUFFER");
// Ensure the lexer has a grammar.
// This could be done in the lexer module's `lex()`, but for large files,
// passing string arguments from C to Lua is expensive.
- l_getlexerfield(L, "_GRAMMAR");
- int has_grammar = !lua_isnil(L, -1);
- lua_pop(L, 1); // _GRAMMAR
- if (!has_grammar) {
+ if (!lua_getfield(L, -1, "_GRAMMAR")) {
+ lua_pop(L, 2); // _GRAMMAR, lexer object
// Style everything in the default style.
styler.StartAt(startPos);
styler.StartSegment(startPos);
styler.ColourTo(startPos + lengthDoc - 1, STYLE_DEFAULT);
styler.Flush();
return;
- }
+ } else lua_pop(L, 1); // _GRAMMAR
// Start from the beginning of the current style so LPeg matches it.
// For multilang lexers, start at whitespace since embedded languages have
@@ -577,42 +599,42 @@ public:
lengthDoc += startPos - i, startPos = i;
}
- Sci_PositionU startSeg = startPos, endSeg = startPos + lengthDoc;
- int style = 0;
- l_getlexerfield(L, "lex")
- if (lua_isfunction(L, -1)) {
- l_getlexerobj(L);
- lua_pushlstring(L, buffer->BufferPointer() + startPos, lengthDoc);
- lua_pushinteger(L, styler.StyleAt(startPos));
- if (lua_pcall(L, 3, 1, 0) != LUA_OK) l_error(L);
- // Style the text from the token table returned.
- if (lua_istable(L, -1)) {
- int len = lua_rawlen(L, -1);
- if (len > 0) {
- styler.StartAt(startPos);
- styler.StartSegment(startPos);
- l_getlexerfield(L, "_TOKENSTYLES");
- // Loop through token-position pairs.
- for (int i = 1; i < len; i += 2) {
- style = STYLE_DEFAULT;
- lua_rawgeti(L, -2, i), lua_rawget(L, -2); // _TOKENSTYLES[token]
- if (!lua_isnil(L, -1)) style = lua_tointeger(L, -1);
- lua_pop(L, 1); // _TOKENSTYLES[token]
- lua_rawgeti(L, -2, i + 1); // pos
- unsigned int position = lua_tointeger(L, -1) - 1;
- lua_pop(L, 1); // pos
- if (style >= 0 && style <= STYLE_MAX)
- styler.ColourTo(startSeg + position - 1, style);
- else
- l_error(L, "Bad style number");
- if (position > endSeg) break;
- }
- lua_pop(L, 2); // _TOKENSTYLES and token table returned
- styler.ColourTo(endSeg - 1, style);
- styler.Flush();
- }
- } else l_error(L, "Table of tokens expected from 'lexer.lex'");
- } else l_error(L, "'lexer.lex' function not found");
+ if (lua_getfield(L, -1, "lex") != LUA_TFUNCTION)
+ return log_error(L, "'lexer.lex' function not found");
+ lua_pushvalue(L, -2);
+ lua_pushlstring(L, buffer->BufferPointer() + startPos, lengthDoc);
+ lua_pushinteger(L, styler.StyleAt(startPos));
+ if (lua_pcall(L, 3, 1, 0) != LUA_OK) return log_error(L);
+ if (!lua_istable(L, -1))
+ return log_error(L, "Table of tokens expected from 'lexer.lex'");
+ // Style the text from the token table returned.
+ int len = lua_rawlen(L, -1);
+ if (len > 0) {
+ int style = STYLE_DEFAULT;
+ styler.StartAt(startPos);
+ styler.StartSegment(startPos);
+ lua_getfield(L, -2, "_TOKENSTYLES");
+ // Loop through token-position pairs.
+ for (int i = 1; i < len; i += 2) {
+ style = STYLE_DEFAULT;
+ if (lua_rawgeti(L, -2, i), lua_rawget(L, -2))
+ style = lua_tointeger(L, -1);
+ lua_pop(L, 1); // _TOKENSTYLES[token]
+ lua_rawgeti(L, -2, i + 1); // pos
+ unsigned int position = lua_tointeger(L, -1) - 1;
+ lua_pop(L, 1); // pos
+ if (style >= 0 && style <= STYLE_MAX)
+ styler.ColourTo(startPos + position - 1, style);
+ else
+ log_error(L, "Bad style number");
+ if (position > startPos + lengthDoc) break;
+ }
+ lua_pop(L, 1); // _TOKENSTYLES
+ styler.ColourTo(startPos + lengthDoc - 1, style);
+ styler.Flush();
+ }
+ lua_pop(L, 2); // token table returned, lexer object
+ //assert(lua_gettop(L) == orig_stack_top);
}
/**
@@ -625,31 +647,33 @@ public:
void SCI_METHOD Fold(Sci_PositionU startPos, Sci_Position lengthDoc,
int, IDocument *buffer) override {
if ((reinit && !Init()) || !L) return;
- lua_pushlightuserdata(L, reinterpret_cast<void *>(&props));
- lua_setfield(L, LUA_REGISTRYINDEX, "sci_props");
+ //int orig_stack_top = lua_gettop(L);
+ lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
+ lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+ lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
lua_pushlightuserdata(L, reinterpret_cast<void *>(buffer));
- lua_setfield(L, LUA_REGISTRYINDEX, "sci_buffer");
+ lua_setfield(L, -2, "_BUFFER");
LexAccessor styler(buffer);
- l_getlexerfield(L, "fold");
- if (lua_isfunction(L, -1)) {
- l_getlexerobj(L);
- Sci_Position currentLine = styler.GetLine(startPos);
- lua_pushlstring(L, buffer->BufferPointer() + startPos, lengthDoc);
- lua_pushinteger(L, startPos);
- lua_pushinteger(L, currentLine);
- lua_pushinteger(L, styler.LevelAt(currentLine) & SC_FOLDLEVELNUMBERMASK);
- if (lua_pcall(L, 5, 1, 0) != LUA_OK) l_error(L);
- // Fold the text from the fold table returned.
- if (lua_istable(L, -1)) {
- lua_pushnil(L);
- while (lua_next(L, -2)) { // line = level
- styler.SetLevel(lua_tointeger(L, -2), lua_tointeger(L, -1));
- lua_pop(L, 1); // level
- }
- lua_pop(L, 1); // fold table returned
- } else l_error(L, "Table of folds expected from 'lexer.fold'");
- } else l_error(L, "'lexer.fold' function not found");
+ if (lua_getfield(L, -1, "fold") != LUA_TFUNCTION)
+ return log_error(L, "'lexer.fold' function not found");
+ lua_insert(L, -2);
+ Sci_Position currentLine = styler.GetLine(startPos);
+ lua_pushlstring(L, buffer->BufferPointer() + startPos, lengthDoc);
+ lua_pushinteger(L, startPos);
+ lua_pushinteger(L, currentLine);
+ lua_pushinteger(L, styler.LevelAt(currentLine) & SC_FOLDLEVELNUMBERMASK);
+ if (lua_pcall(L, 5, 1, 0) != LUA_OK) return log_error(L);
+ if (!lua_istable(L, -1))
+ return log_error(L, "Table of folds expected from 'lexer.fold'");
+ // Fold the text from the fold table returned.
+ lua_pushnil(L);
+ while (lua_next(L, -2)) { // line = level
+ styler.SetLevel(lua_tointeger(L, -2), lua_tointeger(L, -1));
+ lua_pop(L, 1); // level
+ }
+ lua_pop(L, 1); // fold table returned
+ //assert(lua_gettop(L) == orig_stack_top);
}
/** This lexer implements the original lexer interface. */
@@ -673,12 +697,13 @@ public:
if (reinit)
Init();
else if (L && SS && sci && strncmp(key, "style.", 6) == 0) {
- lua_pushlightuserdata(L, reinterpret_cast<void *>(&props));
- lua_setfield(L, LUA_REGISTRYINDEX, "sci_props");
- l_getlexerfield(L, "_TOKENSTYLES");
- lua_pushstring(L, key + 6), lua_rawget(L, -2);
- lua_pushstring(L, key), lL_getexpanded(L, -1), lua_replace(L, -2);
- if (lua_isnumber(L, -2)) {
+ //int orig_stack_top = lua_gettop(L);
+ lua_pushlightuserdata(L, reinterpret_cast<void *>(this));
+ lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexer_lpeg");
+ lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+ lua_getfield(L, -1, "_TOKENSTYLES");
+ if (lua_pushstring(L, key + 6), lua_rawget(L, -2) == LUA_TNUMBER) {
+ lua_pushstring(L, key), expand_property(L);
int style_num = lua_tointeger(L, -2);
SetStyle(style_num, lua_tostring(L, -1));
if (style_num == STYLE_DEFAULT)
@@ -686,7 +711,8 @@ public:
// Subsequent style settings will be based on the default.
SS(sci, SCI_STYLECLEARALL, 0, 0);
}
- lua_pop(L, 3); // style, style number, _TOKENSTYLES
+ lua_pop(L, 4); // style, style number, _TOKENSTYLES, lexer object
+ //assert(lua_gettop(L) == orig_stack_top);
}
return -1; // no need to re-lex
}
@@ -705,7 +731,7 @@ public:
* @return void *data
*/
void * SCI_METHOD PrivateCall(int code, void *arg) override {
- sptr_t lParam = reinterpret_cast<sptr_t>(arg);
+ auto lParam = reinterpret_cast<sptr_t>(arg);
const char *val = nullptr;
switch(code) {
case SCI_GETDIRECTFUNCTION:
@@ -717,10 +743,6 @@ public:
case SCI_CHANGELEXERSTATE:
if (own_lua) lua_close(L);
L = reinterpret_cast<lua_State *>(lParam);
- lua_getfield(L, LUA_REGISTRYINDEX, "sci_lexers");
- if (lua_isnil(L, -1))
- lua_newtable(L), lua_setfield(L, LUA_REGISTRYINDEX, "sci_lexers");
- lua_pop(L, 1); // sci_lexers or nil
own_lua = false;
return nullptr;
case SCI_SETLEXERLANGUAGE:
@@ -735,7 +757,9 @@ public:
return nullptr;
case SCI_GETLEXERLANGUAGE:
if (L) {
- l_getlexerfield(L, "_NAME");
+ //int orig_stack_top = lua_gettop(L);
+ lua_rawgetp(L, LUA_REGISTRYINDEX, reinterpret_cast<void *>(this));
+ lua_getfield(L, -1, "_NAME");
if (SS && sci && multilang) {
int pos = SS(sci, SCI_GETCURRENTPOS, 0, 0);
while (pos >= 0 && !ws[SS(sci, SCI_GETSTYLEAT, pos, 0)]) pos--;
@@ -750,8 +774,9 @@ public:
lua_pushlstring(L, name, p - name);
lua_concat(L, 3);
}
- val = lua_tostring(L, -1);
- lua_pop(L, 1); // lexer_name or lexer language string
+ val = lua_tostring(L, -1); // no need to copy; will remain in memory
+ lua_pop(L, 2); // lexer_name or lexer language string, lexer object
+ //assert(lua_gettop(L) == orig_stack_top);
}
return StringResult(lParam, val ? val : "null");
case SCI_GETSTATUS: