diff --git a/content/programming/projects/muscript.tree b/content/programming/projects/muscript.tree index 07cfebc..d3a3231 100644 --- a/content/programming/projects/muscript.tree +++ b/content/programming/projects/muscript.tree @@ -261,7 +261,7 @@ - I don't know if I'll ever optimize this to be even more efficient than it already is, but source ranges are mostly irrelevant to the high level task of matching tokens, so maybe arranging the storage like - ```rs + ```rust struct Tokens { kinds: Vec, source_ranges: Vec>, diff --git a/content/treehouse/dev/syntax-highlighting.tree b/content/treehouse/dev/syntax-highlighting.tree index 2526ac6..99e5928 100644 --- a/content/treehouse/dev/syntax-highlighting.tree +++ b/content/treehouse/dev/syntax-highlighting.tree @@ -132,3 +132,64 @@ } } ``` + +- `lua` + + - patterns + ```lua + -- single-line comment + --[[ + multi-line comment + NOTE: comments with [==[ ]==] are not supported due to a lack of backreference support + in Rust regex + ]] + + 'string' "string" [[multiline + string]] + 0xABCD 0xA.B 0xAp+3 0xCE.DE5p-2 + 123 1.0 1.41e-3 1.42E+4 1.43e1 + + ... + + - * / % ^ == ~= <= >= # + funciton() ident + ``` + + - keywords + ```lua + if then else elseif end do function repeat until while for break return local in not and or goto + self + true false nil + + ``` + + - sample + ```lua + -- Ticks the scheduler: executes every active fiber, removes inactive fibers, + -- and ignores sleeping fibers. + -- + -- Extra arguments passed to this function are passed to all running fibers. + function Scheduler:tick(...) + local time = timer.getTime() + local i = 1 + while i <= #self.fibers do + local fiber = self.fibers[i] + local coro = fiber.coro + if time >= fiber.wakeAt then + local ok, result = coroutine.resume(coro, ...) + if not ok then + error("scheduler for '"..self.name.."': ".. + "ticking '"..fiber.name.."' failed with an error\n"..result) + else + if coroutine.status(coro) == "dead" then + self.fibers[i] = self.fibers[#self.fibers] + self.fibers[#self.fibers] = nil + i = i - 1 + elseif result ~= nil and result > 0 then + fiber.wakeAt = time + result + end + end + end + i = i + 1 + end + end + ``` diff --git a/crates/treehouse/src/html/highlight/tokenize.rs b/crates/treehouse/src/html/highlight/tokenize.rs index 30865ce..b90e8a2 100644 --- a/crates/treehouse/src/html/highlight/tokenize.rs +++ b/crates/treehouse/src/html/highlight/tokenize.rs @@ -51,6 +51,11 @@ impl CompiledSyntax { ); last_match_end = capture.range().end; } + push_token( + &mut tokens, + types.default, + i + last_match_end..i + whole_match.range().end, + ); i += whole_match.range().end; had_match = true; break; diff --git a/static/syntax/lua.json b/static/syntax/lua.json new file mode 100644 index 0000000..30cef12 --- /dev/null +++ b/static/syntax/lua.json @@ -0,0 +1,74 @@ +{ + "patterns": [ + { + "regex": "--\\[\\[.*?\\]\\]", + "flags": ["dotMatchesNewline"], + "is": "comment" + }, + { "regex": "--.*", "is": "comment" }, + { "regex": "'(\\\\'|[^'])*'", "is": "string" }, + { "regex": "\"(\\\\\"|[^\"])*\"", "is": "string" }, + { + "regex": "\\[\\[.+?\\]\\]", + "flags": ["dotMatchesNewline"], + "is": "string" + }, + { + "regex": "0[xX][0-9a-fA-F]+(\\.[0-9a-fA-F]*)?([pP][-+]?[0-9]+)?", + "is": "literal" + }, + { "regex": "0[xX]\\.[0-9a-fA-F]+([pP][-+]?[0-9]+)?", "is": "literal" }, + { "regex": "[0-9_]+(\\.[0-9_]*([eE][-+]?[0-9_]+)?)?", "is": "literal" }, + { + "regex": "<([a-zA-Z_][a-zA-Z0-9_]*)>", + "is": { + "default": "punct", + "captures": ["error error-attribute"] + } + }, + { "regex": "\\.\\.\\.", "is": "punct" }, + { "regex": "[+=/*^%#<>~.-]+", "is": "operator" }, + { + "regex": "([a-zA-Z_][a-zA-Z0-9_]*)\\(", + "is": { + "default": "default", + "captures": ["function"] + } + }, + { "regex": "[a-zA-Z_][a-zA-Z0-9_]*", "is": "identifier" } + ], + "keywords": { + "if": { "into": "keyword1" }, + "then": { "into": "keyword1" }, + "else": { "into": "keyword1" }, + "elseif": { "into": "keyword1" }, + "end": { "into": "keyword1" }, + "do": { "into": "keyword1" }, + "function": { "into": "keyword1" }, + "repeat": { "into": "keyword1" }, + "until": { "into": "keyword1" }, + "while": { "into": "keyword1" }, + "for": { "into": "keyword1" }, + "break": { "into": "keyword1" }, + "return": { "into": "keyword1" }, + "local": { "into": "keyword1" }, + "in": { "into": "keyword1" }, + "not": { "into": "keyword1" }, + "and": { "into": "keyword1" }, + "or": { "into": "keyword1" }, + "goto": { "into": "keyword1" }, + "self": { "into": "keyword2" }, + "true": { "into": "literal" }, + "false": { "into": "literal" }, + "nil": { "into": "literal" }, + + "close": { + "into": "keyword1", + "onlyReplaces": "error error-attribute" + }, + "const": { + "into": "keyword1", + "onlyReplaces": "error error-attribute" + } + } +}