这是叉子!
该存储库已从luaj的原始CVS来源分配。提交历史已转换为确保詹姆斯·罗斯伯勒(James Roseborough)和伊恩·法默(Ian Farmer)的原始作品不会丢失。不幸的是,我无法与James或Ian联系,以移交我原本打算的GitHub组织/回购的所有权。但是,社区似乎很感兴趣,可以继续在原始资源上工作,因此我决定确保从现在开始合并任何可能为原始代码库增加一些价值的有用的拉力请求。
– 本杰明·荣格(Benjamin P. Jung),2018年1月26日
luaj入门
詹姆斯·罗斯伯勒(James Roseborough),伊恩·法默(Ian Farmer),版本3.0.2
版权所有©2009-2014 luaj .org。根据luaj许可证的条款免费提供。
简介·示例·概念·图书馆· luaj api·解析器
1-简介
luaj的目标
luaj是基于Lua的Lua解释器,牢记了以下目标:
- 以Java为中心的LUA VM实施,旨在利用标准Java功能。
- LUA轻巧,高性能执行。
- 多平台能够在JME,JSE或JEE环境上运行。
- 完整的库和工具集合到现实世界项目中。
- 由于对VM和库功能的足够单位测试,可靠。
luaj版本和lua版本
luaj 3.0.x
支持LUA 5.2.x功能:
- _ENV环境模型。
- 来自PCALL或METATAGS的屈服。
- 位操作员库。
它还包括对luaj 2.0.x的其他改进:
- 更好的线程安全。
- 更兼容的表行为。
- 更好的与Coroutine相关的垃圾收集。
- Maven整合。
- 使用关闭时更好的调试报告。
- 解析语法树中的行号。
luaj 2.0.x
支持LUA 5.1.x功能,加上:
- 支持将LUA源代码编译到Java源代码中。
- 支持将LUA字节码直接编译到Java字节码中。
- 无固定的VM设计以动态键入对象为中心。
- 与C API的良好对齐(有关详细信息,请参见names.csv)
- 弱键和值的实现以及所有metatags。
luaj 1.0.x
支持大多数LUA 5.1.x功能。
表现
良好的表现是luaj的主要目标。下表与标准C分布相比,从计算机语言基准游戏的基准的子集上提供了测量的执行时间。
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
luaj在解释模式下的基准表现良好,当使用Lua-to-Java-bytecode( luaj C)编译器时,使用更好的是,实际上在某些情况下比基于C的LUA更快。
对于所有测试的基准测试,它也比Java-Lua实施吉尔(Jill),卡卢阿(Kahlua)和Mochalua更快。
2-例子
在Java SE中运行LUA脚本
从主要分销目录行类型:
Java -cp luaj -jse -3.0.2.jar lua示例/lua/hello.lua
您应该看到以下输出:
你好世界
要查看luaj如何用于吸收大多数Java API,包括摇摆,请尝试:
Java -cp luaj -jse -3.0.2.jar lua示例/lua/swingapp.lua
链接到来源:
示例/lua/hello.lua 示例/lua/swingapp.lua
编译LUA源到LUA字节码
从主要分销目录行类型:
Java -cp luaj -jse -3.0.2.jar luac示例/lua/hello.lua Java -cp luaj -jse -3.0.2.2.jar lua luac.out
编译的输出“ luac.out”是LUA字节码,应运行并产生相同的结果。
编译LUA源或字节码到Java字节码
如果BCEL库在类路径上, luaj可以将LUA源或二进制文件直接编译为Java字节码。从主要分销目录行类型:
蚂蚁bcel-lib Java -CP“ luaj -JSE -3.0.2.jar; lib/bcel -5.2.2.jar” luaj c -s示例/lua -d。你好 Java -cp“ luaj -JSE -3.0.2.jar;。” lua -l你好
输出Hello.Class是Java字节码,应运行并产生相同的结果。 BCEL库没有运行时的依赖性,但是编译的类必须在运行时的类路径中,除非需要通过luaj C和BCEL进行运行时汇总(请参阅后面的部分)。
LUA脚本也可以直接在此模式下运行,而无需使用-b选项使用LUA命令进行预编译,并在类路径中提供BCEL库:
java -cp“ luaj -jse -3.0.2.2.jar; lib/bcel -5.2.2.jar” lua -B示例/lua/hello.lua
在Java应用程序中运行脚本
一个简单的Hello, luaj中的世界示例是:
导入组织。 luaj .vm2。*; 导入组织。 luaj .vm2.lib.jse。*; Globals Globals = jseplatform.standardglobals(); Luavalue块= Globals.load(“打印\'Hello,World\'”); chunk.call();
从文件加载是通过globals.loadfile()完成的:
luavalue块= globals.loadfile(“示例/lua/hello.lua”);
也可以从Reader中加载块作为文本源
块= globals.load(new StringReader(“打印\'Hello,world\'”),“ main.lua”);
或要加载为文本源“ t”或二进制lua文件“ b”的输入流:
块= globals.load(new fileInputsStream(“示例/lua/hello.lua”),“ main.lua”,“ bt”));
可以在
示例/jse/samplejsemain.java
您必须在您的课程路径中包含luaj -jse -3.0.2.2的库。
在中间运行脚本
对于Midlets,使用Jmeplatform :
导入组织。 luaj .vm2。*; 导入组织。 luaj .vm2.lib.jme。*; Globals Globals = Jmeplatform.standardglobals(); luavalue块= globals.loadfile(“示例/lua/hello.lua”); chunk.call();
该文件必须是Midlet Jar内部的资源,以便加载程序找到它。通过require()包含的任何文件也必须是Midlet资源的一部分。
可以在
示例/jme/samplemidlet.java
您必须在Midlet Jar中包含luaj -jme -3.0.2.jar的图书馆。
构建和运行midlet的蚂蚁脚本正在
build-midlet.xml
您必须安装无线工具包,并定义WTK_HOME才能使用此脚本。
使用JSR-223动态脚本运行脚本
可以使用JSR-223脚本引擎的标准使用:
ScriptEngineManager mgr = new ScriptEngineManager(); ScriptEngine E = mgr.getEngineByName(“ luaj ”); e.put(“ x”,25); e.eval(“ y = Math.sqrt(x)”); system.out.println(“ y =”+e.get(“ y”));
您还可以通过语言“ LUA”或MIMETYPES“文本/LUA”或“ Application/Lua”来查找引擎。
支持脚本引擎的所有标准方面,包括编译语句。
您必须在您的课程路径中包含luaj -jse -3.0.2.2的库。
可以在
示例/jse/scriptEnginesample.java
使用Java 1.6或更高的Java进行编译和运行:
Javac -cp luaj -jse -3.0.2.jar示例/jse/scriptEnginesample.java java -cp“ luaj -jse -3.0.2.jar;示例/jse” scriptEnginesEmple
不包括LUA字节码编译器
默认情况下,每当调用standardGlobals()或debugglobals()时,都会包括编译器。
没有编译器,仍然可以执行文件,但必须事先在其他地方进行编译。为此目的,JSE罐子中提供了“ LUAC”实用程序,或者可以使用标准的LUA编译器。
要排除Lua-to-Lua-bytecode编译器,请勿调用standardGlobals()或debugglobals() ,而是将Globals初始初始化,仅包括只有那些需要的库并省略该行:
org。 luaj .vm2.compiler.luac.install(Globals);
包括luaj c lua-bytecode to-java-bytecode编译器
要从Lua到Java字节码,用于在运行时加载的所有LUA,请将luaj C编译器安装到Globals对象中:
org。 luaj .vm2.jse。 luaj c。 luaj C.Install(Globals);
这将将所有LUA字节码编译到Java字节码中,无论它们是将其加载为LUA源或Lua二进制文件。
要求BCEL在类路径上,而JSE或CDC的类负载器。
3-概念
全球群体
平台的旧概念已被全球创建所取代。 Globals类具有执行封闭所需的全球状态,并提供了用于编译和加载脚本的便利功能。
平台
为了简化全球群体的构建,并封装了支持Java Runtimes多样化家族所需的差异, luaj使用了平台概念。通常,平台用于构建全球群体,然后将其作为客户端脚本的全局环境提供。
jseplatform
JSEPLATFORM类可用作典型Java SE应用程序中全球群体的工厂。包括所有标准库以及luaj Ava库。默认搜索路径是当前目录,数学操作包括Java SE支持的所有功能。
安卓
Android应用程序应使用JSEPLATFORM,并且可以包括luaj Ava库来简化对基础Android API的访问。
应该提供专门的Globals.Finder来查找用于加载的脚本和数据。请参阅示例/android/src/android/ luaj view.java,以加载“ Res” Android Project目录的示例。蚂蚁构建脚本是示例/android/build.xml。
小程序
浏览器中的小程序应使用jseplatform。小程序中的权限模型非常限制,因此必须使用使用默认类加载的luaj Ava库的专业化。在示例applet示例/jse/sampleapplet.java中进行了说明,可以使用build-applet.xml构建。
jmeplatform
JMeplatform类可用于为Java ME应用程序设置基本环境。默认搜索路径仅限于JAR资源,并且数学操作仅限于Java ME支持的操作。除了luaj Ava外,所有库都包括在内,并且OS,IO和数学库仅限于可以在该平台上支持的功能。
Midlet
Midlet需要Jmeplatform。
JME平台有几个限制,这些局限性延伸到luaj 。特别是Globals.finder被覆盖为资源,因此脚本应与Midlet Jar文件中的类文件共封闭。无法使用luaj ava。 camples代码在
示例/jme/samplemidlet.java,可以使用build-midlet.xml构建。
线程安全
luaj 3.0可以在多个线程中运行,并具有以下限制:
- 客户代码创建的每个线程都必须具有自己的不同的全球实例
- 每个线程都不能允许从其他线程访问全球
- 用于数字,字符串,线程,功能,布尔值和NIL的MetaTables共享,因此一旦LUA代码在任何线程中运行,就不应突变。
有关在多个线程中加载每线程全球和调用脚本的示例
作为替代方案,可以使用JSR-223脚本接口,并且应通过内部使用ThreadLocal,始终每个脚本引擎实例提供单独的Globals实例。
沙箱
Lua和luaj可以轻松地在服务器环境中对脚本进行沙箱。
考虑因素包括
- 调试和luaj ava库使对luaj VM和Java VM的访问不受约束,因此可以滥用
- 操作系统, IO和Coroutine图书馆的某些部分容易滥用
- 流氓脚本可能需要被限制或杀死
- 共享metaTables(字符串,布尔值等)需要通过luaj classloader等类加载程序进行读取或隔离
luaj提供了涵盖各种方法的示例代码:
- 示例/jse/samplesandboxed.java一个java沙盒,该沙盒限制库,每个脚本限制字节码,并使共享表格只读取仅读取
- 示例/jse/samplesandboxed.lua lua沙盒,该沙盒限制库,每个脚本限制字节码,并使共享表格仅读取仅读取
- 示例/jse/samplesclassloader.java一个更重但强大的luaj盒
4-库
标准库
对库进行编码以与请参见标准LUA文档中指定的行为紧密匹配,以获取库API的详细信息
以下库由jseplatform.standardglobals()和jmeplatform.standardglobals()加载:
根据 位32 Coroutine io 数学 操作系统 包裹 细绳 桌子
jseplatform.standardglobals() Globals还包括:
luaj Ava
jseplatform.debugglobals()和jseplatform.debugglobals()函数产生的全球功能包括:
调试
I/O库
IO库的实现因平台限制而有所不同。
jmeplatform.standardglobals()实例化了IO库IO
src/jme/org/ luaj /vm2/lib/jme/jmeiolib.java
jseplatform.standardglobals()包括对随机访问的支持,并且在
src/jse/org/ luaj /vm2/lib/jse/jseiolib.java
操作系统库
OS库的实现也有所不同。
Jmeplatform使用的基本OS库实现我们使用:
src/core/org/ luaj /lib/oslib.java
jseplatform使用的更丰富版本是:
src/jse/org/ luaj /vm2/lib/jse/jseoslib.java
时间是自时代以来的秒数表示,并且未实现语言环境。
Coroutine库
Coroutine库是使用每个Coroutine的一个Javathread实现的。这允许从任何地方调用coroutine.yield() ,就像基于C的LUA中的任何位置。
luaj使用弱提示和孤立的误差,以确保不再参考的coroutines被正确收集。为了进行线程安全,不应被Java代码捕获的孤儿。有关详细信息,请参见Luathread和OrphanedThread Javadoc。示例中的示例代码/jse/collectingorphanedCoroutines.java提供了工作示例。
调试库
默认情况下, jmeplatform.standardglobals()或jseplatform.standardglobsls()不包含调试库。
函数JMeplatform.debugglobals()和jseplatform.debugglobsls()创建除其他标准库之外包含DEBUG库的全球范围。
从LUA动态安装,请使用基于Java级的require ::
需要\'org。 luaj .vm2.lib.debuglib\'
LUA命令行实用程序默认情况下包括调试库。
luaj Ava图书馆
jseplatform.standardglobals()包括luaj ava库,该库简化了与Java类和方法的绑定。它是在原始的luaj Ava项目之后进行的。
以下LUA脚本将在Java SE上打开一个秋千框架:
jframe = luaj ava.bindclass(“ javax.swing.jframe”) 帧= luaj ava.newinstance(“ javax.swing.jframe”,“ texts”); 帧:setDefaultClosePoration(jframe.exit_on_close) 框架:设置(300,400) 框架:固定(true)
有关详细信息,请参见示例/lua/swingapp.lua中的较长示例,包括简单的动画循环,渲染图形,鼠标和键处理以及图像加载。或尝试使用以下方式运行它:
Java -cp luaj -jse -3.0.2.jar lua示例/lua/swingapp.lua
Java ME平台不包括此库,由于Java Me缺乏反射API,因此无法使用它。
Lua Connand Line工具包括luaj Ava 。
5 -luaj luaj
API Javadoc
luaj API中主要类的Javadoc在线
http://lu*aj.or*g*/ luaj /3.0/api
您还可以使用来源构建本地版本
蚂蚁文档
Luavalue和Varargs
现在,所有LUA值操作都是在Luavalue周围组织的,Luavalue暴露了大多数用于LUA计算的接口。
org。 luaj .vm2.luavalue
共同的功能
Luavalue公开了luaj中每个操作的功能。一些常用的功能和常数包括:
称呼(); //没有参数的函数 致电(luavalue arg1); //用1个参数调用函数 调用(varargs arg); //用可变参数调用函数,可变返回值 获取(int index); //使用整数键获取表条目 获取(luavalue键); //使用任意键获取表条目,可能是Luainteger RAWGET(int index); // raw获取没有MetaTable呼叫 valueof(int i); //返回与整数相对应的luavalue valueof(string s); //返回与字符串相对应的luavalue toint(); //返回值作为Java int tojstring(); //返回值作为Java字符串 isnil(); //是零值 零; //零值 没有任何; //一个无值的varargs实例
varargs
接口Varargs为变量参数列表和多个返回值提供了抽象。为了方便起见, Luavalue实施了Varargs,因此可以在任何预期可变参数的地方提供单个值。
org。 luaj .vm2.varargs
共同的功能
Varargs公开了访问元素的功能,并将其胁迫到特定类型:
narg(); //返回参数 arg1(); //返回第一个参数 arg(int n); //返回第n个参数 isnil(int n); //如果第n个论点为nil,则为true 检查(int n); //退货表或投掷错误 Optlong(int n,长d); //返回n如果长,则d,如果没有参数,则返回n
有关完整列表,请参见Varargs API。
libfunction
实现函数的最简单方法是根据该功能的参数数量选择基类。 luaj为此目的提供5个基类,这取决于功能是否具有0、1、2、3或变量参数,以及是否提供多个返回值。
org。 luaj .vm2.lib.ZeroArgFunction org。 luaj .vm2.lib.EneargFunction org。 luaj .vm2.lib.twoargfunction org。 luaj .vm2.lib.threeargfunction org。 luaj .vm2.lib.varargfunction
这些函数中的每一个都有一个必须实现的抽象方法,并且在调用每个Java函数时,这些函数是由类自动完成的。
一个没有参数的函数的示例,但有用的返回值可能是:
耻骨类主机名扩展了ZeroArgFunction {
公共Luavalue呼叫(){
返回valueOf(java.net.inetaddress.getLocalHost()。gethostName());
}
}
值env是函数的环境,通常在使用默认加载时由实例化对象提供。
从LUA调用此功能可以通过:
本地主机名= require(\'HostName\')
从Java调用此功能时,看起来像:
new HostName()。call();
请注意,在LUA和Java案例中,将忽略额外的参数,并调用该函数。
另外,无需虚拟机实例来调用该函数。为了允许参数或返回多个值,请扩展其他基本类之一。
Java功能的库
当调用()被调用时,它将首先尝试将模块作为实现Luafunction的Java类加载。要成功,必须满足以下要求:
- 该类必须在类名称为modName的课程中。
- 该类必须具有公共默认构造函数。
- 该类必须从luafunction继承。
如果luaj可以找到符合这些标准的类,它将实例化,将其施加到luafunction ,然后调用()带有两个参数的实例:呼叫中使用的modName to require()和该功能的环境。 Java可能会使用这些值。一个典型的情况是在环境中创建可以从LUA调用的命名函数。
简单玩具库的Java代码的完整示例是示例/jse/yrombolic.java
导入组织。 luaj .vm2.luavalue; 导入组织。 luaj .vm2.lib。*;公共类双曲线扩展了TwargFunction {
public hyperbolic() {} public LuaValue call(LuaValue modname, LuaValue env) { LuaValue library = tableOf(); library.set( \"sinh\", new sinh() ); library.set( \"cosh\", new cosh() ); env.set( \"hyperbolic\", library ); return library; } static class sinh extends OneArgFunction { public LuaValue call(LuaValue x) { return LuaValue.valueOf(Math.sinh(x.checkdouble())); } } static class cosh extends OneArgFunction { public LuaValue call(LuaValue x) { return LuaValue.valueOf(Math.cosh(x.checkdouble())); } }}
在这种情况下,要求需要调用库本身来初始化它。库实现将条目放入表中,并将该表存储在环境中。
用于加载和测试的LUA脚本在示例/lua/hyprobolicapp.lua中
需要“双曲线”print(\'hyperbolic\', hyperbolic) print(\'hyperbolic.sinh\', hyperbolic.sinh) print(\'hyperbolic.cosh\', hyperbolic.cosh) print(\'sinh(0.5)\', hyperbolic.sinh(0.5)) print(\'cosh(0.5)\', hyperbolic.cosh(0.5))为了使此示例可以在4sybolic.java中使用代码,必须编译并放入类路径上。
关闭
关闭仍然存在于此框架中,但是可选的,仅用于实现LUA字节码执行,并且通常不会由luaj的用户直接操纵。
参见组织。 luaj .vm2.LuAclosure Javadoc有关直接使用该类别的详细信息。
6-解析器
Javacc语法
开发了一种JavACC语法,以简化为LUA语言创建基于Java的解析器。语法是为JAVACC 5.0版指定的,因为该工具会生成不需要单独运行时的独立解析器。
语法/lua52.jj可用的一个普通的未装饰性语法,而生成键入parse树的语法是语法/luaparser.jj
从LUA来源创建解析树
默认的LU编译器将LUA源的单元编译到LUA字节码,因此没有产生明确的解析树。
为了简化LUA来源的抽象语法树的创建,Luaparser类是JME构建的一部分。要使用它,提供一个输入流并调用根生成器,如果文件有效,该块将返回块,或者如果存在语法错误,则将parseexception丢弃。
例如,要解析文件并打印所有变量名称,请使用类似的代码:
尝试 { 字符串文件=“ main.lua”; Luaparser Parser = new Luaparser(new FileInputStream(file)); 块块= parser.chunk(); chunk.accept(new Visitor(){ public void访问(exp.nameexp exp){ system.out.println(“使用中的名称:”+exp.name.name +“ line”+exp.Beginline +“ col”+exp.begincolumn); } }); } catch(parseexception e){ system.out.println(“ parse失败:” + e.getMessage() +“ \\ n” +“令牌映像:\'” + e.currenttoken.image +“\'\\ n” +“位置:” + e.currenttoken.beginline +“:” + e.currenttoken.begincolumn +“ - ” + e.currenttoken.endline +“,” + e.currenttoken.endcolumn); }在文件中打印所有功能定义位置的一个示例可以在文件中找到
示例/jse/sampleparser.java参见组织。 luaj .vm2.AST软件包Javadoc用于与所产生的语法树有关的API。
7-建筑和测试
Maven整合
现在,主要的JAR文件已部署在Maven Central存储库中。要在基于Maven的项目中使用它们,请将其列为一个依赖性:
对于JSE项目,将此依赖性添加到luaj -jse Jar:
<依赖项> <groupId> org。 luaj </groupid> <Artifactid> luaj -jse </artifactid> <版本> 3.0.2 </version> </dependency>在JME项目中,使用luaj -Jme Jar:
<依赖项> <groupId> org。 luaj </groupid> <Artifactid> luaj -jme </artifactid> <版本> 3.0.2 </version> </dependency>一个示例Skelton Maven POM文件用于骨架项目
示例/maven/pom.xml建造罐子
Root Directory包含一个ANT文件,该文件默认情况下构建库。
存在其他目标来创建分发文件,以测量单位测试的代码覆盖范围。
单位测试
luaj主要Junit测试被组织成Junit 3 Suite:
test/junit/org/ luaj /vm2/alltests.lua单位测试脚本可以在这些位置找到
测试/lua/*。lua 测试/lua/errors/*。lua 测试/lua/perf/*。lua 测试/ lua/ luaj 3.0.2-tests.zip代码覆盖范围
用于运行单元测试和生成代码覆盖统计信息的构建脚本在
build-coverage.xml它依靠Cobertura代码覆盖库库。
8-下载
下载和项目页面
在SourceForge或Luaforge上可用的所有版本下载。来源托管在SourceForge上,并通过sourceforge.net获得
sourceforge luaj项目页面 SourceForge luaj下载区域JAR文件也可以从Maven Central存储库下载,请参见Maven集成。
文件不再在Luaforge托管。
9-发行笔记
主版本的主要更改
|
已知问题
限制
- 一些混淆器可能不会完全删除调试代码
- 调试信息中未跟踪尾声
- 不支持在同一Java VM中混合不同版本的luaj
- 与键相关的值可能会持续时间比预期的更长
- 使用安全管理器时luaj的行为尚未完全表征
- 负零被视为与整个luaj的整数值零相同
- 使用luaj c编译为Java字节码的LUA无法使用String.dump()或XPCALL()
- 不支持使用String.format()的数字格式。
- 同一类加载程序中的全球实例共享字符串,布尔等共享的metatables
- 除非运行垃圾和足够的时间,否则不会收集孤立的线
文件字符编码
可以将源文件视为在UTF-8或ISO-8859-1中编码,并且结果应如预期的,字面字符串Contian引用的字符汇编为与输入相同的字节序列。
但是,对于诸如EBSDIC之类的非ASCII兼容编码,有限制:
- 向Globals提供读取器。load()优先于inputstream变体
- 在大多数情况下,使用FileReader或InputStreamReader获取默认的OS编码应起作用
- 带有引用字符的字符串文字可能不会在生成的代码中产生预期值
- 命令行工具LUA,LUAC和luaj C将需要-c CP037来指定编码
这些限制主要是如何将语言定义为允许字节文字在源文件中的字符串中的副作用。
在LUA内生成并用LUA的LOAD()函数编译的代码应按预期工作,因为这些字符串永远不会用主机的本机字符编码来表示。
