Sie sind nicht angemeldet.

rdhoore108

Schüler

  • »rdhoore108« ist der Autor dieses Themas

Beiträge: 89

Wohnort: Belgium

Beruf: Systems and Network Administrator

  • Nachricht senden

1

Sonntag, 12. September 2010, 09:49

More on dereferencing: how to copy content into a new variable?

In short, my question is: how to make a new variable a and give it the same content as an existing object?

Let's say I have the following:

Quellcode

1
2
3
4
5
    <enum name="floors">
	<item name="floor_1" data="mydata" />
	<item name="floor_2" data="mydata" />
	<item name="floor_3" data="mydata" />
    </enum>
So I can do:

Quellcode

1
 trace(enum[floors].item[0].name, " has as data: ", enum[floors].item[0].data);


Now I wish to make a new variable a which should get the same contents as my first item node above, so that "a" is the equivalent of "enum[floors].item[0]", and I could do things like:

Quellcode

1
trace(a.name, " has as data: ", a.data);

Is there any way to accomplish this? I tried:

Quellcode

1
copy(a, enum[floors].item[0]);

This will make a.name available, but not a.data.

Then I tried adding:

Quellcode

1
copy(a.content, enum[floors].item[0].content);

but it doesn't help, still no a.data... And if I only do this copy by itself, without the copy above, then even a.name is null...

Can anyone shed some light on this? Thanks!

The reason I'm asking this, is to make it part of a foreach action where one can straight away give the commands one wants to execute on the object's nodes, instead of having to refer to yet another action. But then of course one needs to pass a name for the temporary object one wants to use in the command that needs to be iterated. And that's where the trouble above started...
- Ronny D'Hoore

2

Sonntag, 12. September 2010, 12:52

Hi Ronny,

Zitat

Is there any way to accomplish this? I tried:

Quellcode

1
copy(a, enum[floors].item[0]);
This will make a.name available, but not a.data.
I have tried this:

Quellcode

1
2
3
trace(enum[floors].item[0].name, " has as data: ", enum[floors].item[0].data);
copy(a, enum[floors].item[0]);
trace(a.name, " has as data: ", a.data );

and for me it works...

SAlut.

rdhoore108

Schüler

  • »rdhoore108« ist der Autor dieses Themas

Beiträge: 89

Wohnort: Belgium

Beruf: Systems and Network Administrator

  • Nachricht senden

3

Sonntag, 12. September 2010, 14:08

Hmmm.... You are right! *confused*

After some more investigation, I figured that in my attempts to simplify my problem so that I could post it here without scaring everyone away, I also eliminated the bug that I obviously made in my real application.

Anyway, now that my problem is solved, I proudly present here a sibling of Steve's foreach() function. In this version, it is not required to pass the name of an action, but one can write the actual command string instead. Note that Steve's version will execute faster, as it does not need to copy around data internally. But mine also has a right to exist. ;-)

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!-- 
  foreach ( <object>, <loop variable>, <object variable> <command(s)> );

  "foreach" loop function executes a command string for each child of the given object.

  Example: foreach(enum[floors].item, i, a, trace("#", i, ': ', a.name, " has as data: ", a.data);";);
  This will execute the given trace command as many times as there are "item" nodes in the 
  <enum name="floors"> object. As we passed "a" as object variable, we can use the same "a"
  in our command string to represents the child object itself, instead of having to use
  enum[floors].item[get(i)].

  Sample data format for the above example:
    <enum name="floors">
	<item name="floor_1" data="mydata" />
	<item name="floor_2" data="mydata" />
	<item name="floor_3" data="mydata" />
    </enum>

-->

	<action name="foreach">
		_foreach_for(
		set(%2,0), 
		%2 LT %1.count, 
		inc(%2), 
		%4,
                copy(%3, %1[get(i)]);
		);
	</action>
	<action name="_foreach_for">
		push(action[_foreach_action].content);
		set(action[_foreach_action].content, "%1;");
		_foreach_action();
		set(action[_foreach_action].content, "%5; if(%2, %4; %3; _foreach_action(););");
		_foreach_action();
		pop(action[_foreach_action].content);
	</action>
	<action name="_foreach_action">
		trace("Error in foreach loop: push/pop stack corrupted"); <!-- this line should never execute -->
	</action>


Now, having the same data as above, one can loop through them as follows:

Quellcode

1
2
3
<action name="test">
	foreach(enum[floors].item, i, a, trace("#", i, " is ", a.name, " and has as data: ", a.data ); );
</action>


The output is:
INFO: #0 is floor_1 and has as data: mydata
INFO: #1 is floor_2 and has as data: mydata
INFO: #2 is floor_3 and has as data: mydata


PS. Of course one can specify more than one command, as usual, by separating them with semicolons ";".
- Ronny D'Hoore

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »rdhoore108« (12. September 2010, 14:30)


rdhoore108

Schüler

  • »rdhoore108« ist der Autor dieses Themas

Beiträge: 89

Wohnort: Belgium

Beruf: Systems and Network Administrator

  • Nachricht senden

4

Sonntag, 12. September 2010, 22:42

There are two issues with this actually:

  1. if you change the value of any items that are part of the temporary object (a in this example), then of course these changes will not reflect back to the original object. It would come handy if one could assign variables by reference instead of by value, so that a and enum[floors].item[get(i)] would both refer to the same structure in memory.

  2. get(i) should have been get(%2).


Below is the corrected code that fixes these issues, and was also optimized in a few ways.

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<!-- 
  foreach ( <object>, <loop variable>, <object variable> <command(s)> );

  "foreach" loop function executes a command string for each child of the given object.

  Example: foreach(enum[floors].item, i, a, trace("#", i, ': ', a.name, " has as data: ", a.data);";);
  This will execute the given trace command as many times as there are "item" nodes in the 
  <enum name="floors"> object. As we passed "a" as object variable, we can use the same "a"
  in our command string to represents the child object itself, instead of having to use
  enum[floors].item[get(i)].

  Sample data format for the above example:
    <enum name="floors">
	<item name="floor_1" data="mydata" />
	<item name="floor_2" data="mydata" />
	<item name="floor_3" data="mydata" />
    </enum>

-->
	<action name="foreach">
		set(%2,0);
		push(action[_foreach_action].content);
		set(action[_foreach_action].content, "
			copy(%3, %1[get(%2)]); 
			if(%2 LT %1.count, 
				%4; 
				copy(%1[get(%2)], %3); 
				inc(%2); 
				_foreach_action();
			);
		");
		_foreach_action();
		pop(action[_foreach_action].content);
	</action>
	<action name="_foreach_action">
		trace("Error in for loop: push/pop stack corrupted"); <!-- this line should never execute -->
	</action>
- Ronny D'Hoore

Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von »rdhoore108« (18. September 2010, 10:07)