Using table keys with periods in Lua - lua

In Lua, assigning a table with a specified key might go like this:
a = { x = 4 }
...or perhaps like...
a = { ['x'] = 4 }
Easy enough. However, if I introduce periods into the key (as in a domain name) nothing seems to work. All of the following fail:
a = { "a.b.c" = 4 }
a = { a.b.c = 4 }
a = { ['a.b.c'] = 4 }
a = { ["a.b.c"] = 4 }
a = { [a.b.c] = 4 }
All of these return the same error:
$ ./script.lua
/usr/bin/lua: ./script.lua:49: `}' expected near `='
What am I missing here? Several of the examples seem quite straight-forward and should work (while others have apparent problems).

In lua table element may be either a Name or an Expression. Citing language reference, "Names (also called identifiers) in Lua can be any string of letters, digits, and underscores, not beginning with a digit.", and everything else is interpreted as an identifier in this context. Therefore, a.b.c as a table index is treated as expression, which is evaluated to get the actual table index. This would work, but would be useless:
a = { b = { c = 1 } }
x = {}
x['a.b.c'] = 7
print(x['a.b.c'])
Also note, that foo.a.b.c is equal to foo['a']['b']['c'] and not to foo['a.b.c'].

a = { ['a.b.c'] = 4 }
a = { ["a.b.c"] = 4 }
These two are all valid.
a = { [a.b.c] = 4 }
This could be valid, depending on the exact identifiers used. For example
b = { c = { d = "Ohai!" } } }
a = { [b.c.d] = 4 }
would be valid.
If your interpreter is telling you they are not valid, then you've either done something else wrong, or there's a bug in the interpreter. The others however would not be valid.

Is there something else wrong in your script?
$ ./lua
Lua 5.1.4 Copyright (C) 1994-2008 Lua.org, PUC-Rio
> a = { ["a.b.c"] = 4 }
> print (a["a.b.c"])
4
> print (a.a)
nil

Related

In F#, how to update/replace a nested record using a list index?

