mirror of
https://github.com/CCLeonOS/LeonOS.git
synced 2026-03-03 15:17:01 +00:00
feat: 初始提交 LeonOS 实现
添加 LeonOS 的基本实现,包括: - 核心 API 模块(colors, disk, gps, keys, multishell, parallel, rednet, redstone, settings, vector) - 命令行程序(about, alias, bg, clear, copy, delete, edit, fg, help, list, lua, mkdir, move, paint, peripherals, programs, reboot, set, shutdown, threads) - 系统启动脚本和包管理 - 文档(README.md, LICENSE) - 开发工具(devbin)和更新程序 实现功能: - 完整的线程管理系统 - 兼容 ComputerCraft 的 API 设计 - 改进的 shell 和命令补全系统 - 多标签终端支持 - 设置管理系统
This commit is contained in:
198
data/computercraft/lua/rom/modules/main/edit/syntax.lua
Normal file
198
data/computercraft/lua/rom/modules/main/edit/syntax.lua
Normal file
@@ -0,0 +1,198 @@
|
||||
-- A simple, fairly clever method of tokenizing code.
|
||||
-- Each token is defined by a set of rules. These rules are
|
||||
-- accordingly defined in the relevant syntax definition file.
|
||||
-- A rule takes the form of a triplet of functions:
|
||||
-- - The first function takes a single character, and returns
|
||||
-- whether that character is valid as part of the corresponding
|
||||
-- token.
|
||||
-- - The second function takes a single character and the current
|
||||
-- token, and returns whether that character is valid as part
|
||||
-- of the token. This allows flexible implementations of highly
|
||||
-- language-specific features such as strings.
|
||||
-- - The third function takes only a token, and returns whether
|
||||
-- that token is valid.
|
||||
--
|
||||
-- Multiple tokens may be evaluated in parallel and the longest is returned.
|
||||
|
||||
local lib = {}
|
||||
|
||||
local syntenv = {
|
||||
char = function(str)
|
||||
return {
|
||||
function(c)
|
||||
return c == str:sub(1,1)
|
||||
end,
|
||||
function(tk, c)
|
||||
return tk .. c == str:sub(1, #tk + 1)
|
||||
end,
|
||||
function(tk)
|
||||
return tk == str
|
||||
end
|
||||
}
|
||||
end,
|
||||
print = print,
|
||||
string = string, table = table,
|
||||
pairs = pairs, ipairs = ipairs,
|
||||
tonumber = tonumber, math = math,
|
||||
globalenv = _G, type = type,
|
||||
}
|
||||
|
||||
-- basic ""reader""
|
||||
local function reader(text)
|
||||
local chars = {}
|
||||
for c in text:gmatch(".") do
|
||||
chars[#chars+1] = c
|
||||
end
|
||||
|
||||
local i = 0
|
||||
return {
|
||||
advance = function()
|
||||
i = i + 1
|
||||
return chars[i]
|
||||
end,
|
||||
backpedal = function()
|
||||
i = math.max(0, i - 1)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
-- Takes a file and returns a builder.
|
||||
function lib.new(file)
|
||||
local definitions = assert(loadfile(file, "t", syntenv))()
|
||||
|
||||
for _, _defs in pairs(definitions) do
|
||||
for i, ent in pairs(_defs) do
|
||||
if type(ent) == "string" then
|
||||
_defs[i] = syntenv.char(ent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return function(text)
|
||||
local read = reader(text)
|
||||
local possibilities = {}
|
||||
local aux = ""
|
||||
|
||||
-- find and return the most likely (aka, longest) token and its class
|
||||
local function most_likely()
|
||||
-- if there are no possibilities, then ...
|
||||
if #possibilities == 0 then
|
||||
-- ... if the aux value has some characters, return that ...
|
||||
if #aux > 0 then
|
||||
local result = aux
|
||||
aux = ""
|
||||
return result
|
||||
else
|
||||
-- ... otherwise return nil.
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
local former_longest, new_longest = 0, 0
|
||||
|
||||
-- remove all invalid possibilites
|
||||
for i=#possibilities, 1, -1 do
|
||||
if not possibilities[i].valid(possibilities[i].token) then
|
||||
former_longest = math.max(#possibilities[i].token, former_longest)
|
||||
table.remove(possibilities, i)
|
||||
else
|
||||
new_longest = math.max(#possibilities[i].token, new_longest)
|
||||
end
|
||||
end
|
||||
|
||||
if former_longest > new_longest then
|
||||
for _=new_longest, former_longest - 1 do
|
||||
read.backpedal()
|
||||
end
|
||||
end
|
||||
|
||||
-- sort possibilities by length - and deprioritize whitespace/word
|
||||
table.sort(possibilities, function(a, b)
|
||||
return #a.token > #b.token
|
||||
or (#a.token == #b.token and b.class == "word")
|
||||
or b.class == "whitespace"
|
||||
end)
|
||||
|
||||
if #possibilities == 0 then
|
||||
--read.backpedal()
|
||||
return most_likely()
|
||||
end
|
||||
|
||||
-- grab the first (longest) one
|
||||
local token, class = possibilities[1].token, possibilities[1].class
|
||||
-- reset possibilities
|
||||
possibilities = {}
|
||||
|
||||
aux = ""
|
||||
|
||||
-- return it
|
||||
return token, class
|
||||
end
|
||||
|
||||
-- return an iterator!
|
||||
return function()
|
||||
while true do
|
||||
local c = read.advance()
|
||||
|
||||
-- if no character, return the most likely token
|
||||
if not c then return most_likely() end
|
||||
|
||||
if #possibilities == 0 then
|
||||
-- if no current possibilities, then go through and check for them
|
||||
for class, defs in pairs(definitions) do
|
||||
for _, funcs in pairs(defs) do
|
||||
if funcs[1](c) then
|
||||
-- if the token is valid, add it here
|
||||
possibilities[#possibilities+1] = {
|
||||
check = funcs[2], class = class, token = c,
|
||||
valid = funcs[3] or function()return true end, active = true
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- if there are now some possibilities, return whatever the "aux"
|
||||
-- value was
|
||||
if #possibilities > 0 then
|
||||
if #aux > 0 then
|
||||
local temp = aux--:sub(1,-2)
|
||||
aux = ""
|
||||
return temp
|
||||
end
|
||||
aux = c
|
||||
else
|
||||
-- otherwise, add c to the aux value
|
||||
aux = aux .. c
|
||||
end
|
||||
else
|
||||
aux = aux .. c
|
||||
-- whether any possibilities matched
|
||||
local valid_for_any = false
|
||||
|
||||
for _, p in ipairs(possibilities) do
|
||||
-- 'active' is roughly equal to whether the last character matched
|
||||
if p.active then
|
||||
-- if valid, set valid_for_any to true and add c to its valid
|
||||
if p.check(p.token, c) then
|
||||
valid_for_any = true
|
||||
p.token = p.token .. c
|
||||
else
|
||||
-- otherwise, disable it from future checks
|
||||
p.active = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- if nothing was valid, retract the current character
|
||||
-- and return the most likely token
|
||||
if not valid_for_any then
|
||||
read.backpedal()
|
||||
return most_likely()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return lib
|
||||
Reference in New Issue
Block a user