PDA

View Full Version : Getting started with LUA/pas2lua



Robert Kosek
16-02-2007, 02:55 PM
Alrighty, I'm looking at starting a simple project shortly, but it isn't a game. I easily get frustrated by things like batch files and their limited functionality, and I have never messed with the windows "powershell" that now exists. And on linux my knowledge is basic. However linux has a bonus over windows, in that Cron Jobs is super easy to use if you understand it, and so can automate your tasks.

What I am looking at writing, as a way to learn Lua, is a "luaexec" application that acts as a windows service and periodically executes various Lua scripts. For example if I wanted to clean my temp dir, and my delphi projects area of unneeded stuff I could have the script run once a week.

However I am wondering about a few things.

How would I execute a script, giving it information it may need as "configuration" that is dependent upon a per-script basis? For example, returning a table of named keys for the settings. IE:
settings = {
extensions = {
".dcu",
".log",
},
whitelist = {
"mydocs",
},
blacklist = {
"user_tempdir"
},
mainDir = "C:\Delphi",
}I am guessing it would be better to create a threaded lua script that checks the given timeframe, and then executes a script given the 'settings' variable. So I guess you could say something like this would be effective.


luaExec = {
Tasks = {},
}

function luaExec:AddTask(script, settings, period)
tables.insert(luaExec.Tasks,{ func = script, options = settings, frequency = period, });
end

function luaExec:Init()
luaExec.AddTask();
end

function luaExec:Process()

end

luaExec.Init()
CreateThreadedProcess('luaExec', 'Process')
Starting to loose my though process in writing that... Anyhow. Bascially, is it better to have an XML configuration file with settings, scripts, and date/numerical periods to execute a script, or is there a way I could do it all in a sort of library fashion? Like put all the scripts into the library and then you just configure when you want them to run, and any settings they may need.

I'm confusing myself here. Gah. So I'll just start with the simple question: How do I pass a lua table from Delphi to a given lua script? Where it may contain a table or multiple tables within itself.

And, what is better in my case? Making a main lua script that handles most the gruntwork, or sort of splitting it between the two?

jdarling
16-02-2007, 05:54 PM
I'll do my best to answer your questions. Though, not quite in order :).

When it comes to where to store your configuration information, that all depends on the level of customization you want to give to the user. While its true that a script offers more flexibility, it also bloats the application and makes the configuration more complex. To this, simpler is typically better. Think XML or INI as your root configuration manager. Keep a recording of scripts, times, and run instances that need to occur some place outside of the scripting environment.

That being said, you can also have a global script instance that modifies your current run state. Make sure that this is optional, as many users arn't going to need this functionality.

For individual task scripts, think of it this way. You will need to initialize an instance of Lua for each separate task that you want to run where anything from another script should not affect it. If your using my TLuaObject and TLua objects, then simply fire up a new instance of TLua for each script that you want to execute. Then release that instance and clean up after yourself when the execution is complete. If you want config options from your root script to affect other scripts that run in separate TLua instances then you will have to manually migrate them. That can be a bit tricky, but it can be done :).

Something to keep in mind is that Lua maintains state information until you call close. So if you run "a = 5" and then run "print(a)" you will get an output of 5, unless you called close between the two calls. Use this to your advantage.

Looking at: SDL, Lua and FPC game engine sample (http://www.eonclash.com/ViewProduct.php?ProductID=23) should be of some use. Also join the Lua Mailing List. Finally take a look at: My version of LuaTut and Lua FPC/Delphi wrappers (http://www.eonclash.com/LUA/LuaTutfpc.zip), that has an updated version of LuaObject and LuaWrapper. New bug fixes that arn't in production yet, and some other fun stuff that will be presented in the book when its released.

Once you get your basic test bed working, feel free to post it up here with questions. I'll be happy to follow up and answer everything that I can.

Oh yeah, final note, PIL (http://www.lua.org/pil/) and PIL 2 are your friends. Read them, and buy a copy if you can afford it.

Robert Kosek
16-02-2007, 10:56 PM
Oh yeah, final note, PIL (http://www.lua.org/pil/) and PIL 2 are your friends. Read them, and buy a copy if you can afford it.Gracious, you weren't kidding! LUA is far more efficient and powerful than I had originally thought. Hmm. I am nowhere near done reading though. I may end up buying PIL 1 & 2 for references, and so that I can also employ Lua in any of my future projects. It is certainly far more powerful than I imagined!

I think my program, instead of being a service, will just be a tray application with a configuration that writes to an XML file. This way I can change the icon when something is running, or even change it to a textual "gauge" to show progress of a weightier script. I think it would be best that way, because I can also bind it to let the user execute any script in their library directory at any time by a direct right-click menu. I think that would work just fine. :) Not to mention, I have absolutely no clue how to install a service application.

As to some more advanced date/time manipulation, I am still thinking. I don't want the memory overhead of keeping a "minute counter" per item, so the best way would be a "last run" date. Then I could just do a fast boolean check of when the "lastrun+interval <= now" evaluates true; I think I can use a sort of addition expression to the dates in Delphi, but I must do some research on that.

When a task is called, multiple ones may be called at once, I will add the script name and operating object to a stringlist but I won't support threaded function calls. At least initially. I am uncertain at this point, still haven't read far enough, about how I would go about marking a script as free. As for task configuration the simplest way will be a key=value list, an editor/component for which already exists. This way I just create (using a certain ECXML object :)) an entry into the configuration like this:

<luaExec>
<!-- Generic Options -->
<options></options>
<tasks>
<task option="value" ... />
</tasks>
</luaExec>
So then when loading the configuration file I just pull specific options like "script" and "interval" out and dump the rest to a Lua table that could be considered a "global object" independently put into each script. For that, perhaps a record of the lua-object, script name, and configuration record would be more expedient.

To handle the task icon I have a few components already, so I'm not concerned. However I will code some Lua functions to update the hint, progress "label" in the icon, and (in general) permit switching between the two standard icon, and dynamically modified one.

I will of course extend Lua with recursive searching of the file system, returning a table/array of strings, and a few other simpler matters. However one thing a person will always want, is the ability to track execution and errors in your tasks ... so I think I might employ a simple RSS feed which you can "subscribe" to on your own computer, and which is updated upon each (un)successful operation. This would involve a global script, as in this way the data gathering is much more dynamic and used in a very rapid form. This way I can also permit greater flexibility in logging through this functionality, while using built in I/O functions to write the data to the file.


Something to keep in mind is that Lua maintains state information until you call close. So if you run "a = 5" and then run "print(a)" you will get an output of 5, unless you called close between the two calls. Use this to your advantage. I am not entirely certain what you mean by this. From what I understand if you execute the script and the execution runs through, it consists of one "pass". Therefore of course the variable persists, but do you mean that between concurrent executions without freeing the script the variables are held? Or would this change at all in a threaded execution of a given function? Like I said, I'm scarcely into part 1, section 7.1, so I haven't read a whole heck of a lot about Lua yet.

I have never exactly understood mailing lists, or used them, so I am not sure how I would join or post messages to it. Is it like a newsgroup? I don't know how to do more than read those, and sending messages are restricted to special servers an ISP or generic web server may have.

Thanks for the updated version of the Lua objects; I will try and create a test bed soon, but aside from reading and planning the actual operation of this application ... I think my hands will be too full for that yet! :lol:

Thanks for taking the time to answer all of my questions. :)

