aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerek Bailey <derek.bailey@thermofisher.com>2018-07-05 15:55:57 -0700
committerWouter van Oortmerssen <aardappel@gmail.com>2018-07-05 15:55:57 -0700
commitba5eb3b5cfb6eea74727e67cad599409f9d0af99 (patch)
tree45ef72d9acc8934b6dc62f070078dc4b1fe8485f
parent8ea293b9881e707e1735dea503878b9ad6d9ef14 (diff)
downloadflatbuffers-ba5eb3b5cfb6eea74727e67cad599409f9d0af99.tar.gz
Lua (5.3) Language addition (#4804)
* starting Lua port of python implmention. Syncing commit * Bulk of Lua module port from Python done. Not tested, only static analysis. Need to work on binary strings. Started work on flatc lua code generation * Fixed all the basic errors to produced a binary output from the builder, don't know if it is generated correctly, but it contains data, so that must be good * fixed binary set command that was extending the array improperly * continued improvement * Moved lua submodules down a directory so their names don't clash with potential other modules. Added compat module to provide Lua versioning logic * Successful sample port from Python * working on testing Lua code with formal tests * continued to work on tests and fixes to code to make tests pass * Added reading buffer test * Changed binaryarray implmentation to use a temporary table for storing data, and then serialize it to a string when requested. This double the rate of building flatbuffers compared to the string approach. * Didn't need encode module as it just added another layer of indirection that isn't need * profiled reading buffers, optimizations to increase read performance of monster data to ~7 monster / millisecond * Writing profiler improvments. Get about ~2 monsters/millisecond building rate * removed Numpy generation from Lua (came from the Python port) * math.pow is deprecated in Lua 5.3, so changed to ^ notation. Also added .bat script for starting Lua tests * adding results of generate_code.bat * simple edits for code review in PR. * There was a buffer overflow in inserting the keywords into the unorder set for both the Lua and Python code gens. Changed insertion to use iterators. * fixed spacing issue * basic documenation/tutorial updates. Updated sample_binary.lua to reflect the tutorial better * removed windows-specific build step in Lua tests
-rw-r--r--.gitignore4
-rw-r--r--CMakeLists.txt1
-rw-r--r--docs/source/FlatBuffers.md4
-rw-r--r--docs/source/LuaUsage.md81
-rw-r--r--docs/source/Tutorial.md194
-rw-r--r--docs/source/doxyfile1
-rw-r--r--docs/source/doxygen_layout.xml2
-rw-r--r--include/flatbuffers/idl.h7
-rw-r--r--lua/flatbuffers.lua8
-rw-r--r--lua/flatbuffers/binaryarray.lua123
-rw-r--r--lua/flatbuffers/builder.lua368
-rw-r--r--lua/flatbuffers/compat.lua17
-rw-r--r--lua/flatbuffers/numTypes.lua198
-rw-r--r--lua/flatbuffers/view.lua97
-rw-r--r--samples/lua/MyGame/Sample/Color.lua11
-rw-r--r--samples/lua/MyGame/Sample/Equipment.lua10
-rw-r--r--samples/lua/MyGame/Sample/Monster.lua122
-rw-r--r--samples/lua/MyGame/Sample/Vec3.lua35
-rw-r--r--samples/lua/MyGame/Sample/Weapon.lua42
-rw-r--r--samples/sample_binary.lua107
-rw-r--r--src/flatc_main.cpp4
-rw-r--r--src/idl_gen_lua.cpp729
-rw-r--r--src/idl_gen_python.cpp2
-rw-r--r--tests/LuaTest.bat6
-rw-r--r--tests/MyGame/Example/Ability.lua31
-rw-r--r--tests/MyGame/Example/Any.lua12
-rw-r--r--tests/MyGame/Example/Color.lua11
-rw-r--r--tests/MyGame/Example/Monster.lua542
-rw-r--r--tests/MyGame/Example/Referrable.lua35
-rw-r--r--tests/MyGame/Example/Stat.lua50
-rw-r--r--tests/MyGame/Example/Test.lua32
-rw-r--r--tests/MyGame/Example/TestSimpleTableWithEnum.lua35
-rw-r--r--tests/MyGame/Example/TypeAliases.lua141
-rw-r--r--tests/MyGame/Example/Vec3.lua54
-rw-r--r--tests/MyGame/Example2/Monster.lua27
-rw-r--r--tests/MyGame/InParentNamespace.lua27
-rw-r--r--tests/generate_code.bat4
-rwxr-xr-xtests/generate_code.sh4
-rw-r--r--tests/luatest.lua294
39 files changed, 3466 insertions, 6 deletions
diff --git a/.gitignore b/.gitignore
index 8f026d3a..77731612 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,7 +12,9 @@
*.vcxproj.user
*.sln
*.suo
+*.opendb
*.keystore
+**/.vs/**
**/bin/**
**/gen/**
**/libs/**
@@ -25,6 +27,8 @@
**/CMakeTestfile.cmake
**/Debug/**
**/Release/**
+**/RelWithDebInfo/**
+**/x64/ #build artifacts from VS
build.xml
local.properties
project.properties
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 90860c35..ffaff111 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -51,6 +51,7 @@ set(FlatBuffers_Compiler_SRCS
src/idl_gen_js.cpp
src/idl_gen_php.cpp
src/idl_gen_python.cpp
+ src/idl_gen_lua.cpp
src/idl_gen_fbs.cpp
src/idl_gen_grpc.cpp
src/idl_gen_json_schema.cpp
diff --git a/docs/source/FlatBuffers.md b/docs/source/FlatBuffers.md
index ff27476f..351c38ed 100644
--- a/docs/source/FlatBuffers.md
+++ b/docs/source/FlatBuffers.md
@@ -4,7 +4,7 @@ FlatBuffers {#flatbuffers_index}
# Overview {#flatbuffers_overview}
[FlatBuffers](@ref flatbuffers_overview) is an efficient cross platform
-serialization library for C++, C#, C, Go, Java, JavaScript, TypeScript, PHP, and Python.
+serialization library for C++, C#, C, Go, Java, JavaScript, Lua, TypeScript, PHP, and Python.
It was originally created at Google for game development and other
performance-critical applications.
@@ -134,6 +134,8 @@ sections provide a more in-depth usage guide.
in your own programs.
- How to [use the generated Go code](@ref flatbuffers_guide_use_go) in your
own programs.
+- How to [use the generated Lua code](@ref flatbuffers_guide_use_lua) in your
+ own programs.
- How to [use the generated JavaScript code](@ref flatbuffers_guide_use_javascript) in your
own programs.
- How to [use the generated TypeScript code](@ref flatbuffers_guide_use_typescript) in your
diff --git a/docs/source/LuaUsage.md b/docs/source/LuaUsage.md
new file mode 100644
index 00000000..75b1f3b8
--- /dev/null
+++ b/docs/source/LuaUsage.md
@@ -0,0 +1,81 @@
+Use in Lua {#flatbuffers_guide_use_lua}
+=============
+
+## Before you get started
+
+Before diving into the FlatBuffers usage in Lua, it should be noted that the
+[Tutorial](@ref flatbuffers_guide_tutorial) page has a complete guide to general
+FlatBuffers usage in all of the supported languages (including Lua). This
+page is designed to cover the nuances of FlatBuffers usage, specific to
+Lua.
+
+You should also have read the [Building](@ref flatbuffers_guide_building)
+documentation to build `flatc` and should be familiar with
+[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler) and
+[Writing a schema](@ref flatbuffers_guide_writing_schema).
+
+## FlatBuffers Lua library code location
+
+The code for the FlatBuffers Lua library can be found at
+`flatbuffers/lua`. You can browse the library code on the
+[FlatBuffers GitHub page](https://github.com/google/flatbuffers/tree/master/lua).
+
+## Testing the FlatBuffers Lua library
+
+The code to test the Lua library can be found at `flatbuffers/tests`.
+The test code itself is located in [luatest.lua](https://github.com/google/
+flatbuffers/blob/master/tests/luatest.lua).
+
+To run the tests, use the [LuaTest.sh](https://github.com/google/flatbuffers/
+blob/master/tests/LuaTest.sh) shell script.
+
+*Note: This script requires [Lua 5.3](https://www.lua.org/) to be
+installed.*
+
+## Using the FlatBuffers Lua library
+
+*Note: See [Tutorial](@ref flatbuffers_guide_tutorial) for a more in-depth
+example of how to use FlatBuffers in Lua.*
+
+There is support for both reading and writing FlatBuffers in Lua.
+
+To use FlatBuffers in your own code, first generate Lua classes from your
+schema with the `--lua` option to `flatc`. Then you can include both
+FlatBuffers and the generated code to read or write a FlatBuffer.
+
+For example, here is how you would read a FlatBuffer binary file in Lua:
+First, require the module and the generated code. Then read a FlatBuffer binary
+file into a `string`, which you pass to the `GetRootAsMonster` function:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lua}
+ -- require the library
+ local flatbuffers = require("flatbuffers")
+
+ -- require the generated code
+ local monster = require("MyGame.Sample.Monster")
+
+ -- read the flatbuffer from a file into a string
+ local f = io.open('monster.dat', 'rb')
+ local buf = f:read('*a')
+ f:close()
+
+ -- parse the flatbuffer to get an instance to the root monster
+ local monster1 = monster.GetRootAsMonster(buf, 0)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Now you can access values like this:
+
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.lua}
+ -- use the : notation to access member data
+ local hp = monster1:Hp()
+ local pos = monster1:Pos()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+## Text Parsing
+
+There currently is no support for parsing text (Schema's and JSON) directly
+from Lua, though you could use the C++ parser through SWIG or ctypes. Please
+see the C++ documentation for more on text parsing.
+
+<br>
diff --git a/docs/source/Tutorial.md b/docs/source/Tutorial.md
index 2d0e0d8e..11fe4c8c 100644
--- a/docs/source/Tutorial.md
+++ b/docs/source/Tutorial.md
@@ -31,6 +31,7 @@ Please select your desired language for our quest:
<input type="radio" name="language" value="php">PHP</input>
<input type="radio" name="language" value="c">C</input>
<input type="radio" name="language" value="dart">Dart</input>
+ <input type="radio" name="language" value="lua">Lua</input>
</form>
\endhtmlonly
@@ -136,6 +137,10 @@ For your chosen language, please cross-reference with:
<div class="language-dart">
[example.dart](https://github.com/google/flatbuffers/blob/master/dart/example/example.dart)
</div>
+<div class="language-lua">
+[sample_binary.lua](https://github.com/google/flatbuffers/blob/master/dart/example/sample_binary.lua)
+</div>
+
## Writing the Monsters' FlatBuffer Schema
@@ -322,6 +327,12 @@ Please be aware of the difference between `flatc` and `flatcc` tools.
./../flatc --dart monster.fbs
~~~
</div>
+<div class="language-lua">
+~~~{.sh}
+ cd flatbuffers/sample
+ ./../flatc --lua monster.fbs
+~~~
+</div>
For a more complete guide to using the `flatc` compiler, please read the
[Using the schema compiler](@ref flatbuffers_guide_using_schema_compiler)
@@ -439,6 +450,19 @@ The first step is to import/include the library, generated files, etc.
import 'monster_my_game.sample_generated.dart' as myGame;
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ -- require the flatbuffers module
+ local flatbuffers = require("flatbuffers")
+
+ -- require the generated files from `flatc`.
+ local color = require("MyGame.Sample.Color")
+ local equipment = require("MyGame.Sample.Equipment")
+ local monster = require("MyGame.Sample.Monster")
+ local vec3 = require("MyGame.Sample.Vec3")
+ local weapon = require("MyGame.Sample.Weapon")
+~~~
+</div>
Now we are ready to start building some buffers. In order to start, we need
to create an instance of the `FlatBufferBuilder`, which will contain the buffer
@@ -518,6 +542,12 @@ which will grow automatically if needed:
var builder = new fb.Builder(initialSize: 1024);
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ -- get access to the builder, providing an array of size 1024
+ local builder = flatbuffers.Builder(1024)
+~~~
+</div>
After creating the `builder`, we can start serializing our data. Before we make
our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
@@ -705,6 +735,24 @@ our `orc` Monster, lets create some `Weapon`s: a `Sword` and an `Axe`.
);
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ local weaponOne = builder:CreateString("Sword")
+ local weaponTwo = builder:CreateString("Axe")
+
+ -- Create the first 'Weapon'
+ weapon.Start(builder)
+ weapon.AddName(builder, weaponOne)
+ weapon.AddDamage(builder, 3)
+ local sword = weapon.End(builder)
+
+ -- Create the second 'Weapon'
+ weapon.Start(builder)
+ weapon.AddName(builder, weaponTwo)
+ weapon.AddDamage(builder, 5)
+ local axe = weapon.End(builder)
+~~~
+</div>
Now let's create our monster, the `orc`. For this `orc`, lets make him
`red` with rage, positioned at `(1.0, 2.0, 3.0)`, and give him
@@ -852,6 +900,21 @@ traversal. This is generally easy to do on any tree structures.
final List<int> treasure = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
~~~
</div>
+<div class="language-lua">
+~~~{.py}
+ -- Serialize a name for our mosnter, called 'orc'
+ local name = builder:CreateString("Orc")
+
+ -- Create a `vector` representing the inventory of the Orc. Each number
+ -- could correspond to an item that can be claimed after he is slain.
+ -- Note: Since we prepend the bytes, this loop iterates in reverse.
+ monster.StartInventoryVector(builder, 10)
+ for i=10,1,-1 do
+ builder:PrependByte(i)
+ end
+ local inv = builder:EndVector(10)
+~~~
+</div>
We serialized two built-in data types (`string` and `vector`) and captured
their return values. These values are offsets into the serialized data,
@@ -964,6 +1027,16 @@ offsets.
final List<myGame.WeaponBuilder> weaps = [sword, axe];
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ -- Create a FlatBuffer vector and prepend the weapons.
+ -- Note: Since we prepend the data, prepend them in reverse order.
+ monster.StartWeaponsVector(builder, 2)
+ builder:PrependUOffsetTRelative(axe)
+ builder:PrependUOffsetTRelative(sword)
+ local weapons = builder:EndVector(2)
+~~~
+</div>
<div class="language-cpp">
<br>
@@ -1063,6 +1136,16 @@ for the `path` field above:
];
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ -- Create a FlatBuffer vector and prepend the path locations.
+ -- Note: Since we prepend the data, prepend them in reverse order.
+ monster.StartPathVector(builder, 2)
+ vec3.CreateVec3(builder, 1.0, 2.0, 3.0)
+ vec3.CreateVec3(builder, 4.0, 5.0, 6.0)
+ local path = builder:EndVector(2)
+~~~
+</div>
We have now serialized the non-scalar components of the orc, so we
can serialize the monster itself:
@@ -1267,6 +1350,22 @@ can serialize the monster itself:
final int orc = orcBuilder.finish(builder);
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ -- Create our monster by using Start() andEnd()
+ monster.Start(builder)
+ monster.AddPos(builder, vec3.CreateVec3(builder, 1.0, 2.0, 3.0))
+ monster.AddHp(builder, 300)
+ monster.AddName(builder, name)
+ monster.AddInventory(builder, inv)
+ monster.AddColor(builder, color.Red)
+ monster.AddWeapons(builder, weapons)
+ monster.AddEquippedType(builder, equipment.Weapon)
+ monster.AddEquipped(builder, axe)
+ monster.AddPath(builder, path)
+ local orc = monster.End(builder)
+~~~
+</div>
Note how we create `Vec3` struct in-line in the table. Unlike tables, structs
are simple combinations of scalars that are always stored inline, just like
@@ -1409,6 +1508,12 @@ Here is a repetition these lines, to help highlight them more clearly:
equipped: axe, // Union data
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ monster.AddEquippedType(builder, equipment.Weapon) -- Union type
+ monster.AddEquipped(builder, axe) -- Union data
+~~~
+</div>
After you have created your buffer, you will have the offset to the root of the
data in the `orc` variable, so you can finish the buffer by calling the
@@ -1480,6 +1585,13 @@ appropriate `finish` method.
// See the next code section, as in Dart `finish` will also return the byte array.
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ -- Call 'Finish()' to instruct the builder that this monster is complete.
+ builder:Finish(orc)
+~~~
+</div>
+
The buffer is now ready to be stored somewhere, sent over the network, be
compressed, or whatever you'd like to do with it. You can access the buffer
@@ -1577,6 +1689,13 @@ like so:
final Uint8List buf = builder.finish(orc);
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ -- Get the flatbuffer as a string containing the binary data
+ local bufAsString = builder:Output()
+~~~
+</div>
+
Now you can write the bytes to a file, send them over the network..
**Make sure your file mode (or tranfer protocol) is set to BINARY, not text.**
@@ -1690,6 +1809,19 @@ import 'package:flat_buffers/flat_buffers.dart' as fb;
import './monster_my_game.sample_generated.dart' as myGame;
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ -- require the flatbuffers module
+ local flatbuffers = require("flatbuffers")
+
+ -- require the generated files from `flatc`.
+ local color = require("MyGame.Sample.Color")
+ local equipment = require("MyGame.Sample.Equipment")
+ local monster = require("MyGame.Sample.Monster")
+ local vec3 = require("MyGame.Sample.Vec3")
+ local weapon = require("MyGame.Sample.Weapon")
+~~~
+</div>
Then, assuming you have a buffer of bytes received from disk,
network, etc., you can create start accessing the buffer like so:
@@ -1798,6 +1930,17 @@ List<int> data = ... // the data, e.g. from file or network
myGame.Monster monster = new myGame.Monster(data);
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ local bufAsString = -- The data you just read in
+
+ -- Convert the string representation into binary array Lua structure
+ local buf = flatbuffers.binaryArray.New(bufAsString)
+
+ -- Get an accessor to the root object insert the buffer
+ local mon = monster.GetRootAsMonster(buf, 0)
+~~~
+</div>
If you look in the generated files from the schema compiler, you will see it generated
accessors for all non-`deprecated` fields. For example:
@@ -1876,6 +2019,13 @@ accessors for all non-`deprecated` fields. For example:
var name = monster.name;
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ local hp = mon:Hp()
+ local mana = mon:Mana()
+ local name = mon:Name()
+~~~
+</div>
These should hold `300`, `150`, and `"Orc"` respectively.
@@ -1969,6 +2119,15 @@ To access sub-objects, in the case of our `pos`, which is a `Vec3`:
double z = pos.z;
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ local pos = mon:Pos()
+ local x = pos:X()
+ local y = pos:Y()
+ local z = pos:Z()
+~~~
+</div>
+
`x`, `y`, and `z` will contain `1.0`, `2.0`, and `3.0`, respectively.
@@ -2041,6 +2200,12 @@ FlatBuffers `vector`.
var thirdItem = monster.inventory[2];
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ local invLength = mon:InventoryLength()
+ local thirdItem = mon:Inventory(3) -- Lua is 1-based
+~~~
+</div>
For `vector`s of `table`s, you can access the elements like any other vector,
except your need to handle the result as a FlatBuffer `table`:
@@ -2122,6 +2287,13 @@ except your need to handle the result as a FlatBuffer `table`:
var secondWeaponDamage = monster.Weapons[1].damage;
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ local weaponsLength = mon:WeaponsLength()
+ local secondWeaponName = mon:Weapon(2):Name()
+ local secondWeaponDamage = mon:Weapon(2):Damage()
+~~~
+</div>
Last, we can access our `Equipped` FlatBuffer `union`. Just like when we created
the `union`, we need to get both parts of the `union`: the type and the data.
@@ -2257,6 +2429,19 @@ We can access the type to dynamically cast the data as needed (since the
}
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ local unionType = mon:EquippedType()
+
+ if unionType == equipment.Weapon then
+ local unionWeapon = weapon.New()
+ unionWeapon:Init(mon:Equipped().bytes, mon:Equipped().pos)
+
+ local weaponName = unionWeapon:Name() -- 'Axe'
+ local weaponDamage = unionWeapon:Damage() -- 5
+ end
+~~~
+</div>
## Mutating FlatBuffers
@@ -2337,6 +2522,11 @@ mutators like so:
<API for mutating FlatBuffers not yet available in Dart.>
~~~
</div>
+<div class="language-lua">
+~~~{.lua}
+ <API for mutating FlatBuffers is not yet available in Lua.>
+~~~
+</div>
We use the somewhat verbose term `mutate` instead of `set` to indicate that this
is a special use case, not to be confused with the default way of constructing
@@ -2449,5 +2639,9 @@ For your chosen language, see:
<div class="language-dart">
[Use in Dart](@ref flatbuffers_guide_use_dart)
</div>
+<div class="language-lua">
+[Use in Lua](@ref flatbuffers_guide_use_lua)
+</div>
+
<br>
diff --git a/docs/source/doxyfile b/docs/source/doxyfile
index b4e84fa9..8cc46cc6 100644
--- a/docs/source/doxyfile
+++ b/docs/source/doxyfile
@@ -758,6 +758,7 @@ INPUT = "FlatBuffers.md" \
"TypeScriptUsage.md" \
"PHPUsage.md" \
"PythonUsage.md" \
+ "LuaUsage.md" \
"Support.md" \
"Benchmarks.md" \
"WhitePaper.md" \
diff --git a/docs/source/doxygen_layout.xml b/docs/source/doxygen_layout.xml
index c7233143..c0022956 100644
--- a/docs/source/doxygen_layout.xml
+++ b/docs/source/doxygen_layout.xml
@@ -41,6 +41,8 @@
title="Use in Python"/>
<tab type="user" url="@ref flatbuffers_guide_use_dart"
title="Use in Dart"/>
+ <tab type="user" url="@ref flatbuffers_guide_use_lua"
+ title="Use in Lua"/>
<tab type="user" url="@ref flexbuffers"
title="Schema-less version"/>
<tab type="usergroup" url="" title="gRPC">
diff --git a/include/flatbuffers/idl.h b/include/flatbuffers/idl.h
index 88d9553d..55ef89d1 100644
--- a/include/flatbuffers/idl.h
+++ b/include/flatbuffers/idl.h
@@ -408,6 +408,7 @@ struct IDLOptions {
kTs = 1 << 9,
kJsonSchema = 1 << 10,
kDart = 1 << 11,
+ kLua = 1 << 12,
kMAX
};
@@ -814,6 +815,12 @@ extern bool GeneratePython(const Parser &parser,
const std::string &path,
const std::string &file_name);
+// Generate Lua files from the definitions in the Parser object.
+// See idl_gen_lua.cpp.
+extern bool GenerateLua(const Parser &parser,
+ const std::string &path,
+ const std::string &file_name);
+
// Generate Json schema file
// See idl_gen_json_schema.cpp.
extern bool GenerateJsonSchema(const Parser &parser,
diff --git a/lua/flatbuffers.lua b/lua/flatbuffers.lua
new file mode 100644
index 00000000..1c85c4e6
--- /dev/null
+++ b/lua/flatbuffers.lua
@@ -0,0 +1,8 @@
+local m = {}
+
+m.Builder = require("flatbuffers.builder").New
+m.N = require("flatbuffers.numTypes")
+m.view = require("flatbuffers.view")
+m.binaryArray = require("flatbuffers.binaryarray")
+
+return m \ No newline at end of file
diff --git a/lua/flatbuffers/binaryarray.lua b/lua/flatbuffers/binaryarray.lua
new file mode 100644
index 00000000..bf728cdd
--- /dev/null
+++ b/lua/flatbuffers/binaryarray.lua
@@ -0,0 +1,123 @@
+local m = {} -- the module table
+
+local mt = {} -- the module metatable
+
+-- given a binary array, set a metamethod to return its length
+-- (e.g., #binaryArray, calls this)
+function mt:__len()
+ return self.size
+end
+
+-- Create a new binary array of an initial size
+function m.New(sizeOrString)
+ -- the array storage itself
+ local o = {}
+
+ if type(sizeOrString) == "string" then
+ o.str = sizeOrString
+ o.size = #sizeOrString
+ elseif type(sizeOrString) == "number" then
+ o.data = {}
+ o.size = sizeOrString
+ else
+ error("Expect a integer size value or string to construct a binary array")
+ end
+ -- set the inheritance
+ setmetatable(o, {__index = mt, __len = mt.__len})
+ return o
+end
+
+-- Get a slice of the binary array from start to end position
+function mt:Slice(startPos, endPos)
+ startPos = startPos or 0
+ endPos = endPos or self.size
+ local d = self.data
+ if d then
+ -- if the self.data is defined, we are building the buffer
+ -- in a Lua table
+
+ -- new table to store the slice components
+ local b = {}
+
+ -- starting with the startPos, put all
+ -- values into the new table to be concat later
+ -- updated the startPos based on the size of the
+ -- value
+ while startPos < endPos do
+ local v = d[startPos] or '/0'
+ table.insert(b, v)
+ startPos = startPos + #v
+ end
+
+ -- combine the table of strings into one string
+ -- this is faster than doing a bunch of concats by themselves
+ return table.concat(b)
+ else
+ -- n.b start/endPos are 0-based incoming, so need to convert
+ -- correctly. in python a slice includes start -> end - 1
+ return self.str:sub(startPos+1, endPos)
+ end
+end
+
+-- Grow the binary array to a new size, placing the exisiting data
+-- at then end of the new array
+function mt:Grow(newsize)
+ -- the new table to store the data
+ local newT = {}
+
+ -- the offset to be applied to existing entries
+ local offset = newsize - self.size
+
+ -- loop over all the current entries and
+ -- add them to the new table at the correct
+ -- offset location
+ local d = self.data
+ for i,data in pairs(d) do
+ newT[i + offset] = data
+ end
+
+ -- update this storage with the new table and size
+ self.data = newT
+ self.size = newsize
+end
+
+-- memorization for padding strings
+local pads = {}
+
+-- pad the binary with n \0 bytes at the starting position
+function mt:Pad(n, startPos)
+ -- use memorization to avoid creating a bunch of strings
+ -- all the time
+ local s = pads[n]
+ if not s then
+ s = string.rep('\0', n)
+ pads[n] = s
+ end
+
+ -- store the padding string at the start position in the
+ -- Lua table
+ self.data[startPos] = s
+end
+
+-- Sets the binary array value at the specified position
+function mt:Set(value, position)
+ self.data[position] = value
+end
+
+-- locals for slightly faster access
+local sunpack = string.unpack
+local spack = string.pack
+
+-- Pack the data into a binary representation
+function m.Pack(fmt, ...)
+ return spack(fmt, ...)
+end
+
+-- Unpack the data from a binary representation in
+-- a Lua value
+function m.Unpack(fmt, s, pos)
+ return sunpack(fmt, s.str, pos + 1)
+end
+
+-- Return the binary array module
+return m \ No newline at end of file
diff --git a/lua/flatbuffers/builder.lua b/lua/flatbuffers/builder.lua
new file mode 100644
index 00000000..d20783bd
--- /dev/null
+++ b/lua/flatbuffers/builder.lua
@@ -0,0 +1,368 @@
+local N = require("flatbuffers.numTypes")
+local ba = require("flatbuffers.binaryarray")
+local compat = require("flatbuffers.compat")
+
+local m = {}
+
+local mt = {}
+
+-- get locals for faster access
+local VOffsetT = N.VOffsetT
+local UOffsetT = N.UOffsetT
+local SOffsetT = N.SOffsetT
+local Bool = N.Bool
+local Uint8 = N.Uint8
+local Uint16 = N.Uint16
+local Uint32 = N.Uint32
+local Uint64 = N.Uint64
+local Int8 = N.Int8
+local Int16 = N.Int16
+local Int32 = N.Int32
+local Int64 = N.Int64
+local Float32 = N.Float32
+local Float64 = N.Float64
+
+local MAX_BUFFER_SIZE = 0x80000000 -- 2 GB
+local VtableMetadataFields = 2
+
+local getAlignSize = compat.GetAlignSize
+
+local function vtableEqual(a, objectStart, b)
+ UOffsetT:EnforceNumber(objectStart)
+ if (#a * VOffsetT.bytewidth) ~= #b then
+ return false
+ end
+
+ for i, elem in ipairs(a) do
+ local x = VOffsetT:Unpack(b, i * VOffsetT.bytewidth)
+ if x ~= 0 or elem ~= 0 then
+ local y = objectStart - elem
+ if x ~= y then
+ return false
+ end
+ end
+ end
+ return true
+end
+
+function m.New(initialSize)
+ assert(0 <= initialSize and initialSize < MAX_BUFFER_SIZE)
+ local o =
+ {
+ finished = false,
+ bytes = ba.New(initialSize),
+ nested = false,
+ head = initialSize,
+ minalign = 1,
+ vtables = {}
+ }
+ setmetatable(o, {__index = mt})
+ return o
+end
+
+function mt:Output(full)
+ assert(self.finished, "Builder Not Finished")
+ if full then
+ return self.bytes:Slice()
+ else
+ return self.bytes:Slice(self.head)
+ end
+end
+
+function mt:StartObject(numFields)
+ assert(not self.nested)
+
+ local vtable = {}
+
+ for _=1,numFields do
+ table.insert(vtable, 0)
+ end
+
+ self.currentVTable = vtable
+ self.objectEnd = self:Offset()
+ self.minalign = 1
+ self.nested = true
+end
+
+function mt:WriteVtable()
+ self:PrependSOffsetTRelative(0)
+ local objectOffset = self:Offset()
+
+ local exisitingVTable
+ local i = #self.vtables
+ while i >= 1 do
+ if self.vtables[i] == 0 then
+ table.remove(self.vtables,i)
+ end
+ i = i - 1
+ end
+
+ while i >= 1 do
+
+ local vt2Offset = self.vtables[i]
+ local vt2Start = #self.bytes - vt2Offset
+ local vt2len = VOffsetT:Unpack(self.bytes, vt2Start)
+
+ local metadata = VtableMetadataFields * VOffsetT.bytewidth
+ local vt2End = vt2Start + vt2Len
+ local vt2 = self.bytes:Slice(vt2Start+metadata,vt2End)
+
+ if vtableEqual(self.currentVTable, objectOffset, vt2) then
+ exisitingVTable = vt2Offset
+ break
+ end
+
+ i = i - 1
+ end
+
+ if not exisitingVTable then
+ i = #self.currentVTable
+ while i >= 1 do
+ local off = 0
+ local a = self.currentVTable[i]
+ if a and a ~= 0 then
+ off = objectOffset - a
+ end
+ self:PrependVOffsetT(off)
+
+ i = i - 1
+ end
+
+ local objectSize = objectOffset - self.objectEnd
+ self:PrependVOffsetT(objectSize)
+
+ local vBytes = #self.currentVTable + VtableMetadataFields
+ vBytes = vBytes * VOffsetT.bytewidth
+ self:PrependVOffsetT(vBytes)
+
+ local objectStart = #self.bytes - objectOffset
+ self.bytes:Set(SOffsetT:Pack(self:Offset() - objectOffset),objectStart)
+
+ table.insert(self.vtables, self:Offset())
+ else
+ local objectStart = #self.bytes - objectOffset
+ self.head = objectStart
+ self.bytes:Set(SOffsetT:Pack(exisitingVTable - objectOffset),self.head)
+ end
+
+ self.currentVTable = nil
+ return objectOffset
+end
+
+function mt:EndObject()
+ assert(self.nested)
+ self.nested = false
+ return self:WriteVtable()
+end
+
+local function growByteBuffer(self, desiredSize)
+ local s = #self.bytes
+ assert(s < MAX_BUFFER_SIZE, "Flat Buffers cannot grow buffer beyond 2 gigabytes")
+ local newsize = s
+ repeat
+ newsize = math.min(newsize * 2, MAX_BUFFER_SIZE)
+ if newsize == 0 then newsize = 1 end
+ until newsize > desiredSize
+
+ self.bytes:Grow(newsize)
+end
+
+function mt:Head()
+ return self.head
+end
+
+function mt:Offset()
+ return #self.bytes - self.head
+end
+
+function mt:Pad(n)
+ if n > 0 then
+ -- pads are 8-bit, so skip the bytewidth lookup
+ local h = self.head - n -- UInt8
+ self.head = h
+ self.bytes:Pad(n, h)
+ end
+end
+
+function mt:Prep(size, additionalBytes)
+ if size > self.minalign then
+ self.minalign = size
+ end
+
+ local h = self.head
+
+ local k = #self.bytes - h + additionalBytes
+ local alignsize = ((~k) + 1) & (size - 1) -- getAlignSize(k, size)
+
+ local desiredSize = alignsize + size + additionalBytes
+
+ while self.head < desiredSize do
+ local oldBufSize = #self.bytes
+ growByteBuffer(self, desiredSize)
+ local updatedHead = self.head + #self.bytes - oldBufSize
+ self.head = updatedHead
+ end
+
+ self:Pad(alignsize)
+end
+
+function mt:PrependSOffsetTRelative(off)
+ self:Prep(SOffsetT.bytewidth, 0)
+ assert(off <= self:Offset(), "Offset arithmetic error")
+ local off2 = self:Offset() - off + SOffsetT.bytewidth
+ self:Place(off2, SOffsetT)
+end
+
+function mt:PrependUOffsetTRelative(off)
+ self:Prep(UOffsetT.bytewidth, 0)
+ local soffset = self:Offset()
+ if off <= soffset then
+ local off2 = soffset - off + UOffsetT.bytewidth
+ self:Place(off2, UOffsetT)
+ else
+ error("Offset arithmetic error")
+ end
+end
+
+function mt:StartVector(elemSize, numElements, alignment)
+ assert(not self.nested)
+ self.nested = true
+ self:Prep(Uint32.bytewidth, elemSize * numElements)
+ self:Prep(alignment, elemSize * numElements)
+ return self:Offset()
+end
+
+function mt:EndVector(vectorNumElements)
+ assert(self.nested)
+ self.nested = false
+ self:Place(vectorNumElements, UOffsetT)
+ return self:Offset()
+end
+
+function mt:CreateString(s)
+ assert(not self.nested)
+ self.nested = true
+
+ assert(type(s) == "string")
+
+ self:Prep(UOffsetT.bytewidth, (#s + 1)*Uint8.bytewidth)
+ self:Place(0, Uint8)
+
+ local l = #s
+ self.head = self.head - l
+
+ self.bytes:Set(s, self.head, self.head + l)
+
+ return self:EndVector(#s)
+end
+
+function mt:CreateByteVector(x)
+ assert(not self.nested)
+ self.nested = true
+ self:Prep(UOffsetT.bytewidth, #x*Uint8.bytewidth)
+
+ local l = #x
+ self.head = self.head - l
+
+ self.bytes:Set(x, self.head, self.head + l)
+
+ return self:EndVector(#x)
+end
+
+function mt:Slot(slotnum)
+ assert(self.nested)
+ -- n.b. slot number is 0-based
+ self.currentVTable[slotnum + 1] = self:Offset()
+end
+
+local function finish(self, rootTable, sizePrefix)
+ UOffsetT:EnforceNumber(rootTable)
+ local prepSize = UOffsetT.bytewidth
+ if sizePrefix then
+ prepSize = prepSize + Int32.bytewidth
+ end
+
+ self:Prep(self.minalign, prepSize)
+ self:PrependUOffsetTRelative(rootTable)
+ if sizePrefix then
+ local size = #self.bytes - self.head
+ Int32:EnforceNumber(size)
+ self:PrependInt32(size)
+ end
+ self.finished = true
+ return self.head
+end
+
+function mt:Finish(rootTable)
+ return finish(self, rootTable, false)
+end
+
+function mt:FinishSizePrefixed(rootTable)
+ return finish(self, rootTable, true)
+end
+
+function mt:Prepend(flags, off)
+ self:Prep(flags.bytewidth, 0)
+ self:Place(off, flags)
+end
+
+function mt:PrependSlot(flags, o, x, d)
+ flags:EnforceNumber(x)
+ flags:EnforceNumber(d)
+ if x ~= d then
+ self:Prepend(flags, x)
+ self:Slot(o)
+ end
+end
+
+function mt:PrependBoolSlot(...) self:PrependSlot(Bool, ...) end
+function mt:PrependByteSlot(...) self:PrependSlot(Uint8, ...) end
+function mt:PrependUint8Slot(...) self:PrependSlot(Uint8, ...) end
+function mt:PrependUint16Slot(...) self:PrependSlot(Uint16, ...) end
+function mt:PrependUint32Slot(...) self:PrependSlot(Uint32, ...) end
+function mt:PrependUint64Slot(...) self:PrependSlot(Uint64, ...) end
+function mt:PrependInt8Slot(...) self:PrependSlot(Int8, ...) end
+function mt:PrependInt16Slot(...) self:PrependSlot(Int16, ...) end
+function mt:PrependInt32Slot(...) self:PrependSlot(Int32, ...) end
+function mt:PrependInt64Slot(...) self:PrependSlot(Int64, ...) end
+function mt:PrependFloat32Slot(...) self:PrependSlot(Float32, ...) end
+function mt:PrependFloat64Slot(...) self:PrependSlot(Float64, ...) end
+
+function mt:PrependUOffsetTRelativeSlot(o,x,d)
+ if x~=d then
+ self:PrependUOffsetTRelative(x)
+ self:Slot(o)
+ end
+end
+
+function mt:PrependStructSlot(v,x,d)
+ UOffsetT:EnforceNumber(d)
+ if x~=d then
+ UOffsetT:EnforceNumber(x)
+ assert(x == self:Offset(), "Tried to write a Struct at an Offset that is different from the current Offset of the Builder.")
+ self:Slot(v)
+ end
+end
+
+function mt:PrependBool(x) self:Prepend(Bool, x) end
+function mt:PrependByte(x) self:Prepend(Uint8, x) end
+function mt:PrependUint8(x) self:Prepend(Uint8, x) end
+function mt:PrependUint16(x) self:Prepend(Uint16, x) end
+function mt:PrependUint32(x) self:Prepend(Uint32, x) end
+function mt:PrependUint64(x) self:Prepend(Uint64, x) end
+function mt:PrependInt8(x) self:Prepend(Int8, x) end
+function mt:PrependInt16(x) self:Prepend(Int16, x) end
+function mt:PrependInt32(x) self:Prepend(Int32, x) end
+function mt:PrependInt64(x) self:Prepend(Int64, x) end
+function mt:PrependFloat32(x) self:Prepend(Float32, x) end
+function mt:PrependFloat64(x) self:Prepend(Float64, x) end
+function mt:PrependVOffsetT(x) self:Prepend(VOffsetT, x) end
+
+function mt:Place(x, flags)
+ local d = flags:EnforceNumberAndPack(x)
+ local h = self.head - flags.bytewidth
+ self.head = h
+ self.bytes:Set(d, h)
+end
+
+return m \ No newline at end of file
diff --git a/lua/flatbuffers/compat.lua b/lua/flatbuffers/compat.lua
new file mode 100644
index 00000000..89c992be
--- /dev/null
+++ b/lua/flatbuffers/compat.lua
@@ -0,0 +1,17 @@
+local m = {}
+
+local getAlignSize
+if _VERSION == "Lua 5.3" then
+ getAlignSize = function(k, size)
+ return ((~k) + 1) & (size - 1)
+ end
+else
+ getAlignSize = function(self, size, additionalBytes)
+ local alignsize = bit32.bnot(#self.bytes-self:Head() + additionalBytes) + 1
+ return bit32.band(alignsize,(size - 1))
+ end
+end
+
+m.GetAlignSize = getAlignSize
+
+return m \ No newline at end of file
diff --git a/lua/flatbuffers/numTypes.lua b/lua/flatbuffers/numTypes.lua
new file mode 100644
index 00000000..e8d87e12
--- /dev/null
+++ b/lua/flatbuffers/numTypes.lua
@@ -0,0 +1,198 @@
+local m = {}
+
+local ba = require("flatbuffers.binaryarray")
+
+local bpack = ba.Pack
+local bunpack = ba.Unpack
+
+local type_mt = {}
+
+function type_mt:Pack(value)
+ return bpack(self.packFmt, value)
+end
+
+function type_mt:Unpack(buf, pos)
+ return bunpack(self.packFmt, buf, pos)
+end
+
+function type_mt:ValidNumber(n)
+ if not self.min_value and not self.max_value then return true end
+ return self.min_value <= n and n <= self.max_value
+end
+
+function type_mt:EnforceNumber(n)
+ -- duplicate code since the overhead of function calls
+ -- for such a popular method is time consuming
+ if not self.min_value and not self.max_value then
+ return
+ end
+
+ if self.min_value <= n and n <= self.max_value then
+ return
+ end
+
+ error("Number is not in the valid range")
+end
+
+function type_mt:EnforceNumberAndPack(n)
+ return bpack(self.packFmt, n)
+end
+
+function type_mt:ConvertType(n, otherType)
+ assert(self.bytewidth == otherType.bytewidth, "Cannot convert between types of different widths")
+ if self == otherType then
+ return n
+ end
+ return otherType:Unpack(self:Pack(n))
+end
+
+local bool_mt =
+{
+ bytewidth = 1,
+ min_value = false,
+ max_value = true,
+ lua_type = type(true),
+ name = "bool",
+ packFmt = "<b"
+}
+
+local uint8_mt =
+{
+ bytewidth = 1,
+ min_value = 0,
+ max_value = 2^8-1,
+ lua_type = type(1),
+ name = "uint8",
+ packFmt = "<I1"
+}
+
+local uint16_mt =
+{
+ bytewidth = 2,
+ min_value = 0,
+ max_value = 2^16-1,
+ lua_type = type(1),
+ name = "uint16",
+ packFmt = "<I2"
+}
+
+local uint32_mt =
+{
+ bytewidth = 4,
+ min_value = 0,
+ max_value = 2^32-1,
+ lua_type = type(1),
+ name = "uint32",
+ packFmt = "<I4"
+}
+
+local uint64_mt =
+{
+ bytewidth = 8,
+ min_value = 0,
+ max_value = 2^64-1,
+ lua_type = type(1),
+ name = "uint64",
+ packFmt = "<I8"
+}
+
+local int8_mt =
+{
+ bytewidth = 1,
+ min_value = -2^7,
+ max_value = 2^7-1,
+ lua_type = type(1),
+ name = "int8",
+ packFmt = "<i1"
+}
+
+local int16_mt =
+{
+ bytewidth = 2,
+ min_value = -2^15,
+ max_value = 2^15-1,
+ lua_type = type(1),
+ name = "int16",
+ packFmt = "<i2"
+}
+
+local int32_mt =
+{
+ bytewidth = 4,
+ min_value = -2^15,
+ max_value = 2^15-1,
+ lua_type = type(1),
+ name = "int32",
+ packFmt = "<i4"
+}
+
+local int64_mt =
+{
+ bytewidth = 8,
+ min_value = -2^63,
+ max_value = 2^63-1,
+ lua_type = type(1),
+ name = "int64",
+ packFmt = "<i8"
+}
+
+local float32_mt =
+{
+ bytewidth = 4,
+ min_value = nil,
+ max_value = nil,
+ lua_type = type(1.0),
+ name = "float32",
+ packFmt = "<f"
+}
+
+local float64_mt =
+{
+ bytewidth = 8,
+ min_value = nil,
+ max_value = nil,
+ lua_type = type(1.0),
+ name = "float64",
+ packFmt = "<d"
+}
+
+-- register the base class
+setmetatable(bool_mt, {__index = type_mt})
+setmetatable(uint8_mt, {__index = type_mt})
+setmetatable(uint16_mt, {__index = type_mt})
+setmetatable(uint32_mt, {__index = type_mt})
+setmetatable(uint64_mt, {__index = type_mt})
+setmetatable(int8_mt, {__index = type_mt})
+setmetatable(int16_mt, {__index = type_mt})
+setmetatable(int32_mt, {__index = type_mt})
+setmetatable(int64_mt, {__index = type_mt})
+setmetatable(float32_mt, {__index = type_mt})
+setmetatable(float64_mt, {__index = type_mt})
+
+
+m.Bool = bool_mt
+m.Uint8 = uint8_mt
+m.Uint16 = uint16_mt
+m.Uint32 = uint32_mt
+m.Uint64 = uint64_mt
+m.Int8 = int8_mt
+m.Int16 = int16_mt
+m.Int32 = int32_mt
+m.Int64 = int64_mt
+m.Float32 = float32_mt
+m.Float64 = float64_mt
+
+m.UOffsetT = uint32_mt
+m.VOffsetT = uint16_mt
+m.SOffsetT = int32_mt
+
+function GenerateTypes(listOfTypes)
+ for _,t in pairs(listOfTypes) do
+ t.Pack = function(self, value) return bpack(self.packFmt, value) end
+ t.Unpack = function(self, buf, pos) return bunpack(self.packFmt, buf, pos) end
+ end
+end
+
+GenerateTypes(m)
+
+return m \ No newline at end of file
diff --git a/lua/flatbuffers/view.lua b/lua/flatbuffers/view.lua
new file mode 100644
index 00000000..da0f8bf7
--- /dev/null
+++ b/lua/flatbuffers/view.lua
@@ -0,0 +1,97 @@
+local m = {}
+local mt = {}
+
+local mt_name = "flatbuffers.view.mt"
+
+local N = require("flatbuffers.numTypes")
+local binaryarray = require("flatbuffers.binaryarray")
+
+function m.New(buf, pos)
+ N.UOffsetT:EnforceNumber(pos)
+
+ -- need to convert from a string buffer into
+ -- a binary array
+
+ local o = {
+ bytes = type(buf) == "string" and binaryarray.New(buf) or buf,
+ pos = pos
+ }
+ setmetatable(o, {__index = mt, __metatable = mt_name})
+ return o
+end
+
+function mt:Offset(vtableOffset)
+ local vtable = self.pos - self:Get(N.SOffsetT, self.pos)
+ local vtableEnd = self:Get(N.VOffsetT, vtable)
+ if vtableOffset < vtableEnd then
+ return self:Get(N.VOffsetT, vtable + vtableOffset)
+ end
+ return 0
+end
+
+function mt:Indirect(off)
+ N.UOffsetT:EnforceNumber(off)
+ return off + N.UOffsetT:Unpack(self.bytes, off)
+end
+
+function mt:String(off)
+ N.UOffsetT:EnforceNumber(off)
+ off = off + N.UOffsetT:Unpack(self.bytes, off)
+ local start = off + N.UOffsetT.bytewidth
+ local length = N.UOffsetT:Unpack(self.bytes, off)
+ return self.bytes:Slice(start, start+length)
+end
+
+function mt:VectorLen(off)
+ N.UOffsetT:EnforceNumber(off)
+ off = off + self.pos
+ off = off + N.UOffsetT:Unpack(self.bytes, off)
+ return N.UOffsetT:Unpack(self.bytes, off)
+end
+
+function mt:Vector(off)
+ N.UOffsetT:EnforceNumber(off)
+
+ off = off + self.pos
+ local x = off + self:Get(N.UOffsetT, off)
+ x = x + N.UOffsetT.bytewidth
+ return x
+end
+
+function mt:Union(t2, off)
+ assert(getmetatable(t2) == mt_name)
+ N.UOffsetT:EnforceNumber(off)
+
+ off = off + self.pos
+ t2.pos = off + self:Get(N.UOffsetT, off)
+ t2.bytes = self.bytes
+end
+
+function mt:Get(flags, off)
+ N.UOffsetT:EnforceNumber(off)
+ return flags:Unpack(self.bytes, off)
+end
+
+function mt:GetSlot(slot, d, validatorFlags)
+ N.VOffsetT:EnforceNumber(slot)
+ if validatorFlags then
+ validatorFlags:EnforceNumber(d)
+ end
+ local off = self:Offset(slot)
+ if off == 0 then
+ return d
+ end
+ return self:Get(validatorFlags, self.pos + off)
+end
+
+function mt:GetVOffsetTSlot(slot, d)
+ N.VOffsetT:EnforceNumber(slot)
+ N.VOffsetT:EnforceNumber(d)
+ local off = self:Offset(slot)
+ if off == 0 then
+ return d
+ end
+ return off
+end
+
+return m \ No newline at end of file
diff --git a/samples/lua/MyGame/Sample/Color.lua b/samples/lua/MyGame/Sample/Color.lua
new file mode 100644
index 00000000..8bf62e1d
--- /dev/null
+++ b/samples/lua/MyGame/Sample/Color.lua
@@ -0,0 +1,11 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Sample
+
+local Color = {
+ Red = 0,
+ Green = 1,
+ Blue = 2,
+}
+
+return Color -- return the module \ No newline at end of file
diff --git a/samples/lua/MyGame/Sample/Equipment.lua b/samples/lua/MyGame/Sample/Equipment.lua
new file mode 100644
index 00000000..0a20b364
--- /dev/null
+++ b/samples/lua/MyGame/Sample/Equipment.lua
@@ -0,0 +1,10 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Sample
+
+local Equipment = {
+ NONE = 0,
+ Weapon = 1,
+}
+
+return Equipment -- return the module \ No newline at end of file
diff --git a/samples/lua/MyGame/Sample/Monster.lua b/samples/lua/MyGame/Sample/Monster.lua
new file mode 100644
index 00000000..b55c27e9
--- /dev/null
+++ b/samples/lua/MyGame/Sample/Monster.lua
@@ -0,0 +1,122 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Sample
+
+local flatbuffers = require('flatbuffers')
+
+local Monster = {} -- the module
+local Monster_mt = {} -- the class metatable
+
+function Monster.New()
+ local o = {}
+ setmetatable(o, {__index = Monster_mt})
+ return o
+end
+function Monster.GetRootAsMonster(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = Monster.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function Monster_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Monster_mt:Pos()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ local x = o + self.view.pos
+ local obj = require('MyGame.Sample.Vec3').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:Mana()
+ local o = self.view:Offset(6)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
+ end
+ return 150
+end
+function Monster_mt:Hp()
+ local o = self.view:Offset(8)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
+ end
+ return 100
+end
+function Monster_mt:Name()
+ local o = self.view:Offset(10)
+ if o ~= 0 then
+ return self.view:String(o + self.view.pos)
+ end
+end
+function Monster_mt:Inventory(j)
+ local o = self.view:Offset(14)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1))
+ end
+ return 0
+end
+function Monster_mt:InventoryLength()
+ local o = self.view:Offset(14)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Color()
+ local o = self.view:Offset(16)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int8, o + self.view.pos)
+ end
+ return 2
+end
+function Monster_mt:Weapons(j)
+ local o = self.view:Offset(18)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 4)
+ x = self.view:Indirect(x)
+ local obj = require('MyGame.Sample.Weapon').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:WeaponsLength()
+ local o = self.view:Offset(18)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:EquippedType()
+ local o = self.view:Offset(20)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Equipped()
+ local o = self.view:Offset(22)
+ if o ~= 0 then
+ local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)
+ self.view:Union(obj, o)
+ return obj
+ end
+end
+function Monster.Start(builder) builder:StartObject(10) end
+function Monster.AddPos(builder, pos) builder:PrependStructSlot(0, pos, 0) end
+function Monster.AddMana(builder, mana) builder:PrependInt16Slot(1, mana, 150) end
+function Monster.AddHp(builder, hp) builder:PrependInt16Slot(2, hp, 100) end
+function Monster.AddName(builder, name) builder:PrependUOffsetTRelativeSlot(3, name, 0) end
+function Monster.AddInventory(builder, inventory) builder:PrependUOffsetTRelativeSlot(5, inventory, 0) end
+function Monster.StartInventoryVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function Monster.AddColor(builder, color) builder:PrependInt8Slot(6, color, 2) end
+function Monster.AddWeapons(builder, weapons) builder:PrependUOffsetTRelativeSlot(7, weapons, 0) end
+function Monster.StartWeaponsVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
+function Monster.AddEquippedType(builder, equippedType) builder:PrependUint8Slot(8, equippedType, 0) end
+function Monster.AddEquipped(builder, equipped) builder:PrependUOffsetTRelativeSlot(9, equipped, 0) end
+function Monster.End(builder) return builder:EndObject() end
+
+return Monster -- return the module \ No newline at end of file
diff --git a/samples/lua/MyGame/Sample/Vec3.lua b/samples/lua/MyGame/Sample/Vec3.lua
new file mode 100644
index 00000000..d42b0555
--- /dev/null
+++ b/samples/lua/MyGame/Sample/Vec3.lua
@@ -0,0 +1,35 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Sample
+
+local flatbuffers = require('flatbuffers')
+
+local Vec3 = {} -- the module
+local Vec3_mt = {} -- the class metatable
+
+function Vec3.New()
+ local o = {}
+ setmetatable(o, {__index = Vec3_mt})
+ return o
+end
+function Vec3_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Vec3_mt:X()
+ return self.view:Get(flatbuffers.N.Float32, self.view.pos + 0)
+end
+function Vec3_mt:Y()
+ return self.view:Get(flatbuffers.N.Float32, self.view.pos + 4)
+end
+function Vec3_mt:Z()
+ return self.view:Get(flatbuffers.N.Float32, self.view.pos + 8)
+end
+function Vec3.CreateVec3(builder, x, y, z)
+ builder:Prep(4, 12)
+ builder:PrependFloat32(z)
+ builder:PrependFloat32(y)
+ builder:PrependFloat32(x)
+ return builder:Offset()
+end
+
+return Vec3 -- return the module \ No newline at end of file
diff --git a/samples/lua/MyGame/Sample/Weapon.lua b/samples/lua/MyGame/Sample/Weapon.lua
new file mode 100644
index 00000000..60442b95
--- /dev/null
+++ b/samples/lua/MyGame/Sample/Weapon.lua
@@ -0,0 +1,42 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Sample
+
+local flatbuffers = require('flatbuffers')
+
+local Weapon = {} -- the module
+local Weapon_mt = {} -- the class metatable
+
+function Weapon.New()
+ local o = {}
+ setmetatable(o, {__index = Weapon_mt})
+ return o
+end
+function Weapon.GetRootAsWeapon(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = Weapon.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function Weapon_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Weapon_mt:Name()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ return self.view:String(o + self.view.pos)
+ end
+end
+function Weapon_mt:Damage()
+ local o = self.view:Offset(6)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
+ end
+ return 0
+end
+function Weapon.Start(builder) builder:StartObject(2) end
+function Weapon.AddName(builder, name) builder:PrependUOffsetTRelativeSlot(0, name, 0) end
+function Weapon.AddDamage(builder, damage) builder:PrependInt16Slot(1, damage, 0) end
+function Weapon.End(builder) return builder:EndObject() end
+
+return Weapon -- return the module \ No newline at end of file
diff --git a/samples/sample_binary.lua b/samples/sample_binary.lua
new file mode 100644
index 00000000..da965395
--- /dev/null
+++ b/samples/sample_binary.lua
@@ -0,0 +1,107 @@
+-- need to update the Lua path to point to the local flatbuffers implementation
+package.path = string.format("../lua/?.lua;%s",package.path)
+package.path = string.format("./lua/?.lua;%s",package.path)
+
+-- require the library
+local flatbuffers = require("flatbuffers")
+
+local binaryArray = flatbuffers.binaryArray-- for hex dump utility
+
+-- require the files generated from the schema
+local weapon = require("MyGame.Sample.Weapon")
+local monster = require("MyGame.Sample.Monster")
+local vec3 = require("MyGame.Sample.Vec3")
+local color = require("MyGame.Sample.Color")
+local equipment = require("MyGame.Sample.Equipment")
+
+-- get access to the builder, providing an array of size 1024
+local builder = flatbuffers.Builder(1024)
+
+local weaponOne = builder:CreateString("Sword")
+local weaponTwo = builder:CreateString("Axe")
+
+-- Create the first 'Weapon'
+weapon.Start(builder)
+weapon.AddName(builder, weaponOne)
+weapon.AddDamage(builder, 3)
+local sword = weapon.End(builder)
+
+-- Create the second 'Weapon'
+weapon.Start(builder)
+weapon.AddName(builder, weaponTwo)
+weapon.AddDamage(builder, 5)
+local axe = weapon.End(builder)
+
+-- Serialize a name for our mosnter, called 'orc'
+local name = builder:CreateString("Orc")
+
+-- Create a `vector` representing the inventory of the Orc. Each number
+-- could correspond to an item that can be claimed after he is slain.
+-- Note: Since we prepend the bytes, this loop iterates in reverse.
+monster.StartInventoryVector(builder, 10)
+for i=10,1,-1 do
+ builder:PrependByte(i)
+end
+local inv = builder:EndVector(10)
+
+-- Create a FlatBuffer vector and prepend the weapons.
+-- Note: Since we prepend the data, prepend them in reverse order.
+monster.StartWeaponsVector(builder, 2)
+builder:PrependUOffsetTRelative(axe)
+builder:PrependUOffsetTRelative(sword)
+local weapons = builder:EndVector(2)
+
+-- Create our monster by using Start() andEnd()
+monster.Start(builder)
+monster.AddPos(builder, vec3.CreateVec3(builder, 1.0, 2.0, 3.0))
+monster.AddHp(builder, 300)
+monster.AddName(builder, name)
+monster.AddInventory(builder, inv)
+monster.AddColor(builder, color.Red)
+monster.AddWeapons(builder, weapons)
+monster.AddEquippedType(builder, equipment.Weapon)
+monster.AddEquipped(builder, axe)
+local orc = monster.End(builder)
+
+-- Call 'Finish()' to instruct the builder that this monster is complete.
+builder:Finish(orc)
+
+-- Get the flatbuffer as a string containing the binary data
+local bufAsString = builder:Output()
+
+-- Convert the string representation into binary array Lua structure
+local buf = flatbuffers.binaryArray.New(bufAsString)
+
+-- Get an accessor to the root object insert the buffer
+local mon = monster.GetRootAsMonster(buf, 0)
+
+assert(mon:Mana() == 150)
+assert(mon:Hp() == 300)
+assert(mon:Name() == "Orc")
+assert(mon:Color() == color.Red)
+assert(mon:Pos():X() == 1.0)
+assert(mon:Pos():Y() == 2.0)
+assert(mon:Pos():Z() == 3.0)
+
+for i=1,mon:InventoryLength() do
+ assert(mon:Inventory(i) == i)
+end
+
+local expected = {
+ {w = 'Sword', d = 3},
+ {w = 'Axe', d = 5}
+}
+
+for i=1,mon:WeaponsLength() do
+ assert(mon:Weapons(i):Name() == expected[i].w)
+ assert(mon:Weapons(i):Damage() == expected[i].d)
+end
+
+assert(mon:EquippedType() == equipment.Weapon)
+
+local unionWeapon = weapon.New()
+unionWeapon:Init(mon:Equipped().bytes,mon:Equipped().pos)
+assert(unionWeapon:Name() == "Axe")
+assert(unionWeapon:Damage() == 5)
+
+print("The Lua FlatBuffer example was successfully created and verified!") \ No newline at end of file
diff --git a/src/flatc_main.cpp b/src/flatc_main.cpp
index 1fed8952..09efe795 100644
--- a/src/flatc_main.cpp
+++ b/src/flatc_main.cpp
@@ -71,6 +71,10 @@ int main(int argc, const char *argv[]) {
flatbuffers::IDLOptions::kPython,
"Generate Python files for tables/structs",
flatbuffers::GeneralMakeRule },
+ { flatbuffers::GenerateLua, "-l", "--lua", "Lua", true, nullptr,
+ flatbuffers::IDLOptions::kLua,
+ "Generate Lua files for tables/structs",
+ flatbuffers::GeneralMakeRule },
{ flatbuffers::GeneratePhp, nullptr, "--php", "PHP", true, nullptr,
flatbuffers::IDLOptions::kPhp, "Generate PHP files for tables/structs",
flatbuffers::GeneralMakeRule },
diff --git a/src/idl_gen_lua.cpp b/src/idl_gen_lua.cpp
new file mode 100644
index 00000000..86264918
--- /dev/null
+++ b/src/idl_gen_lua.cpp
@@ -0,0 +1,729 @@
+/*
+ * Copyright 2014 Google Inc. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ // independent from idl_parser, since this code is not needed for most clients
+
+#include <string>
+
+#include "flatbuffers/code_generators.h"
+#include "flatbuffers/flatbuffers.h"
+#include "flatbuffers/idl.h"
+#include "flatbuffers/util.h"
+
+#include <unordered_set>
+
+namespace flatbuffers {
+namespace lua {
+
+ // Hardcode spaces per indentation.
+ const char * Indent = " ";
+ const char * Comment = "-- ";
+ const char * End = "end\n";
+ const char * EndFunc = "end\n";
+ const char * SelfData = "self.view";
+ const char * SelfDataPos = "self.view.pos";
+ const char * SelfDataBytes = "self.view.bytes";
+
+ class LuaGenerator : public BaseGenerator {
+ public:
+ LuaGenerator(const Parser &parser, const std::string &path,
+ const std::string &file_name)
+ : BaseGenerator(parser, path, file_name, "" /* not used */,
+ "" /* not used */) {
+ static const char * const keywords[] = {
+ "and",
+ "break",
+ "do",
+ "else",
+ "elseif",
+ "end",
+ "false",
+ "for",
+ "function",
+ "goto",
+ "if",
+ "in",
+ "local",
+ "nil",
+ "not",
+ "or",
+ "repeat",
+ "return",
+ "then",
+ "true",
+ "until",
+ "while"
+ };
+ keywords_.insert(std::begin(keywords), std::end(keywords));
+ }
+
+ // Most field accessors need to retrieve and test the field offset first,
+ // this is the prefix code for that.
+ std::string OffsetPrefix(const FieldDef &field) {
+ return std::string(Indent) +
+ "local o = " + SelfData + ":Offset(" + NumToString(field.value.offset) + ")\n" +
+ Indent + "if o ~= 0 then\n";
+ }
+
+ // Begin a class declaration.
+ void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "local " + NormalizedName(struct_def) + " = {} -- the module\n";
+ code += "local " + NormalizedMetaName(struct_def) + " = {} -- the class metatable\n";
+ code += "\n";
+ }
+
+ // Begin enum code with a class declaration.
+ void BeginEnum(const std::string class_name, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "local " + class_name + " = {\n";
+ }
+
+ std::string EscapeKeyword(const std::string &name) const {
+ return keywords_.find(name) == keywords_.end() ? name : "_" + name;
+ }
+
+ std::string NormalizedName(const Definition &definition) const {
+ return EscapeKeyword(definition.name);
+ }
+
+ std::string NormalizedName(const EnumVal &ev) const {
+ return EscapeKeyword(ev.name);
+ }
+
+ std::string NormalizedMetaName(const Definition &definition) const {
+ return EscapeKeyword(definition.name) + "_mt";
+ }
+
+ // A single enum member.
+ void EnumMember(const EnumVal ev, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Indent) + NormalizedName(ev) + " = " + NumToString(ev.value) + ",\n";
+ }
+
+ // End enum code.
+ void EndEnum(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "}\n";
+ }
+
+ void GenerateNewObjectPrototype(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "function " + NormalizedName(struct_def) + ".New()\n";
+ code += std::string(Indent) + "local o = {}\n";
+ code += std::string(Indent) + "setmetatable(o, {__index = " + NormalizedMetaName(struct_def) + "})\n";
+ code += std::string(Indent) + "return o\n";
+ code += EndFunc;
+ }
+
+ // Initialize a new struct or table from existing data.
+ void NewRootTypeFromBuffer(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "function " + NormalizedName(struct_def) + ".GetRootAs" + NormalizedName(struct_def) + "(buf, offset)\n";
+ code += std::string(Indent) + "local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)\n";
+ code += std::string(Indent) + "local o = " + NormalizedName(struct_def) + ".New()\n";
+ code += std::string(Indent) + "o:Init(buf, n + offset)\n";
+ code += std::string(Indent) + "return o\n";
+ code += EndFunc;
+ }
+
+ // Initialize an existing object with other data, to avoid an allocation.
+ void InitializeExisting(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += "Init(buf, pos)\n";
+ code += std::string(Indent) + SelfData + " = flatbuffers.view.New(buf, pos)\n";
+ code += EndFunc;
+ }
+
+ // Get the length of a vector.
+ void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "Length()\n";
+ code += OffsetPrefix(field);
+ code += std::string(Indent) + Indent + "return " + SelfData + ":VectorLen(o)\n";
+ code += std::string(Indent) + End;
+ code += std::string(Indent) + "return 0\n";
+ code += EndFunc;
+ }
+
+ // Get the value of a struct's scalar.
+ void GetScalarFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += std::string(Indent) + "return " + getter;
+ code += std::string(SelfDataPos) + " + " + NumToString(field.value.offset) + ")\n";
+ code += EndFunc;
+ }
+
+ // Get the value of a table's scalar.
+ void GetScalarFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ std::string getter = GenGetter(field.value.type);
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += OffsetPrefix(field);
+ getter += std::string("o + ") + SelfDataPos + ")";
+ auto is_bool = field.value.type.base_type == BASE_TYPE_BOOL;
+ if (is_bool) {
+ getter = "(" + getter + " ~= 0)";
+ }
+ code += std::string(Indent) + Indent + "return " + getter + "\n";
+ code += std::string(Indent) + End;
+ std::string default_value;
+ if (is_bool) {
+ default_value = field.value.constant == "0" ? "false" : "true";
+ }
+ else {
+ default_value = field.value.constant;
+ }
+ code += std::string(Indent) + "return " + default_value + "\n";
+ code += EndFunc;
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Struct.
+ void GetStructFieldOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(obj)\n";
+ code += std::string(Indent) + "obj:Init(" + SelfDataBytes + ", " + SelfDataPos + " + ";
+ code += NumToString(field.value.offset) + ")\n";
+ code += std::string(Indent) + "return obj\n";
+ code += EndFunc;
+ }
+
+ // Get a struct by initializing an existing struct.
+ // Specific to Table.
+ void GetStructFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += OffsetPrefix(field);
+ if (field.value.type.struct_def->fixed) {
+ code += std::string(Indent) + Indent + "local x = o + " + SelfDataPos + "\n";
+ }
+ else {
+ code += std::string(Indent) + Indent + "local x = " + SelfData + ":Indirect(o + " + SelfDataPos + ")\n";
+ }
+ code += std::string(Indent) + Indent + "local obj = require('" + TypeNameWithNamespace(field) + "').New()\n";
+ code += std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
+ code += std::string(Indent) + Indent + "return obj\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a string.
+ void GetStringField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "()\n";
+ code += OffsetPrefix(field);
+ code += std::string(Indent) + Indent + "return " + GenGetter(field.value.type);
+ code += std::string("o + ") + SelfDataPos + ")\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a union from an object.
+ void GetUnionField(const StructDef &struct_def, const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field)) + "()\n";
+ code += OffsetPrefix(field);
+
+ // TODO(rw): this works and is not the good way to it:
+ //bool is_native_table = TypeName(field) == "*flatbuffers.Table";
+ //if (is_native_table) {
+ // code += std::string(Indent) + Indent + "from flatbuffers.table import Table\n";
+ //} else {
+ // code += std::string(Indent) + Indent +
+ // code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
+ //}
+ code += std::string(Indent) + Indent + "local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)\n";
+ code += std::string(Indent) + Indent + GenGetter(field.value.type) + "obj, o)\n";
+ code += std::string(Indent) + Indent + "return obj\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a vector's struct member.
+ void GetMemberOfVectorOfStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(j)\n";
+ code += OffsetPrefix(field);
+ code += std::string(Indent) + Indent + "local x = " + SelfData + ":Vector(o)\n";
+ code += std::string(Indent) + Indent + "x = x + ((j-1) * ";
+ code += NumToString(InlineSize(vectortype)) + ")\n";
+ if (!(vectortype.struct_def->fixed)) {
+ code += std::string(Indent) + Indent + "x = " + SelfData + ":Indirect(x)\n";
+ }
+ code += std::string(Indent) + Indent + "local obj = require('" + TypeNameWithNamespace(field) + "').New()\n";
+ code += std::string(Indent) + Indent + "obj:Init(" + SelfDataBytes + ", x)\n";
+ code += std::string(Indent) + Indent + "return obj\n";
+ code += std::string(Indent) + End;
+ code += EndFunc;
+ }
+
+ // Get the value of a vector's non-struct member. Uses a named return
+ // argument to conveniently set the zero value for the result.
+ void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
+ const FieldDef &field,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ auto vectortype = field.value.type.VectorType();
+
+ GenReceiver(struct_def, code_ptr);
+ code += MakeCamel(NormalizedName(field));
+ code += "(j)\n";
+ code += OffsetPrefix(field);
+ code += std::string(Indent) + Indent + "local a = " + SelfData + ":Vector(o)\n";
+ code += std::string(Indent) + Indent;
+ code += "return " + GenGetter(field.value.type);
+ code += "a + ((j-1) * ";
+ code += NumToString(InlineSize(vectortype)) + "))\n";
+ code += std::string(Indent) + End;
+ if (vectortype.base_type == BASE_TYPE_STRING) {
+ code += std::string(Indent) + "return ''\n";
+ }
+ else {
+ code += std::string(Indent) + "return 0\n";
+ }
+ code += EndFunc;
+ }
+
+ // Begin the creator function signature.
+ void BeginBuilderArgs(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+
+ code += "function " + NormalizedName(struct_def) + ".Create" + NormalizedName(struct_def);
+ code += "(builder";
+ }
+
+ // Recursively generate arguments for a constructor, to deal with nested
+ // structs.
+ void StructBuilderArgs(const StructDef &struct_def,
+ const char *nameprefix, std::string *code_ptr) {
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (IsStruct(field.value.type)) {
+ // Generate arguments for a struct inside a struct. To ensure names
+ // don't clash, and to make it obvious these arguments are constructing
+ // a nested struct, prefix the name with the field name.
+ StructBuilderArgs(*field.value.type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
+ }
+ else {
+ std::string &code = *code_ptr;
+ code += (std::string) ", " + nameprefix;
+ code += MakeCamel(NormalizedName(field), false);
+ }
+ }
+ }
+
+ // End the creator function signature.
+ void EndBuilderArgs(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += ")\n";
+ }
+
+ // Recursively generate struct construction statements and instert manual
+ // padding.
+ void StructBuilderBody(const StructDef &struct_def,
+ const char *nameprefix, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Indent) + "builder:Prep(" + NumToString(struct_def.minalign) + ", ";
+ code += NumToString(struct_def.bytesize) + ")\n";
+ for (auto it = struct_def.fields.vec.rbegin();
+ it != struct_def.fields.vec.rend(); ++it) {
+ auto &field = **it;
+ if (field.padding)
+ code += std::string(Indent) + "builder:Pad(" + NumToString(field.padding) + ")\n";
+ if (IsStruct(field.value.type)) {
+ StructBuilderBody(*field.value.type.struct_def,
+ (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr);
+ }
+ else {
+ code += std::string(Indent) + "builder:Prepend" + GenMethod(field) + "(";
+ code += nameprefix + MakeCamel(NormalizedName(field), false) + ")\n";
+ }
+ }
+ }
+
+ void EndBuilderBody(std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Indent) + "return builder:Offset()\n";
+ code += EndFunc;
+ }
+
+ // Get the value of a table's starting offset.
+ void GetStartOfTable(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".Start";
+ code += "(builder) ";
+ code += "builder:StartObject(";
+ code += NumToString(struct_def.fields.vec.size());
+ code += ") end\n";
+ }
+
+ // Set the value of a table's field.
+ void BuildFieldOfTable(const StructDef &struct_def,
+ const FieldDef &field, const size_t offset,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".Add" + MakeCamel(NormalizedName(field));
+ code += "(builder, ";
+ code += MakeCamel(NormalizedName(field), false);
+ code += ") ";
+ code += "builder:Prepend";
+ code += GenMethod(field) + "Slot(";
+ code += NumToString(offset) + ", ";
+ // todo: i don't need to cast in Lua, but am I missing something?
+ // if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
+ // code += "flatbuffers.N.UOffsetTFlags.py_type";
+ // code += "(";
+ // code += MakeCamel(NormalizedName(field), false) + ")";
+ // } else {
+ code += MakeCamel(NormalizedName(field), false);
+ // }
+ code += ", " + field.value.constant;
+ code += ") end\n";
+ }
+
+ // Set the value of one of the members of a table's vector.
+ void BuildVectorOfTable(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".Start";
+ code += MakeCamel(NormalizedName(field));
+ code += "Vector(builder, numElems) return builder:StartVector(";
+ auto vector_type = field.value.type.VectorType();
+ auto alignment = InlineAlignment(vector_type);
+ auto elem_size = InlineSize(vector_type);
+ code += NumToString(elem_size);
+ code += ", numElems, " + NumToString(alignment);
+ code += ") end\n";
+ }
+
+ // Get the offset of the end of a table.
+ void GetEndOffsetOnTable(const StructDef &struct_def,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedName(struct_def) + ".End";
+ code += "(builder) ";
+ code += "return builder:EndObject() end\n";
+ }
+
+ // Generate the receiver for function signatures.
+ void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += "function " + NormalizedMetaName(struct_def) + ":";
+ }
+
+ // Generate a struct field, conditioned on its child type(s).
+ void GenStructAccessor(const StructDef &struct_def,
+ const FieldDef &field, std::string *code_ptr) {
+ GenComment(field.doc_comment, code_ptr, nullptr, Comment);
+ if (IsScalar(field.value.type.base_type)) {
+ if (struct_def.fixed) {
+ GetScalarFieldOfStruct(struct_def, field, code_ptr);
+ }
+ else {
+ GetScalarFieldOfTable(struct_def, field, code_ptr);
+ }
+ }
+ else {
+ switch (field.value.type.base_type) {
+ case BASE_TYPE_STRUCT:
+ if (struct_def.fixed) {
+ GetStructFieldOfStruct(struct_def, field, code_ptr);
+ }
+ else {
+ GetStructFieldOfTable(struct_def, field, code_ptr);
+ }
+ break;
+ case BASE_TYPE_STRING: GetStringField(struct_def, field, code_ptr); break;
+ case BASE_TYPE_VECTOR: {
+ auto vectortype = field.value.type.VectorType();
+ if (vectortype.base_type == BASE_TYPE_STRUCT) {
+ GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
+ }
+ else {
+ GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
+ }
+ break;
+ }
+ case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
+ default: FLATBUFFERS_ASSERT(0);
+ }
+ }
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ GetVectorLen(struct_def, field, code_ptr);
+ }
+ }
+
+ // Generate table constructors, conditioned on its members' types.
+ void GenTableBuilders(const StructDef &struct_def,
+ std::string *code_ptr) {
+ GetStartOfTable(struct_def, code_ptr);
+
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ auto offset = it - struct_def.fields.vec.begin();
+ BuildFieldOfTable(struct_def, field, offset, code_ptr);
+ if (field.value.type.base_type == BASE_TYPE_VECTOR) {
+ BuildVectorOfTable(struct_def, field, code_ptr);
+ }
+ }
+
+ GetEndOffsetOnTable(struct_def, code_ptr);
+ }
+
+ // Generate struct or table methods.
+ void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
+ if (struct_def.generated) return;
+
+ GenComment(struct_def.doc_comment, code_ptr, nullptr, Comment);
+ BeginClass(struct_def, code_ptr);
+
+ GenerateNewObjectPrototype(struct_def, code_ptr);
+
+ if (!struct_def.fixed) {
+ // Generate a special accessor for the table that has been declared as
+ // the root type.
+ NewRootTypeFromBuffer(struct_def, code_ptr);
+ }
+
+ // Generate the Init method that sets the field in a pre-existing
+ // accessor object. This is to allow object reuse.
+ InitializeExisting(struct_def, code_ptr);
+ for (auto it = struct_def.fields.vec.begin();
+ it != struct_def.fields.vec.end(); ++it) {
+ auto &field = **it;
+ if (field.deprecated) continue;
+
+ GenStructAccessor(struct_def, field, code_ptr);
+ }
+
+ if (struct_def.fixed) {
+ // create a struct constructor function
+ GenStructBuilder(struct_def, code_ptr);
+ }
+ else {
+ // Create a set of functions that allow table construction.
+ GenTableBuilders(struct_def, code_ptr);
+ }
+ }
+
+ // Generate enum declarations.
+ void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
+ if (enum_def.generated) return;
+
+ GenComment(enum_def.doc_comment, code_ptr, nullptr, Comment);
+ BeginEnum(NormalizedName(enum_def), code_ptr);
+ for (auto it = enum_def.vals.vec.begin(); it != enum_def.vals.vec.end();
+ ++it) {
+ auto &ev = **it;
+ GenComment(ev.doc_comment, code_ptr, nullptr, Comment);
+ EnumMember(ev, code_ptr);
+ }
+ EndEnum(code_ptr);
+ }
+
+ // Returns the function name that is able to read a value of the given type.
+ std::string GenGetter(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return std::string(SelfData) + ":String(";
+ case BASE_TYPE_UNION: return std::string(SelfData) + ":Union(";
+ case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
+ default:
+ return std::string(SelfData) + ":Get(flatbuffers.N." +
+ MakeCamel(GenTypeGet(type)) + ", ";
+ }
+ }
+
+ // Returns the method name for use with add/put calls.
+ std::string GenMethod(const FieldDef &field) {
+ return IsScalar(field.value.type.base_type)
+ ? MakeCamel(GenTypeBasic(field.value.type))
+ : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
+ }
+
+ std::string GenTypeBasic(const Type &type) {
+ static const char *ctypename[] = {
+ // clang-format off
+ #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
+ CTYPE, JTYPE, GTYPE, NTYPE, PTYPE) \
+ #PTYPE,
+ FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
+ #undef FLATBUFFERS_TD
+ // clang-format on
+ };
+ return ctypename[type.base_type];
+ }
+
+ std::string GenTypePointer(const Type &type) {
+ switch (type.base_type) {
+ case BASE_TYPE_STRING: return "string";
+ case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
+ case BASE_TYPE_STRUCT: return type.struct_def->name;
+ case BASE_TYPE_UNION:
+ // fall through
+ default: return "*flatbuffers.Table";
+ }
+ }
+
+ std::string GenTypeGet(const Type &type) {
+ return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
+ }
+
+ std::string GetNamespace(const Type &type) {
+ return type.struct_def->defined_namespace->GetFullyQualifiedName(type.struct_def->name);
+ }
+
+ std::string TypeName(const FieldDef &field) {
+ return GenTypeGet(field.value.type);
+ }
+
+ std::string TypeNameWithNamespace(const FieldDef &field) {
+ return GetNamespace(field.value.type);
+ }
+
+ // Create a struct with a builder and the struct's arguments.
+ void GenStructBuilder(const StructDef &struct_def,
+ std::string *code_ptr) {
+ BeginBuilderArgs(struct_def, code_ptr);
+ StructBuilderArgs(struct_def, "", code_ptr);
+ EndBuilderArgs(code_ptr);
+
+ StructBuilderBody(struct_def, "", code_ptr);
+ EndBuilderBody(code_ptr);
+ }
+
+ bool generate() {
+ if (!generateEnums()) return false;
+ if (!generateStructs()) return false;
+ return true;
+ }
+
+ private:
+ bool generateEnums() {
+ for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
+ ++it) {
+ auto &enum_def = **it;
+ std::string enumcode;
+ GenEnum(enum_def, &enumcode);
+ if (!SaveType(enum_def, enumcode, false)) return false;
+ }
+ return true;
+ }
+
+ bool generateStructs() {
+ for (auto it = parser_.structs_.vec.begin();
+ it != parser_.structs_.vec.end(); ++it) {
+ auto &struct_def = **it;
+ std::string declcode;
+ GenStruct(struct_def, &declcode);
+ if (!SaveType(struct_def, declcode, true)) return false;
+ }
+ return true;
+ }
+
+ // Begin by declaring namespace and imports.
+ void BeginFile(const std::string name_space_name, const bool needs_imports,
+ std::string *code_ptr) {
+ std::string &code = *code_ptr;
+ code += std::string(Comment) + FlatBuffersGeneratedWarning() + "\n\n";
+ code += std::string(Comment) + "namespace: " + name_space_name + "\n\n";
+ if (needs_imports) {
+ code += "local flatbuffers = require('flatbuffers')\n\n";
+ }
+ }
+
+ // Save out the generated code for a Lua Table type.
+ bool SaveType(const Definition &def, const std::string &classcode,
+ bool needs_imports) {
+ if (!classcode.length()) return true;
+
+ std::string namespace_dir = path_;
+ auto &namespaces = def.defined_namespace->components;
+ for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
+ if (it != namespaces.begin()) namespace_dir += kPathSeparator;
+ namespace_dir += *it;
+ //std::string init_py_filename = namespace_dir + "/__init__.py";
+ //SaveFile(init_py_filename.c_str(), "", false);
+ }
+
+ std::string code = "";
+ BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
+ code += classcode;
+ code += "\n";
+ code += "return " + NormalizedName(def) + " " + Comment + "return the module";
+ std::string filename =
+ NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".lua";
+ return SaveFile(filename.c_str(), code, false);
+ }
+ private:
+ std::unordered_set<std::string> keywords_;
+ };
+
+} // namespace lua
+
+bool GenerateLua(const Parser &parser, const std::string &path,
+ const std::string &file_name) {
+ lua::LuaGenerator generator(parser, path, file_name);
+ return generator.generate();
+}
+
+} // namespace flatbuffers
diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp
index d2f518f2..e000ada9 100644
--- a/src/idl_gen_python.cpp
+++ b/src/idl_gen_python.cpp
@@ -72,7 +72,7 @@ class PythonGenerator : public BaseGenerator {
"with",
"yield"
};
- for (auto kw = keywords; *kw; kw++) keywords_.insert(*kw);
+ keywords_.insert(std::begin(keywords), std::end(keywords));
}
// Most field accessors need to retrieve and test the field offset first,
diff --git a/tests/LuaTest.bat b/tests/LuaTest.bat
new file mode 100644
index 00000000..2bbf1d0e
--- /dev/null
+++ b/tests/LuaTest.bat
@@ -0,0 +1,6 @@
+set buildtype=Release
+if "%1"=="-b" set buildtype=%2
+
+..\%buildtype%\flatc.exe --lua -I include_test monster_test.fbs
+
+lua53.exe luatest.lua \ No newline at end of file
diff --git a/tests/MyGame/Example/Ability.lua b/tests/MyGame/Example/Ability.lua
new file mode 100644
index 00000000..7fb664ac
--- /dev/null
+++ b/tests/MyGame/Example/Ability.lua
@@ -0,0 +1,31 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local Ability = {} -- the module
+local Ability_mt = {} -- the class metatable
+
+function Ability.New()
+ local o = {}
+ setmetatable(o, {__index = Ability_mt})
+ return o
+end
+function Ability_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Ability_mt:Id()
+ return self.view:Get(flatbuffers.N.Uint32, self.view.pos + 0)
+end
+function Ability_mt:Distance()
+ return self.view:Get(flatbuffers.N.Uint32, self.view.pos + 4)
+end
+function Ability.CreateAbility(builder, id, distance)
+ builder:Prep(4, 8)
+ builder:PrependUint32(distance)
+ builder:PrependUint32(id)
+ return builder:Offset()
+end
+
+return Ability -- return the module \ No newline at end of file
diff --git a/tests/MyGame/Example/Any.lua b/tests/MyGame/Example/Any.lua
new file mode 100644
index 00000000..03225ba2
--- /dev/null
+++ b/tests/MyGame/Example/Any.lua
@@ -0,0 +1,12 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local Any = {
+ NONE = 0,
+ Monster = 1,
+ TestSimpleTableWithEnum = 2,
+ MyGame_Example2_Monster = 3,
+}
+
+return Any -- return the module \ No newline at end of file
diff --git a/tests/MyGame/Example/Color.lua b/tests/MyGame/Example/Color.lua
new file mode 100644
index 00000000..c3ec0922
--- /dev/null
+++ b/tests/MyGame/Example/Color.lua
@@ -0,0 +1,11 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local Color = {
+ Red = 1,
+ Green = 2,
+ Blue = 8,
+}
+
+return Color -- return the module \ No newline at end of file
diff --git a/tests/MyGame/Example/Monster.lua b/tests/MyGame/Example/Monster.lua
new file mode 100644
index 00000000..a656f9b2
--- /dev/null
+++ b/tests/MyGame/Example/Monster.lua
@@ -0,0 +1,542 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+-- /// an example documentation comment: monster object
+local Monster = {} -- the module
+local Monster_mt = {} -- the class metatable
+
+function Monster.New()
+ local o = {}
+ setmetatable(o, {__index = Monster_mt})
+ return o
+end
+function Monster.GetRootAsMonster(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = Monster.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function Monster_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Monster_mt:Pos()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ local x = o + self.view.pos
+ local obj = require('MyGame.Example.Vec3').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:Mana()
+ local o = self.view:Offset(6)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
+ end
+ return 150
+end
+function Monster_mt:Hp()
+ local o = self.view:Offset(8)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
+ end
+ return 100
+end
+function Monster_mt:Name()
+ local o = self.view:Offset(10)
+ if o ~= 0 then
+ return self.view:String(o + self.view.pos)
+ end
+end
+function Monster_mt:Inventory(j)
+ local o = self.view:Offset(14)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1))
+ end
+ return 0
+end
+function Monster_mt:InventoryLength()
+ local o = self.view:Offset(14)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Color()
+ local o = self.view:Offset(16)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int8, o + self.view.pos)
+ end
+ return 8
+end
+function Monster_mt:TestType()
+ local o = self.view:Offset(18)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Test()
+ local o = self.view:Offset(20)
+ if o ~= 0 then
+ local obj = flatbuffers.view.New(require('flatbuffers.binaryarray').New(0), 0)
+ self.view:Union(obj, o)
+ return obj
+ end
+end
+function Monster_mt:Test4(j)
+ local o = self.view:Offset(22)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 4)
+ local obj = require('MyGame.Example.Test').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:Test4Length()
+ local o = self.view:Offset(22)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Testarrayofstring(j)
+ local o = self.view:Offset(24)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:String(a + ((j-1) * 4))
+ end
+ return ''
+end
+function Monster_mt:TestarrayofstringLength()
+ local o = self.view:Offset(24)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+-- /// an example documentation comment: this will end up in the generated code
+-- /// multiline too
+function Monster_mt:Testarrayoftables(j)
+ local o = self.view:Offset(26)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 4)
+ x = self.view:Indirect(x)
+ local obj = require('MyGame.Example.Monster').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:TestarrayoftablesLength()
+ local o = self.view:Offset(26)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Enemy()
+ local o = self.view:Offset(28)
+ if o ~= 0 then
+ local x = self.view:Indirect(o + self.view.pos)
+ local obj = require('MyGame.Example.Monster').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:Testnestedflatbuffer(j)
+ local o = self.view:Offset(30)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1))
+ end
+ return 0
+end
+function Monster_mt:TestnestedflatbufferLength()
+ local o = self.view:Offset(30)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Testempty()
+ local o = self.view:Offset(32)
+ if o ~= 0 then
+ local x = self.view:Indirect(o + self.view.pos)
+ local obj = require('MyGame.Example.Stat').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:Testbool()
+ local o = self.view:Offset(34)
+ if o ~= 0 then
+ return (self.view:Get(flatbuffers.N.Bool, o + self.view.pos) ~= 0)
+ end
+ return false
+end
+function Monster_mt:Testhashs32Fnv1()
+ local o = self.view:Offset(36)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int32, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashu32Fnv1()
+ local o = self.view:Offset(38)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint32, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashs64Fnv1()
+ local o = self.view:Offset(40)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashu64Fnv1()
+ local o = self.view:Offset(42)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashs32Fnv1a()
+ local o = self.view:Offset(44)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int32, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashu32Fnv1a()
+ local o = self.view:Offset(46)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint32, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashs64Fnv1a()
+ local o = self.view:Offset(48)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testhashu64Fnv1a()
+ local o = self.view:Offset(50)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:Testarrayofbools(j)
+ local o = self.view:Offset(52)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Bool, a + ((j-1) * 1))
+ end
+ return 0
+end
+function Monster_mt:TestarrayofboolsLength()
+ local o = self.view:Offset(52)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Testf()
+ local o = self.view:Offset(54)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Float32, o + self.view.pos)
+ end
+ return 3.14159
+end
+function Monster_mt:Testf2()
+ local o = self.view:Offset(56)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Float32, o + self.view.pos)
+ end
+ return 3.0
+end
+function Monster_mt:Testf3()
+ local o = self.view:Offset(58)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Float32, o + self.view.pos)
+ end
+ return 0.0
+end
+function Monster_mt:Testarrayofstring2(j)
+ local o = self.view:Offset(60)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:String(a + ((j-1) * 4))
+ end
+ return ''
+end
+function Monster_mt:Testarrayofstring2Length()
+ local o = self.view:Offset(60)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Testarrayofsortedstruct(j)
+ local o = self.view:Offset(62)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 8)
+ local obj = require('MyGame.Example.Ability').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:TestarrayofsortedstructLength()
+ local o = self.view:Offset(62)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Flex(j)
+ local o = self.view:Offset(64)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint8, a + ((j-1) * 1))
+ end
+ return 0
+end
+function Monster_mt:FlexLength()
+ local o = self.view:Offset(64)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:Test5(j)
+ local o = self.view:Offset(66)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 4)
+ local obj = require('MyGame.Example.Test').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:Test5Length()
+ local o = self.view:Offset(66)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:VectorOfLongs(j)
+ local o = self.view:Offset(68)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Int64, a + ((j-1) * 8))
+ end
+ return 0
+end
+function Monster_mt:VectorOfLongsLength()
+ local o = self.view:Offset(68)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:VectorOfDoubles(j)
+ local o = self.view:Offset(70)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Float64, a + ((j-1) * 8))
+ end
+ return 0
+end
+function Monster_mt:VectorOfDoublesLength()
+ local o = self.view:Offset(70)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:ParentNamespaceTest()
+ local o = self.view:Offset(72)
+ if o ~= 0 then
+ local x = self.view:Indirect(o + self.view.pos)
+ local obj = require('MyGame.InParentNamespace').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:VectorOfReferrables(j)
+ local o = self.view:Offset(74)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 4)
+ x = self.view:Indirect(x)
+ local obj = require('MyGame.Example.Referrable').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:VectorOfReferrablesLength()
+ local o = self.view:Offset(74)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:SingleWeakReference()
+ local o = self.view:Offset(76)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:VectorOfWeakReferences(j)
+ local o = self.view:Offset(78)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint64, a + ((j-1) * 8))
+ end
+ return 0
+end
+function Monster_mt:VectorOfWeakReferencesLength()
+ local o = self.view:Offset(78)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:VectorOfStrongReferrables(j)
+ local o = self.view:Offset(80)
+ if o ~= 0 then
+ local x = self.view:Vector(o)
+ x = x + ((j-1) * 4)
+ x = self.view:Indirect(x)
+ local obj = require('MyGame.Example.Referrable').New()
+ obj:Init(self.view.bytes, x)
+ return obj
+ end
+end
+function Monster_mt:VectorOfStrongReferrablesLength()
+ local o = self.view:Offset(80)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:CoOwningReference()
+ local o = self.view:Offset(82)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:VectorOfCoOwningReferences(j)
+ local o = self.view:Offset(84)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint64, a + ((j-1) * 8))
+ end
+ return 0
+end
+function Monster_mt:VectorOfCoOwningReferencesLength()
+ local o = self.view:Offset(84)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster_mt:NonOwningReference()
+ local o = self.view:Offset(86)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function Monster_mt:VectorOfNonOwningReferences(j)
+ local o = self.view:Offset(88)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Uint64, a + ((j-1) * 8))
+ end
+ return 0
+end
+function Monster_mt:VectorOfNonOwningReferencesLength()
+ local o = self.view:Offset(88)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function Monster.Start(builder) builder:StartObject(43) end
+function Monster.AddPos(builder, pos) builder:PrependStructSlot(0, pos, 0) end
+function Monster.AddMana(builder, mana) builder:PrependInt16Slot(1, mana, 150) end
+function Monster.AddHp(builder, hp) builder:PrependInt16Slot(2, hp, 100) end
+function Monster.AddName(builder, name) builder:PrependUOffsetTRelativeSlot(3, name, 0) end
+function Monster.AddInventory(builder, inventory) builder:PrependUOffsetTRelativeSlot(5, inventory, 0) end
+function Monster.StartInventoryVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function Monster.AddColor(builder, color) builder:PrependInt8Slot(6, color, 8) end
+function Monster.AddTestType(builder, testType) builder:PrependUint8Slot(7, testType, 0) end
+function Monster.AddTest(builder, test) builder:PrependUOffsetTRelativeSlot(8, test, 0) end
+function Monster.AddTest4(builder, test4) builder:PrependUOffsetTRelativeSlot(9, test4, 0) end
+function Monster.StartTest4Vector(builder, numElems) return builder:StartVector(4, numElems, 2) end
+function Monster.AddTestarrayofstring(builder, testarrayofstring) builder:PrependUOffsetTRelativeSlot(10, testarrayofstring, 0) end
+function Monster.StartTestarrayofstringVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
+function Monster.AddTestarrayoftables(builder, testarrayoftables) builder:PrependUOffsetTRelativeSlot(11, testarrayoftables, 0) end
+function Monster.StartTestarrayoftablesVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
+function Monster.AddEnemy(builder, enemy) builder:PrependUOffsetTRelativeSlot(12, enemy, 0) end
+function Monster.AddTestnestedflatbuffer(builder, testnestedflatbuffer) builder:PrependUOffsetTRelativeSlot(13, testnestedflatbuffer, 0) end
+function Monster.StartTestnestedflatbufferVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function Monster.AddTestempty(builder, testempty) builder:PrependUOffsetTRelativeSlot(14, testempty, 0) end
+function Monster.AddTestbool(builder, testbool) builder:PrependBoolSlot(15, testbool, 0) end
+function Monster.AddTesthashs32Fnv1(builder, testhashs32Fnv1) builder:PrependInt32Slot(16, testhashs32Fnv1, 0) end
+function Monster.AddTesthashu32Fnv1(builder, testhashu32Fnv1) builder:PrependUint32Slot(17, testhashu32Fnv1, 0) end
+function Monster.AddTesthashs64Fnv1(builder, testhashs64Fnv1) builder:PrependInt64Slot(18, testhashs64Fnv1, 0) end
+function Monster.AddTesthashu64Fnv1(builder, testhashu64Fnv1) builder:PrependUint64Slot(19, testhashu64Fnv1, 0) end
+function Monster.AddTesthashs32Fnv1a(builder, testhashs32Fnv1a) builder:PrependInt32Slot(20, testhashs32Fnv1a, 0) end
+function Monster.AddTesthashu32Fnv1a(builder, testhashu32Fnv1a) builder:PrependUint32Slot(21, testhashu32Fnv1a, 0) end
+function Monster.AddTesthashs64Fnv1a(builder, testhashs64Fnv1a) builder:PrependInt64Slot(22, testhashs64Fnv1a, 0) end
+function Monster.AddTesthashu64Fnv1a(builder, testhashu64Fnv1a) builder:PrependUint64Slot(23, testhashu64Fnv1a, 0) end
+function Monster.AddTestarrayofbools(builder, testarrayofbools) builder:PrependUOffsetTRelativeSlot(24, testarrayofbools, 0) end
+function Monster.StartTestarrayofboolsVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function Monster.AddTestf(builder, testf) builder:PrependFloat32Slot(25, testf, 3.14159) end
+function Monster.AddTestf2(builder, testf2) builder:PrependFloat32Slot(26, testf2, 3.0) end
+function Monster.AddTestf3(builder, testf3) builder:PrependFloat32Slot(27, testf3, 0.0) end
+function Monster.AddTestarrayofstring2(builder, testarrayofstring2) builder:PrependUOffsetTRelativeSlot(28, testarrayofstring2, 0) end
+function Monster.StartTestarrayofstring2Vector(builder, numElems) return builder:StartVector(4, numElems, 4) end
+function Monster.AddTestarrayofsortedstruct(builder, testarrayofsortedstruct) builder:PrependUOffsetTRelativeSlot(29, testarrayofsortedstruct, 0) end
+function Monster.StartTestarrayofsortedstructVector(builder, numElems) return builder:StartVector(8, numElems, 4) end
+function Monster.AddFlex(builder, flex) builder:PrependUOffsetTRelativeSlot(30, flex, 0) end
+function Monster.StartFlexVector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function Monster.AddTest5(builder, test5) builder:PrependUOffsetTRelativeSlot(31, test5, 0) end
+function Monster.StartTest5Vector(builder, numElems) return builder:StartVector(4, numElems, 2) end
+function Monster.AddVectorOfLongs(builder, vectorOfLongs) builder:PrependUOffsetTRelativeSlot(32, vectorOfLongs, 0) end
+function Monster.StartVectorOfLongsVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
+function Monster.AddVectorOfDoubles(builder, vectorOfDoubles) builder:PrependUOffsetTRelativeSlot(33, vectorOfDoubles, 0) end
+function Monster.StartVectorOfDoublesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
+function Monster.AddParentNamespaceTest(builder, parentNamespaceTest) builder:PrependUOffsetTRelativeSlot(34, parentNamespaceTest, 0) end
+function Monster.AddVectorOfReferrables(builder, vectorOfReferrables) builder:PrependUOffsetTRelativeSlot(35, vectorOfReferrables, 0) end
+function Monster.StartVectorOfReferrablesVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
+function Monster.AddSingleWeakReference(builder, singleWeakReference) builder:PrependUint64Slot(36, singleWeakReference, 0) end
+function Monster.AddVectorOfWeakReferences(builder, vectorOfWeakReferences) builder:PrependUOffsetTRelativeSlot(37, vectorOfWeakReferences, 0) end
+function Monster.StartVectorOfWeakReferencesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
+function Monster.AddVectorOfStrongReferrables(builder, vectorOfStrongReferrables) builder:PrependUOffsetTRelativeSlot(38, vectorOfStrongReferrables, 0) end
+function Monster.StartVectorOfStrongReferrablesVector(builder, numElems) return builder:StartVector(4, numElems, 4) end
+function Monster.AddCoOwningReference(builder, coOwningReference) builder:PrependUint64Slot(39, coOwningReference, 0) end
+function Monster.AddVectorOfCoOwningReferences(builder, vectorOfCoOwningReferences) builder:PrependUOffsetTRelativeSlot(40, vectorOfCoOwningReferences, 0) end
+function Monster.StartVectorOfCoOwningReferencesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
+function Monster.AddNonOwningReference(builder, nonOwningReference) builder:PrependUint64Slot(41, nonOwningReference, 0) end
+function Monster.AddVectorOfNonOwningReferences(builder, vectorOfNonOwningReferences) builder:PrependUOffsetTRelativeSlot(42, vectorOfNonOwningReferences, 0) end
+function Monster.StartVectorOfNonOwningReferencesVector(builder, numElems) return builder:StartVector(8, numElems, 8) end
+function Monster.End(builder) return builder:EndObject() end
+
+return Monster -- return the module \ No newline at end of file
diff --git a/tests/MyGame/Example/Referrable.lua b/tests/MyGame/Example/Referrable.lua
new file mode 100644
index 00000000..9b0f5a19
--- /dev/null
+++ b/tests/MyGame/Example/Referrable.lua
@@ -0,0 +1,35 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local Referrable = {} -- the module
+local Referrable_mt = {} -- the class metatable
+
+function Referrable.New()
+ local o = {}
+ setmetatable(o, {__index = Referrable_mt})
+ return o
+end
+function Referrable.GetRootAsReferrable(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = Referrable.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function Referrable_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Referrable_mt:Id()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function Referrable.Start(builder) builder:StartObject(1) end
+function Referrable.AddId(builder, id) builder:PrependUint64Slot(0, id, 0) end
+function Referrable.End(builder) return builder:EndObject() end
+
+return Referrable -- return the module \ No newline at end of file
diff --git a/tests/MyGame/Example/Stat.lua b/tests/MyGame/Example/Stat.lua
new file mode 100644
index 00000000..69991843
--- /dev/null
+++ b/tests/MyGame/Example/Stat.lua
@@ -0,0 +1,50 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local Stat = {} -- the module
+local Stat_mt = {} -- the class metatable
+
+function Stat.New()
+ local o = {}
+ setmetatable(o, {__index = Stat_mt})
+ return o
+end
+function Stat.GetRootAsStat(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = Stat.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function Stat_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Stat_mt:Id()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ return self.view:String(o + self.view.pos)
+ end
+end
+function Stat_mt:Val()
+ local o = self.view:Offset(6)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int64, o + self.view.pos)
+ end
+ return 0
+end
+function Stat_mt:Count()
+ local o = self.view:Offset(8)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint16, o + self.view.pos)
+ end
+ return 0
+end
+function Stat.Start(builder) builder:StartObject(3) end
+function Stat.AddId(builder, id) builder:PrependUOffsetTRelativeSlot(0, id, 0) end
+function Stat.AddVal(builder, val) builder:PrependInt64Slot(1, val, 0) end
+function Stat.AddCount(builder, count) builder:PrependUint16Slot(2, count, 0) end
+function Stat.End(builder) return builder:EndObject() end
+
+return Stat -- return the module \ No newline at end of file
diff --git a/tests/MyGame/Example/Test.lua b/tests/MyGame/Example/Test.lua
new file mode 100644
index 00000000..154067bf
--- /dev/null
+++ b/tests/MyGame/Example/Test.lua
@@ -0,0 +1,32 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local Test = {} -- the module
+local Test_mt = {} -- the class metatable
+
+function Test.New()
+ local o = {}
+ setmetatable(o, {__index = Test_mt})
+ return o
+end
+function Test_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Test_mt:A()
+ return self.view:Get(flatbuffers.N.Int16, self.view.pos + 0)
+end
+function Test_mt:B()
+ return self.view:Get(flatbuffers.N.Int8, self.view.pos + 2)
+end
+function Test.CreateTest(builder, a, b)
+ builder:Prep(2, 4)
+ builder:Pad(1)
+ builder:PrependInt8(b)
+ builder:PrependInt16(a)
+ return builder:Offset()
+end
+
+return Test -- return the module \ No newline at end of file
diff --git a/tests/MyGame/Example/TestSimpleTableWithEnum.lua b/tests/MyGame/Example/TestSimpleTableWithEnum.lua
new file mode 100644
index 00000000..c17fb967
--- /dev/null
+++ b/tests/MyGame/Example/TestSimpleTableWithEnum.lua
@@ -0,0 +1,35 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local TestSimpleTableWithEnum = {} -- the module
+local TestSimpleTableWithEnum_mt = {} -- the class metatable
+
+function TestSimpleTableWithEnum.New()
+ local o = {}
+ setmetatable(o, {__index = TestSimpleTableWithEnum_mt})
+ return o
+end
+function TestSimpleTableWithEnum.GetRootAsTestSimpleTableWithEnum(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = TestSimpleTableWithEnum.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function TestSimpleTableWithEnum_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function TestSimpleTableWithEnum_mt:Color()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int8, o + self.view.pos)
+ end
+ return 2
+end
+function TestSimpleTableWithEnum.Start(builder) builder:StartObject(1) end
+function TestSimpleTableWithEnum.AddColor(builder, color) builder:PrependInt8Slot(0, color, 2) end
+function TestSimpleTableWithEnum.End(builder) return builder:EndObject() end
+
+return TestSimpleTableWithEnum -- return the module \ No newline at end of file
diff --git a/tests/MyGame/Example/TypeAliases.lua b/tests/MyGame/Example/TypeAliases.lua
new file mode 100644
index 00000000..90f569cd
--- /dev/null
+++ b/tests/MyGame/Example/TypeAliases.lua
@@ -0,0 +1,141 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local TypeAliases = {} -- the module
+local TypeAliases_mt = {} -- the class metatable
+
+function TypeAliases.New()
+ local o = {}
+ setmetatable(o, {__index = TypeAliases_mt})
+ return o
+end
+function TypeAliases.GetRootAsTypeAliases(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = TypeAliases.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function TypeAliases_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function TypeAliases_mt:I8()
+ local o = self.view:Offset(4)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int8, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:U8()
+ local o = self.view:Offset(6)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint8, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:I16()
+ local o = self.view:Offset(8)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int16, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:U16()
+ local o = self.view:Offset(10)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint16, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:I32()
+ local o = self.view:Offset(12)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int32, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:U32()
+ local o = self.view:Offset(14)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint32, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:I64()
+ local o = self.view:Offset(16)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Int64, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:U64()
+ local o = self.view:Offset(18)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Uint64, o + self.view.pos)
+ end
+ return 0
+end
+function TypeAliases_mt:F32()
+ local o = self.view:Offset(20)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Float32, o + self.view.pos)
+ end
+ return 0.0
+end
+function TypeAliases_mt:F64()
+ local o = self.view:Offset(22)
+ if o ~= 0 then
+ return self.view:Get(flatbuffers.N.Float64, o + self.view.pos)
+ end
+ return 0.0
+end
+function TypeAliases_mt:V8(j)
+ local o = self.view:Offset(24)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Int8, a + ((j-1) * 1))
+ end
+ return 0
+end
+function TypeAliases_mt:V8Length()
+ local o = self.view:Offset(24)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function TypeAliases_mt:Vf64(j)
+ local o = self.view:Offset(26)
+ if o ~= 0 then
+ local a = self.view:Vector(o)
+ return self.view:Get(flatbuffers.N.Float64, a + ((j-1) * 8))
+ end
+ return 0
+end
+function TypeAliases_mt:Vf64Length()
+ local o = self.view:Offset(26)
+ if o ~= 0 then
+ return self.view:VectorLen(o)
+ end
+ return 0
+end
+function TypeAliases.Start(builder) builder:StartObject(12) end
+function TypeAliases.AddI8(builder, i8) builder:PrependInt8Slot(0, i8, 0) end
+function TypeAliases.AddU8(builder, u8) builder:PrependUint8Slot(1, u8, 0) end
+function TypeAliases.AddI16(builder, i16) builder:PrependInt16Slot(2, i16, 0) end
+function TypeAliases.AddU16(builder, u16) builder:PrependUint16Slot(3, u16, 0) end
+function TypeAliases.AddI32(builder, i32) builder:PrependInt32Slot(4, i32, 0) end
+function TypeAliases.AddU32(builder, u32) builder:PrependUint32Slot(5, u32, 0) end
+function TypeAliases.AddI64(builder, i64) builder:PrependInt64Slot(6, i64, 0) end
+function TypeAliases.AddU64(builder, u64) builder:PrependUint64Slot(7, u64, 0) end
+function TypeAliases.AddF32(builder, f32) builder:PrependFloat32Slot(8, f32, 0.0) end
+function TypeAliases.AddF64(builder, f64) builder:PrependFloat64Slot(9, f64, 0.0) end
+function TypeAliases.AddV8(builder, v8) builder:PrependUOffsetTRelativeSlot(10, v8, 0) end
+function TypeAliases.StartV8Vector(builder, numElems) return builder:StartVector(1, numElems, 1) end
+function TypeAliases.AddVf64(builder, vf64) builder:PrependUOffsetTRelativeSlot(11, vf64, 0) end
+function TypeAliases.StartVf64Vector(builder, numElems) return builder:StartVector(8, numElems, 8) end
+function TypeAliases.End(builder) return builder:EndObject() end
+
+return TypeAliases -- return the module \ No newline at end of file
diff --git a/tests/MyGame/Example/Vec3.lua b/tests/MyGame/Example/Vec3.lua
new file mode 100644
index 00000000..ff7d13c6
--- /dev/null
+++ b/tests/MyGame/Example/Vec3.lua
@@ -0,0 +1,54 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example
+
+local flatbuffers = require('flatbuffers')
+
+local Vec3 = {} -- the module
+local Vec3_mt = {} -- the class metatable
+
+function Vec3.New()
+ local o = {}
+ setmetatable(o, {__index = Vec3_mt})
+ return o
+end
+function Vec3_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Vec3_mt:X()
+ return self.view:Get(flatbuffers.N.Float32, self.view.pos + 0)
+end
+function Vec3_mt:Y()
+ return self.view:Get(flatbuffers.N.Float32, self.view.pos + 4)
+end
+function Vec3_mt:Z()
+ return self.view:Get(flatbuffers.N.Float32, self.view.pos + 8)
+end
+function Vec3_mt:Test1()
+ return self.view:Get(flatbuffers.N.Float64, self.view.pos + 16)
+end
+function Vec3_mt:Test2()
+ return self.view:Get(flatbuffers.N.Int8, self.view.pos + 24)
+end
+function Vec3_mt:Test3(obj)
+ obj:Init(self.view.bytes, self.view.pos + 26)
+ return obj
+end
+function Vec3.CreateVec3(builder, x, y, z, test1, test2, test3_a, test3_b)
+ builder:Prep(16, 32)
+ builder:Pad(2)
+ builder:Prep(2, 4)
+ builder:Pad(1)
+ builder:PrependInt8(test3_b)
+ builder:PrependInt16(test3_a)
+ builder:Pad(1)
+ builder:PrependInt8(test2)
+ builder:PrependFloat64(test1)
+ builder:Pad(4)
+ builder:PrependFloat32(z)
+ builder:PrependFloat32(y)
+ builder:PrependFloat32(x)
+ return builder:Offset()
+end
+
+return Vec3 -- return the module \ No newline at end of file
diff --git a/tests/MyGame/Example2/Monster.lua b/tests/MyGame/Example2/Monster.lua
new file mode 100644
index 00000000..347b5dba
--- /dev/null
+++ b/tests/MyGame/Example2/Monster.lua
@@ -0,0 +1,27 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: Example2
+
+local flatbuffers = require('flatbuffers')
+
+local Monster = {} -- the module
+local Monster_mt = {} -- the class metatable
+
+function Monster.New()
+ local o = {}
+ setmetatable(o, {__index = Monster_mt})
+ return o
+end
+function Monster.GetRootAsMonster(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = Monster.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function Monster_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function Monster.Start(builder) builder:StartObject(0) end
+function Monster.End(builder) return builder:EndObject() end
+
+return Monster -- return the module \ No newline at end of file
diff --git a/tests/MyGame/InParentNamespace.lua b/tests/MyGame/InParentNamespace.lua
new file mode 100644
index 00000000..b3fa0c85
--- /dev/null
+++ b/tests/MyGame/InParentNamespace.lua
@@ -0,0 +1,27 @@
+-- automatically generated by the FlatBuffers compiler, do not modify
+
+-- namespace: MyGame
+
+local flatbuffers = require('flatbuffers')
+
+local InParentNamespace = {} -- the module
+local InParentNamespace_mt = {} -- the class metatable
+
+function InParentNamespace.New()
+ local o = {}
+ setmetatable(o, {__index = InParentNamespace_mt})
+ return o
+end
+function InParentNamespace.GetRootAsInParentNamespace(buf, offset)
+ local n = flatbuffers.N.UOffsetT:Unpack(buf, offset)
+ local o = InParentNamespace.New()
+ o:Init(buf, n + offset)
+ return o
+end
+function InParentNamespace_mt:Init(buf, pos)
+ self.view = flatbuffers.view.New(buf, pos)
+end
+function InParentNamespace.Start(builder) builder:StartObject(0) end
+function InParentNamespace.End(builder) return builder:EndObject() end
+
+return InParentNamespace -- return the module \ No newline at end of file
diff --git a/tests/generate_code.bat b/tests/generate_code.bat
index 04125769..26362255 100644
--- a/tests/generate_code.bat
+++ b/tests/generate_code.bat
@@ -15,8 +15,8 @@
set buildtype=Release
if "%1"=="-b" set buildtype=%2
-..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
-..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
+..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --lua --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
+..\%buildtype%\flatc.exe --cpp --java --csharp --go --binary --python --lua --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
..\%buildtype%\flatc.exe --cpp --js --ts --php --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs
..\%buildtype%\flatc.exe -b --schema --bfbs-comments -I include_test monster_test.fbs
..\%buildtype%\flatc.exe --jsonschema --schema -I include_test monster_test.fbs
diff --git a/tests/generate_code.sh b/tests/generate_code.sh
index c5304b69..32a59e83 100755
--- a/tests/generate_code.sh
+++ b/tests/generate_code.sh
@@ -14,8 +14,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-../flatc --cpp --java --csharp --dart --go --binary --python --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
-../flatc --cpp --java --csharp --dart --go --binary --python --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
+../flatc --cpp --java --csharp --dart --go --binary --lua --python --js --ts --php --grpc --gen-mutable --reflect-names --gen-object-api --no-includes --cpp-ptr-type flatbuffers::unique_ptr --no-fb-import -I include_test monster_test.fbs monsterdata_test.json
+../flatc --cpp --java --csharp --dart --go --binary --lua --python --js --ts --php --gen-mutable --reflect-names --no-fb-import --cpp-ptr-type flatbuffers::unique_ptr -o namespace_test namespace_test/namespace_test1.fbs namespace_test/namespace_test2.fbs
../flatc --cpp --js --ts --php --gen-mutable --reflect-names --gen-object-api --cpp-ptr-type flatbuffers::unique_ptr -o union_vector ./union_vector/union_vector.fbs
../flatc -b --schema --bfbs-comments -I include_test monster_test.fbs
../flatc --jsonschema --schema -I include_test monster_test.fbs
diff --git a/tests/luatest.lua b/tests/luatest.lua
new file mode 100644
index 00000000..23bc0f29
--- /dev/null
+++ b/tests/luatest.lua
@@ -0,0 +1,294 @@
+package.path = string.format("../lua/?.lua;./?.lua;%s",package.path)
+
+local function checkReadBuffer(buf, offset, sizePrefix)
+ offset = offset or 0
+
+ if type(buf) == "string" then
+ buf = flatbuffers.binaryArray.New(buf)
+ end
+
+ if sizePrefix then
+ local size = flatbuffers.N.Int32:Unpack(buf, offset)
+ -- no longer matches python tests, but the latest 'monsterdata_test.mon'
+ -- is 448 bytes, minus 4 to arrive at the 444
+ assert(size == 444)
+ offset = offset + flatbuffers.N.Int32.bytewidth
+ end
+
+ local mon = monster.GetRootAsMonster(buf, offset)
+ assert(mon:Hp() == 80, "Monster Hp is not 80")
+ assert(mon:Mana() == 150, "Monster Mana is not 150")
+ assert(mon:Name() == "MyMonster", "Monster Name is not MyMonster")
+
+ local vec = assert(mon:Pos(), "Monster Position is nil")
+ assert(vec:X() == 1.0)
+ assert(vec:Y() == 2.0)
+ assert(vec:Z() == 3.0)
+ assert(vec:Test1() == 3.0)
+ assert(vec:Test2() == 2)
+
+ local t = require("MyGame.Example.Test").New()
+ t = assert(vec:Test3(t))
+
+ assert(t:A() == 5)
+ assert(t:B() == 6)
+
+ local ut = require("MyGame.Example.Any")
+ assert(mon:TestType() == ut.Monster)
+
+ local table2 = mon:Test()
+ assert(getmetatable(table2) == "flatbuffers.view.mt")
+
+ local mon2 = monster.New()
+ mon2:Init(table2.bytes, table2.pos)
+
+ assert(mon2:Name() == "Fred")
+
+ assert(mon:InventoryLength() == 5)
+ local invsum = 0
+ for i=1,mon:InventoryLength() do
+ local v = mon:Inventory(i)
+ invsum = invsum + v
+ end
+ assert(invsum == 10)
+
+ for i=1,5 do
+ assert(mon:VectorOfLongs(i) == 10^((i-1)*2))
+ end
+
+ local dbls = { -1.7976931348623157e+308, 0, 1.7976931348623157e+308}
+ for i=1,mon:VectorOfDoublesLength() do
+ assert(mon:VectorOfDoubles(i) == dbls[i])
+ end
+
+ assert(mon:Test4Length() == 2)
+
+ local test0 = mon:Test4(1)
+ local test1 = mon:Test4(2)
+
+ local v0 = test0:A()
+ local v1 = test0:B()
+ local v2 = test1:A()
+ local v3 = test1:B()
+
+ local sumtest12 = v0 + v1 + v2 + v3
+ assert(sumtest12 == 100)
+
+ assert(mon:TestarrayofstringLength() == 2)
+ assert(mon:Testarrayofstring(1) == "test1")
+ assert(mon:Testarrayofstring(2) == "test2")
+
+ assert(mon:TestarrayoftablesLength() == 0)
+ assert(mon:TestnestedflatbufferLength() == 0)
+ assert(mon:Testempty() == nil)
+end
+
+local function generateMonster(sizePrefix)
+ local b = flatbuffers.Builder(0)
+ local str = b:CreateString("MyMonster")
+ local test1 = b:CreateString("test1")
+ local test2 = b:CreateString("test2")
+ local fred = b:CreateString("Fred")
+
+ monster.StartInventoryVector(b, 5)
+ b:PrependByte(4)
+ b:PrependByte(3)
+ b:PrependByte(2)
+ b:PrependByte(1)
+ b:PrependByte(0)
+ local inv = b:EndVector(5)
+
+ monster.Start(b)
+ monster.AddName(b, fred)
+ local mon2 = monster.End(b)
+
+ monster.StartTest4Vector(b, 2)
+ test.CreateTest(b, 10, 20)
+ test.CreateTest(b, 30, 40)
+ local test4 = b:EndVector(2)
+
+ monster.StartTestarrayofstringVector(b, 2)
+ b:PrependUOffsetTRelative(test2)
+ b:PrependUOffsetTRelative(test1)
+ local testArrayOfString = b:EndVector(2)
+
+ monster.StartVectorOfLongsVector(b, 5)
+ b:PrependInt64(100000000)
+ b:PrependInt64(1000000)
+ b:PrependInt64(10000)
+ b:PrependInt64(100)
+ b:PrependInt64(1)
+ local vectorOfLongs = b:EndVector(5)
+
+ monster.StartVectorOfDoublesVector(b, 3)
+ b:PrependFloat64(1.7976931348623157e+308)
+ b:PrependFloat64(0)
+ b:PrependFloat64(-1.7976931348623157e+308)
+ local vectorOfDoubles = b:EndVector(3)
+
+ monster.Start(b)
+ local pos = vec3.CreateVec3(b, 1.0, 2.0, 3.0, 3.0, 2, 5, 6)
+ monster.AddPos(b, pos)
+
+ monster.AddHp(b, 80)
+ monster.AddName(b, str)
+ monster.AddInventory(b, inv)
+ monster.AddTestType(b, 1)
+ monster.AddTest(b, mon2)
+ monster.AddTest4(b, test4)
+ monster.AddTestarrayofstring(b, testArrayOfString)
+ monster.AddVectorOfLongs(b, vectorOfLongs)
+ monster.AddVectorOfDoubles(b, vectorOfDoubles)
+ local mon = monster.End(b)
+
+ if sizePrefix then
+ b:FinishSizePrefixed(mon)
+ else
+ b:Finish(mon)
+ end
+ return b:Output(true), b:Head()
+end
+
+local function sizePrefix(sizePrefix)
+ local buf,offset = generateMonster(sizePrefix)
+ checkReadBuffer(buf, offset, sizePrefix)
+end
+
+local function testCanonicalData()
+ local f = assert(io.open('monsterdata_test.mon', 'rb'))
+ local wireData = f:read("*a")
+ f:close()
+ checkReadBuffer(wireData)
+end
+
+local function benchmarkMakeMonster(count)
+ local length = #(generateMonster())
+
+ --require("flatbuffers.profiler")
+ --profiler = newProfiler("call")
+ --profiler:start()
+
+ local s = os.clock()
+ for i=1,count do
+ generateMonster()
+ end
+ local e = os.clock()
+
+ --profiler:stop()
+
+ --local outfile = io.open( "profile.txt", "w+" )
+ --profiler:report( outfile, true)
+ --outfile:close()
+
+
+ local dur = (e - s)
+ local rate = count / (dur * 1000)
+ local data = (length * count) / (1024 * 1024)
+ local dataRate = data / dur
+
+ print(string.format('built %d %d-byte flatbuffers in %.2fsec: %.2f/msec, %.2fMB/sec',
+ count, length, dur, rate, dataRate))
+end
+
+local function benchmarkReadBuffer(count)
+ local f = assert(io.open('monsterdata_test.mon', 'rb'))
+ local buf = f:read("*a")
+ f:close()
+
+ local s = os.clock()
+ for i=1,count do
+ checkReadBuffer(buf)
+ end
+ local e = os.clock()
+
+ local dur = (e - s)
+ local rate = count / (dur * 1000)
+ local data = (#buf * count) / (1024 * 1024)
+ local dataRate = data / dur
+
+ print(string.format('traversed %d %d-byte flatbuffers in %.2fsec: %.2f/msec, %.2fMB/sec',
+ count, #buf, dur, rate, dataRate))
+end
+
+local tests =
+{
+ {
+ f = sizePrefix,
+ d = "Test size prefix",
+ args = {{true}, {false}}
+ },
+ {
+ f = testCanonicalData,
+ d = "Tests Canonical flatbuffer file included in repo"
+ },
+ {
+ f = benchmarkMakeMonster,
+ d = "Benchmark making monsters",
+ args = {
+ {100},
+ {1000},
+ {10000},
+ }
+ },
+ {
+ f = benchmarkReadBuffer,
+ d = "Benchmark reading monsters",
+ args = {
+ {100},
+ {1000},
+ {10000},
+ -- uncomment following to run 1 million to compare.
+ -- Took ~141 seconds on my machine
+ --{1000000},
+ }
+ },
+}
+
+local result, err = xpcall(function()
+ flatbuffers = assert(require("flatbuffers"))
+ monster = assert(require("MyGame.Example.Monster"))
+ test = assert(require("MyGame.Example.Test"))
+ vec3 = assert(require("MyGame.Example.Vec3"))
+
+ local function buildArgList(tbl)
+ local s = ""
+ for _,item in ipairs(tbl) do
+ s = s .. tostring(item) .. ","
+ end
+ return s:sub(1,-2)
+ end
+
+ local testsPassed, testsFailed = 0,0
+ for _,test in ipairs(tests) do
+ local allargs = test.args or {{}}
+ for _,args in ipairs(allargs) do
+ local results, err = xpcall(test.f,debug.traceback, table.unpack(args))
+ if results then
+ testsPassed = testsPassed + 1
+ else
+ testsFailed = testsFailed + 1
+ print(string.format(" Test [%s](%s) failed: \n\t%s",
+ test.d or "",
+ buildArgList(args),
+ err))
+ end
+ end
+ end
+
+ local totalTests = testsPassed + testsFailed
+ print(string.format("# of test passed: %d / %d (%.2f%%)",
+ testsPassed,
+ totalTests,
+ totalTests ~= 0
+ and 100 * (testsPassed / totalTests)
+ or 0)
+ )
+
+ return 0
+end, debug.traceback)
+
+if not result then
+ print("Unable to run tests due to test framework error: ",err)
+end
+
+os.exit(result or -1)