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
|
||||
152
data/computercraft/lua/rom/modules/main/edit/syntax/lua.lua
Normal file
152
data/computercraft/lua/rom/modules/main/edit/syntax/lua.lua
Normal file
@@ -0,0 +1,152 @@
|
||||
local syn = {
|
||||
whitespace = {
|
||||
{
|
||||
function(c)
|
||||
return c:match("[ \n\r\t]")
|
||||
end,
|
||||
function()
|
||||
return false
|
||||
end,
|
||||
function(c)
|
||||
return c:match("^[ \n\r\t]+")
|
||||
end
|
||||
},
|
||||
},
|
||||
word = {
|
||||
{
|
||||
function(c)
|
||||
return not not c:match("[a-zA-Z_]")
|
||||
end,
|
||||
function(_, c)
|
||||
return not not c:match("[a-zA-Z_0-9]")
|
||||
end
|
||||
}
|
||||
},
|
||||
keyword = {
|
||||
"const", "close", "local", "while", "for", "repeat", "until", "do", "if",
|
||||
"in", "else", "elseif", "and", "or", "not", "then", "end", "return",
|
||||
"goto", "break",
|
||||
},
|
||||
builtin = {
|
||||
"function",
|
||||
},
|
||||
separator = {
|
||||
",", "(", ")", "{", "}", "[", "]",
|
||||
},
|
||||
operator = {
|
||||
"+", "-", "/", "*", "//", "==", ">>", "<<", ">", "<", "=", "&",
|
||||
"|", "^", "%", "~", "...", "..", "~=", "#", ".", ":"
|
||||
},
|
||||
boolean = {
|
||||
"true", "false", "nil"
|
||||
},
|
||||
comment = {
|
||||
{
|
||||
function(c)
|
||||
return c == "-"
|
||||
end,
|
||||
function(t,c)
|
||||
if t == "-" and c ~= "-" then return false end
|
||||
return c ~= "\n"
|
||||
end,
|
||||
function(t)
|
||||
return #t > 1
|
||||
end
|
||||
},
|
||||
{
|
||||
function(c)
|
||||
return c == "-"
|
||||
end,
|
||||
function(t,c)
|
||||
if t == "-" and c == "-" then return true
|
||||
elseif t == "--" and c == "[" then return true
|
||||
elseif t == "--[" and c == "=" and c == "[" then return true
|
||||
elseif t:match("^%-%-%[(=*)$") and c == "=" and c == "[" then
|
||||
return true
|
||||
end
|
||||
local eqs = t:match("^%-%-%[(=*)")
|
||||
if not eqs then
|
||||
return false
|
||||
else
|
||||
if #t == #eqs + 3 and c == "[" then return true end
|
||||
if t:sub(-(#eqs+2)) == "]"..eqs.."]" then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
function(t)
|
||||
return #t > 3
|
||||
end
|
||||
}
|
||||
},
|
||||
string = {
|
||||
{
|
||||
function(c)
|
||||
return c == "'" or c == '"'
|
||||
end,
|
||||
function(t, c)
|
||||
local first = t:sub(1,1)
|
||||
local last = t:sub(#t)
|
||||
local penultimate = t:sub(-2, -2)
|
||||
if #t == 1 then return true end
|
||||
if first == last and penultimate ~= "\\" then return false end
|
||||
return true
|
||||
end
|
||||
},
|
||||
{
|
||||
function(c)
|
||||
return c == "["
|
||||
end,
|
||||
function(t,c)
|
||||
if t == "[" then
|
||||
return c == "=" or c == "["
|
||||
elseif t:match("^%[(=*)$") and (c == "=" or c == "[") then
|
||||
return true
|
||||
end
|
||||
local eqs = t:match("^%[(=*)")
|
||||
if not eqs then
|
||||
return false
|
||||
else
|
||||
if #t == #eqs + 3 and c == "[" then return true end
|
||||
if t:sub(-(#eqs+2)) == "]"..eqs.."]" then
|
||||
return false
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
end,
|
||||
function(t)
|
||||
return #t > 2
|
||||
end
|
||||
}
|
||||
},
|
||||
number = {
|
||||
{
|
||||
function(c)
|
||||
return not not tonumber(c)
|
||||
end,
|
||||
function(t, c)
|
||||
return not not tonumber(t .. c .. "0")
|
||||
end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
local seen = {}
|
||||
local function add(k, v)
|
||||
if not v then return end
|
||||
if seen[v] then return end
|
||||
seen[v] = true
|
||||
for _k, _v in pairs(v) do
|
||||
syn.builtin[#syn.builtin+1] = char((k and k.."." or "").._k)
|
||||
if type(_v) == "table" then
|
||||
add((k and k.."." or "").._k, _v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
add(nil, globalenv)
|
||||
|
||||
return syn
|
||||
Reference in New Issue
Block a user