What are Lua's introspection features? I know that you can query the type of a variable at runtime using type(var) and that the debug package provides some features for inspecting the environment, but it is not clear what that gives me.
What other introspection features are in Lua? Any good resources?
Lua values can have 7 types: nil, boolean, number, string, function, userdata, thread, and table. You can get the type of a value using the type function from the standard library.
If you are working with tables, you can iterate over its keys using the pairs function.
Finally, values in Lua can have metatables and this is often used in to program in an object oriented style. You can get a value's metatable using the getmetatable function.
You actually have to use the built-in function type() to get a variable's type at run time
t = 'asdf'
print(type(t))
for example. As far as introspection, the debug library is pretty much it for vanilla Lua. The best place to begin poking around would be in the reference manual for the debug library.
Related
In Lua when you use the method tostring(table) it returns something like this: table: 0xb5b1f0. So I was wondering if there is any way of reversing this and turning it back into the regular table.
This actually prints the pointer to the table data as a hex integer. You cannot use the numeric value of a pointer in Lua to access the data directly (in a standard way).
If you are really interested, you can serialize (convert a table to a string) (recursively), and then back into a table, but that is much less convenient than an 8 digit hex. If you are using any framework or library, there is a good chance that it comes with a built-in table serialization function. If not, then just look up "lua table serialization function" on any search engine. (I'll find a good function and write it here)
Something else you might want to know, is that you can do something like this with functions: string.dump will dump the Lua binary for the function in a Lua string, and can then later be converted to a function using loadstring().
I am creating a game in love2d (LuaJIT) and I am creating a debug window for changing values at runtime. I was able to do that, however, I also now want to be able to call functions. For example, I traverse a table and there is a function in this table called "hello" which is written like this:
self.hello = function(str, num)
print(string.format("%s: %d", str, num))
end
From the expression of type(object.hello) I only see function. If it had been a table, I could have traversed it and see the keys and values, but it is just a "function" and I have no idea how to properly call it, as I don't know what arguments does it take and how many. Is there a way to find this out at runtime in lua? Maybe this information is also stored in some table elsewhere?
it is just a "function" and I have no idea how to properly call it
Neither does Lua. As far as Lua is concerned, any Lua function can take any number of parameters and return any number of parameters. These parameters could be of any type, as could its return values.
Lua itself does not store this information. Or at least, not in any way you could retrieve without doing some decompiling of its byte-code. And since you're using LuaJIT, that "decompiling" might require decompiling assembly.
I would like to apply different conversion function to the parameters of an option.
Consider this following code:
parser:option('-c --circle')
:argname{'<radius>', '<coordinates>'}
-- does not work like this:
-- :convert{['<radius>']=tonumber, ['<coordinates>']=tocoords}
:default{1, {0,0}}
:args(2)
:count '0-1'
As you can see the program has an option -c which takes two parameters: radius and coordinates. I would like to apply to different conversion functions (tonumber and tocoords) respectively. Reading the documentation I can't figure out how to do this.
Is this possible and if so then what is the correct way to set this up?
Since argparse 0.6.0 this works:
:convert{tonumber, tocoords}
See documentation:
If convert property of an element is an array of functions, they will be used as converters for corresponding arguments in case the element accepts multiple arguments.
If you are correct that the Lua Argparse system does not allow you to specify multiple functions to convert the arguments to a specific option, then there may still be a way to do it. After all, Argparse has to call your conversion function once for each argument. And there's no rule that the conversion function has to do the same thing for each invocation. The only information you don't have is the particular argument it is being called on.
So... cheat. Create that information, by using Lua's first-class functions (note: the following uses Lua 5.3):
local function multi_arg_parser(...)
local index = 0
local funcs = table.pack(...)
return function(...)
index = index + 1
return funcs[index](...)
end
end
parser:option('-c --circle')
:argname{'<radius>', '<coordinates>'}
:convert(multi_arg_parser(tonumber, tocoords))
:default{1, {0,0}}
:args(2)
:count '0-1'
This will work provided that Argparse will call the convert function exactly once for each argument and call convert on the arguments in the order they appear in the command line. That is almost certainly not guaranteed by Argparse, but it's a reasonable assumption.
I would suggest using the Lapp Framework. It supports conversions via a converter method passed to the add_type method. Also, it comes with other convenient features, like assertions and default values.
I am writing an interpreter for a mathematical language in Rust which is intended to be used to solve mathematical expressions.
When lexing, the program needs to know based on the characters used in a token, what type of token it is (for example is it a function or an operator).
Currently I use an enumeration to represent a type of token:
pub enum IdentifierType {
Function,
Variable,
Operator,
Integer,
}
To check the type of a token I use a function which takes an IdentifierType as input and matches based on input to return a bool. The data structures that could be used in this case are relatively simple as tokens only have a single property: allowed characters.
When parsing to an Abstract Syntax Tree (AST), I would like to know what specific operator or function is being used based on a token and to be able to add a reference to that operator and its associated functions to the AST.
When interpreting, I would like to be able to call execute on a node and have it know how to perform its own function.
I have tried to come up with a solution to store all of these related items, but none that I have encountered as felt satisfactory.
For example I stored all of the operators in a TOML file (a type of configuration file that maps to a hash table) but storing enumerations (values that are constrained) is difficult and there is no way to store an operators function. I also want to be able to search by multiple keys, such as operator associativity (e.g. get all operators that are right associative), which means storing within source code is not very satisfactory.
Other possible ideas I have had are using some kind of SQL hybrid system, however that seems tough to implement
In the process of transforming a given efficient pointer-based hash map implementation into a generic hash map implementation, I stumbled across the following problem:
I have a class representing a hash node (the hash map implementation uses a binary tree)
THashNode <KEY_TYPE, VALUE_TYPE> = class
public
Key : KEY_TYPE;
Value : VALUE_TYPE;
Left : THashNode <KEY_TYPE, VALUE_TYPE>;
Right : THashNode <KEY_TYPE, VALUE_TYPE>;
end;
In addition to that there is a function that should return a pointer to a hash node. I wanted to write
PHashNode = ^THashNode <KEY_TYPE, VALUE_TYPE>
but that doesn't compile (';' expected but '<' found).
How can I have a pointer to a generic type?
And adressed to Barry Kelly: if you read this: yes, this is based on your hash map implementation. You haven't written such a generic version of your implementation yourself, have you? That would save me some time :)
Sorry, Smasher. Pointers to open generic types are not supported because generic pointer types are not supported, although it is possible (compiler bug) to create them in certain circumstances (particularly pointers to nested types inside a generic type); this "feature" can't be removed in an update in case we break someone's code. The limitation on generic pointer types ought to be removed in the future, but I can't make promises when.
If the type in question is the one in JclStrHashMap I wrote (or the ancient HashList unit), well, the easiest way to reproduce it would be to change the node type to be a class and pass around any double-pointers as Pointer with appropriate casting. However, if I were writing that unit again today, I would not implement buckets as binary trees. I got the opportunity to write the dictionary in the Generics.Collections unit, though with all the other Delphi compiler work time was too tight before shipping for solid QA, and generic feature support itself was in flux until fairly late.
I would prefer to implement the hash map buckets as one of double-hashing, per-bucket dynamic arrays or linked lists of cells from a contiguous array, whichever came out best from tests using representative data. The logic is that cache miss cost of following links in tree/list ought to dominate any difference in bucket search between tree and list with a good hash function. The current dictionary is implemented as straight linear probing primarily because it was relatively easy to implement and worked with the available set of primitive generic operations.
That said, the binary tree buckets should have been an effective hedge against poor hash functions; if they were balanced binary trees (=> even more modification cost), they would be O(1) on average and O(log n) worst case performance.
To actually answer your question, you can't make a pointer to a generic type, because "generic types" don't exist. You have to make a pointer to a specific type, with the type parameters filled in.
Unfortunately, the compiler doesn't like finding angle brackets after a ^. But it will accept the following:
TGeneric<T> = record
value: T;
end;
TSpecific = TGeneric<string>;
PGeneric = ^TSpecific;
But "PGeneric = ^TGeneric<string>;" gives a compiler error. Sounds like a glitch to me. I'd report that over at QC if I was you.
Why are you trying to make a pointer to an object, anyway? Delphi objects are a reference type, so they're pointers already. You can just cast your object reference to Pointer and you're good.
If Delphi supported generic pointer types at all, it would have to look like this:
type
PHashNode<K, V> = ^THashNode<K, V>;
That is, mention the generic parameters on the left side where you declare the name of the type, and then use those parameters in constructing the type on the right.
However, Delphi does not support that. See QC 66584.
On the other hand, I'd also question the necessity of having a pointer to a class type at all. Generic or not. they are needed only very rarely.
There's a generic hash map called TDictionary in the Generics.Collections unit. Unfortunately, it's badly broken at the moment, but it's apparently going to be fixed in update #3, which is due out within a matter of days, according to Nick Hodges.