jdarling
17-02-2007, 01:08 AM
You have some very ambitious ideas in there Robert. As I said, I would keep it simple to start with. Something that lets you select a script, schedule it, and run it. Believe me, an efficient scheduling system is not as trivial as it sounds :). The threading system should be next. Then the rest of your stuff.

You will find (as you read more) that the io library already has almost everything you need to execute a full tree walk (in Linux, Windows and MAC)!

As for ECXML, its a very good component, but please remember that its over 10 years old (believe it or not). I haven't updated it in quite some time, as there are other things on my plate taking priority. The newer version, for FPC, is still in early beta and has a few bugs. Though, its my choice any more :). Also, you will find that there are ALOT of good libraries for parsing XML in Lua (that way your config file is actually read by a script that can be customized by any user). Of course thats up to you.

For the persistence thing, here is a quick example:
var Lua : TLua;
begin
Lua := TLua.Create;
Lua.LoadScript('a = 0'#13#10'function Test()'#13#10'print(a.."\n")'#13#10'a=a+1'#13#10'end'#13#10'Test()');
Lua.Execute;
Lua.CallFunction('Test')
Lua.CallFunction('Test')
Lua.Free;
end

Output:

0
1
2


If you called .Execute instead of .CallFunction then you would see the output as 0, 0, 0. Of course, if you did a nil test then an assignment and used .Execute you would get 0, 1, 2 as the Lua State is never closed. You will learn more about that as you read PIL.

Personally, I bought PIL 1 and 2. More because I respect the author posting 1 for free then anything. I find reading them online a better option, but I like the feeling that I'm supporting the guy at some level :).

Some place on my hard drive I have ALOT of sample code. I'll look around and see if I can find it. If so I'll zip it up and make it available for download for you.

On the subject of the mailing list. You can sign up at:
http://www.lua.org/lua-l.html

Basically, you give it a valid e-mail address and then everyone on the list gets a copy of each others messages that are sent to the list. Its the "Primary form of Support for Lua". There are some really smart people on the list, and I've yet to have a problem getting help when I need it. I'm just now starting to post answers, as I'm just getting to the point that I know enough to answer competently :)

AthenaOfDelphi
17-02-2007, 01:33 AM
Hi Robert,

I'll save you some time on the date manipulation....

TDateTime is a float. The integer part represents the day while the decimal part represents time.

Its your standard offset idea, so 0 equates to 12/30/1899 12:00 am.

To offset this by 1 second, you add 1/86400 (86400 = 24 x 60 x 60 = The number of seconds in 1 day). To offset by 1 day, you add 1. Using this method, you can go forward and backwards in time quickly and easily.

I've used this kind of manipulation quite extensively for scheduling in the past... it works a treat.

Robert Kosek
17-02-2007, 11:34 PM
Athena, thank you very much! That is indeed simple and easy to use; it will fit my intents and purposes most perfectly! :)

Heh, you make me grin Jeremy. I am as stubborn as the day is long, and as determined to tackle the whole thing right at the beginning as I was before. Me, start with the easy stuff? No way! :lol: But, seriously, I won't be taking things too quickly here. I need to do some serious experimentation with Lua first to get my bearings, but it won't take long after that to write the full application. My intents aren't cross platform as of this moment because my intent is to design a tray application, which I don't know how to do in other OSes and have no interest in plumbing the depths of at this moment. That makes things easier since I can assume several things such as the existence of certain OS specific functions and methods.

I'm now on PIL 20.1 (Part III) and looking into pattern matching. This makes the whole business of making an RSS feed child's play to me, being a web designer/developer (self taught thus far), and would let me make "inter-script" functions; I assume that there is a way to call "CallFunction" with parameters, and its existence would make things simpler. Else there are clear and simple work-arounds.

I misunderstood the mailing-list for a newsgroup; newsgroups I dislike due to their rather restrictive nature of "You must have thus and such server to post a message" when for the most part I don't know what they're even babbling about. :?

So at the moment the design plan is as follows:

Step 1: Create the barebones application consisting of functions and a simple tray application. Icons are crafted at this stage too, to indicate whether a script is running or not, and if
there has been an error. An error console is of utmost importance, as well as a tabbed options dialog; I think an auto-show the error log might be important to begin with. Been there, done that, so it's mostly just deja vu -- and ensuring future expandability.

Step 2: Given a stable and versatile barebones app, with functions for dynamic menus and such, here is where the initial scheduling will occur. My first idea is to limit the execution to a maximum of once every two months, all the way down to once every few minutes or so. The "library" directory will be implemented as well as reading/writing of options to an application specific directory (partly for Vista support). For ease of installation of new scripts, I will enable a simple check item in the icon's menu that shows a square "drop form" at a selectable corner of the screen.

Step 3: With that done simple testing of scheduled "alert" scripts will take place to verify my timing/scheduling system operates. As well as some performance testing of it; for instance detecting the general load of the computer, testing to see if something is fullscreen (not entirely sure how to though) to ensure a script is not executed at a time of moderately high load. For instance, in the midst of a game. Waiting until the game ends will not hurt a thing. ;) And a menu to allow for forced execution of the scheduled scripts, updating their last-run date, will also help allow a user override. The icon switching actually begins here, not sooner.

