Lua 语言介绍

                   罗进
       luojinlj@gmail.com
简单、高效、易移植、易嵌入

                             C/C++


      Objective-C



                                                     .Net

                                                                     Awesome
   Java
                                                            Fortan



                                                     LuaPerl

          Erlang

                                     RubyLuaBridge

                    Lunatic Python
                                      Numeric Lua
了解从比较开始
                Lua5.1              Python2.6         Ruby1.9
生日              1993                1989              1995
籍贯              巴西                  荷兰                日本
安装 http         luarocks            easyinstall       gem
交互 console      ilua                ipython           irb
注释              --                  #                 #
程序库             少                   多多                多
类型数量            8                   37                >50
虚拟机 VM          基于寄存器               基于栈               基于栈
体积 win dll      120k, 可裁剪           2.155M            1.983M
速度 mandelbrot   GCC(0.41ms)         Java(4.96ms)      PHP(9.19ms)
( 分形图形 )        1.94ms              11.85ms           29.71ms
JIT 即时编译        LuaJIT     ~ x150   Pypy      ~ x20   Rubinius   ~ x20
简单: 8 种类型
•   string :” abcdfeg” , 0 结尾
•   nil : null
•   boolean : true , false
•   number :统一 short,integer,float 到 double
•   function :带有逻辑的变量
    local f = function (x) return x*x, x*x*x end
    f(2) --4, 8
• userdata : C 指针,用户自定义类型
• thread :非抢占式协程 coroutine
• table : hash 表,统一了序列式和关联式容器,索引从 1 开始
    t1 = {1,2,3}   t2= {s=“abs”,n=1.2,f=function(x) return x end}
    t1[2] --2      t2.s --abs t2.n --1.2 t2.f(2) –2
只有 string, table, function, thread4 中类型分配在堆上,需要 GC 回收,其他类型分配在栈上
简单:基于原型的面向对象
                                   metatable
String = {}
function String:new(s)
  return setmetatable({value = s or ''}, {__index = String})
end
function String:print() print(self.value) end
function String:print2() print(self.value) end
String:new(‘hello ’):print() --hello

-- inheritance
Child=String:new(‘inheritance’)
function Child:print() print(‘child of string: ’ .. self.value) end
c = setmetatable({}, {__index = Child}}
c:print() -- child of string: inheritance
c:print2() -- inheritance
简单: Coroutines 非抢占式多任务
下载文件从指定地址                                              test

threads = {} -- list of all live threads               host = "www.w3.org"
function get (host, file) -- create coroutine
  co = coroutine.create(function()                     get(host, "/…/html40.txt")
    …                                                  get(host, "/…/xhtml1.pdf")
    if status == "timeout" then                        get(host, "/../html.html")
       coroutine.yield(connection)
    end                                                dispatch() -- main loop
  end)
  table.insert(threads, co)
end

function dispatch ()
  while true do
    if threads[i] == nil then -- no more threads?      将底层细节和多状态模式
      …                                                屏蔽,使得逻辑流畅易懂
    local status, res = coroutine.resume(threads[i])
                                                       提高了工业强度
    if not res then table.remove(threads, i) end
  end
                                                       调度可控,显式优于隐式
end
高效:基于寄存器 VM , LuaJIT
基于寄存器 4 条指令                        基于栈       11 条指令
local a,t,i 1: LOADNIL   0 2 0     local a,t,i 1:   PUSHNIL      3
a=a+i       2: ADD       0 0 2     a=a+i       2:   GETLOCAL     0 ; a
                                               3:   GETLOCAL     2 ; i
                                               4:   ADD
                                               5:   SETLOCAL     0 ; a
a=a+1      3: ADD        0 0 250   a=a+1       6:   GETLOCAL     0 ; a
                                               7:   ADDI 1
                                               8:   SETLOCAL     0   ;   a
a=t[i]     4: GETTABLE 0 1 2       a=t[i]      9:   GETLOCAL     1   ;   t
                                              10:   GETINDEXED   2   ;   i
                                              11:   SETLOCAL     0   ;   a



LuaJIT
解释器使用自定义字节码格式
直接派发,替代了以前的 switch
用汇编重写
易移植 易嵌入: Lua 虚拟机快
       照
lua_State    lua_State
  stack        stack
  callinfo     callinfo




                          global_State MM GC
