diff options
author | 最萌小汐 <sumneko@hotmail.com> | 2019-01-08 13:51:39 +0800 |
---|---|---|
committer | 最萌小汐 <sumneko@hotmail.com> | 2019-01-08 13:51:39 +0800 |
commit | 94a2a89a87e7851c0336b1963fc1aa5afd988126 (patch) | |
tree | 5cce1ae71914deea7268a1ac9571c708f29609b2 | |
parent | ca5d53e6f5a6c8d9480d5a1f2d35c2a8d859f3a9 (diff) | |
download | lua-language-server-94a2a89a87e7851c0336b1963fc1aa5afd988126.zip |
基本完成了语法检查
-rw-r--r-- | README.md | 2 | ||||
-rw-r--r-- | server/src/parser/ast.lua | 183 | ||||
-rw-r--r-- | server/src/parser/grammar.lua | 110 |
3 files changed, 242 insertions, 53 deletions
@@ -16,7 +16,7 @@ - [x] Signature Help - [x] Document Symbols - [x] Support Dirty Script -- [ ] Syntax Check +- [x] Syntax Check - [ ] Multi Workspace - [ ] Type Format - [ ] Accurate Type Inference diff --git a/server/src/parser/ast.lua b/server/src/parser/ast.lua index 458e50c0..5efa9611 100644 --- a/server/src/parser/ast.lua +++ b/server/src/parser/ast.lua @@ -4,6 +4,7 @@ local utf8_char = utf8.char local type = type local Errs +local State local function pushError(err) if err.finish < err.start then err.finish = err.start @@ -67,6 +68,18 @@ local defs = { [1] = false, } end, + LongComment = function (beforeEq, afterEq, missPos) + if missPos then + pushError { + type = 'MISS_SYMBOL', + start = missPos, + finish = missPos, + info = { + symbol = ']' .. ('='):rep(afterEq-beforeEq) .. ']' + } + } + end + end, String = function (start, str, finish) return { type = 'string', @@ -91,7 +104,6 @@ local defs = { Char10 = function (char) char = tonumber(char) if not char or char < 0 or char > 255 then - -- TODO 记录错误 return '' end return string_char(char) @@ -136,12 +148,27 @@ local defs = { return utf8_char(v) end, Number = function (start, number, finish) - return { - type = 'number', - start = start, - finish = finish - 1, - [1] = tonumber(number), - } + local n = tonumber(number) + if n then + return { + type = 'number', + start = start, + finish = finish - 1, + [1] = n, + } + else + pushError { + type = 'MALFORMED_NUMBER', + start = start, + finish = finish - 1, + } + return { + type = 'number', + start = start, + finish = finish - 1, + [1] = 0, + } + end end, Name = function (start, str, finish) if RESERVED[str] then @@ -534,10 +561,25 @@ local defs = { action.finish = finish - 1 return action end, - Break = function () - return { - type = 'break', - } + Break = function (finish) + if State.Break > 0 then + return { + type = 'break', + } + else + pushError { + type = 'BREAK_OUTSIDE', + start = finish - #'break', + finish = finish - 1, + } + return false + end + end, + BreakStart = function () + State.Break = State.Break + 1 + end, + BreakEnd = function () + State.Break = State.Break - 1 end, Return = function (exp) if exp == nil or exp == '' then @@ -558,12 +600,54 @@ local defs = { end, Label = function (name) name.type = 'label' + local labels = State.Label[#State.Label] + local str = name[1] + if labels[str] then + pushError { + type = 'REDEFINE_LABEL', + start = name.start, + finish = name.finish, + info = { + label = str, + related = {labels[str].start, labels[str].finish}, + } + } + else + labels[str] = name + end return name end, GoTo = function (name) name.type = 'goto' + local labels = State.Label[#State.Label] + labels[#labels+1] = name return name end, + -- TODO 这里的检查不完整,但是完整的检查比较复杂,开销比较高 + -- 不能jump到另一个局部变量的作用域 + -- 函数会切断goto与label + -- 不能从block外jump到block内,但是可以从block内jump到block外 + LabelStart = function () + State.Label[#State.Label+1] = {} + end, + LabelEnd = function () + local labels = State.Label[#State.Label] + State.Label[#State.Label] = nil + for i = 1, #labels do + local name = labels[i] + local str = name[1] + if not labels[str] then + pushError { + type = 'NO_VISIBLE_LABEL', + start = name.start, + finish = name.finish, + info = { + label = str, + } + } + end + end + end, IfBlock = function (exp, start, ...) local obj = { filter = exp, @@ -876,10 +960,87 @@ local defs = { } } end, + MissDo = function (pos) + pushError { + type = 'MISS_SYMBOL', + start = pos, + finish = pos, + info = { + symbol = 'do', + } + } + end, + MissComma = function (pos) + pushError { + type = 'MISS_SYMBOL', + start = pos, + finish = pos, + info = { + symbol = ',', + } + } + end, + MissIn = function (pos) + pushError { + type = 'MISS_SYMBOL', + start = pos, + finish = pos, + info = { + symbol = 'in', + } + } + end, + MissUntil = function (pos) + pushError { + type = 'MISS_SYMBOL', + start = pos, + finish = pos, + info = { + symbol = 'until', + } + } + end, + MissThen = function (pos) + pushError { + type = 'MISS_SYMBOL', + start = pos, + finish = pos, + info = { + symbol = 'then', + } + } + end, + ExpInAction = function (start, exp, finish) + pushError { + type = 'EXP_IN_ACTION', + start = start, + finish = finish - 1, + } + return exp + end, + ActionAfterReturn = function (start, ...) + if not start or start == '' then + return + end + local actions = table.pack(...) + local max = actions.n + local finish = actions[max] + actions[max] = nil + pushError { + type = 'ACTION_AFTER_RETURN', + start = start, + finish = finish - 1, + } + return table.unpack(actions) + end, } return function (self, lua, mode) Errs = {} + State= { + Break = 0, + Label = {{}}, + } local suc, res, err = pcall(self.grammar, lua, mode, defs) if not suc then return nil, res diff --git a/server/src/parser/grammar.lua b/server/src/parser/grammar.lua index 53884fee..f8b619b8 100644 --- a/server/src/parser/grammar.lua +++ b/server/src/parser/grammar.lua @@ -89,8 +89,11 @@ end grammar 'Comment' [[ Comment <- '--' (LongComment / ShortComment) -LongComment <- '[' {:eq: '='* :} '[' CommentClose -CommentClose <- ']' =eq ']' / . CommentClose +LongComment <- ('[' {} {:eq: '='* :} {} '[' + (!CommentClose .)* + (CommentClose / {})) + -> LongComment +CommentClose <- ']' =eq ']' ShortComment <- (!%nl .)* ]] @@ -198,13 +201,17 @@ Nothing <- {} -> Nothing TOCLOSE <- Sp '*toclose' -DirtyAssign <- ASSIGN / {} -> MissAssign -DirtyBR <- BR {} / {} -> MissBR -DirtyTR <- TR {} / {} -> MissTR -DirtyPR <- PR {} / {} -> DirtyPR -DirtyLabel <- LABEL / {} -> MissLabel -MaybePR <- PR / {} -> MissPR -MaybeEnd <- END / {} -> MissEnd +DirtyBR <- BR {} / {} -> MissBR +DirtyTR <- TR {} / {} -> MissTR +DirtyPR <- PR {} / {} -> DirtyPR +DirtyLabel <- LABEL / {} -> MissLabel +NeedPR <- PR / {} -> MissPR +NeedEnd <- END / {} -> MissEnd +NeedDo <- DO / {} -> MissDo +NeedAssign <- ASSIGN / {} -> MissAssign +NeedComma <- COMMA / {} -> MissComma +NeedIn <- IN / {} -> MissIn +NeedUntil <- UNTIL / {} -> MissUntil ]] grammar 'Nil' [[ @@ -241,14 +248,14 @@ ErrNumber <- ({} {([0-9a-zA-Z] / '.')+}) Number10 <- Float10 Float10Exp? / Integer10 Float10? Float10Exp? -Integer10 <- [0-9]+ '.'? [0-9]* +Integer10 <- [0-9]+ ('.' [0-9]*)? Float10 <- '.' [0-9]+ Float10Exp <- [eE] [+-]? [0-9]+ / ({} [eE] [+-]? {}) -> MissExponent Number16 <- '0' [xX] Float16 Float16Exp? / '0' [xX] Integer16 Float16? Float16Exp? -Integer16 <- X16+ '.'? X16* +Integer16 <- X16+ ('.' X16*)? / ({} {Word*}) -> MustX16 Float16 <- '.' X16+ / '.' ({} {Word*}) -> MustX16 @@ -339,18 +346,23 @@ Table <- Sp ({} TL TableFields? DirtyTR) TableFields <- (TableSep {} / TableField)+ TableSep <- COMMA / SEMICOLON TableField <- NewIndex / NewField / Exp -NewIndex <- Sp ({} BL !BL !ASSIGN DirtyExp DirtyBR DirtyAssign DirtyExp) +NewIndex <- Sp ({} BL !BL !ASSIGN DirtyExp DirtyBR NeedAssign DirtyExp) -> NewIndex NewField <- (MustName ASSIGN DirtyExp) -> NewField Function <- Sp ({} FunctionBody {}) -> Function -FuncArg <- PL ArgList MaybePR +FuncArg <- PL ArgList NeedPR / {} -> MissPL Nothing FunctionBody<- FUNCTION FuncArg + LabelStart (!END Action)* - MaybeEnd + LabelEnd + NeedEnd + +LabelStart <- {} -> LabelStart +LabelEnd <- {} -> LabelEnd -- 纯占位,修改了 `relabel.lua` 使重复定义不抛错 Action <- !END . @@ -374,27 +386,32 @@ CrtAction <- Semicolon / Local / Set / Call - / Exp + / ExpInAction UnkAction <- ({} {Word+}) -> UnknownSymbol / ({} {. (!Sps !CrtAction .)*}) -> UnknownSymbol +ExpInAction <- Sp ({} Exp {}) + -> ExpInAction Semicolon <- SEMICOLON -> Skip SimpleList <- (Simple (COMMA Simple)*) -> List -Do <- Sp ({} DO DoBody MaybeEnd {}) +Do <- Sp ({} DO DoBody NeedEnd {}) -> Do DoBody <- (!END Action)* -> DoBody -Break <- BREAK - -> Break +Break <- BREAK {} -> Break +BreakStart <- {} -> BreakStart +BreakEnd <- {} -> BreakEnd Return <- RETURN MustExpList? -> Return + (Sp {} (!END !UNTIL !ELSEIF !ELSE Action)+ {})? + -> ActionAfterReturn Label <- LABEL MustName -> Label DirtyLabel @@ -408,18 +425,14 @@ IfHead <- (IfPart -> IfBlock) IfBody <- IfHead (ElseIfPart -> ElseIfBlock)* (ElsePart -> ElseBlock)? - MaybeEnd -IfPart <- IF Exp THEN - {} (!ELSEIF !ELSE !END Action)* {} - / IF DirtyExp THEN + NeedEnd +IfPart <- IF DirtyExp THEN {} (!ELSEIF !ELSE !END Action)* {} - / IF DirtyExp - {} {} -ElseIfPart <- ELSEIF Exp THEN - {} (!ELSE !ELSEIF !END Action)* {} - / ELSEIF DirtyExp THEN + / IF DirtyExp {}->MissThen + {} {} +ElseIfPart <- ELSEIF DirtyExp THEN {} (!ELSE !ELSEIF !END Action)* {} - / ELSEIF DirtyExp + / ELSEIF DirtyExp {}->MissThen {} {} ElsePart <- ELSE {} (!END Action)* {} @@ -429,33 +442,42 @@ For <- Loop / In Loop <- Sp ({} LoopBody {}) -> Loop -LoopBody <- FOR LoopStart LoopFinish LoopStep DO? +LoopBody <- FOR LoopStart LoopFinish LoopStep NeedDo + BreakStart (!END Action)* - MaybeEnd + BreakEnd + NeedEnd LoopStart <- MustName ASSIGN DirtyExp -LoopFinish <- COMMA? Exp - / COMMA? DirtyName -LoopStep <- COMMA DirtyExp - / COMMA? Exp +LoopFinish <- NeedComma DirtyExp +LoopStep <- COMMA DirtyExp + / NeedComma Exp / Nothing In <- Sp ({} InBody {}) -> In -InBody <- FOR NameList IN? ExpList DO? +InBody <- FOR InNameList NeedIn ExpList NeedDo + BreakStart (!END Action)* - MaybeEnd + BreakEnd + NeedEnd +InNameList <- &IN DirtyName + / NameList While <- Sp ({} WhileBody {}) -> While -WhileBody <- WHILE Exp DO +WhileBody <- WHILE DirtyExp NeedDo + BreakStart (!END Action)* - MaybeEnd + BreakEnd + NeedEnd Repeat <- Sp ({} RepeatBody {}) -> Repeat RepeatBody <- REPEAT + BreakStart (!UNTIL Action)* - UNTIL Exp + BreakEnd + NeedUntil DirtyExp Local <- (LOCAL TOCLOSE? NameList (ASSIGN ExpList)?) -> Local @@ -473,15 +495,21 @@ NamedFunction -> NamedFunction FunctionNamedBody <- FUNCTION FuncName FuncArg + LabelStart (!END Action)* - MaybeEnd + LabelEnd + NeedEnd FuncName <- (MustName (DOT MustName)* FuncMethod?) -> Simple FuncMethod <- COLON Name / COLON {} -> MissMethod ]] grammar 'Lua' [[ -Lua <- Head? Action* -> Lua Sp +Lua <- Head? + LabelStart + Action* -> Lua + LabelEnd + Sp Head <- '#' (!%nl .)* ]] |