Step 4: With step 3 out of the way, the real bulk of the work picks up. Integrating Lua with the options, scheduling, and even per-script configuration (if really necessary). I don't think a global script does much at this stage, so that will come later, if at all. However the RSS functionality I want to write in lua at least, for instance "RSS.RegisterResult({result = 'pass', overview = 'yadda yadda yadda'})", so that on a per script basis things can be put together and then sent back to the application. If I do decide to use a global script at this time, the RSS functionality will be built in, and receive "messages" from other scripts by pass-thru functions to allow updating the feed. I will permit the user to set a limit upon the age of notifications, so they do not have too large a file to load.

Step 5: No real plan here just yet, but I figure the optimization, tweaking, and extension of Lua begins here. I'd like to add zip support, I'll use TurboPower Abbrevia, so that scheduled backups can happen and maybe hashing to generate file lists with built in hash information.

Robert Kosek
20-02-2007, 05:29 PM
All things considered, it's fun spec'ing projects out, and it's another to actually research/architect them. At the moment, looking at this again, I'm considering that this isn't what I need; the nuance of scheduling lua scripts to run at any time I choose on my computer does not outweigh my need to get accustomed to the language. While I still like this idea, I've opted for a simpler start, since I'm not entirely sure how to pass more than 20 (the buffer length of Lua) results at once, or in a table. That's a bit overkill, but I don't want to tackle such problems when I am still super new to using the language myself.

So, instead, I'll just make a barebones FPC console application that has a "library" directory, a main script that acts as the actual program, and some various "library" extension objects to Lua. Not to mention that with very little work indeed, I can make a console roguelike with just a simple script -- a very simple one, but functional nonetheless.

PS: Jeremy, this is just where you'll have to let me "think myself out", as you caught me early in the brainstorm process and I was needing a bit of input. ;)

Quick question on the topic of Lazarus/FPC, but does the DOS unit work in finding files cross-platform? I was wondering and looking, but I couldn't tell -- the remarks in the documentation mentioned that it was revised for cross-platform compatibility, but not what did work across them. If I am going to implement a "library" directory like I intend, I must be able to enumerate the files within it, so that's the main thing stopping me right now.

jdarling
20-02-2007, 06:02 PM
Can't answer the question about finding files, as I don't use the DOS unit at all in FPC :).

On the problem of returning 20 items from a function. Its a very simple fix. Return a table instead, then you can have as many items as you want. So for example:

function MyTest&#40;&#41;
local i = &#123;&#125;
for n=1,1000 do
i&#91;n&#93;=tostring&#40;n&#41;
end
return i
end

In pascal then just call luaToVariant(L, idx) on your result type and expect to get back a variant array. It took along time to modify luaToVariant to accept variant arrays, but its been a very worth while effort :)

Robert Kosek
20-02-2007, 06:07 PM
Well, what do you use in FPC to find a given file? Or, do you even do that in your stuff? :?

I mean a pascal function passing more than 20 results to lua, which I figured would be best as a table. Though, passing a table as a result is a little cryptic to me.

jdarling
20-02-2007, 07:38 PM
FindFirst/FindNext (from http://www.delphibasics.co.uk/RTL.asp?Name=FindNext) var
searchResult : TSearchRec;

begin
// Try to find regular files matching Unit1.d* in the current dir
if FindFirst('Unit1.d*', faAnyFile, searchResult) = 0 then
begin
repeat
ShowMessage('File name = '+searchResult.Name);
ShowMessage('File size = '+IntToStr(searchResult.Size));
until FindNext(searchResult) <> 0;

// Must free up resources used by these successful finds
FindClose(searchResult);
end;
end;

Robert Kosek
20-02-2007, 07:44 PM
That's what I was going to use, but in FPC it is in the DOS unit ... so I wasn't sure. I might as well try it I guess. :)

Edit: I'm thinking of, in that loop, using a "callback" to the script to as a function to add a string to the record. How would I code the pascal part to accept the parameter of an "inline" function, and then call that function with a single variable during that loop? I'd call the function sorta like this:
system.find&#40;"library/*.lua",function&#40;file&#41; table.insert&#40;library_files,file&#41; end&#41;

jdarling
20-02-2007, 07:59 PM
Well, actually, you don't include the DOS library directly. You include the SysUtils lib directly. Then depending on platform it will include the right implementation of findfirst/next. This way it works on Mac, Unix, Linux, Windows, etc...

On your question, can you give me a full blown example. I'm a bit lost as to what your wanting, and the one liner didn't do it for me :). High level will work:

FindFirst()
CallScript(MyFunction)
FindNext()
ReturnToCallScript()

Then what you want the script to do and what your global records/objects/variables should be.

Robert Kosek
20-02-2007, 08:16 PM
I just looked in the RTL document and you're 100% right. Silly me. :roll:

I do that so often I sometimes want to beat my head against the table. Anyhow.

I can't really give a full blown example at the moment because I haven't written anything; I need a function that finds all scripts in the library directory and gives that to my main script. So there's one of two methods: passing back a table, or calling a handler function. I'm not entirely certain how to do either. What I would do is register a global variable, we'll just call it library, with a sub-table named scripts.

IE:
-- Main.lua

library = &#123;
scripts = &#123;&#125;,
&#125;

So I would do something like register this function (forgive me, I'm really crawling in the dark on how to make a table in Lua) with Lua:procedure system_search(L : PLua_State);
var
searchResult : TSearchRec;
mask: string;
results: longint;
begin
mask := lua_tostring(L,1);
if FindFirst(mask, faAnyFile, searchResult) = 0 then
begin
repeat
// lua_pushstring(L,searchResult.Name); ?
inc(results);
until FindNext(searchResult) <> 0;

// Must free up resources used by these successful finds
FindClose(searchResult);
end;
lua_settable(L,-results); // ?
end;

Then I'd call it in the script sort of like this:
library.scripts = system.find&#40;"library/*.lua"&#41;And it would return something about like this:
&#123;
"hello.lua",
"recursive_search.lua",
&#125;And so on.

Like I said, I'm really lost on how to mess with functions and passing back and forth parameters and results. Not to mention just how to go about designing a function like that, since I've never worked with a stack before.

jdarling
20-02-2007, 08:42 PM
Gotcha! Ok, try this:function lua_Search(L : PLua_State) : integer; cdecl;
var
i, n, idx : integer;
searchResult : TSearchRec;
path, mask: AnsiString; // You should always use AnsiStrings and not Strings
begin
n := lua_gettop(L); // Get the number of items being passed in
if n > 0 then
begin
path := luatostring(L, 1);
if n > 1 then
mask := luatostring(L, 2)
else
mask := '*.*';
end
else
begin
mask := '*.*';
path := ExtractFilePath(ParamStr(0));
end;
lua_newtable(L); // Create a new table
idx := lua_tointeger(L, 1);
lua_Search := 1;
i := 1;
if FindFirst(path + mask, faAnyFile, searchResult) = 0 then
begin
repeat
lua_pushinteger(L, i);
inc(i);
luapushstring(path + mask);
lua_settable(L, idx);
until FindNext(searchResult) <> 0;
FindClose(searchResult);
end;
end;

Later (if your using my TLua object) register the function with:Lua.RegisterMethod('FindFiles', @lua_Search)
If you are using pure Lua, then registering the function becomes:luapushstring(L, 'FindFiles');
lua_pushcfunction(L, @lua_Search);
lua_settable(L, LUA_GLOBALSINDEX);

Then for a lua script:
results = FindFiles&#40;SomePath, '*.bmp'&#41;
if results~= nil then
for k, v in pairs&#40;results&#41; do
print&#40;v&#41;
end
end


On a side note; really you should allow for a recursive flag, allow path and filename to be passed in a new table instead of all in one, and other options. By default, FindFirst/FindNext are not recursive, and you would have to write handlers to manage this. Unfortunately (for you) I never completed the code I was working on for a good cross platform lua_FindFiles implementation, if I do, I'll post it up :)

Robert Kosek
20-02-2007, 09:50 PM
Thank you very much Jeremy, I'll try that in a little bit. I know how to make things recursive, but it will take some additional helper functions and all. I'll make a testbed for that later. ;) But it isn't too hard to do.