易移植 易嵌入: Lua 虚拟机结
       构
      C Library
易嵌入: Lua 虚拟机的栈                                                 与宿主程序交互



 struct lua_State {
                                      C API           正 逆             栈 lua_State
  global_State *l_G;                                  索 索               statck
                                                      引 引
   StkId stack;               lua_pushlightuserdata   6   -1   <…>
   StkId top;
                              lua_getglobal           5   -2   (cfunction)
   StkId base;
 …                            lua_pushcfunction                0x20120729
 };                           lua_newtable            4   -3   (table)
                              lua_rawseti                      {‘lua,’ ’pyton’,’ruby’}
/*Function Prototypes*/       lua_pushstring          3   -4   (string)
struct Proto {                lua_tostring                     “script language”
  TValue *k; /*constants */   lua_pushboolean         2   -5   true
  Instruction *code;
                              lua_pushnumber          1   -6   123
 Tstring **upvalues;          lua_tonumber
 /*inside funcs*/
                                                               function(Lua)
 struct Proto **p;
…
};
嵌入示例 在栈上交互调用
C 宿主程序 test.c                                                        Lua 嵌入脚本 test.lua
#include <lua.h>                                                     function lua_func(x)
static int c_func (lua_State *L) {                                     if x<= 1 then
  double d = lua_tonumber(L, 1); /* get argument */                       return 1
  lua_pushnumber(L, sqrt(d)); /* push result */                        end
  return 1; /* number of results */                                    return ((lua_func(x-2))+
}                                                                                lua_func((x-1)))
static int register_c_func (lua_State *L, const char *func_name) {   end
  lua_pushcfunction(l, c_func);
  lua_setglobal(l, func_name);                                       function lua_call_c(x)
}                                                                      return c_func(x)
static int call_lua_func (lua_State *L, const char *func_name) {     end
  lua_getglobal(L, func_name);/*get lua function by name*/
  lua_pushnumber(L, 1); /*push argument in local stack*/             --test
  lua_pcall(L, 1, 1, 0); /*call function*/                           local fibonacci = lua_func
  return lua_tointeger(L, 1); /*get result from local stack*/        for i = 0, 10 do
}                                                                       print(fibonacci (i))
int main(int argc, char* argv[]) {                                   end
  lua_State *L = luaL_newstate(); /*1.create interpreter*/
  luaL_openlibs(L);                   /*2.register standard libs*/   local sqrt= lua_call_c
  register_c_func (L, “c_func“); /*3.register callback function*/    for i = 0, 10 do
  luaL_dofile(L, “test.lua”);          /*4.load script file*/          print(sqrt(i))
  call_lua_func (L, “lua_func”);       /*5. call lua function*/      end
  lua_close(L);                        /*6. bye Lua*/
}
嵌入示例 Lua and C array 共享同一内
                                                     存
