diff options
-rw-r--r-- | server-beta/src/core/highlight.lua | 94 | ||||
-rw-r--r-- | server-beta/src/parser/ast.lua | 127 | ||||
-rw-r--r-- | server-beta/src/parser/grammar.lua | 59 | ||||
-rw-r--r-- | server-beta/src/parser/guide.lua | 2 | ||||
-rw-r--r-- | server-beta/test/highlight/init.lua | 99 |
5 files changed, 288 insertions, 93 deletions
diff --git a/server-beta/src/core/highlight.lua b/server-beta/src/core/highlight.lua index 16c82a16..8c609485 100644 --- a/server-beta/src/core/highlight.lua +++ b/server-beta/src/core/highlight.lua @@ -13,7 +13,6 @@ local function ofLocal(source, callback) end local function ofField(source, uri, callback) - callback(source) local parent = source.parent if not parent or not parent.node then return @@ -55,23 +54,96 @@ local function find(source, uri, callback) elseif source.type == 'field' or source.type == 'method' then ofField(source, uri, callback) - elseif source.type == 'string' then - ofIndex(source, uri, callback) - callback(source) - elseif source.type == 'boolean' + elseif source.type == 'string' + or source.type == 'boolean' or source.type == 'number' then ofIndex(source, uri, callback) + callback(source) + elseif source.type == 'nil' then + callback(source) elseif source.type == 'goto' or source.type == 'label' then ofLabel(source, callback) end end +local function checkInIf(source, text, offset) + -- 检查 end + local endA = source.finish - #'end' + 1 + local endB = source.finish + if offset >= endA + and offset <= endB + and text:sub(endA, endB) == 'end' then + return true + end + -- 检查每个子模块 + for _, block in ipairs(source) do + for i = 1, #block.keyword, 2 do + local start = block.keyword[i] + local finish = block.keyword[i+1] + if offset >= start and offset <= finish then + return true + end + end + end + return false +end + +local function makeIf(source, text, callback) + -- end + local endA = source.finish - #'end' + 1 + local endB = source.finish + if text:sub(endA, endB) == 'end' then + callback(endA, endB) + end + -- 每个子模块 + for _, block in ipairs(source) do + for i = 1, #block.keyword, 2 do + local start = block.keyword[i] + local finish = block.keyword[i+1] + callback(start, finish) + end + end + return false +end + +local function findKeyword(source, text, offset, callback) + if source.type == 'do' + or source.type == 'function' + or source.type == 'loop' + or source.type == 'in' + or source.type == 'while' + or source.type == 'repeat' then + local ok + for i = 1, #source.keyword, 2 do + local start = source.keyword[i] + local finish = source.keyword[i+1] + if offset >= start and offset <= finish then + ok = true + break + end + end + if ok then + for i = 1, #source.keyword, 2 do + local start = source.keyword[i] + local finish = source.keyword[i+1] + callback(start, finish) + end + end + elseif source.type == 'if' then + local ok = checkInIf(source, text, offset) + if ok then + makeIf(source, text, callback) + end + end +end + return function (uri, offset) local ast = files.getAst(uri) if not ast then return nil end + local text = files.getText(uri) local results = {} local mark = {} guide.eachSourceContain(ast.ast, offset, function (source) @@ -106,7 +178,10 @@ return function (uri, offset) or target.type == 'setglobal' or target.type == 'label' then kind = define.DocumentHighlightKind.Write - elseif target.type == 'string' then + elseif target.type == 'string' + or target.type == 'boolean' + or target.type == 'number' + or target.type == 'nil' then kind = define.DocumentHighlightKind.Text else log.warn('Unknow target.type:', target.type) @@ -122,6 +197,13 @@ return function (uri, offset) kind = kind, } end) + findKeyword(source, text, offset, function (start, finish) + results[#results+1] = { + start = start, + finish = finish, + kind = define.DocumentHighlightKind.Write + } + end) end) if #results == 0 then return nil diff --git a/server-beta/src/parser/ast.lua b/server-beta/src/parser/ast.lua index ded42891..ff5a6ae1 100644 --- a/server-beta/src/parser/ast.lua +++ b/server-beta/src/parser/ast.lua @@ -662,6 +662,9 @@ local Defs = { return e end, Binary = function (first, op, second, ...) + if not first then + return second + end if not op then return first end @@ -836,20 +839,28 @@ local Defs = { finish = start, } end, - Function = function (start, args, actions, finish) + Function = function (functionStart, functionFinish, args, actions, endStart, endFinish) actions.type = 'function' - actions.start = start - actions.finish = finish - 1 + actions.start = functionStart + actions.finish = endFinish - 1 actions.args = args - checkMissEnd(start) + actions.keyword= { + functionStart, functionFinish - 1, + endStart, endFinish - 1, + } + checkMissEnd(functionStart) return actions end, - NamedFunction = function (start, name, args, actions, finish) + NamedFunction = function (functionStart, functionFinish, name, args, actions, endStart, endFinish) actions.type = 'function' - actions.start = start - actions.finish = finish - 1 + actions.start = functionStart + actions.finish = endFinish - 1 actions.args = args - checkMissEnd(start) + actions.keyword= { + functionStart, functionFinish - 1, + endStart, endFinish - 1, + } + checkMissEnd(functionStart) if not name then return end @@ -864,13 +875,18 @@ local Defs = { name.value = actions end name.range = actions.finish + name.vstart = functionStart return name end, - LocalFunction = function (start, name, args, actions, finish) + LocalFunction = function (start, functionStart, functionFinish, name, args, actions, endStart, endFinish) actions.type = 'function' actions.start = start - actions.finish = finish - 1 + actions.finish = endFinish - 1 actions.args = args + actions.keyword= { + functionStart, functionFinish - 1, + endStart, endFinish - 1, + } checkMissEnd(start) if not name then @@ -888,6 +904,7 @@ local Defs = { local loc = createLocal(name, name.start, actions) loc.localfunction = true + loc.vstart = functionStart return loc end, @@ -1126,10 +1143,14 @@ local Defs = { end return tableUnpack(keys) end, - Do = function (start, actions, finish) + Do = function (start, actions, endA, endB) actions.type = 'do' actions.start = start - actions.finish = finish - 1 + actions.finish = endB - 1 + actions.keyword= { + start, start + #'do' - 1, + endA , endB - 1, + } checkMissEnd(start) return actions end, @@ -1184,30 +1205,41 @@ local Defs = { name.type = 'goto' return name end, - IfBlock = function (start, exp, actions, finish) + IfBlock = function (ifStart, ifFinish, exp, thenStart, thenFinish, actions, finish) actions.type = 'ifblock' - actions.start = start + actions.start = ifStart actions.finish = finish - 1 actions.filter = exp + actions.keyword= { + ifStart, ifFinish - 1, + thenStart, thenFinish - 1, + } return actions end, - ElseIfBlock = function (start, exp, actions, finish) + ElseIfBlock = function (elseifStart, elseifFinish, exp, thenStart, thenFinish, actions, finish) actions.type = 'elseifblock' - actions.start = start + actions.start = elseifStart actions.finish = finish - 1 actions.filter = exp + actions.keyword= { + elseifStart, elseifFinish - 1, + thenStart, thenFinish - 1, + } return actions end, - ElseBlock = function (start, actions, finish) + ElseBlock = function (elseStart, elseFinish, actions, finish) actions.type = 'elseblock' - actions.start = start + actions.start = elseStart actions.finish = finish - 1 + actions.keyword= { + elseStart, elseFinish - 1, + } return actions end, - If = function (start, blocks, finish) + If = function (start, blocks, endStart, endFinish) blocks.type = 'if' blocks.start = start - blocks.finish = finish - 1 + blocks.finish = endFinish - 1 local hasElse for i = 1, #blocks do local block = blocks[i] @@ -1235,23 +1267,34 @@ local Defs = { checkMissEnd(start) return blocks end, - Loop = function (start, arg, steps, blockStart, block, finish) + Loop = function (forA, forB, arg, steps, doA, doB, blockStart, block, endA, endB) local loc = createLocal(arg, blockStart, steps[1]) block.type = 'loop' - block.start = start - block.finish = finish - 1 + block.start = forA + block.finish = endB - 1 block.loc = loc block.max = steps[2] block.step = steps[3] - checkMissEnd(start) + block.keyword= { + forA, forB - 1, + doA , doB - 1, + endA, endB - 1, + } + checkMissEnd(forA) return block end, - In = function (start, keys, exp, blockStart, block, finish) + In = function (forA, forB, keys, inA, inB, exp, doA, doB, blockStart, block, endA, endB) local func = tableRemove(exp, 1) block.type = 'in' - block.start = start - block.finish = finish - 1 + block.start = forA + block.finish = endB - 1 block.keys = keys + block.keyword= { + forA, forB - 1, + inA , inB - 1, + doA , doB - 1, + endA, endB - 1, + } local values if func then @@ -1270,22 +1313,31 @@ local Defs = { createLocal(loc, blockStart) end end - checkMissEnd(start) + checkMissEnd(forA) return block end, - While = function (start, filter, block, finish) + While = function (whileA, whileB, filter, doA, doB, block, endA, endB) block.type = 'while' - block.start = start - block.finish = finish - 1 + block.start = whileA + block.finish = endB - 1 block.filter = filter - checkMissEnd(start) + block.keyword= { + whileA, whileB - 1, + doA , doB - 1, + endA , endB - 1, + } + checkMissEnd(whileA) return block end, - Repeat = function (start, block, filter, finish) + Repeat = function (repeatA, repeatB, block, untilA, untilB, filter, finish) block.type = 'repeat' - block.start = start + block.start = repeatA block.finish = finish block.filter = filter + block.keyword= { + repeatA, repeatB - 1, + untilA , untilB - 1, + } return block end, Lua = function (start, actions, finish) @@ -1491,6 +1543,7 @@ local Defs = { symbol = 'end', } } + return pos, pos end, MissDo = function (pos) PushError { @@ -1501,6 +1554,7 @@ local Defs = { symbol = 'do', } } + return pos, pos end, MissComma = function (pos) PushError { @@ -1521,6 +1575,7 @@ local Defs = { symbol = 'in', } } + return pos, pos end, MissUntil = function (pos) PushError { @@ -1531,6 +1586,7 @@ local Defs = { symbol = 'until', } } + return pos, pos end, MissThen = function (pos) PushError { @@ -1541,6 +1597,7 @@ local Defs = { symbol = 'then', } } + return pos, pos end, MissName = function (pos) PushError { @@ -1639,6 +1696,7 @@ local Defs = { } } } + return start, finish end, ErrDo = function (start, finish) PushError { @@ -1654,6 +1712,7 @@ local Defs = { } } } + return start, finish end, } diff --git a/server-beta/src/parser/grammar.lua b/server-beta/src/parser/grammar.lua index 944f34ea..b64f6277 100644 --- a/server-beta/src/parser/grammar.lua +++ b/server-beta/src/parser/grammar.lua @@ -112,28 +112,30 @@ Rest <- (!%nl .)* AND <- Sp {'and'} Cut BREAK <- Sp 'break' Cut -DO <- Sp 'do' Cut - / Sp ({} 'then' Cut {}) -> ErrDo -ELSE <- Sp 'else' Cut -ELSEIF <- Sp 'elseif' Cut -END <- Sp 'end' Cut FALSE <- Sp 'false' Cut -FOR <- Sp 'for' Cut -FUNCTION <- Sp 'function' Cut GOTO <- Sp 'goto' Cut -IF <- Sp 'if' Cut -IN <- Sp 'in' Cut LOCAL <- Sp 'local' Cut NIL <- Sp 'nil' Cut NOT <- Sp 'not' Cut OR <- Sp {'or'} Cut -REPEAT <- Sp 'repeat' Cut RETURN <- Sp 'return' Cut -THEN <- Sp 'then' Cut - / Sp ({} 'do' Cut {}) -> ErrThen TRUE <- Sp 'true' Cut -UNTIL <- Sp 'until' Cut -WHILE <- Sp 'while' Cut + +DO <- Sp {} 'do' {} Cut + / Sp({} 'then' {} Cut) -> ErrDo +IF <- Sp {} 'if' {} Cut +ELSE <- Sp {} 'else' {} Cut +ELSEIF <- Sp {} 'elseif' {} Cut +END <- Sp {} 'end' {} Cut +FOR <- Sp {} 'for' {} Cut +FUNCTION <- Sp {} 'function' {} Cut +IN <- Sp {} 'in' {} Cut +REPEAT <- Sp {} 'repeat' {} Cut +THEN <- Sp {} 'then' {} Cut + / Sp({} 'do' {} Cut) -> ErrThen +UNTIL <- Sp {} 'until' {} Cut +WHILE <- Sp {} 'while' {} Cut + Esc <- '\' -> '' EChar @@ -365,7 +367,7 @@ NewIndex <- Sp ({} Index NeedAssign DirtyExp {}) NewField <- Sp ({} MustName ASSIGN DirtyExp {}) -> NewField -Function <- Sp ({} FunctionBody {}) +Function <- FunctionBody -> Function FuncArgs <- Sp ({} PL {| FuncArg+ |} DirtyPR {}) -> FuncArgs @@ -415,8 +417,7 @@ SimpleList <- {| Simple (Sp ',' Simple)* |} Do <- Sp ({} 'do' Cut {| (!END Action)* |} - NeedEnd - {}) + NeedEnd) -> Do Break <- Sp ({} BREAK {}) @@ -435,14 +436,14 @@ Label <- Sp ({} LABEL MustName DirtyLabel {}) GoTo <- Sp ({} GOTO MustName {}) -> GoTo -If <- Sp ({} {| IfHead IfBody* |} NeedEnd {}) +If <- Sp ({} {| IfHead IfBody* |} NeedEnd) -> If -IfHead <- Sp ({} IfPart {}) -> IfBlock - / Sp ({} ElseIfPart {}) -> ElseIfBlock - / Sp ({} ElsePart {}) -> ElseBlock -IfBody <- Sp ({} ElseIfPart {}) -> ElseIfBlock - / Sp ({} ElsePart {}) -> ElseBlock +IfHead <- Sp (IfPart {}) -> IfBlock + / Sp (ElseIfPart {}) -> ElseIfBlock + / Sp (ElsePart {}) -> ElseBlock +IfBody <- Sp (ElseIfPart {}) -> ElseIfBlock + / Sp (ElsePart {}) -> ElseBlock IfPart <- IF DirtyExp NeedThen {| (!ELSEIF !ELSE !END Action)* |} ElseIfPart <- ELSEIF DirtyExp NeedThen @@ -452,7 +453,7 @@ ElsePart <- ELSE For <- Loop / In -Loop <- Sp ({} LoopBody {}) +Loop <- LoopBody -> Loop LoopBody <- FOR LoopArgs NeedDo {} {| (!END Action)* |} @@ -461,7 +462,7 @@ LoopArgs <- MustName AssignOrEQ ({} {| (COMMA / !DO !END Exp)* |} {}) -> PackLoopArgs -In <- Sp ({} InBody {}) +In <- InBody -> In InBody <- FOR InNameList NeedIn InExpList NeedDo {} {| (!END Action)* |} @@ -471,13 +472,13 @@ InNameList <- ({} {| (COMMA / !IN !DO !END Name)* |} {}) InExpList <- ({} {| (COMMA / !DO !DO !END Exp)* |} {}) -> PackInExpList -While <- Sp ({} WhileBody {}) +While <- WhileBody -> While WhileBody <- WHILE DirtyExp NeedDo {| (!END Action)* |} NeedEnd -Repeat <- Sp ({} RepeatBody {}) +Repeat <- (RepeatBody {}) -> Repeat RepeatBody <- REPEAT {| (!UNTIL Action)* |} @@ -499,11 +500,11 @@ Call <- Simple -> SimpleCall LocalFunction - <- Sp ({} LOCAL FunctionNamedBody {}) + <- Sp ({} LOCAL FunctionNamedBody) -> LocalFunction NamedFunction - <- Sp ({} FunctionNamedBody {}) + <- FunctionNamedBody -> NamedFunction FunctionNamedBody <- FUNCTION FuncName FuncArgs diff --git a/server-beta/src/parser/guide.lua b/server-beta/src/parser/guide.lua index a5b8202e..4750fcaf 100644 --- a/server-beta/src/parser/guide.lua +++ b/server-beta/src/parser/guide.lua @@ -268,7 +268,7 @@ end --- --- 主要针对赋值等语句时,key包含value function m.isInRange(source, offset) - return source.start <= offset and (source.range or source.finish) >= offset - 1 + return (source.vstart or source.start) <= offset and (source.range or source.finish) >= offset - 1 end --- 添加child diff --git a/server-beta/test/highlight/init.lua b/server-beta/test/highlight/init.lua index 6298fc2e..fbde194b 100644 --- a/server-beta/test/highlight/init.lua +++ b/server-beta/test/highlight/init.lua @@ -35,58 +35,111 @@ local function founded(targets, results) end function TEST(script) - files.removeAll() local target = catch_target(script) - local start = script:find('<?', 1, true) - local finish = script:find('?>', 1, true) - local pos = (start + finish) // 2 + 1 - local new_script = script:gsub('<[!?]', ' '):gsub('[!?]>', ' ') - files.setText('', new_script) - - local positions = core('', pos) - if positions then - assert(founded(target, positions)) - else - assert(#target == 0) + for _, enter in ipairs(target) do + local start, finish = enter.start, enter.finish + files.removeAll() + local pos = (start + finish) // 2 + 1 + local new_script = script:gsub('<[!?~]', ' '):gsub('[!?~]>', ' ') + files.setText('', new_script) + + local positions = core('', pos) + if positions then + assert(founded(target, positions)) + else + assert(#target == 0) + end end end TEST [[ -local <?a?> = 1 +local <!a!> = 1 ]] TEST [[ -local <?a?> = 1 +local <!a!> = 1 <!a!> = 2 <!a!> = <!a!> ]] TEST [[ -t.<?a?> = 1 +t.<!a!> = 1 a = t.<!a!> ]] TEST [[ t[<!'a'!>] = 1 -a = t.<?a?> -]] - -TEST [[ -t[<?'a'?>] = 1 a = t.<!a!> ]] TEST [[ -:: <?a?> :: +:: <!a!> :: goto <!a!> ]] TEST [[ local function f(<!a!>) - return <?a?> + return <!a!> end ]] TEST [[ -local s = <?'asd/gadasd.fad.zxczg'?> +local s = <!'asd/gadasd.fad.zxczg'!> +]] + +TEST [[ +local b = <!true!> +]] + +TEST [[ +local n = <!nil!> +]] + +TEST [[ +local n = <!1.2354!> +]] + +TEST [[ +local <!function!> f () <!end!> +]] + +TEST [[ +<!function!> f () <!end!> +]] + +TEST [[ +return <!function!> () <!end!> +]] + +TEST [[ +<!if!> true <!then!> +<!elseif!> true <!then!> +<!elseif!> true <!then!> +<!else!> +<!end!> +]] + +TEST [[ +<!for!> _ <!in!> _ <!do!> +<!end!> +]] + +TEST [[ +<!for!> i = 1, 10 <!do!> +<!end!> +]] + +TEST [[ +<!while!> true <!do!> +<!end!> +]] + +TEST [[ +<!repeat!> +<!until!> true +]] + +TEST [[ +<!do!> +<!end!> ]] |