I just was lost on how to pass stuff to Lua. So I'll write up a cross platform, recursive, findfiles function soon enough and then share it with you.

Robert Kosek
21-02-2007, 07:30 PM
Uh, Jeremy? I just tried compiling a sandbox, and it gave me about 48 errors in FPC 2.0.4 saying that "result is undefined". Did I leave something out?

luaexec.pas:
program luaexec;

&#123;$MODE DELPHI&#125;

uses LuaWrapper, lua, LuaUtils, SysUtils, crt;

function lua_Search&#40;L &#58; PLua_State&#41; &#58; integer; cdecl;
var
i, n, idx &#58; integer;
searchResult &#58; TSearchRec;
path, mask&#58; AnsiString; // You should always use AnsiStrings and not Strings
begin
n &#58;= lua_gettop&#40;L&#41;; // Get the number of items being passed in
if n > 0 then
begin
path &#58;= luatostring&#40;L, 1&#41;;
if n > 1 then
mask &#58;= luatostring&#40;L, 2&#41;
else
mask &#58;= '*.*';
end
else
begin
mask &#58;= '*.*';
path &#58;= ExtractFilePath&#40;ParamStr&#40;0&#41;&#41;;
end;
lua_newtable&#40;L&#41;; // Create a new table
idx &#58;= lua_tointeger&#40;L, 1&#41;;
lua_Search &#58;= 1;
i &#58;= 1;
if FindFirst&#40;path + mask, faAnyFile, searchResult&#41; = 0 then
begin
repeat
lua_pushinteger&#40;L, i&#41;;
inc&#40;i&#41;;
luapushstring&#40;path + mask&#41;;
lua_settable&#40;L, idx&#41;;
until FindNext&#40;searchResult&#41; <> 0;
FindClose&#40;searchResult&#41;;
end;
end;

function lua_KeyPressed&#40;L &#58; PLua_State&#41; &#58; integer; cdecl;
begin
luapushboolean&#40;L,KeyPressed&#41;;
end;

var main&#58; TLua;

BEGIN
main &#58;= TLua.Create&#40;nil&#41;;
main.LoadFile&#40;'main.lua'&#41;;
main.RegisterMethod&#40;'FindFiles', @lua_Search&#41;;
main.RegisterMethod&#40;'KeyPressed', @lua_KeyPressed&#41;;
main.Execute;
main.free;
END.
main.lua:
-- MAIN.LUA

print&#40;"Greetings Terran!"&#41;;
while not KeyPressed&#40;&#41; do end

Should work according to what I know. FPC has always seemed picky to me though, so I never quite understood the problem with things like this. I thought result was always assumed in a function.

Errors raised:
lua.pas&#40;796,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;814,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;840,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;845,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;850,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;855,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;860,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;865,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;870,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;875,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;880,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;900,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;905,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;915,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;934,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;946,5&#41; Error&#58; Identifier not found "result"
lua.pas&#40;948,5&#41; Error&#58; Identifier not found "result"
lua.pas&#40;953,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;958,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;963,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;968,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;973,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;978,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;983,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;988,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;989,6&#41; Error&#58; Identifier not found "result"
lua.pas&#40;990,5&#41; Error&#58; Identifier not found "result"
lua.pas&#40;995,3&#41; Error&#58; Identifier not found "result"
lua.pas&#40;996,6&#41; Error&#58; Identifier not found "result"
lua.pas&#40;997,5&#41; Error&#58; Identifier not found "result"
lua.pas&#40;1026,5&#41; Error&#58; Identifier not found "result"
lua.pas&#40;1030,5&#41; Error&#58; Identifier not found "result"
lua.pas&#40;1073&#41; Fatal&#58; There were 32 errors compiling module, stopping
lua.pas&#40;5,46&#41; Fatal&#58; Compilation aborted

jdarling
21-02-2007, 08:11 PM
Robert, good first try. There are a few things in the lua.pas file that arn't quite right. Apparently I haven't updated the lua.pas that is on the website in a while :( (my apologies).

Try downloading: http://www.eonclash.com/LUA/luaexec.zip

It is an updated version of what you posted that runs just fine :). You will want to use the units (lua, luawrapper, luautils, cutils, and luaobject) from this zip file for your projects. Basically part of the problem was that in FPC result doesn't exist, you have to use function name:// This won't work in fpc
function Test():Integer;
begin
result := 1;
end;
// This is the "proper" way to do it
function Test():Integer;
begin
Test := 1;
end;

Also, in your lua_KeyPressed method you never set the method result. So I added it in for you :). Now everything should work fine.

I also had a problem in the code I gave you. I did a create table and then a tointeger, that tointeger should have been a gettop :)

Finally, a minor fix in the push to accommodate searchResult.Name instead of path + mask makes it all work hunky dory.

Robert Kosek
21-02-2007, 08:58 PM
Oh, I understand. I think that's a little silly though that they didn't reuse result like Delphi does as a standard feature. It would help when someone starts out with the compiler.

Thanks for updating the headers again. :)

