Rulesets for table-based function params#86
Conversation
There was a problem hiding this comment.
Pull request overview
Adds a reusable “fluent builder” serialization layer to turn Lua parameter tables into deterministic tag/value rule lists, with initial coverage for particle-system style parameters and collection-valued params.
Changes:
- Introduces
llfluent_builder(C++ implementation + public header) for descriptor-driven table→rules-list serialization, including flag-bit merging and collection semantics. - Adds conformance tests exercising particle rule serialization and collection serialization.
- Updates build packaging/tooling inputs (CMake sources, staged headers, definitions bundle version, and a few build scripts/ignores).
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| VM/src/llfluent_builder.cpp | New fluent-builder implementation: descriptor sorting, flag merging, and table serialization into rules lists. |
| VM/include/llfluent_builder.h | Public API for building fluent-builder descriptor defs and registering fluent functions. |
| tests/SLConformance.test.cpp | Adds harness wiring + new test cases that register mock fluent functions and validate serialized output. |
| tests/conformance/llprim_particle.lua | New Lua conformance test validating particle param/flag serialization behavior. |
| tests/conformance/fluent_builder_collection.lua | New Lua conformance test validating collection semantics serialization. |
| Sources.cmake | Wires new fluent-builder sources into the VM build. |
| init_debian_buster.sh | Updates toolchain alternatives and git safe.directory setup in the Debian buster init script. |
| builtins.txt | Updates bundled LSL definitions output (parameter naming and added constants). |
| build-cmd.sh | Stages llfluent_builder.h into the build artifacts include set. |
| autobuild.xml | Bumps lsl_definitions dependency version and associated archive hash/url. |
| .gitignore | Ignores *.tar.bz2 artifacts. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
monty-linden
left a comment
There was a problem hiding this comment.
Small asks here:
- C++ include conventions
- Comments to warn about hazards
Additional comments for consideration.
| assert(#r == 0, "csv nil: output should be empty") | ||
|
|
||
| -- Array index order is preserved in the CSV. | ||
| r = apply({ whitelist = {"first", "second", "third"} }) |
There was a problem hiding this comment.
When unit testing something like this, maybe not have entries in lexical order.
| @@ -0,0 +1,61 @@ | |||
| #pragma once | |||
| #include <stddef.h> | |||
| #include <string> | ||
| #include <vector> | ||
| #include <unordered_map> | ||
| #include <algorithm> |
There was a problem hiding this comment.
System before application includes.
| int field_tag; // tag of the integer field holding the bits, e.g. 0 for "flags" | ||
| }; | ||
|
|
||
| // Opaque handle — definition lives in llfluent_builder.cpp. |
There was a problem hiding this comment.
Not really an opaque. That would be 'void *' with casting. This is forward declaration/incomplete definition.
|
|
||
| struct FluentParamDescriptor | ||
| { | ||
| const char* name; // effective property name (pretty alias or strict fallback) |
There was a problem hiding this comment.
Not owned storage, correct? Owner of FPD needs to guarantee safety. Normally, would consider this and the other occurrences a hazard. This might be short-lived temporary state which allows you to handwave it off, but still. Wondering if 'constexpr'ing these could actually be used to give safety.
There was a problem hiding this comment.
The generator constructs these as
static const FluentParamDescriptor [] = { }and they are owned by the imbedding process, in our case the simulator.. There is never a case where one would be created dynamically.
I've updated the comment for fluent_builder_def_build to call for static storage.
There was a problem hiding this comment.
I see this done in one or two other locations in VM/include. It's generally poor programming. But can be okay when it's used to point to const, read-only memory. I.e. compile-time text constants or constexprs. That wasn't the case here. It was really just duplicating c_str() in another form and requiring more memory.
| def->names[i] = descs[i].name; | ||
| def->descs[i] = descs[i]; | ||
| def->descs[i].name = def->names[i].c_str(); | ||
| } |
There was a problem hiding this comment.
Here and below with the moves... we have tons of live pointers into other objects that must not be reallocated in any way or those pointers become invalid. Lay down some clear comments for the next developer if we're going to do this kind of hazard.
There was a problem hiding this comment.
Your comment above gave me an idea for a refactor.
These structures all have static const lifetimes.
| for (int i = 0; i < (int)count; ++i) | ||
| def->name_to_index[def->descs[i].name] = i; |
There was a problem hiding this comment.
Now that we have a sorted list, we could probably binary search it faster than the amortized cost of a small unordered map. (Not a serious request but vector beats everything at small numbers.)
There was a problem hiding this comment.
I think these got left in from an earlier pass... I've removed them.
f06cef8 to
318c1b8
Compare
monty-linden
left a comment
There was a problem hiding this comment.
It's late and I'm tired and hot. So not a particularly good review. I like that there's less code. Green light but with a few questions/nits.
|
|
||
| struct FluentParamDescriptor | ||
| { | ||
| const char* name; // effective property name (pretty alias or strict fallback) |
There was a problem hiding this comment.
I see this done in one or two other locations in VM/include. It's generally poor programming. But can be okay when it's used to point to const, read-only memory. I.e. compile-time text constants or constexprs. That wasn't the case here. It was really just duplicating c_str() in another form and requiring more memory.
| csv += s[k]; | ||
| } | ||
| } | ||
| lua_pop(L, 1); |
There was a problem hiding this comment.
Does this pop need to occur after lua_rawgeti() even if slua_fluent_to_string() fails?
|
I couldn't respond to your second comment @monty-linden: // A note about C++20 porting.
// The const char* name fields in the descriptors must have static storage duration
// (e.g. string literals).
// This is not enforced at compile time,
// but when moving to C++20 we can do something like the following:
//
// struct LiteralString
// {
// consteval LiteralString(const char* p) noexcept : ptr(p) {}
// operator const char*() const noexcept { return ptr; }
// const char* ptr;
// };
// The consteval constructor ensures that only string literals can be used
// to construct a LiteralString. |
…functions requiring lists.
c9ca524 to
bb194f6
Compare
Generates a lua interface for functions requiring structured lists of parameters with an initial implementation for
ll.ParticleSystemas a POC.Setting to draft for the moment for comments.
Requires 143
Related PRs:
secondlife/lsl-definitions#143
https://github.com/secondlife/server/pull/2574