ooc-lang / rock

:ocean: self-hosted ooc compiler that generates c99
http://ooc-lang.org/
MIT License
401 stars 40 forks source link

Rock can now extend generic classes #969

Closed alexnask closed 8 years ago

alexnask commented 8 years ago

There are a couple of known issues I will be fixing (just leaving the PR up for updates):

Other than that, it seems to be solid enough.

alexnask commented 8 years ago

Will eventually close #830

alexnask commented 8 years ago

I will probably end up doing a pretty huge rewrite of typearg-related code.
Will split up TypeArg access/definition into their own types, with a Generic/Template enum, all index based and replace accesses with TypeArgAccesses.

Anyway, this may take some time but I'm confident it will be nice to have in the long run.

thomasfanell commented 8 years ago

Goodie! I'm looking forward to this one!

alexnask commented 8 years ago

Here is the structure I am thinking about (keep in mind it is way too early to tell if this is refined enough):

TypeArgType: enum {
    Generic, Template, Unknwon
}

TypeArg: class {
    index: Int
    type: TypeArgType

    init: func (=index, =type)
}

TypeArgDecl: class {
    originalName: String // only used in codegen
    typeArg: TypeArg

    init: func (=originalName, =typeArg) // Unknown type triggers an internal compiler error, we should never get one
}

TypeArgInstance: class {
    typeArg: TypeArg
    type: Type

    ref: TypeArgDecl // We get this by resolving the Node, like always

    init: func (index: Int, =type) {
        // We also get the typeArg type by resolving
        typeArg = TypeArg new(index, TypeArgType Unknown)
    }
}

TypeArgMap: class extends HashMap<String, TypeArg> {
    // helper methods etc.
}

TypeArgAccess: class {
    name: String
    ref: TypeArgDecl // Get this by resolving

    init: func (=name)
}

TypeDecls and FunctionDecls have their List of TypeArgDecls Types have their List of TypeArgInstances Addons have a TypeArgMap TypeDecls have a TypeArgMap for their super type or from type

To resolve TypeArgAccesses, we go up the trail calling resolveTypeArg (like we do with calls, accesses and types) until we get a candidate that fits.

Types and VariableAccesses can somehow (TM) be replaced by TypeArgAccesses.

Will probably start writing code and experimenting later today.

EDIT: All development will be done one my new_typeargs branch.

alexnask commented 8 years ago

This seems to work well!
Will be adding a couple of tests and opening up a PR for magic-lang too soon.

thomasfanell commented 8 years ago

Nice! :+1:

alexnask commented 8 years ago

Extending template classes also works by the way (it's pretty nice since you can simulate specialization):

TCell: class template <T> {
    value: T

    init: func (=value)
}

extend TCell<Int> {
    magic: func {
        value toString() println()
    }
}

extend TCell<String> {
    magic: func {
        value println()
    }
}

cell1 := TCell<Int> new(42)
cell2 := TCell<String> new("Hello World!")

cell1 magic()
cell2 magic()
alexnask commented 8 years ago

Also, mixed extensions!


Foo: class <T> template <U> {
    val1: T
    val2: U

    init: func (=val1, =val2)
}

extend Foo<U, String> {
    print: func {
        "#{val1 as Pointer}: #{val2}" println()
    }
}

// Works!
foo := Foo<Int, String> new(42, "Hello World!")
foo print()

// Fails, as it should
bar := Foo<Int, Int> new(0, 42)
bar print()
horasal commented 8 years ago

amazing! :+1:

alexnask commented 8 years ago

This is a really huge change, there are probably some bugs but they should be mostly the kind of things that you come across if you intentionally try to do really weird things.

A rewrite of the whole TypeArg system is still probably needed at this point though.