Is there a specific reason for the cdecl; tagged onto the functions? I'm not entirely sure what it does, though I suspect it makes things easier in interfacing with a DLL. And the result variable of a function is the number of parameters returned, right? I think I'm starting to get a hang of this.

Now to start implementing the better aspects of FPC's console functions and making something better out of it. :D Like, columns displaying library scripts, window functionality, and some basic readkey stuff to tie all that into an easy executable for my scripts. Then there's no need to touch the app for a while, as I change things around and mess with stuff. I might end up writing a batch image converter to take screenshots from a given directory, convert them to jpeg/png and then dump them into another directory.

Thanks much for your help thus far! Maybe once I get a hang of this stuff and have a little more time I can help you out with your game engine. That would be kinda fun I think, but I honestly don't know enough right now on top of lacking the time to do more than fiddle around. But hey, getting acquainted with the language and its usage is half the battle. ;)

(As a side note, I might have a use for this knowledge in my work. Our web server stuff is just about inbetween a rock and a hard place, and Lua just might be able to get us out. Assuming I can talk my coworkers into it. Keep your fingers crossed!)

Robert Kosek
21-02-2007, 09:41 PM
I'll quick run this by you to see if I understand it right, but I think I do. I'm writing a simplistic library for pascal/lua to handle the CRT functionality of Freepascal. So I've written a function supporting multiple types, integer and string, and use that to set the text color of the console. (IE, the foreground color)

function lua_TextColor(L: PLua_State) : integer; cdecl;
var n,i: integer;
c: byte;
s: string;
const colors: array[0..15] of string = ('black','blue','green','cyan','red','magenta','br own','lightgray','darkgray',
'lightblue','lightgreen','lightcyan','lightred','l ightmagenta','yellow','white');
begin
n := lua_gettop(L);
assert(n = 1, 'Number of arguments to TextColor must be 1.');
lua_TextColor := 0;

if lua_isstring(L,1) then begin
s := lua_tostring(L,1);
c := 15; // The default color.
for i := 0 to 15 do
if lowercase(s) == colors[i] then begin
c := i;
break;
end;
end else if lua_isnumber(L,1) then
c := byte(min(lua_tointeger(L,1),15));
else assert(false,'Error, invalid type passed to TextColor!');

assert((c >= 0)and(c < 16), 'TextColor must be called with a value equal to, or between 0 and 15.');
TextColor(c);
end;

So eventually I want to register a library, not just a function. Referencing this page (http://www.lua.org/pil/26.2.html) I think I know how to do it, save one thing. Must I include the ending (nil,nil) entry? And how do I define a constant 2D array in FreePascal? I never was good at constant multidepth arrays. :roll: Like this?
const crtlib&#58; array of array of variant = &#40;&#40;"KeyPressed", @lua_KeyPressed&#41;, &#40;"TextColor", @lua_TextColor&#41;, &#40;nil,nil&#41;&#41;;Or, is this impossible with FPC? Seems like a messy array of variants to me. :? Can I actually do this in pascal, or not? I'm guessing that, as a long shot, I could register it the normal way as "crt.TextColor" rather than just "TextColor".

jdarling
21-02-2007, 09:43 PM
Well, cdecl tells the compiler to place the items in C fashion for the methods (functions/procedures). Since Lua is developed in C it expects the method params and return values in C style and not pascal style (more on this all over the web if you want to research it).

Yes, the result of the function is the number of variables that YOU placed onto the stack (or returned). If you have variables in a table then you only count the table :).

On the topic of Result, this is something that Borland introduced into the pascal language. The pascal standard states that you should use the method name and not a generic handler :). So actually, its Borland Delphi thats wrong :).

Finally, hate to burst your bubble, but I am very selective of the people I let work on the game engine. In fact, right now there is only one other person that ever looks at the code, and he doesn't modify it :). On most of my projects I don't mind, but this one is close to the heart and has paying customers, so I keep a very tight lid on the source. Though, if you ever decide to do one of your own, feel free to ask questions, as I think I've managed to screw up about everything that could be screwed up :).

jdarling
21-02-2007, 09:47 PM
That article does show one way of doing libraries in your code. Here is what I do for libraries though:procedure RegisterBackgroundMusic(L : Plua_State);
var
idx, mt : Integer;
begin
lua_pushliteral(L, 'BackgroundMusic');
lua_newtable(L);
idx := lua_gettop(L);
RegisterMethod(L, 'Play', @BackgroundMusic_Play, idx);
RegisterMethod(L, 'PlaySong', @BackgroundMusic_PlaySong, idx);
RegisterMethod(L, 'Stop', @BackgroundMusic_Stop, idx);
RegisterMethod(L, 'AddMusicFile', @BackgroundMusic_AddMusicFile, idx);
RegisterMethod(L, 'Delete', @BackgroundMusic_Delete, idx);
RegisterMethod(L, 'Next', @BackgroundMusic_Next, idx);
RegisterMethod(L, 'Previous', @BackgroundMusic_Previous, idx);
RegisterMethod(L, 'First', @BackgroundMusic_First, idx);
RegisterMethod(L, 'Last', @BackgroundMusic_Last, idx);
lua_newtable(L);
mt := lua_gettop(L);
RegisterMethod(L, '__index', @index_BackgroundMusic, mt);
//RegisterMethod(L, '__newindex', @index_BackgroundMusic, idx);
RegisterMethod(L, '__newindex', @newindex_BackgroundMusic, mt);
//RegisterMethod(L, '__mt', @newindex_BackgroundMusic, idx);
lua_setmetatable(L, idx);
lua_settable(L, LUA_GLOBALSINDEX);
end;

That should at least give you an idea of how it can work. The nice thing about Lua is there are literally 100's of ways to achieve a single task. The bad thing about Lua is there are literally 100's of ways to achieve a single task.

Sorry, that code basically creates a table called BackgroundMusic (the same thing as a library in the end). So you call methods out of it as BackgroundMusic.MethodName(Params)

Robert Kosek
21-02-2007, 10:01 PM
Well, that'll help.

I can't say that I paid too much attention to the details about your engine before, but I was surprised that you are making that for paying customers. Congratulations! That's one of the hardest things to do sometimes, make an engine especially for a paying customer. :D No wonder you keep it very near and dear to your heart, and I don't blame you.

So, I assume the function looks right for returning no results? And just general structure too, of course.

jdarling
21-02-2007, 10:29 PM
It looks fine to me, though you might want to look into lua_error instead of assert :).

