waneck / haxe-genc

20 stars 2 forks source link

Enum representation #1

Closed Simn closed 11 years ago

Simn commented 11 years ago

Figure out the best way to represent enums. If it makes sense, we can distinguish "flat" enums (those that have no constructors expecting arguments).

waneck commented 11 years ago

I think the best way is to make a simple enum be just an int, and detect when it's boxed so we can box it in a strongly typed manner. Enums with parameters are a little harder to make it right. We could use unions, but it may be hard to get the arguments out correctly when having grouped cases.

Simn commented 11 years ago

"grouped cases"?

waneck commented 11 years ago

Like:

enum Test
{
A(d:Float, s:String, b:Int);
B(i:Int, s:String);
C;
}

switch(t)
{
case A(_,s,_), B(_,s): //grouped case
default:
}
Simn commented 11 years ago

Oh don't worry about that, TMatch doesn't exist anymore so we either get nested TSwitch nodes that have some TVars using TEnumParameter, or (once we activate it) TPatMatch which allows us to go goto-crazy.

Simn commented 11 years ago

I have committed something and would appreciate a review. Given this enum:

enum MyEnum {
    A;
    B(s:String);
}

It generates this header file MyEnum.h:

// constructor structure;
typedef void* MyEnum_A;
typedef struct {
    char* s;
} MyEnum_B;
// enum structure;
typedef struct {
    int index;
    union {
        MyEnum_A A;
        MyEnum_B B;
    } args;
} MyEnum;
// constructor functions;
MyEnum* new_MyEnum_A() {
    MyEnum* this = (MyEnum*) GC_MALLOC(sizeof(MyEnum));
    this->index = 0;
    return this;
}
MyEnum* new_MyEnum_B(char* s) {
    MyEnum* this = (MyEnum*) GC_MALLOC(sizeof(MyEnum));
    this->index = 1;
    this->args.B.s = s;
    return this;
}

A pattern matching then looks like this:

x = new_MyEnum_B("foo");
switch((x)->index){
    case 0:
        haxe_Log_trace("A",0);
        break;
    case 1:
        s = x->args.B.s;
        haxe_Log_trace(s,0);
        break;
}
waneck commented 11 years ago

It's looking great, Simon! We just need to make sure that our ultimate GC host will accept union declarations (I wouldn't like to keep with boehm). Otherwise we may need to only use unions for basic types.

waneck commented 11 years ago

Also when I was writing the Java/C# targets, I decided to go with the usual Array when I realized that many Type enum methods really expect the parameters to be as Array. E.g. we'd need maybe to create a fromArray() method for each of the enum constructors

Simn commented 11 years ago

fromArray sounds good. We don't want to make the basic structures slower/less type safe just to support reflection if we can avoid it. That's like a general rule of this project. ;)

waneck commented 11 years ago

Okay, you're right! :) Though the amount of code may be a little big (fromArray and toArray for each construct... Imagine for something like Expr) We may figure out another way to deal with that though... Maybe something intelligent using offsetof() for each enum type / argument number would work nicely!

Simn commented 11 years ago

We could, in general, split up all types into a file for the static/typed definitions and one for the dynamic/reflection definitions. This way we can have a concise MyEnum.h, and if need be also a MyEnum__dyn.h file with all the reflection information in some lut or whatever one uses in C for that.

This would make it easy to allow omitting these dynamic portions via a combination of a compiler flag (to disable them) and a type metadata (to enable them individually).

waneck commented 11 years ago

That's a great idea. Though by omitting the dynamic portions, we won't be able to neither box the enum, nor get a string representation of it. I think it's a fair trade.

ousado commented 11 years ago

For the statically typed part, it's very simple to feed whatever type to a corresponding function, to print or do whatever else with them.

Simn commented 11 years ago

I suppose this can be considered done. We can still tweak the representation and optimize it, but it's basically working.