scanner.lua 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. --[[
  2. SaferLua [safer_lua]
  3. ====================
  4. Copyright (C) 2017-2020 Joachim Stolberg
  5. AGPL v3
  6. See LICENSE.txt for more information
  7. scanner.lua:
  8. ]]--
  9. local function trim(s)
  10. return (s:gsub("^%s*(.-)%s*$", "%1"))
  11. end
  12. function safer_lua:word(ch, pttrn)
  13. local word = ""
  14. while ch:match(pttrn) do
  15. word = word .. ch
  16. self.pos = self.pos + 1
  17. ch = self.line:sub(self.pos, self.pos)
  18. end
  19. return word
  20. end
  21. function safer_lua:string(pttrn)
  22. self.pos = self.pos + 1
  23. local ch = self.line:sub(self.pos, self.pos)
  24. while not ch:match(pttrn) and self.pos < #self.line do
  25. if ch == "\\" then
  26. self.pos = self.pos + 1
  27. end
  28. self.pos = self.pos + 1
  29. ch = self.line:sub(self.pos, self.pos)
  30. end
  31. self.pos = self.pos + 1
  32. -- result is not needed
  33. end
  34. local function lines(str)
  35. local t = {}
  36. local function helper(line)
  37. table.insert(t, line)
  38. return ""
  39. end
  40. helper((str:gsub("(.-)\r?\n", helper)))
  41. return t
  42. end
  43. function safer_lua:scanner(text)
  44. local lToken = {}
  45. for idx, line in ipairs(lines(text)) do
  46. self.line = line
  47. self.pos = 1
  48. self.line = trim(self.line)
  49. self.line = string.split(self.line, "--", true, 1)[1]
  50. table.insert(lToken, idx) -- line number
  51. if self.line then
  52. -- devide line in tokens
  53. while true do
  54. if self.pos > #self.line then break end
  55. local ch = self.line:sub(self.pos, self.pos)
  56. if ch:match("[%u%l_]") then -- identifier?
  57. table.insert(lToken, self:word(ch, "[%w_]"))
  58. elseif ch:match("[%d]") then -- number?
  59. table.insert(lToken, self:word(ch, "[%d%xx]"))
  60. elseif ch:match("'") then -- string?
  61. self:string("'")
  62. elseif ch:match('"') then -- string?
  63. self:string('"')
  64. elseif ch:match("[%s]") then -- Space?
  65. self.pos = self.pos + 1
  66. elseif ch:match("[:{}]") then -- critical tokens?
  67. table.insert(lToken,ch)
  68. self.pos = self.pos + 1
  69. else
  70. self.pos = self.pos + 1
  71. end
  72. end
  73. end
  74. end
  75. return lToken
  76. end
  77. local InvalidKeywords = {
  78. ["while"] = true,
  79. ["repeat"] = true,
  80. ["until"] = true,
  81. ["for"] = true,
  82. ["range"] = true,
  83. --["function"] = true,
  84. ["_G"] = true,
  85. ["__load"] = true,
  86. ["__dump"] = true,
  87. }
  88. local InvalidChars = {
  89. [":"] = true,
  90. ["{"] = true,
  91. ["["] = true,
  92. ["]"] = true,
  93. ["}"] = true,
  94. }
  95. function safer_lua:check(pos, text, label, err_clbk)
  96. local lToken = self:scanner(text)
  97. local lineno = 0
  98. local errno = 0
  99. for idx,token in ipairs(lToken) do
  100. if type(token) == "number" then
  101. lineno = token
  102. elseif InvalidKeywords[token] then
  103. if token == "for" then
  104. -- invalid for statement?
  105. if lToken[idx + 3] == "in" and lToken[idx + 5] == "next" then
  106. --
  107. elseif lToken[idx + 2] == "in" and lToken[idx + 3] == "range" then
  108. --
  109. else
  110. err_clbk(pos, label..":"..lineno..": Invalid use of 'for'")
  111. errno = errno + 1
  112. end
  113. elseif token == "range" then
  114. if lToken[idx - 1] ~= "in" then
  115. err_clbk(pos, label..":"..lineno..": Invalid use of 'range'")
  116. errno = errno + 1
  117. end
  118. else
  119. err_clbk(pos, label..":"..lineno..": Invalid keyword '"..token.."'")
  120. errno = errno + 1
  121. end
  122. elseif InvalidChars[token] then
  123. err_clbk(pos, label..":"..lineno..": Invalid character '"..token.."'")
  124. errno = errno + 1
  125. end
  126. end
  127. return errno
  128. end