summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author最萌小汐 <sumneko@hotmail.com>2019-01-08 13:51:39 +0800
committer最萌小汐 <sumneko@hotmail.com>2019-01-08 13:51:39 +0800
commit94a2a89a87e7851c0336b1963fc1aa5afd988126 (patch)
tree5cce1ae71914deea7268a1ac9571c708f29609b2
parentca5d53e6f5a6c8d9480d5a1f2d35c2a8d859f3a9 (diff)
downloadlua-language-server-94a2a89a87e7851c0336b1963fc1aa5afd988126.zip
基本完成了语法检查
-rw-r--r--README.md2
-rw-r--r--server/src/parser/ast.lua183
-rw-r--r--server/src/parser/grammar.lua110
3 files changed, 242 insertions, 53 deletions
diff --git a/README.md b/README.md
index 947f773d..a6a8ad9f 100644
--- a/README.md
+++ b/README.md
@@ -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 .)*
]]