(Totally Newbie).
Please assume the following in F#
module Visit =
type Model =
{ Name: string }
module Cell =
type Model =
{ Visit: Visit.Model option }
module Column =
type Model =
{ AppointmentCount: int
InnerRows: Cell.Model list }
module App =
...stuff with List.tryFind to return an open column ...
let AddVisit (c:Column.Model, v:Visit) =
{ c with c.InnerRows[AppointmentCount] = { c.InnerRows[AppointmentCount] with Visit = v } }
Assuming there will be 4 cells per column, the Visit is supplied by a database read, and the column instance is found through a couple of List.tryFind's, can a nested record (i.e., the visit of a cell) be replaced/updated with the AppointmentCount as an index?
That is, this fails:
let AddVisit (c:Column.Model, v:Visit) =
{ c with c.InnerRows[AppointmentCount] = { c.InnerRows[AppointmentCount] with Visit = v } }
Error: Field bindings must have the form 'id = expr,'
Thank you.
Take for instance a newly created record.
let myRecord2 = { MyRecord.X = 1; MyRecord.Y = 2; MyRecord.Z = 3 }
To update only two fields in that record you can use the copy and update record expression:
let myRecord3 = { myRecord2 with Y = 100; Z = 2 }
Copy and Update Record Expressions
let AddVisit (c:Column.Model, v:Visit) =
{ c.InnerRows.[c.AppointmentCount] with Visit = Some v }
Note that c.InnerRows.[c.AppointmentCount] specifies a specific cell.model to which the Visit will be set. (Also, the "." in front of the [ allows for direct indexing into the list.

How to define different indentation levels in the same document with Xtext formatter

Is it possible to format a document as follows, using Xtext formatting? As you can see, Test children are indented with 4 spaces while External children are indented with 2 spaces only. I am using Xtext 2.12.0.
Test my_prog {
Device = "my_device";
Param = 0;
}
External {
Path = "my_path";
File = "my_file";
}
you could try to work with custom replacers, dont know if this will work with nested block though
def dispatch void format(External model, extension IFormattableDocument document) {
model.regionFor.keyword("}").prepend[newLine]
for (l : model.ids) {
val region = l.regionFor.feature(MyDslPackage.Literals.IDX__NAME)
region.prepend[newLine]
val r = new AbstractTextReplacer(document, region) {
override createReplacements(ITextReplacerContext it) {
val offset = region.offset
it.addReplacement(region.textRegionAccess.rewriter.createReplacement(offset, 0, " "))
it
}
}
addReplacer(r)
}
}

What is the function of square brackets around table keys in lua?

I came across tables that have square brackets around keys:
local commands_json =
{
["request"] = {
["application"] = PW_APPLICATION,
["push_token"] = deviceToken
}
}
Can the square brackets be omitted?
It's simply the long form of specifying keys in a table. You can put any value between the [] (except nil. And floating-point NaNs). Whereas without them, you can only use identifiers.
For example:
tbl =
{
key name = 5,
}
That's a compile error, since "key name" isn't an identifier (due to the space). This works:
tbl =
{
["key name"] = 5,
}
And this:
tbl =
{
"key name" = 5,
}
Is also a compile error. If Lua sees a naked value like this, it thinks you're trying to add to the array part of the table. That is, it confuses it with:
tbl =
{
"key name",
}
Which creates a 1-element array, with tbl[1] equal to "key name". By using [], the compiler can easily tell that you meant for something to be a key rather than the value of an array element.
The long form also lets you distinguish between:
local name = "a name";
tbl =
{
["name"] = 5,
[name] = 7,
}
The second part means to evaluate the expression name, the result of which will be the key. So this table has the keys "name" and "a name".
You cannot omit the brackets
> x = { 'a' = 1 }
stdin:1: '}' expected near '='
the correct code is
> x = { ['a'] = 1 }
> print(x['a'])
1
or
> x = { a = 1 }
> print(x['a'])
1
However, the second one has its limitations. What if you want to have a key called "-"?
> x = { - = 1 }
stdin:1: unexpected symbol near '='
> x = { '-' = 1 }
stdin:1: '}' expected near '='
again the correct way is to use brackets
> x = { ['-'] = 1 }
> print(x['-'])
1
Or you want to create a field of name which is contained in a variable called a?
> a = 'cat'
> x = { [a] = 1 }
> print(x['cat'])
1
Brackets are used as a general form of key creation, they give you ability to put any hashable object as a key - not only strings.

How to prefix a Lua table?

I have a lua file whose content is lua Table as below:
A={},
A.B={},
A.B.C=0;,
The problem is I want to add prefix XYZ before each above statements. So after the parse the database should have something loke this:
XYZ.A={},
XYZ.A.B={},
XYZ.A.B.C={},
Any ideas? Thanks in advance
You can load the file with XYZ as is environment: loadfile("mydata","t",XYZ). See loadfile in the manual.
This works in Lua 5.2. For Lua 5.1, use loadfile followed by setfenv.
If you can afford polluting your global space with A, simply assign it later:
-- load the file
-- if XYZ doesn't exist, XYZ = { A = A } would be probably shorter
XYZ.A = A
A = nil
I think this is what you want:
XYZ = {}
XYZ.A = {}
XYZ.A.B = {}
XYZ.A.B.C = 0
How about you simply do:
XYZ = {
A = {
B = {
C = 0
}
}
}
If you don't want to nest objects so deep then you may do:
XYZ = {
A = A
}
A = nil
This assumes that you have already declared the object A before.

How to reference lua table member from table member?

i have a table in lua:
enUS = {
LOCALE_STHOUSANDS = ",", --Thousands separator e.g. comma
patNumber = "%d+["..LOCALE_STHOUSANDS.."%d]*", --regex to find a number
["PreScanPatterns"] = {
["^("..patNumber..") Armor$"] = "ARMOR",
}
}
So you see there is a whole chain of self-references in this table:
LOCAL_STHOUSANDS
patNumber
["^("..patNumber..") Armor$"]
How can i perform self-referencing in an lua table?
What i don't want to do is have to hard-replace the values; there are hundreds of references:
enUS = {
LOCALE_STHOUSANDS = ",", --Thousands separator e.g. comma
patNumber = "%d+[,%d]*", --regex to find a number
["PreScanPatterns"] = {
["^(%d+[,%d]*) Armor$"] = "ARMOR",
}
}
How can i perform self-referencing in an lua table?
You don't.
Lua is not C. Until the table is constructed, none of the table entries exist. Because the table itself doesn't exist yet. Therefore, you can't have one entry in a table constructor reference another entry in a table that doesn't exist.
If you want to cut down on repeated typing, then you should use local variables and do/end blocks:
do
local temp_thousands_separator = ","
local temp_number_pattern = "%d+["..LOCALE_STHOUSANDS.."%d]*"
enUS = {
LOCALE_STHOUSANDS = temp_thousands_separator, --Thousands separator e.g. comma
patNumber = "%d+["..temp_thousands_separator.."%d]*", --regex to find a number
["PreScanPatterns"] = {
["^("..temp_number_pattern..") Armor$"] = "ARMOR",
}
}
end
The do/end block is there so that the temporary variables don't exist outside of the table creation code.
Alternatively, you can do the construction in stages:
enUS = {}
enUS.LOCALE_STHOUSANDS = ",", --Thousands separator e.g. comma
enUS.patNumber = "%d+["..enUS.LOCALE_STHOUSANDS.."%d]*", --regex to find a number
enUS["PreScanPatterns"] = {
["^("..enUS.patNumber..") Armor$"] = "ARMOR",
}
There's no way of doing this inside the constructor itself, but you can do it after creating the table like so:
enUS = {
LOCALE_STHOUSANDS = ","
}
enUS.patNumber = "%d+["..enUS.LOCALE_STHOUSANDS.."%d]*"
enUS.PreScanPatterns = {
["^("..enUS.patNumber..") Armor$"] = "ARMOR",
}
If you specifically need to refer to the current table, Lua provides a "self" parameter, but it's only accessible in functions.
local t = {
x = 1,
y = function(self) return self.x end
}
-- this is functionally identical to t.y
function t:z() return self.x end
-- these are identical and interchangeable
print(t:y(), t.z(t))
-- 1, 1

Resources