I try to summarize all my feedback after this work.
I hope give you some subjects for next parrot sketches.
I) ISSUES
1) Closure & lexical scoping rules
This is the biggest issue versus Lua specifications.
The TODO test in languages/lua/t/closure.t (line 73) shows it
(see also http://www.lua.org/manual/5.1/manual.html#2.6).
I think that Lua needs some think like a specific DynLexPad,
but I can't do this task (too complex for me).
2) Metamethod __call
2 TODO tests in languages/lua/t/metatable.t (line 506 & 539) show this issue.
In languages/lua/pmc/luaany.pmc (line 250), the invoke method must manipulate
arguments because with the following PIR example :
result = obj(arg1, arg2)
the metamethod __call retrieved in the metatable of obj, must be call with
3 parameters (obj, arg1, arg2).
3) garbage collection
How write code without GC problems ?
How track down and fix GC problems ?
4) library debug
This library deals with some low level of the Lua VM (see
http://www.lua.org/manual/5.1/manual.html#5.9).
What's possible with Parrot VM ?
5) back trace & friends
Currently, back trace speaks PIR, and it's fine for debugging.
But in future, it must speak Lua (source name & line number).
II) SUGGESTIONS & QUESTIONS
Concerns the scope of Parrot core, platform assumption (POSIX ?)
1) os.time needs mktime
My current implementation uses a NCI method in lua.pmc (line 206).
Another implementation could be an opcode mktime (the reverse of
decodelocaltime, with the same array definition)
There are the following opcodes : time, gmtime, localtime, decodetime
& decodelocaltime.
It seems that Parrot follows Perl5 where gmtime, localtime, time, times are
builtins functions and mktime is supplied by POSIX::mktime.
If someone has a better explanation or the real reason, I'm interested.
2) os.tmpname
My current implementation uses a NCI method in lua.pmc (line 312)
that calls a C POSIX function (platform dependant: tmpnam or mkstemp).
Another implementation could be a method in the PMC random or ParrotIO.
3) os.tmpfile
My current implementation uses a ParrotIO (so, a standard file) and
the POSIX behavior of unlink for the final destroy.
So, this implementation depends of the platform (really POSIX or not).
Another implementation could be ParrotIO-tmp : a subclass of ParrotIO
with a constructor without filename and a finalizer responsible of the
destroy of the file.
Another implementation could be ParrotIO-String (like the Perl module
IO::String) where temporary files live only in memory.
4) io.popen
pipe in ParrotIO not fully implemented.
5) file:setvbuf
My implementation depends on the methods buffer_type & buffer_size of
ParrotIO PMC.
Currently, these 2 methods are only specified, but not implemented.
6) lfs.touch (utime)
Not yet implemented.
utime could be a method of OS PMC (not found in any documentation).
7) lfs.lock & lfs.unlock
Same as lfs.touch.
III) CRAZY BUGS
1) command line arguments lost in the call tree
$ cat arg.lua
print(...)
print(debug.traceback())
$ parrot luap.pir --target=pir arg.lua > arg.pir
$ parrot --no-gc arg.pir arg1 arg2
# correct
arg1 arg2
stack traceback:
arg.pir:41 in function '&main_10'
languages/lua/lib/luaaux.pir:601 in function 'docall'
arg.pir:17 in function '&start'
$ parrot --no-gc lua.pbc arg.lua arg1 arg2
# BAD: all arguments are lost
stack traceback:
EVAL_1:41 in function '&main_10'
languages/lua/lib/luaaux.pir:601 in function 'docall'
lua.pir:302 in function 'handle_script'
lua.pir:122 in function 'main'
When I add some trace code, I see the correct value in 'docall' just before
line 601and after it's the same generated code.
2) other argument lost
On Lua, the mecanism of package uses 2 functions : require & module.
$ cat mod.lua
print("modname:", ...) -- must print "mod" when called by require
print(debug.traceback())
$ parrot --no-gc lua.pbc -e "require 'mod'"
modname:
stack traceback:
EVAL_2:43 in function '&main_34'
languages/lua/lib/luapackage.pir:463 in function 'require'
EVAL_1:33 in function '&main_10'
languages/lua/lib/luaaux.pir:601 in function 'docall'
lua.pir:352 in function 'dostring'
lua.pir:246 in function 'runargs'
lua.pir:119 in function 'main'
now, if you duplicate the line 463 in luapackage.pir [ $P0 = $P1(modname) ],
the second call is correct.
$ parrot --no-gc lua.pbc -e "require 'mod'"
modname:
stack traceback:
EVAL_2:43 in function '&main_34'
languages/lua/lib/luapackage.pir:463 in function 'require'
EVAL_1:33 in function '&main_10'
languages/lua/lib/luaaux.pir:601 in function 'docall'
lua.pir:352 in function 'dostring'
lua.pir:246 in function 'runargs'
lua.pir:119 in function 'main'
modname: mod
stack traceback:
EVAL_2:43 in function '&main_34'
languages/lua/lib/luapackage.pir:464 in function 'require'
EVAL_1:33 in function '&main_10'
languages/lua/lib/luaaux.pir:601 in function 'docall'
lua.pir:352 in function 'dostring'
lua.pir:246 in function 'runargs'
lua.pir:119 in function 'main'
IV) OTHERS REMARKS
1) Compiler Tools
The size of Lua compiler (without PMC and runtime libraries) is 3 KLOC.
It's a result of the quality of the common tools HLLCompiler, PAST-pm, PGE, TGE
Now, I'm waiting for PCT, the next generation.
2) a Memoize module for compiler
Many languages use regex, but few store regex in variable,
so all others need a Memoize mecanism (well-known optimization) that store
the result of the compilation.
3) learning curve
It's not easy to learn all things needed by language implementation in Parrot.
There are a lot of knowledges :
- Parrot infrastructure (configuration tools, test environment)
- PIR
- PMC
- PGE, TGE, ...
So, in a first step, I write a compiler with Perl & yapp that generates
PIR, after I add a Lua runtime library, and finally I write in PIR (with
PGE/TGE)
a compiler.
That's all for this time.
François.