abstract syntax tree of Lua function - lua

I am new to Lua and I was reading about the AST (abstract syntax tree) but didn't quite get it yet.
I wrote a simple "Hello-World" function in Lua:
function foo()
value = 10
num = "to the"
if value > 2 then
print("Hello World")
end
return value
end
print(foo())
Simple program which it's output is:
Hello World
10
I want to build an abstract syntax tree but not sure where and how to start.
I read about the syntax here, alought didn't figure out how to "design"/"draw" the wanted tree.

I'd start by studying the output of existing modules that build ASTs, as it will make it more clear what the elements of the tree are and how they correspond to the code you write. You can start with Metalua.

Related

lua - How to check if a word is in a string or it is just a word

So I am trying to make a language in lua, and I am replacing the word "output" with "print" and a few more words, but if someone does output("output") it also replaces it. How can i check if it is in a string?
Code:
output('trying to make a new language in lua')
output('\n')
local file = io.open(arg[1],"r")
local code = file:read "*a"
local filename = arg[1]
local function execute()
code = code:gsub("output","print")
code = code:gsub("void","function")
code = code:gsub("{}}","end")
local newfile = io.open(filename:gsub("idk","lua"),"w")
newfile:write(code)
newfile:close()
os.execute("lua test.lua")
end
execute()
Lua patterns are generally unsuitable to build a parser for a programming language; neither do they have the full expressive power of regular expressions required for tokenization (lexical analysis) nor do they get anywhere near the power of a context-free grammar (CFG, syntactical analysis) required for constructing the abstract syntax tree even though they provide some advanced features such as bracket matching which exceed regular expression capabilities.
As a beginner, you'll probably want to start with a handwritten tokenizer; as your language only operates at a token replacement level at this stage, you can simply replace identifier tokens.
You don't need string replacement (gsub) to implement variable renames like print to output when you are in control of how the script is executed: Just replace the global print variable with an output variable holding the print function (you may want to do this only in the environment the scripts written in your language run in):
output = print
print = nil

Running a lua script as a gel script

I have the following lua script that separates a string in its proper words:
names = "aa bb cc dd"
words = {}
for word in names:gmatch("%w+") do table.insert(words, word) end
for k,v in pairs(words) do print(k,v) end
I am using a program called Graphite, which is a platform for computer graphics and more. In its readme it is written:
You can write a LUA script and run it with Graphite. Just load the
script using GEL -> execute file.
Having very small experience with LUA and zero knowledge about what GEL is, I am having trouble running a script. After some googling I found this: http://gema.sourceforge.net/new/gel.shtml#3_1 ,
but it is still not so clear to me what the connection between gel and lua is. In this website it is described as: a Lua binding for Gema, a general purpose text processing utility.
The above script for example works as intended in the lua interpreter. On the other hand, when I try to execute it as a .gel script (because the software mentioned above requires a .gel script) it returns a syntax error.
Any idea on how to make it run as a .gel script? Or any other comment that might help?
If you read the documentation more closely, you'll notice:
Embed the lua functions in the gema file using the new syntax "![" "!]"
They also have an example provided:
![
function inflog(x)
if x>0 then return math.log(x)
else return "-infty"
end
end
!]
<N>=#lua{return inflog($0)}
Following the same example, the following should work:
![
function split(names)
words = {}
for word in names:gmatch("%w+") do table.insert(words, word) end
for k, v in ipairs(words) do print(k, v) end
return words
end
!]
<N>=#lua{return split($0)}

Lua - why is string after function call allowed?

