adam-mcdaniel / oakc

A portable programming language with a compact intermediate representation
Apache License 2.0
725 stars 21 forks source link

Implemented the `extern` keyword #83

Closed adam-mcdaniel closed 4 years ago

adam-mcdaniel commented 4 years ago

This implements the extern keyword and adds a fix where the extern directive could not grab files in subdirectories. It also removes the foreign_fn!() syntax.

Here's the example in the ffi subdirectory.

// foreign.ok

#[if(TARGET == 'c') {
    #[extern("foreign.c")]
} else {
    #[if(TARGET == 'g') {
        #[extern("foreign.go")]
    } else {
        #[error("this program only supports go and c backends")]
    }]
}]

extern fn test();
extern fn __oak_add as add(a: num, b: num) -> num;

These foreign functions can then be used like so:

// main.ok
#[std]
#[include("lib/foreign.ok")]

fn main() {
    test();
    putnumln(add(5, 6));
}

This PR also applies the fix for #68 to the extern directive, and also to each of the sub-directives in every conditional compilation directive.

adam-mcdaniel commented 4 years ago

What do you think, @kevinramharak? Is there anything I should add or do you have any concerns about this?

adam-mcdaniel commented 4 years ago

I'm also considering removing typechecks for typecasts of a foreign function expression. Right now, foreign functions can only be cast to types of size 1. This means that extern fns can only return types of size 1 (because they expand to a function definition containing a typecasted foreign function call to the return type), but I can imagine people might want to use foreign functions to return compound types, like a DateTime object.

kevinramharak commented 4 years ago

I think this looks way cleaner. Just seein the std.ok function defined like this makes more sense. Does this completely remove ffi!() or just expand to it? Only thing I would personally want is a flag that requests the compiler to generate the code to pass the arguments and return value without the function having to operate on the oak tape. But thats just because it fixes my problem, I think this feature is complete without it.

adam-mcdaniel commented 4 years ago

Yes, this completely removes the ffi!() syntax in favor of calling the extern fn bound function as a regular function call. The intermediate representation can still use foreign functions, but there is no way for users to call them. The syntax just won't allow it.

kevinramharak commented 3 years ago

@adam-mcdaniel The only thing I dislike about this merge is that every foreign function call is now wrapped in oak instructions that setup and tear down a new stackframe. That does not really feel intuitive to me. I'd rather have an helper function provide the bridge from VM values to native values (or have the backend deal with that). As of now every native function has to know how the VM works to be able to interact with user provided parameters and to return a value.