GameMonkey Script

GameMonkey Script Forums
It is currently Sun Jan 20, 2019 10:59 pm

All times are UTC




Post new topic Reply to topic  [ 12 posts ] 
Author Message
 Post subject: foreach extended syntax
PostPosted: Sat Jun 20, 2009 3:42 pm 
Offline

Joined: Thu Jan 01, 2004 4:31 pm
Posts: 307
I've coded the first part of the foreach syntax discussed here

In this update, I've implemented two extensions to the foreach syntax...

The first is:

Code:
foreach(item in items where (<expr>))
{
   // code
}


So, you can write queries such as:

Code:
entities = {
   { id=1, name="Glador", class="wizard", mana=100, hp=20 },
   { id=2, name="Bahr", class="warrior", mana=0, hp=100 },
   { id=3, name="Gandalf", class="wizard", mana=120, hp=50 },
   { id=4, name="SuperWizard", class="wizard", mana=150, hp=50 }
};
         

foreach(e in entities where (e.mana >= 100))
{
   print(e.name, "has lots of mana");
}

foreach(e in entities where (e.class != "wizard"))
{
   print(e.name, "is not a wizard");
}


You can also omit the body of the code and insert the data into tables using the syntax:

Code:
foreach(item in items where(<expr>) into newTable);



Code:
foreach(e in entities where (e.class == "wizard") into wizards);  // get all items that match into a table called 'wizards'

foreach(w in wizards where (e.hp > 30)) // query this new table
{
   print(w.name, "has enough strength");
}




In this extension, you cannot use "foreach(item and key in table where ... )". I should be able to add this in if you want to query keys as well

I'm quite pleased how it works; I hope this is useful to you.


Attachments:
gmsrc_1_25q_foreach.rar [60.23 KiB]
Downloaded 253 times
Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 21, 2009 4:22 am 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
very cool!


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 21, 2009 4:25 am 
Offline

Joined: Sat Apr 25, 2009 1:40 am
Posts: 66
Hey that's awesome! Yeah it would be cool if you could use the key, because i know i've needed the key alot of times in a foreach.

I see you're writing a third tutorial. Maybe one day you could write a tutorial that shows how to change the language like this.


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 21, 2009 6:12 am 
Offline

Joined: Mon Dec 15, 2003 1:38 pm
Posts: 708
Nice one Downgraded :)


Top
 Profile  
Reply with quote  
PostPosted: Mon Jun 22, 2009 12:29 am 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
Yea I think for completeness sake it should support the key as well if possible.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jun 22, 2009 7:41 am 
Offline

Joined: Thu Jan 01, 2004 4:31 pm
Posts: 307
I'll look into adding it - it shouldn't be too hard, but I'll need to restructure the Yacc grammar a bit because a gmCodeTreeNode can only have 4 children at present. This will require it to have have 5.

As for an article on modding GM - what do you mean, like a description of the internals?


Top
 Profile  
Reply with quote  
PostPosted: Wed Jun 24, 2009 8:46 pm 
Offline

Joined: Thu Jan 01, 2004 4:31 pm
Posts: 307
Added support for:

Code:
foreach(item and key in table where(<expr>)) { }


Pretty nice as you can now also use the key in the where syntax; so:

Code:
foreach(item and key in t where(key >= 10 and key <= 20) )
{
   //
}


Works on both the into and normal syntax. I had to change the grammar for the normal foreach slightly, but it works in the same way.

The 'into' syntax creates items in the new table indexed sequentially and loses the original key; do we need so that it takes the original key?


Attachments:
gmsrc_1_25q_foreach2.rar [43.14 KiB]
Downloaded 236 times
Top
 Profile  
Reply with quote  
PostPosted: Thu Jun 25, 2009 2:13 pm 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
Personally, I would think retaining the key would be desired. I don't feel like an indexed table is of any more value than retaining the key, and by retaining the key it is more properly a subset of the table as per the filter in the expression.

Nice work btw, very cool.

Also, IMO it would be nice for the 'into' functionality to be flexible in that it doesn't necessarily have to allocate a new table.

For example

Code:
// sometable local variable is null, so allocate a new table
foreach( item and key in t where(key >= 10) into sometable ) {}

// sometable is already a table, so add to it
foreach( item and key in t2 where(key >= 10) into sometable )


This would allow the user to merge the results into a table of their choosing much easier, and result in a table with the merged key/value pairs from potentially any table source. It should be understood that duplicate keys will overwrite keys of earlier queries.
Code:
mytbl = {}
foreach( item and key in t where(key >= 10) into mytbl ) {}
foreach( item and key in t2 where(key >= 10) into mytbl ) {}


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 26, 2009 6:58 am 
Offline

Joined: Thu Jan 01, 2004 4:31 pm
Posts: 307
Nice idea. I've made the change to fill an existing table.

In regards to keeping the key; that is proving somewhat difficult. The issue is that we're moving into the realms of runtime functionality, not compiler - depending on the type of value in the table's key we'd want to call either SetDot or SetInd on the target table. I'm currently calling setind and incrementing an internal variable to track the position. To decide whether to call SetDot or SetInd, we'd need to know the type of the key variable and then call the relevant method. I have two possible ways thought out, both of which involve adding new bytecode instructions. There's one that's more generic and involves BC_GETTYPEID which basically takes the typeid from the variable top of the stack and pushes it to the stack. Based on this type (eg: if it's an int) we'd call SetInd or SetDot. The other method would involve adding BC_SETDOTORIND and bind it in the runtime to determine the type and then call either SetDot or SetInd on the object- this is my preferred approach as it moves the decision away from bytecode and back into the VM where it'd be faster and more extendable.


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 26, 2009 1:43 pm 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
Why not just call table->Set(machine,key,value); ? They are gmVariables internally, and setdot or setind isnt necessary to set data in the tables, as they are both handled with the Set function. I guess you are trying to keep the functionality type agnostic so you could run this stuff on custom types?


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 26, 2009 2:57 pm 
Offline

Joined: Thu Jan 01, 2004 4:31 pm
Posts: 307
The code for all this is located in the CodeGen class, the class that generates the VM Bytecode for the script. At this point we only know that we have to emit a foreach and that variables are involved. We don't know what type they are or anything about the stack, etc. Basically it's at a point way before the script runs.


Top
 Profile  
Reply with quote  
PostPosted: Fri Jun 26, 2009 3:11 pm 
Offline

Joined: Fri Jan 14, 2005 2:28 am
Posts: 439
ah


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 12 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 1 guest


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group