I'm trying to implement a simple C++ function, which checks a syntax of Lua script. For that I'm using Lua's compiler function luaL_loadbufferx() and checking its return value afterwards.
Recently, I have ran into a problem, because the code, that I thought should be marked invalid, was not detected and instead the script failed later at a runtime (eg. in lua_pcall()).
Example Lua code (can be tested on official Lua demo):
function myfunc()
return "everyone"
end
-- Examples of unexpected behaviour:
-- The following lines pass the compile time check without errors.
print("Hello " .. myfunc() "!") -- Runtime error: attempt to call a string value
print("Hello " .. myfunc() {1,2,3}) -- Runtime error: attempt to call a string value
-- Other examples:
-- The following lines contain examples of invalid syntax, which IS detected by compiler.
print("Hello " myfunc() .. "!") -- Compile error: ')' expected near 'myfunc'
print("Hello " .. myfunc() 5) -- Compile error: ')' expected near '5'
print("Hello " .. myfunc() .. ) -- Compile error: unexpected symbol near ')'
The goal is obviously to catch all syntax errors at compile time. So my questions are:
What exactly is meant by calling a string value?
Why is this syntax allowed in the first place? Is it some Lua feature I'm unaware of, or the luaL_loadbufferx() is faulty in this particular example?
Is it possible to detect such errors by any other method without running it? Unfortunately, my function doesn't have access to global variables at compile time, so I can't just just run the code directly via lua_pcall().
Note: I'm using Lua version 5.3.4 (manual here).
Thank you very much for your help.
Both myfunc() "!" and myfunc(){1,2,3} are valid Lua expressions.
Lua allows calls of the form exp string. See functioncall and prefixexp in the Syntax of Lua.
So myfunc() "!" is a valid function call that calls whatever myfunc returns and call it with the string "!".
The same thing happens for a call of the form exp table-literal.
Another approach is to change string's metatable making a call to a string valid.
local mt = getmetatable ""
mt.__call = function (self, args) return self .. args end
print(("x") "y") -- outputs `xy`
Now those valid syntax calls to a string will result in string concatenation instead of runtime errors.
I'm writing answer to my own question just in case anyone else stumbles upon the similar problem in the future and also looks for solution.
Manual
Lua manual (in its section 3.4.10 – Function Calls) basically states, that there are three different ways of providing arguments to Lua function.
Arguments have the following syntax: args ::= ‘(’ [explist] ‘)’
args ::= tableconstructor
args ::= LiteralString
All argument expressions are evaluated before the call. A call of the form f{fields} is syntactic sugar for f({fields}); that is, the argument list is a single new table. A call of the form f'string' (or f"string" or f[[string]]) is syntactic sugar for f('string'); that is, the argument list is a single literal string.
Explanation
As lhf pointed out in his answer, both myfunc()"!" and myfunc(){1,2,3} are valid Lua expressions. It means the Lua compiler is doing nothing wrong, considering it doesn't know the function return value at a compile time.
The original example code given in the question:
print("Hello " .. myfunc() "!")
Could be then rewritten as:
print("Hello " .. (myfunc()) ("!"))
Which (when executed) translates to:
print("Hello " .. ("everyone") ("!"))
And thus resulting in the runtime error message attempt to call a string value (which could be rewritten as: the string everyone is not a function, so you can't call it).
Solution
As far as I understand, these two alternative ways of supplying arguments have no real benefit over the standard func(arg) syntax. That's why I ended up modyfing the Lua parser files. The disadventage of keeping this alternative syntax was too big. Here is what I've done (relevant for v5.3.4):
In file lparser.c i searched for function:
static void suffixedexp (LexState *ls, expdesc *v)
Inside this function i changed the case statement:
case '(': case TK_STRING: case '{':to case '(':
Warning! By doing this I have modified the Lua language, so as lhf stated in his comment, it can no longer be called pure Lua. If you are unsure whether it is exactly what you want, I can't recommend this approach.
With this slight modification compiler detects the two above mentioned alternative syntaxes as errors. Of course, I can no longer use them inside Lua scripts, but for my specific application it's just fine.
All I need to do is to note this change somewhere to find it in case of upgrading Lua to higher version.

How to invoke Erlang function with variable?

4> abs(1).
1
5> X = abs.
abs
6> X(1).
** exception error: bad function abs
7> erlang:X(1).
1
8>
Is there any particular reason why I have to use the module name when I invoke a function with a variable? This isn't going to work for me because, well, for one thing it is just way too much syntactic garbage and makes my eyes bleed. For another thing, I plan on invoking functions out of a list, something like (off the top of my head):
[X(1) || X <- [abs, f1, f2, f3...]].
Attempting to tack on various module names here is going to make the verbosity go through the roof, when the whole point of what I am doing is to reduce verbosity.
EDIT: Look here: http://www.erlangpatterns.org/chain.html The guy has made some pipe-forward function. He is invoking functions the same way I want to above, but his code doesn't work when I try to use it. But from what I know, the guy is an experienced Erlang programmer - I saw him give some keynote or whatever at a conference (well I saw it online).
Did this kind of thing used to work but not anymore? Surely there is a way I can do what I want - invoke these functions without all the verbosity and boilerplate.
EDIT: If I am reading the documentation right, it seems to imply that my example at the top should work (section 8.6) http://erlang.org/doc/reference_manual/expressions.html
I know abs is an atom, not a function. [...] Why does it work when the module name is used?
The documentation explains that (slightly reorganized):
ExprM:ExprF(Expr1,...,ExprN)
each of ExprM and ExprF must be an atom or an expression that
evaluates to an atom. The function is said to be called by using the
fully qualified function name.
ExprF(Expr1,...,ExprN)
ExprF
must be an atom or evaluate to a fun.
If ExprF is an atom the function is said to be called by using the implicitly qualified function name.
When using fully qualified function names, Erlang expects atoms or expression that evaluates to atoms. In other words, you have to bind X to an atom: X = atom. That's exactly what you provide.
But in the second form, Erlang expects either an atom or an expression that evaluates to a function. Notice that last word. In other words, if you do not use fully qualified function name, you have to bind X to a function: X = fun module:function/arity.
In the expression X=abs, abs is not a function but an atom. If you want thus to define a function,you can do so:
D = fun erlang:abs/1.
or so:
X = fun(X)->abs(X) end.
Try:
X = fun(Number) -> abs(Number) end.
Updated:
After looking at the discussion more, it seems like you're wanting to apply multiple functions to some input.
There are two projects that I haven't used personally, but I've starred on Github that may be what you're looking for.
Both of these projects use parse transforms:
fun_chain https://github.com/sasa1977/fun_chain
pipeline https://github.com/stolen/pipeline
Pipeline is unique because it uses a special syntax:
Result = [fun1, mod2:fun2, fun3] (Arg1, Arg2).
Of course, it could also be possible to write your own function to do this using a list of {module, function} tuples and applying the function to the previous output until you get the result.

Lua print on the same line

In Pascal, I have write and writeln. Apparently Lua's print is similar to writeln of Pascal. Do we have something similar to write of Pascal? How can consecutive print commands send their output to the same line?
print("Hello")
print("World")
Output:
Hello
world
I want to have this:
Hello world
Use io.write instead print, which is meant for simple uses, like debugging, anyway.
Expanding on lhf's correct answer, the io library is preferred for production use.
The print function in the base library is implemented as a primitive capability. It allows for quick and dirty scripts that compute something and print an answer, with little control over its presentation. Its principle benefits are that it coerces all arguments to string and that it separates each argument in the output with tabs and supplies a newline.
Those advantages quickly become defects when detailed control of the output is required. For that, you really need to use io.write. If you mix print and io.write in the same program, you might trip over another defect. print uses the C stdout file handle explicitly. This means that if you use io.output to change the output file handle, io.write will do what you expect but print won't.
A good compromise can be to implement a replacement for print in terms of io.write. It could look as simple as this untested sample where I've tried to write clearly rather than optimally and still handle nil arguments "correctly":
local write = io.write
function print(...)
local n = select("#",...)
for i = 1,n do
local v = tostring(select(i,...))
write(v)
if i~=n then write'\t' end
end
write'\n'
end
Once you are implementing your own version of print, then it can be tempting to improve it in other ways for your application. Using something with more formatting control than offered by tostring() is one good idea. Another is considering a separator other than a tab character.
As an alternative, just build up your string then write it out with a single print
You may not always have access to the io library.
You could use variables for "Hello" and "World". Then concatenate them later. Like this:
local h = "Hello"
local w = "World"
print(h..w)
It will be display, in this case, as "HelloWorld". But that's easy to fix. Hope this helped!
Adding on to #Searous's answer, try the following.
local h = "hello"
local w = "world"
print(h.." "..w)
You can concatenate both together, just concatenate a space between both variables.
local h = "Hello"
local w = "World!"
print(h, w)

Resources