Robert Kosek
21-02-2007, 10:36 PM
Err, I cannot figure out how to actually use it. :? I don't have the reference manual at the moment, so what are the parameters and usage?

jdarling
21-02-2007, 11:04 PM
C Prototype is: lua_error (lua_State *L, const char *s)

so:lua_error(L, 'My Error Message');

Robert Kosek
21-02-2007, 11:21 PM
Then how do I call it, given I find this thing, when in use that there's a pushstring occurring first if I keep searching.


function lua_error&#40;L &#58; Plua_State&#41; &#58; Integer;
cdecl; external LuaDLL;

Do I?:

lua_pushstring&#40;L,'Error!'&#41;;
lua_error&#40;L&#41;;

EDIT:

Found it, LuaUtils.pas. Sorry, should've checked there.

Robert Kosek
22-02-2007, 12:43 AM
I wrote this function for debugging purposes, along the lines of assert and error combined, and I'm finding it a great shortcut! You might find some use for it somewhere, or want to include it in the library.

{
lua_AssertError(lua_state, condition, error message)
}
function lua_AssertError(L: PLua_State; Condition: Boolean; const Msg: string): boolean;
begin
if condition then
LuaError(L,Msg);
{$IFDEF FPC}
lua_AssertError := condition;
{$ELSEIF}
result := condition;
{$ENDIF}
end;

It's not much really, but it makes structuring things easy! Example:function lua_Window(L: PLua_State): integer; cdecl;
begin
if not lua_AssertError(L, lua_gettop(L) <> 4, 'Window() requires four parameters, x1, y1, x2, y2.') then
if not lua_AssertError(L,not (lua_isnumber(L,1) and lua_isnumber(L,2) and
lua_isnumber(L,3) and lua_isnumber(L,4)),'All parameters of Window() must be numbers or numerical strings.') then begin
// Being sneaky here, and cheating a little.
Window(LuaToInteger(L,1),LuaToInteger(L,2),LuaToIn teger(L,3),LuaToInteger(L,4));
end;
lua_Window := 0;
end;

Just remember that it evaluates true on error, shows the message, and then returns true that there was an error. ;) Just in case someone other than us finds use for it. But that simple little thing is saving me debugging time like crazy...

In fact I turned this:function lua_GotoXY(L : PLua_State) : integer; cdecl;
var x,y: integer;
begin
lua_GotoXY := 0;


if lua_gettop(L) = 2 then begin
if not lua_AssertError
if lua_isnumber(L,1) then
x := lua_tointeger(L,1)
else
lua_AssertError(L,false, 'Argument 1 in GotoXY() is not a number.');

if lua_isnumber(L,2) then
y := lua_tointeger(L,2)
else
lua_AssertError(L,false, 'Argument 2 in GotoXY() is not a number.');

lua_AssertError(L, (x = 0) and (y = 0), 'Coordinates must be greater than 0.');

GotoXY(x,y);
end else lua_AssertError(L,false, 'Error, GotoXY() requires two arguments of type integer.');
end;
Into this:function lua_GotoXY(L : PLua_State) : integer; cdecl;
var x,y: integer;
begin
lua_GotoXY := 0;

if not lua_AssertError(L, lua_gettop(L) <> 2, 'Error, GotoXY() requires two arguments of type integer.') then
if not lua_AssertError(L, not (lua_isnumber(L,1) and lua_isnumber(L,2)), 'GotoXY() requires two number friendly values.') then begin
x := lua_tointeger(L,1)
y := lua_tointeger(L,2)
if not lua_AssertError(L, (x = 0) or (y = 0), 'Coordinates must be greater than 0.') then
GotoXY(x,y);
end;
end;

So much easier to understand. :D

Robert Kosek
22-02-2007, 01:53 AM
Okay, this is silly. I found that TLua doesn't contain "RegisterMethod" so I had to use "LuaRegister" instead, but now, after changing a few things for compatibility I now get this when running the executable file:
C&#58;\FPC\projects\luaexec>luaexec
An unhandled exception occurred at $1000C33A &#58;
EAccessViolation &#58; Access violation
$1000C33A
$00407067
$004070CE
$004013D2

I updated the Lazarus project though I am not using that directly, just using straight FPC instead. It might be my register function for the CRT "library" but I really don't know. You can get the whole project from here (http://thewickedflea.freepgs.com/luaexec.zip). What'd I do this time? :?

Also, I noticed numerous errors in my functions and the IFDEF clause the newer definition in the source is much better.

EDIT:

This is screwy. It's telling me that it doesn't want a pointer/address to the function, then I remove the @ symbol it immediately complains of too few arguments. What's going on!? This doesn't even raise an error in the LuaCRT unit, but in the main one it does. :?

JernejL
22-02-2007, 10:53 AM
lua.pas(978,3) Error: Identifier not found "result"


{$mode delphi} // fixes this

Robert Kosek
22-02-2007, 12:13 PM
{$mode delphi} // fixes thisI had mode Delphi defined at the top of the unit. It didn't fix that.

JernejL
22-02-2007, 01:47 PM
{$mode delphi} // fixes thisI had mode Delphi defined at the top of the unit. It didn't fix that.

it has to be defined prior the "unit xyz" part.

Robert Kosek
22-02-2007, 02:04 PM
Oh, I'd have to go back and double check that, thanks for the tip. Though that's the least of my problems currently; I'm having trouble passing a function as an argument (Pointer style) that is making the program choke.

jdarling
22-02-2007, 07:38 PM
Working with functions as parameters isn't near as easy as it sounds. You have to keep a reference to the function in the Lua Registry, and then you have to use that entry to actually call the function.

The following is a "simple" sample:function lua_CallFunc(L : PLua_State) : Integer; cdecl;
var
n, callTimes, funcRef, c, pidx : Integer;
pArray : array of variant;
begin
n := lua_gettop(L); // Get the number of items on the stack
callTimes := lua_tointeger(L, 1); // Get the number of times to call the function
if lua_type(L, 2)=LUA_TFUNCTION then // Make sure we have a function
begin
lua_pushvalue(L, 2); // Make a copy to push to the registry
funcRef := luaL_ref(L, LUA_REGISTRYINDEX); // push to the registry and get the reference
try
SetLength(pArray, n-3); // Get the params that we are passing
for c := 3 to n do
pArray[c-3] := luatovariant(L, c);
for c := 1 to callTimes do
begin
lua_rawgeti(L, LUA_REGISTRYINDEX, funcRef); // Place the reference on the stack
for pidx := 0 to length(pArray)-1 do // place each param on the stack
luapushvariant(L, pArray[pidx]);
lua_call(L, length(pArray), LUA_MULRET); // Call the function
end;
finally
luaL_unref(L, LUA_REGISTRYINDEX, funcRef); // Release the reference to the function
end;
end;
lua_CallFunc := 0;
end;

