转载请注明出处。
https://code.google.com/p/lua-checker/
简介
Lua Checker是一个用来分析lua源代码的一般错误的程序,很想C语言的"lint"。以下的问题已经被定义:
- 使用未声明的变量
- 变量的多重声明
- 尝试改变常量
- 其他计划查看“future”板块
Lua Checker是谷歌Street View团队用来验证Lua脚本而编写的。Lua Checker是在Lua 5.0标准允许的。
Lua Checker包含一个bison兼容的解析器(详见
lua.y)。
背景
诸如C/C++和Java都是强类型的。这意味着每一个变量只有一种类型(比如数组、字符串或者对象),当变量被错误使用的时候,编译器会给出错误信息。所以很多问题都能尽早被发现。
相反地,Lua脚本语言是动态类型的,只有一种简单的类型模型(a simple type model)。变量可被指派为任意类型。这使得脚本语言的开发在某种程度上更加简单,但是它也意味着在一些大型程序中,很多一般的错误只有在程序运行的时候才能被发现。举例:
- 引用一个未声明的变量会返回 nil 。这和引用一个已经声明为 nil 的变量没有差别。因此,在lua脚本语言中,拼写错误不会被发现并且会导致不好的(misbehavior)程序。
- Tables(Lua主要的数据结构)没有类型(原文:Tables and not typed),所以可以包含任意键(key)。当tables被用于类似C的数据结构,拼写的错误将会导致不良的程序。
- 函数参数以及返回值也都是无类型的,有着类似的问题。
事实上,超过1000行的Lua程序tend to累积这些问题,从而使得调试变得困难。一种标准的用来处理未定义的全局变量的Lua惯例是在全局变量的table安装一个特殊的'get-value'句柄,可以警告未定的全局变量。这是有局限性的,因为仍旧只有在程序运行的时候才能发现缺陷。
Lua Checker正式用来解决这些问题的。它在程序运行前执行静态分析,并且可以发现问题并给出警告信息。
用法
为了帮助Lua Checker做这些工作,Lua源码必须被写得更加严谨。
1、所有的全局变量在使用前必须声明,如下:
但是不能像这样,即使作用是相同的:
2、通过_G table进入的全局变量可以被检查机制忽略,所以尽量不要这样做。
3、通过dofile被包含进的源文件也会被扫描,只要dofile用一个单独的字符串参数被调用在outer scope:
4、变量可以被声明为常量,只要添加了以下代码:
--@标记代表着特殊的lua checker关键字将会在同一行出现。const 关键字意味着之前的变量被声明为一个常量。之后任何对这个常量其他的操作
都被认为是错误的。注意特殊的关机子能够跟随lua注释,如下:
命令行参数
CHECK_LUA.SH是用来调用lua_checker的。它是笨拙的并且将被更好的代替。
lua_checker 程序像这样被调用:
可用的flags参数是
- -no_reuse_varnames: 在局部作用域内(inner scopes)变量名不能重用、这比很多强类型的语言更加严格,但是这可能捕获更多的错误。
- -const_functions:所有的函数变量都是常量,一下都是错误的:
实现(Implementation)
Lua Checker的有趣部分被应用在bison解析器中。两个分开的部分被使用,那在两个分开的程序中执行:
- lua_simplifier将lua源代码重写为一种相对简单的格式。简化的代码有很多语法糖扩展并且更少的句法歧义(大多数是通过在每句后加分号)。lua.y 有更详细的描述。简化的关键是为了真正的分析变得更简单。
- lua_checker 对已经简化的代码进行分析
远景(Future)
产品特色:
- 允许将tables指派为一种类型,就像C数据结构。当意外的table字段进入的时候给出警告。
- 允许函数指派参数并且返回值类型。当参数和返回值类型不匹配的时候提出警告。
- 检测从未被指派的变量。
- 检测意外的变量类型改变(比如从number到table)。
- 在局部作用与内定义新的全局函数时提出警告。
- 在函数中使用ellipses但是没有使用ellipses参数,提出警告
- Allow user-defined Lua extensions (e.g. global functions defined by the embedded Lua environment).
- 检测‘require’的模块