struct CArray {                                            CArray * new_CArray (lua_State *L, …){
   size_t size;                                              …
   size_t elemsize;//1:char,2;short,4:int,8:double           CArray *a = (CArray*) lua_newuserdata(L, nbytes);
   float values[1];                                          …
};                                                           luaL_newmetatable(L, "CArray");
static int getarray (lua_State *L) {                         luaL_register(L, NULL, arraylib_m);
   CArray *a = (CArray*)luaL_checkudata(L, 1, “CArray");     lua_setmetatable(L, -2);
   size_t idx= luaL_checkint(L, 2) - 1;                      lua_setglobal(L, array_name);
   luaL_argcheck(L, 0 <= idx …, 2, “error …");               return a;
   …                                                       }
   lua_pushinteger(L, (int*)(a->values)[index]);           CArray *a1 = new_CArray(L, “a1", 200, “int”);
   return 1;                                               CArray *a2 = new_CArray(L, “a2", 100, “double”);
}
                                                           --------------------------------------------------
static const struct luaL_Reg arraylib_m [] = {             Test.lua
   {"__newindex", setarray},                               for i = 1, 10 do
   {"__index", getarray},                                     print(a1(i), a2[i])
   {"__call", array_call},                                    a1[i] , a2[i] = i, i
   {NULL, NULL}                                               print(a1(i), a2[i])
};                                                         end

 将新建的 userdata 附上 metatable(struct luaL_Reg) ,
 就可以在 Lua 中基于对象编程了,实际使用的是宿主函数
Lua 咋个像?


  谢谢

Lua 语言介绍

  • 1.
    Lua 语言介绍 罗进 luojinlj@gmail.com
  • 2.
    简单、高效、易移植、易嵌入 C/C++ Objective-C .Net Awesome Java Fortan LuaPerl Erlang RubyLuaBridge Lunatic Python Numeric Lua
  • 3.
    了解从比较开始 Lua5.1 Python2.6 Ruby1.9 生日 1993 1989 1995 籍贯 巴西 荷兰 日本 安装 http luarocks easyinstall gem 交互 console ilua ipython irb 注释 -- # # 程序库 少 多多 多 类型数量 8 37 >50 虚拟机 VM 基于寄存器 基于栈 基于栈 体积 win dll 120k, 可裁剪 2.155M 1.983M 速度 mandelbrot GCC(0.41ms) Java(4.96ms) PHP(9.19ms) ( 分形图形 ) 1.94ms 11.85ms 29.71ms JIT 即时编译 LuaJIT ~ x150 Pypy ~ x20 Rubinius ~ x20
  • 4.
    简单: 8 种类型 • string :” abcdfeg” , 0 结尾 • nil : null • boolean : true , false • number :统一 short,integer,float 到 double • function :带有逻辑的变量 local f = function (x) return x*x, x*x*x end f(2) --4, 8 • userdata : C 指针,用户自定义类型 • thread :非抢占式协程 coroutine • table : hash 表,统一了序列式和关联式容器,索引从 1 开始 t1 = {1,2,3} t2= {s=“abs”,n=1.2,f=function(x) return x end} t1[2] --2 t2.s --abs t2.n --1.2 t2.f(2) –2 只有 string, table, function, thread4 中类型分配在堆上,需要 GC 回收,其他类型分配在栈上
  • 5.
    简单:基于原型的面向对象 metatable String = {} function String:new(s) return setmetatable({value = s or ''}, {__index = String}) end function String:print() print(self.value) end function String:print2() print(self.value) end String:new(‘hello ’):print() --hello -- inheritance Child=String:new(‘inheritance’) function Child:print() print(‘child of string: ’ .. self.value) end c = setmetatable({}, {__index = Child}} c:print() -- child of string: inheritance c:print2() -- inheritance
  • 6.
    简单: Coroutines 非抢占式多任务 下载文件从指定地址 test threads = {} -- list of all live threads host = "www.w3.org" function get (host, file) -- create coroutine co = coroutine.create(function() get(host, "/…/html40.txt") … get(host, "/…/xhtml1.pdf") if status == "timeout" then get(host, "/../html.html") coroutine.yield(connection) end dispatch() -- main loop end) table.insert(threads, co) end function dispatch () while true do if threads[i] == nil then -- no more threads? 将底层细节和多状态模式 … 屏蔽,使得逻辑流畅易懂 local status, res = coroutine.resume(threads[i]) 提高了工业强度 if not res then table.remove(threads, i) end end 调度可控,显式优于隐式 end
  • 7.
    高效:基于寄存器 VM ,LuaJIT 基于寄存器 4 条指令 基于栈 11 条指令 local a,t,i 1: LOADNIL 0 2 0 local a,t,i 1: PUSHNIL 3 a=a+i 2: ADD 0 0 2 a=a+i 2: GETLOCAL 0 ; a 3: GETLOCAL 2 ; i 4: ADD 5: SETLOCAL 0 ; a a=a+1 3: ADD 0 0 250 a=a+1 6: GETLOCAL 0 ; a 7: ADDI 1 8: SETLOCAL 0 ; a a=t[i] 4: GETTABLE 0 1 2 a=t[i] 9: GETLOCAL 1 ; t 10: GETINDEXED 2 ; i 11: SETLOCAL 0 ; a LuaJIT 解释器使用自定义字节码格式 直接派发,替代了以前的 switch 用汇编重写
  • 8.
    易移植 易嵌入: Lua虚拟机快 照 lua_State lua_State stack stack callinfo callinfo global_State MM GC
  • 9.
    易移植 易嵌入: Lua虚拟机结 构 C Library
  • 10.
    易嵌入: Lua 虚拟机的栈 与宿主程序交互 struct lua_State { C API 正 逆 栈 lua_State global_State *l_G; 索 索 statck 引 引 StkId stack; lua_pushlightuserdata 6 -1 <…> StkId top; lua_getglobal 5 -2 (cfunction) StkId base; … lua_pushcfunction 0x20120729 }; lua_newtable 4 -3 (table) lua_rawseti {‘lua,’ ’pyton’,’ruby’} /*Function Prototypes*/ lua_pushstring 3 -4 (string) struct Proto { lua_tostring “script language” TValue *k; /*constants */ lua_pushboolean 2 -5 true Instruction *code;   lua_pushnumber 1 -6 123 Tstring **upvalues; lua_tonumber /*inside funcs*/ function(Lua) struct Proto **p; … };
  • 11.
    嵌入示例 在栈上交互调用 C 宿主程序test.c Lua 嵌入脚本 test.lua #include <lua.h> function lua_func(x) static int c_func (lua_State *L) { if x<= 1 then double d = lua_tonumber(L, 1); /* get argument */ return 1 lua_pushnumber(L, sqrt(d)); /* push result */ end return 1; /* number of results */ return ((lua_func(x-2))+ } lua_func((x-1))) static int register_c_func (lua_State *L, const char *func_name) { end lua_pushcfunction(l, c_func); lua_setglobal(l, func_name); function lua_call_c(x) } return c_func(x) static int call_lua_func (lua_State *L, const char *func_name) { end lua_getglobal(L, func_name);/*get lua function by name*/ lua_pushnumber(L, 1); /*push argument in local stack*/ --test lua_pcall(L, 1, 1, 0); /*call function*/ local fibonacci = lua_func return lua_tointeger(L, 1); /*get result from local stack*/ for i = 0, 10 do } print(fibonacci (i)) int main(int argc, char* argv[]) { end lua_State *L = luaL_newstate(); /*1.create interpreter*/ luaL_openlibs(L); /*2.register standard libs*/ local sqrt= lua_call_c register_c_func (L, “c_func“); /*3.register callback function*/ for i = 0, 10 do luaL_dofile(L, “test.lua”); /*4.load script file*/ print(sqrt(i)) call_lua_func (L, “lua_func”); /*5. call lua function*/ end lua_close(L); /*6. bye Lua*/ }
  • 12.
    嵌入示例 Lua andC array 共享同一内 存 struct CArray { CArray * new_CArray (lua_State *L, …){ size_t size; … size_t elemsize;//1:char,2;short,4:int,8:double CArray *a = (CArray*) lua_newuserdata(L, nbytes); float values[1]; … }; luaL_newmetatable(L, "CArray"); static int getarray (lua_State *L) { luaL_register(L, NULL, arraylib_m); CArray *a = (CArray*)luaL_checkudata(L, 1, “CArray"); lua_setmetatable(L, -2); size_t idx= luaL_checkint(L, 2) - 1; lua_setglobal(L, array_name); luaL_argcheck(L, 0 <= idx …, 2, “error …"); return a; … } lua_pushinteger(L, (int*)(a->values)[index]); CArray *a1 = new_CArray(L, “a1", 200, “int”); return 1; CArray *a2 = new_CArray(L, “a2", 100, “double”); } -------------------------------------------------- static const struct luaL_Reg arraylib_m [] = { Test.lua {"__newindex", setarray}, for i = 1, 10 do {"__index", getarray}, print(a1(i), a2[i]) {"__call", array_call}, a1[i] , a2[i] = i, i {NULL, NULL} print(a1(i), a2[i]) }; end 将新建的 userdata 附上 metatable(struct luaL_Reg) , 就可以在 Lua 中基于对象编程了,实际使用的是宿主函数
  • 13.

Editor's Notes

  • #3 简单、高效是选择这个语言的基础。易移植、易嵌入体现在多异构平台上 Lr:Adobe photoshop LightRoom, 40% lua code, 工业级应用
  • #4 了解一个新事物从比较开始 . 编译器占体积的 30% ,可以预编译后去掉编译器减小体积。语法 pascal ,语义 scheme. 扩展:作为配置文件,为宿主语言应用提供参数 . 宿主语言使用 Lua 作为逻辑扩展,或静态链接
  • #7 共享内存,但不是抢占式 . Lua Lane 工业强度的语言,需要充足的人力资源、丰富的应用、配套工具来支撑 Actor 抽象的程度更高了
  • #9 嵌入在宿主之上的 Lua
  • #10 嵌入在宿主之上的 Lua