The Lua "Prototype" for this would be:
function CallFunc(NumTimes, FuncPointer, ...)

Of course, for speed, when using a known function you should cache the function registry reference for re-use. Then release it when you no longer need it.

Hope that helps some, just typed it in looking at some working code. But, there may be problems :)

Robert Kosek
22-02-2007, 07:48 PM
Uh, no, check the previous page. I cannot even register the functions... :?


Okay, this is silly. I found that TLua doesn't contain "RegisterMethod" so I had to use "LuaRegister" instead, but now, after changing a few things for compatibility I now get this when running the executable file:
C&#58;\FPC\projects\luaexec>luaexec
An unhandled exception occurred at $1000C33A &#58;
EAccessViolation &#58; Access violation
$1000C33A
$00407067
$004070CE
$004013D2

I updated the Lazarus project though I am not using that directly, just using straight FPC instead. It might be my register function for the CRT "library" but I really don't know. You can get the whole project from here (http://thewickedflea.freepgs.com/luaexec.zip). What'd I do this time? :?

Also, I noticed numerous errors in my functions and the IFDEF clause the newer definition in the source is much better.

EDIT:

This is screwy. It's telling me that it doesn't want a pointer/address to the function, then I remove the @ symbol it immediately complains of too few arguments. What's going on!? This doesn't even raise an error in the LuaCRT unit, but in the main one it does. :?

Also, I noticed that registering the CRT library functions caused that access violation; I don't know how, why, or how to fix it though.

Robert Kosek
22-02-2007, 10:25 PM
Okay, I tried this, and it raises the error that it has insufficient arguments.

procedure RegisterCRT(L: PLua_State);
var
idx : Integer;
begin
lua_pushliteral(L, 'crt');
lua_newtable(L);
idx := lua_gettop(L);
LuaRegisterCustom(L, 'KeyPressed', lua_KeyPressed, idx);
LuaRegisterCustom(L, 'ReadKey', lua_ReadKey, idx);
LuaRegisterCustom(L, 'GetXY', lua_GetXY, idx);
LuaRegisterCustom(L, 'TextColor', lua_TextColor, idx);
LuaRegisterCustom(L, 'BackgroundColor', lua_BackgroundColor, idx);
LuaRegisterCustom(L, 'ClrScr', lua_ClrScr, idx);
LuaRegisterCustom(L, 'ClrEol', lua_ClrEol, idx);
LuaRegisterCustom(L, 'DelLine', lua_DelLine, idx);
LuaRegisterCustom(L, 'GotoXY', lua_GotoXY, idx);
LuaRegisterCustom(L, 'InsLine', lua_InsLine, idx);
LuaRegisterCustom(L, 'Window', lua_Window, idx);
// lua_settable(L,idx);
lua_settable(L, LUA_GLOBALSINDEX);
end;

But when I try this, it completely freaks out with the following error messages:procedure RegisterCRT(L: PLua_State);
var
idx : Integer;
begin
lua_pushliteral(L, 'crt');
lua_newtable(L);
idx := lua_gettop(L);
LuaRegisterCustom(L, 'KeyPressed', @lua_KeyPressed, idx);
LuaRegisterCustom(L, 'ReadKey', @lua_ReadKey, idx);
LuaRegisterCustom(L, 'GetXY', @lua_GetXY, idx);
LuaRegisterCustom(L, 'TextColor', @lua_TextColor, idx);
LuaRegisterCustom(L, 'BackgroundColor', @lua_BackgroundColor, idx);
LuaRegisterCustom(L, 'ClrScr', @lua_ClrScr, idx);
LuaRegisterCustom(L, 'ClrEol', @lua_ClrEol, idx);
LuaRegisterCustom(L, 'DelLine', @lua_DelLine, idx);
LuaRegisterCustom(L, 'GotoXY', @lua_GotoXY, idx);
LuaRegisterCustom(L, 'InsLine', @lua_InsLine, idx);
LuaRegisterCustom(L, 'Window', @lua_Window, idx);
// lua_settable(L,idx);
lua_settable(L, LUA_GLOBALSINDEX);
end;
LuaCRT.pas&#40;76,68&#41; Error&#58; Incompatible type for arg no. 4&#58; Got "SmallInt", expected "<procedure>"
LuaCRT.pas&#40;77,68&#41; Error&#58; Incompatible type for arg no. 4&#58; Got "SmallInt", expected "<procedure>"
LuaCRT.pas&#40;78,68&#41; Error&#58; Incompatible type for arg no. 4&#58; Got "SmallInt", expected "<procedure>"
LuaCRT.pas&#40;79,68&#41; Error&#58; Incompatible type for arg no. 4&#58; Got "SmallInt", expected "<procedure>"
LuaCRT.pas&#40;80,68&#41; Error&#58; Incompatible type for arg no. 4&#58; Got "SmallInt", expected "<procedure>"
LuaCRT.pas&#40;81,68&#41; Error&#58; Incompatible type for arg no. 4&#58; Got "SmallInt", expected "<procedure>"
LuaCRT.pas&#40;82,68&#41; Error&#58; Incompatible type for arg no. 4&#58; Got "SmallInt", expected "<procedure>"
LuaCRT.pas&#40;83,68&#41; Error&#58; Incompatible type for arg no. 4&#58; Got "SmallInt", expected "<procedure>"
LuaCRT.pas&#40;84,68&#41; Error&#58; Incompatible type for arg no. 4&#58; Got "SmallInt", expected "<procedure>"
LuaCRT.pas&#40;85,68&#41; Error&#58; Incompatible type for arg no. 4&#58; Got "SmallInt", expected "<procedure>"
LuaCRT.pas&#40;86,68&#41; Error&#58; Incompatible type for arg no. 4&#58; Got "SmallInt", expected "<procedure>"
LuaCRT.pas&#40;233&#41; Fatal&#58; There were 11 errors compiling module, stopping
LuaCRT.pas&#40;5,50&#41; Fatal&#58; Compilation aborted


Should I try "function as lua_CFunction" or "lua_CFunction(function)"? This is a bit crazy. I hope this doesn't occur very frequently when messing with Lua initially. :?

