• <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>
    • 軟件測試技術
    • 軟件測試博客
    • 軟件測試視頻
    • 開源軟件測試技術
    • 軟件測試論壇
    • 軟件測試沙龍
    • 軟件測試資料下載
    • 軟件測試雜志
    • 軟件測試人才招聘
      暫時沒有公告

    字號: | 推薦給好友 上一篇 | 下一篇

    Lua: technical note 4

    發布: 2007-7-04 20:48 | 作者: admin | 來源:  網友評論 | 查看: 41次 | 進入軟件測試論壇討論

    領測軟件測試網

    Lua Technical Note 4

    A thin API for interlanguage working, or Lua in Four Easy Calls

    by Reuben Thomas

    Abstract

    The obvious way to make Lua interwork with language L is to implement the Lua API in L, but this is daunting for the implementor, and burdens the L programmer with a verbose syntax. A simpler solution is to implement just lua_open, lua_close, lua_dobuffer and lua_register in L, expanding lua_register to do inter-language marshalling. Additional functionality can then be provided in Lua.

    The problem

    The Lua API allows a Lua state to be completely controlled from C. But what if you want to interwork with another language, L? The obvious approach, assuming that L can interwork with C, is to reflect the C API into L. However, this is a rather daunting prospect, as the Lua API is quite large and has some hidden subtleties. Also, while it is a good medium for writing extension libraries and tools for Lua, it does not lead naturally to a convenient syntax for L programmers; the Lua manual shows (see section 5.12 on p. 26 in the 4.0 edition) how the Lua statement

    a,b = f("how", t.x, 4)

    becomes ten calls to the Lua API.

    The solution

    There is an easier way: using the first rule of Lua ("Do it in Lua"):

    lua_dostring(S, "a,b = f(\"how\", t.x, 4)");

    where S is the state in which the code is to be executed. In fact, the only things you can't do with lua_dostring are get values back from Lua, and allow Lua to call L. These can both be achieved with lua_register.

    Hence all that is needed for language interworking is lua_dostring and lua_register, plus lua_open and lua_close to allow Lua states to be created and destroyed. Also, it's better to use lua_dobuffer than lua_dostring, as it can handle pre-compiled code too.

    But wait! In the C API, lua_register says nothing about the argument or result types of the function being registered; these have to be dealt with by inspection and manipulation of the Lua stack. A brutal but simple solution to this is to make lua_register specify the type and number of arguments and return values, and allow only such types as map naturally into L.

    The final list of functions for the thin API is:

    • lua_open and lua_close, to allow Lua states to be created and destroyed
    • lua_dobuffer, to allow Lua to be called from L
    • lua_register (suitably specialised), to allow L to be called from Lua

    Case study: Lua to OPL

    When porting Lua to EPOC, Symbian's OS for mobile devices such as PDAs, I wanted to provide hooks to OS features such as the Eikon GUI. EPOC is C++-based, which looks promising, but for space reasons its libraries contain no symbol information, so run-time dynamic linking by name is impossible. Not wanting to resort to tolua, I decided instead to bind Lua to OPL, EPOC's interpreted BASIC-like RAD language, which has both good support for EPOC, including a wide range of OPXs (OPL libraries implemented in C++), and allows procedures to be called dynamically by name.

    OPL has four basic types: 16-bit and 32-bit integers, 64-bit floats, and strings. 16-bit integers are denoted %, 32-bit integers &, strings $, and floats by nothing. OPL supports C-like function prototypes, for example:

    foo&:(a,b%,c$)

    foo is the name of the function. The & indicates that it returns a 32-bit integer (all OPL functions return a value, which defaults to zero or the empty string if there is no explicit RETURN statement). The colon indicates that foo is a function. Next comes the optional argument list; in this case, there are three arguments: a float a, a 16-bit integer b%, and a string c$. (Strings may be at most 255 characters long; in this API, longer strings may not be exchanged with Lua directly.)

    Hence, I created a small OPX which provided the following OPL functions:

    • LuaOpen&: returns a pointer to the new state
    • LuaClose:(state&) closes the given state
    • Lua&:(state&,chunk$) executes the given chunk (which may be precompiled, but this is unlikely to be useful as it can be at most 255 bytes long) in the given state
    • LuaRegister:(state&,func$,name$) registers the OPL function whose prototype is given by func$ in the given Lua state with Lua name name$
    Lua&: seemed a better name than LuaDoBuffer&: as it is both apt (Lua&: is the function that does some Lua) and a nice short name for what is likely to be the most widely used procedure by far out of the four. When an OPL function registered by LuaRegister: is called from Lua, the arguments are automatically translated to the OPL types, and the result type translated back. It is the programmer's responsibility to check that integer arguments are in range.

    Is a thin API enough?

    At first sight, this interface may seem very limited. For example, there's no simple way to evaluate a Lua expression and return its result to OPL, nor is it possible to traverse Lua tables in OPL. This is intentional: adding these facilities would complicate the API, and omitting them encourages programmers to use OPL only to provide library routines to Lua. After all, the main motivation for linking Lua to OPL was to be able to access EPOC without needing to write lots of C++ libraries for Lua first.

    However, in some cases I might want to write much of the application in the other language, because of its application domain properties (for example, SQL or Prolog). Also, I seem to be promoting Lua from its intended use as application extension language to the main language in which the application is written.

    Actually, there is no conflict here. Think of Lua not so much as an application extension language as a glue language, binding bits of programs written in other languages together. The core of the application's functionality will often be implemented in some other language L, perhaps C for speed, or some domain-specific language. By structuring this core as a library, the L programmer is free to concentrate on providing application primitives in L, without worrying about tying them together; L may well not be suitable for this. The application can then be implemented as a layer of Lua on top of a series of libraries; this separates the different concerns of programming the domain-specific primitives in L from configuring the particular application, which makes the application easier to write, and promotes reuse of both Lua and L code.

    If it is really necessary to implement other parts of the Lua API in L, then, provided it is not for performance reasons, the requisite functionality can still be implemented in Lua with L callbacks. Indeed, it would be possible to write a Lua implementation of the full Lua API which would then work with any language to which Lua was interfaced by the thin API.

    Conclusion

    Lua can be connected to other languages with a very simple API, which is mostly a subset of the standard C API. It is quick to implement, provided that the target language can interwork with C, and provides all the necessary functionality for writing applications in a mixture of Lua and the target language. Some seeming restrictions in the thin API actually help to write more reusable code.


    延伸閱讀

    文章來源于領測軟件測試網 http://www.kjueaiud.com/


    關于領測軟件測試網 | 領測軟件測試網合作伙伴 | 廣告服務 | 投稿指南 | 聯系我們 | 網站地圖 | 友情鏈接
    版權所有(C) 2003-2010 TestAge(領測軟件測試網)|領測國際科技(北京)有限公司|軟件測試工程師培訓網 All Rights Reserved
    北京市海淀區中關村南大街9號北京理工科技大廈1402室 京ICP備10010545號-5
    技術支持和業務聯系:info@testage.com.cn 電話:010-51297073

    軟件測試 | 領測國際ISTQBISTQB官網TMMiTMMi認證國際軟件測試工程師認證領測軟件測試網

    老湿亚洲永久精品ww47香蕉图片_日韩欧美中文字幕北美法律_国产AV永久无码天堂影院_久久婷婷综合色丁香五月

  • <ruby id="5koa6"></ruby>
    <ruby id="5koa6"><option id="5koa6"><thead id="5koa6"></thead></option></ruby>

    <progress id="5koa6"></progress>

  • <strong id="5koa6"></strong>