Reputation: 21
I want to achieve the following functionality:
extend RED GREEN BLUE packet {...}
this line will cause the struct members in the curly brackets, to be added to all the specified subtypes of a certain enumerated type. the result will look like this:
extend RED packet {...}
extend BLUE packet {...}
extend GREEN packet {...}
extend BIG MEDIUM RED BLUE GREEN packet {...}
this line will extend all possible combinations of the items from each enumerated type with the struct members that appear in the curly brackets. the result will look like this:
extend MEDIUM RED packet {...}
extend MEDIUM BLUE packet {...}
extend MEDIUM GREEN packet {...}
extend BIG RED packet {...}
extend BIG BLUE packet {...}
extend BIG GREEN packet {...}
Thanks,
Upvotes: 0
Views: 594
Reputation: 331
This macro solves this problem, yet there is a small limitation. Since this macro is ‘define as computed’ , the struct you are going to apply it on should be defined in a different file than the file that uses the macro. A simple use case is shown here: (suppose this macro is in a file called dac.e):
define <multi_when'statement> "ext_s \[<detr'name>,...\] <base'type> \{<sm'exp>,...\}" as computed {
var our_struct:rf_struct=rf_manager.get_type_by_name(<base'type>).as_a(rf_struct);
var fields:list of rf_field = our_struct.as_a(rf_struct).get_declared_fields();
var rf_type_list:list of rf_type;
var list_of_0_index:list of uint;
var field_names:list of string;
var list_of_enums:list of rf_enum;
var temp_index:uint=0;
var used_types_list:list of rf_type;
var enumerations:list of string;
var indices:list of uint;
var num_of_each_enum:list of uint;
var size_of_final_list_of_enumerations_to_be_used:uint=1;
var enum_items_list:list of rf_enum_item;
var final_list_of_enumerations_to_be_used: list of string;
var multiplication_list_algrtm1:list of uint;
var multiplication_list_algrtm2:list of uint;
var multiplication_uint_algrtm:uint=1;
if (<detr'names>.is_empty()){
error("you did not supply any when subtypes");
};
for each (field) in fields{
rf_type_list.add(field.get_type());
field_names.add(field.get_name());
};
for each (typ) in rf_type_list{
if (rf_type_list[index] is not a rf_enum){
rf_type_list.delete(index);
field_names.delete(index);
};
};
if (rf_type_list.is_empty()){
error("the type ",<base'type>," does not have any enumerated type fields.");
};
for each (typ) using index (typ_index) in rf_type_list {
num_of_each_enum.add(0);
if(indices.is_empty()){
indices.add(0);
}else {
indices.add(indices[typ_index-1])
};
enum_items_list = typ.as_a(rf_enum).get_items();
for each (enum_item) in <detr'names> {
if (enum_items_list.has(it.get_name()==enum_item)){
out(enum_item, " is found in ",typ.get_name());
enumerations.add(append(enum_item,"'",field_names[typ_index]));
indices[typ_index]+=1;
num_of_each_enum[typ_index]+=1;
};
};
};
for each in num_of_each_enum do { // avoid enums that are not used - to
if (it==0){
list_of_0_index.add(index);
};
};
if (!list_of_0_index.is_empty()){
list_of_0_index=list_of_0_index.reverse();
for each in list_of_0_index {
num_of_each_enum.delete(it);
indices.delete(it);
field_names.delete(it);
}
};
enumerations=enumerations.unique(it);
if (enumerations.is_empty()){
error("no legal enumerated values were used in the ext_s macro, please check that the arguments in square brackets are in the form of [<enum_item1>,<enum_item2>,...]");
};
//remove the last index (not relevant - and add 0 in the indices[0]
indices.add0(0);
indices.delete(indices.size()-1);
for each in num_of_each_enum do {
size_of_final_list_of_enumerations_to_be_used*=it;
};
for each in num_of_each_enum do {
multiplication_uint_algrtm*=it;
multiplication_list_algrtm1.add(size_of_final_list_of_enumerations_to_be_used/multiplication_uint_algrtm);
multiplication_list_algrtm2.add(size_of_final_list_of_enumerations_to_be_used/multiplication_list_algrtm1[index]);
};
//build the final list of string to be used in the extend statement:
for i from 1 to size_of_final_list_of_enumerations_to_be_used{
final_list_of_enumerations_to_be_used.add("");
};
for k from 0 to indices.size()-1 do {
temp_index=0;
for j from 0 to multiplication_list_algrtm2[k]-1 do {
for i from 0 to multiplication_list_algrtm1[k]-1 do {
final_list_of_enumerations_to_be_used[temp_index]=append(final_list_of_enumerations_to_be_used[temp_index]," ",enumerations[indices[k]+j%num_of_each_enum[k]]);
temp_index+=1;
};
};
};
for each in final_list_of_enumerations_to_be_used do {
result = appendf("%s extend %s %s {",result,it, <base'type> );
for each in <sm'exps> do {
result= appendf("%s %s;",result,it);
};
result = append(result , "};");
};
print result;
};
Note that this macro solves an interesting problem: Suppose you have a list of a bunch of items of certain types (for example : {a1,a2,b1,b2,c1,c2,c3…}), And you do not preliminarily know how many types are there in this list (in this example there are 3 types-a,b,c - but there could be more or less). So question is, how do you create a list of all possible combinations of all items from all type (for example: 0. a1-b1-c1 1.a1-b1-c2…..11.a2-b2-c3), without knowing how many types are there in the list? You can follow the code and figure out the algorithm to do that (using list of indices, how many items are there from each type and so….). The file that should be loaded prior to macro (dac.e) is :
Struct.e:
<'
type t1:[A1,A2,A3,A4,A5];
type t2:[B1,B2,B3];
type t3:[C1,C2,C3];
struct s{
a:uint(bits:4);
t_1:t1;
t_2:t2;
t_3:t3;
};
'>
And the test file is :
<'
Import dac.e;
import struct.e;
//use the macro
ext_s [A1,A2,B1,B2] s {x:int,keep x==6,y:int,keep y==10};
extend sys{
s1:A1 B1 s;
s2:A2 B1 s;
s3:A1 s;
run() is also{
print s1;
print s2;
print s3;
};
};
'>
Please comment if you have any question.
Upvotes: 2