Sly
23-02-2007, 08:03 AM
What is the declaration of LuaRegisterCustom()?

Robert Kosek
23-02-2007, 12:20 PM
Lua.pas
type
lua_CFunction = function&#40;L &#58; Plua_State&#41; &#58; Integer; cdecl;

LuaRegisterCustom, LuaUtils.pas

procedure LuaRegisterCustom&#40;L&#58; PLua_State; TableIndex&#58; Integer; const Name&#58; PChar; F&#58; lua_CFunction&#41;;
var
Count&#58; Integer;
S&#58; string;
begin
LuaProcessTableName&#40;L, Name, S, TableIndex, Count&#41;;
LuaRawSetTableFunction&#40;L, TableIndex, S, F&#41;;
lua_pop&#40;L, Count&#41;;
end;

All my functions are adhering to both call/definition correctly too. :? That's the strange part. I call the register function for the CRT functions I made, commenting out the search routine (I still cannot register it), and the instant they are registered (output isn't even started) that exception occurs and the application dies.

jdarling
23-02-2007, 02:20 PM
Robert, you don't want to use the register methods from LuaUtils. Instead look at the register methods in my LuaWrapper and LuaObjects units.

Post up a zip of your source files and I'll adjust it to work. Then you can compare the two and see what I'm talking about.

Robert Kosek
23-02-2007, 03:17 PM
I updated the Lazarus project though I am not using that directly, just using straight FPC instead. It might be my register function for the CRT "library" but I really don't know. You can get the whole project from here (http://thewickedflea.freepgs.com/luaexec.zip). What'd I do this time? :?

Also, I noticed numerous errors in my functions and the IFDEF clause the newer definition in the source is much better.

EDIT:

This is screwy. It's telling me that it doesn't want a pointer/address to the function, then I remove the @ symbol it immediately complains of too few arguments. What's going on!? This doesn't even raise an error in the LuaCRT unit, but in the main one it does. :?

Is there something wrong with those register methods? They were the only really simple way to register the functions to a table that I could find. The way you gave me before FPC couldn't find the needed function. :?

EDIT: You mean to try the RegisterMethod from LuaObject.pas? So, I should just use that instead I guess. Though, I honestly don't understand the duplicity and frequency of so many functions to try and do that same thing.

EDIT2: As in something like this to register my functions?procedure RegisterCRT(L: PLua_State);
var
idx : Integer;
begin
lua_pushliteral(L, 'crt');
lua_newtable(L);
idx := lua_gettop(L);
RegisterMethod(L, 'KeyPressed', @lua_KeyPressed, idx);
RegisterMethod(L, 'ReadKey', @lua_ReadKey, idx);
RegisterMethod(L, 'GetXY', @lua_GetXY, idx);
RegisterMethod(L, 'TextColor', @lua_TextColor, idx);
RegisterMethod(L, 'BackgroundColor', @lua_BackgroundColor, idx);
RegisterMethod(L, 'ClrScr', @lua_ClrScr, idx);
RegisterMethod(L, 'ClrEol', @lua_ClrEol, idx);
RegisterMethod(L, 'DelLine', @lua_DelLine, idx);
RegisterMethod(L, 'GotoXY', @lua_GotoXY, idx);
RegisterMethod(L, 'InsLine', @lua_InsLine, idx);
RegisterMethod(L, 'Window', @lua_Window, idx);
// lua_settable(L,idx);
lua_settable(L, LUA_GLOBALSINDEX);
end;Attempting that immediately gave me this when attempting to compile:
LuaObject.pas&#40;462,49&#41; Error&#58; Incompatible type for arg no. 3&#58; Got "<address>", expected "<procedure>"
LuaObject.pas&#40;463,55&#41; Error&#58; Incompatible type for arg no. 3&#58; Got "<address>", expected "<procedure>"
LuaObject.pas&#40;464,46&#41; Error&#58; Incompatible type for arg no. 3&#58; Got "<address>", expected "<procedure>"
LuaObject.pas&#40;465,43&#41; Error&#58; Incompatible type for arg no. 3&#58; Got "<address>", expected "<procedure>"
LuaObject.pas&#40;466,46&#41; Error&#58; Incompatible type for arg no. 3&#58; Got "<address>", expected "<procedure>"
LuaObject.pas&#40;467,43&#41; Error&#58; Incompatible type for arg no. 3&#58; Got "<address>", expected "<procedure>"
LuaObject.pas&#40;484,49&#41; Error&#58; Incompatible type for arg no. 3&#58; Got "<address>", expected "<procedure>"
LuaObject.pas&#40;485,55&#41; Error&#58; Incompatible type for arg no. 3&#58; Got "<address>", expected "<procedure>"
LuaObject.pas&#40;487,43&#41; Error&#58; Incompatible type for arg no. 3&#58; Got "<address>", expected "<procedure>"
LuaObject.pas&#40;488,46&#41; Error&#58; Incompatible type for arg no. 3&#58; Got "<address>", expected "<procedure>"
LuaObject.pas&#40;516&#41; Fatal&#58; There were 10 errors compiling module, stopping
LuaObject.pas&#40;4,50&#41; Fatal&#58; Compilation aborted


Ick; at the moment I'm reconsidering trying to learn Lua using FPC. FPC just isn't very friendly to me no matter what I do, whenever I try. :(

Robert Kosek
02-03-2007, 03:59 PM
I just noticed something, but Jeremy, why are you pushing a procedure like a pointer, when you aren't using the right type? If you adjust your types to include a lua_PCFunction (in Lua.pas) like so:type
lua_CFunction = function(L : Plua_State) : Integer; cdecl;
lua_PCFunction = ^lua_CFunction;And then change your RegisterMethod and lua_pushcfunction to use the lua_PCFunction type it seems to work. You're treating the function like a pointer and FPC is choking all over itself on this. Either it says "I don't want an address!" or when you pass a function "where are the variables for the function?" and so it doesn't work either way in its present implementation.

jdarling
02-03-2007, 05:16 PM
Well, there is more then one way to choke a horse :). Actually it depends on your compiler settings as to what version works best. I'd say, go with what works for you, and I'll make sure and cover both in my article as I complete it.

Robert Kosek
02-03-2007, 05:32 PM
Well, the problem is that nothing is working, and that's the aggravation. What compiler settings can I change to make it work? This is why I am returning to my original dislike of FPC, as it isn't very user friendly. And I don't need Lazarus right now, so I'm not working with that.