Giter Club home page Giter Club logo

fcore's Introduction

F2J: A Compiler for FCore

License BSD 3 Build Status Stories in Ready

Building from Source

The following instructions should work on any platform, from OS X to Ubuntu. It builds the compiler from source, thus may take some time.

  1. Make sure you have installed the dependencies:

    • Java SDK (8 or newer)
    • Apache Ant (version 1.8 or above)
    • stack
  2. Clone the source with git:

    git clone https://github.com/hkuplg/fcore.git
    cd fcore
  1. Quick install with stack:

    make

    You may be prompted to run stack setup, which will automatically download the GHC compiler if needed.

  2. After the installation, invoking f2j in your console will show its usage. If not, you probably want to add ~/.local/bin to your $PATH.

Building on Windows

The above instructions should automatically work on Windows.

Documentation

See doc directory for more details.

Compilation Methods

F2j has a few built-in compilation methods (by default, it doesn't use any optimization), namely apply, stack and unbox.

  • Apply: multi-argument optimization
  • Stack: tail call elimination
  • Unbox: auto-unboxing optimization

To use one or more of them, simply append the compilation methods you want to use as the command line arguments.

For example, say you want to use the apply method, running the following command:

f2j -m apply some_file

If you want to combine different methods (say, apply and stack), just type:

f2j -m apply -m stack some_file

Finally, passing -r flag will make the compiler compile and run the generated Java code.

REPL

There is also a REPL at your service. Simply invoking f2ji will take you to the REPL.

Examples

In the example directory, you will see a lot of example programs written in FCore. You may want to take a look at them to get familiar with the syntax. These examples demonstrate different features of our compiler, such as record syntax, modules, type synonyms, etc.

Particularly, in examples/fractals, there is an interesting program that draws a fractal.

Troubleshooter

If you run into any problem, try to do

make clean

and then

make

If the problem persists, create an issue!

License

BSD 3

See LICENSE at the top-level directory for details.

fcore's People

Contributors

bixuanzju avatar emmabypeng avatar georgeseif avatar guanyingc avatar hy-zhang avatar jerry168 avatar lihuanglx avatar linusyang avatar tomtau avatar vincent717 avatar waffle-iron avatar wxzh avatar xnning avatar yanlinwang avatar zhiyuanshi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

fcore's Issues

Annotate your modules with Haddock headers

This is a task for everyone, so do it and reassign this task to the person below you alphabetically.

https://wiki.haskell.org/Programming_guidelines#File_Format

{- |
Module      :  <File name or $Header$ to be replaced automatically>
Description :  <optional short text displayed on contents page>
Copyright   :  (c) 2014-2015 HKU
License     :  BSD3

Maintainer  :  <email>
Stability   :  unstable | experimental | provisional | stable | frozen
Portability :  portable | non-portable (<reason>)

<module description starting at first column>
-}

A bug in checking recursive definitions involving type synonyms

-- lib/Mixin.sf

type Mixin S = (Unit -> S) -> (Unit -> S) -> S;
let zero S (super : Unit -> S) (this : Unit -> S) : S = super;
let rec mixin S (f : Mixin S) : S
  = let m = mixin S in f (\ (d : Unit). m f) (\ (d : Unit). m f);
let extends S (f : Mixin S) (g : Mixin S) : Mixin S
  = \ (super : Unit -> S). \ (this  : Unit -> S). f (\ (d : Unit). g super this) this;

let fact (super : Unit -> Int -> Int) (this : Unit -> Int -> Int) : Int -> Int
  = \ (n : Int). if n == 0 then 1 else n * this () (n - 1)
and
  foolish (super : Unit -> Int -> Int) (this : Unit -> Int -> Int) : Int -> Int
  = \ (n : Int). { java.lang.System.out.println("Hola"); super () n }
in
mixin (Int -> Int) (extends (Int -> Int) foolish fact) 5
systemfcompiler % f2j lib/Mixin.sf -r
Mixin using [Naive]
  Compiling to Java source code ( lib/Mixin.java )
error: type mismatch in f:
  expected: (Mixin S)
    actual: ((Unit -> S) -> ((Unit -> S) -> S))

Document f2j language features

As the source language grows it becomes hard to know which features are available. We should have a document in the wiki documenting the features and giving a few usage examples.

Replace unsafeCoerce by undebruijn

brunosoliveira created an issue 2014-10-14
Currently we are using unsafeCoerce to get cheap&quick coercions between PHOAS expressions. However I think this is a mistake. We should be using an undebruijn function. The benefit would be better debugging/error-messages and potentially a solution to the weird substitution issue (by enforcing a dedebruijn after every traversal).

Make peval smart enough to detect redundant ids

Simplify adds redundant ids to every argument in the function application. As I can see, according to the type, it translates to some recursively structured identity function. The translation scheme can be described by the following recursive function [ ]:

[a] = λ(x : a). x
[a -> τ] = λ(x : a -> τ). λ(y : a). [τ] (x ((λ(d : a). d) y))

Here is an example:

If we have

λ(f : Int -> Int). λ(x : Int). f x

After simplification

λ(f : Int -> Int). λ(x : Int). f ((λ(y : Int). y) x) 

If we have

λ(f : (Int -> Int) -> Int). λ(g : Int -> Int). f g

After simplification

λ(f : (Int -> Int) -> Int). λ(g : Int -> Int). 
     f ((λ(x : Int -> Int). λ(y : Int). (λ(z : Int). z) (x ((λ(d : Int). d) y))) g)

After peval

\ (f : (Int -> Int) -> Int).
  \ (g : Int -> Int).
    f
      let x = g
      in
      \ (y : Int).
        let z = x let d = y in d
        in
        z

This task is to make the partial evaluator detect such structure, and replaces it by its argument.

f2ji accidently removes source files

As a user of f2ji, I found that if you :run some source code that doesn't typecheck, f2ji will remove it.

f2ji> :run examples/ObjectAlgebra2.sf 
error: eval is not a member of the type IEval
invalid expression sf2Java
f2ji> :run examples/ObjectAlgebra2.sf 
examples/ObjectAlgebra2.sf does not exist
systemfcompiler % hg status 
! examples/ObjectAlgebra2.sf

New unboxing approach

The goal is to try the new unboxing approach. Simply put, incorporate all types (primitive types and references type into one closure class. See the code below:

package boxing;

abstract class Closure {
    int ix; // int input, or other primitive types
    Object ox; // ref input for closure
    int iout; // int output, or other primitive types
    Object oout; // ref output

    abstract void apply();
}

// Int -> Int
class Inc extends Closure {
    public void apply() { // Int -> Int
        this.iout = ix+1;
    }
}

// apply : (A -> B) -> A -> B
// apply = \f . \x . f x
class Apply extends Closure {
    Closure ap = this;

    public void apply() {
        oout = new Closure() {
                public void apply() {
                    Closure f = (Closure) ap.ox;
                    f.ix = this.ix; // set arguments, potentially could have a tag to decide which assignement to make.
                    f.ox = this.ox;
                    f.apply();
                    this.iout = f.iout; // set the outputs
                    this.oout = f.oout;
                }
            };
    }
}

public class Main {
    public static void main(String args[]) {
        Inc inc = new Inc();
        Apply apply = new Apply();
        long start, end;

        start = System.nanoTime();
        apply.ox = inc; // wrap(inc)
        apply.apply();
        Closure c = (Closure) apply.oout;
        c.ix = 10;
        c.apply();
        end = System.nanoTime();

        System.out.println("Time:" + (end - start));

        System.out.println(c.iout);
    }
}

Here, the class Closure has multiple input and output fields, one for each type. The steps are the followings:

  1. Write an example (factorial?) using this approach by hand, and test it to see if it's ok.
  2. Formalize the idea.
  3. Then implement it.

One example to cripple the frontend

As @xieningning points out, the following example should be a valid program:

let rec
  map A B (f:A->B) (n:Int): Bool =
    if(n<0)
    then True
    else map A B f (n-1)
and
  f(x:Int):Int = x+1
in
  map Int Int f 6

However, I am confirmed that in develop branch, the above program crashed somewhere in the frontend, resulting the notorious segmentation fault.

Refactor using Variation Point

Currently in back-ends, there are still a lot of repeated codes around (most of which are quite similar with their counterparts in Base translation).

This task is to use some technique called Variation Point to reduce those repetitions as much as possible. Simply put, we spot those differences, abstract them away and put into new translation records.

Some methods with no variable arguments may offend JVM?

#!haskell

let f A = 0
in 0

This is the minimal program where JVM complains with this pattern.

The SystemF pretty printer gives

#!haskell

let f  = /\A. 0 in 0

But the closureF gives

#!haskell

let f = lam (/\A. 0) in 0

Jeremy has started working on it.

Symbolic Evaluator for Core

Port the code from the partition-checking project.

Complete the following tasks:

  1. Write the standard big-step interpreter for a subset of our core language:
  • variables, application, lambda, if-expressions, primitives, let, type application, type abstraction.
  1. Write the symbolic interpreter & execution trees.

  2. Write the pretty-printer. Improve the simple pretty printer.

  3. Hook up the Symbolic Interpreter to f2ji, allowing users to use it from the command line.

:se exp

  1. Create conditional compilation infrastructure on f2ji to avoid depending on Z3. Talk to Emma.

  2. Port the Z3-related code.

A bug in checking recursive definitions involving type synonyms

-- lib/Mixin.sf

type Mixin S = (Unit -> S) -> (Unit -> S) -> S;
let zero S (super : Unit -> S) (this : Unit -> S) : S = super;
let rec mixin S (f : Mixin S) : S
  = let m = mixin S in f (\ (d : Unit). m f) (\ (d : Unit). m f);
let extends S (f : Mixin S) (g : Mixin S) : Mixin S
  = \ (super : Unit -> S). \ (this  : Unit -> S). f (\ (d : Unit). g super this) this;

let fact (super : Unit -> Int -> Int) (this : Unit -> Int -> Int) : Int -> Int
  = \ (n : Int). if n == 0 then 1 else n * this () (n - 1)
and
  foolish (super : Unit -> Int -> Int) (this : Unit -> Int -> Int) : Int -> Int
  = \ (n : Int). { java.lang.System.out.println("Hola"); super () n }
in
mixin (Int -> Int) (extends (Int -> Int) foolish fact) 5
systemfcompiler % f2j lib/Mixin.sf -r
Mixin using [Naive]
  Compiling to Java source code ( lib/Mixin.java )
error: type mismatch in f:
  expected: (Mixin S)
    actual: ((Unit -> S) -> ((Unit -> S) -> S))

Weird substitution problem v2

There is an example that should typecheck. See the code below:

#!haskell

let getTwo A B (x : A) : A = x;
let getThree A B C (y : B) : B = getTwo B C y;
getThree Int String Int "abc"

Whereas f2j gives the "type mismatch" message:

#!c++

expected: A
  actual: B

Everything is OK if the user tries to avoid such overlapping in source file. But that should be a bug in TypeCheck, and probably similar to the previous substitution problem.

Parse error with "." in parser

As we discussed in the seminar talk, the following code gives parse error.

#!haskell

type ToInt A = Int;
type Hide = { test : forall A. ToInt A -> Int };
let f (x : Hide) = x.test (ToInt String) 5;
0

By Weixin's comment in issue #184, it is

#!haskell

x.test (ToInt String) 5

that causes the error, which uses

#!haskell
javaexpr : aexpr "." LOWERID "(" comma_exprs0 ")"

to parse the code. The parentheses imply an Expr inside, not a Type.

Probably we need curly braces to distinguish Type from Expr.

George please take a look at it. This one should have higher priority than issue #184. Currently we are all engaged in different issues. We will help you later.

Weird substitution problem v2

There is an example that should typecheck. See the code below:

let getTwo [A,B] (x: A): A = x;
let getThree [A,B,C] (y: B): B = getTwo [B,C] y;
getThree [Int,String,Int] "abc"

Whereas f2j gives the "type mismatch" message:

expected: A
  actual: B

Everything is OK if the user tries to avoid such overlapping in source file. But that should be a bug in TypeCheck, and probably similar to the previous substitution problem.

One example to cripple the frontend

As @xieningning points out, the following example should be a valid program:

let rec
  map A B (f:A->B) (n:Int): Bool =
    if(n<0)
    then True
    else map A B f (n-1)
and
  f(x:Int):Int = x+1
in
  map Int Int f 6

However, I am confirmed that in develop branch, the above program crashed somewhere in the frontend, resulting the notorious segmentation fault.

Write tree generator benchmark

something like a custom generator in Haskell’s QuickCheck. E.g. generate a 100,000-node AST of algebraic expressions using mutually recursive calls (kind of opposite of parsing).

Fix the body of clone method

The clone method we have now is problematic in that it only sets the last argument. Instead, we want to clone the arguments all the way up to the outermost closure.

problems with pretty printer

Output like this

\ (f : (Int -> Int) -> Int).
  \ (g : Int -> Int).
    f
      let x = g
      in
      \ (y : Int).
        let z = x let d = y in d
        in
        z

is not pretty. Brackets are still necessary in the above example:

\ (f : (Int -> Int) -> Int).
  \ (g : Int -> Int).
    f
      (let x = g
      in
      \ (y : Int).
        let z = x (let d = y in d)
        in
        z)

Is `make test` faking the result?

I am confirmed when running the following tailfact example

let rec fact (acc : Int) (n : Int) : Int =
if n == 0 then acc
else fact (acc * n) (n - 1)
in
fact 1 10

like f2j -r tail_fact.sf -m apply -m stack in the refactor-base branch will give you an exception, but make test says everything is fine.

Could this have something to do with Emma's recent work of making make test faster?

Outdated runtime.jar's never get updated

runtime.jar does not get updated if there is already an old one in path.

This is the cause of Emma having not been able to use f2j to run compiled Java programs.

Create a better way for returning expressions that are not results of function applications in Stack Translation

Currently, "createWrap" check whether the previous statements contain any "Next.next" assignments (which in this translation correspond to .apply() calls); if not, it creates an empyClosure to wrap the resulting expression, and assigns it to Next.next for the main body loop to be able to process it.

https://bitbucket.org/brunosoliveira/systemfcompiler/src/9b8f3a85d45e19208c9ef46ec62aceb77148961f/compiler/StackTransCFJava.hs?at=default#cl-103

Write zipWithN / high-order fn / partial application benchmark example

a few variant of zipWIth. For example:
zipWith1 : (Int -> Int) -> [Int] -> [Int]
zipWith2 : (Int -> Int -> Int) -> [Int] -> [Int] -> [Int]
zipWith5 : (Int -> Int -> Int -> Int -> Int -> Int) -> [Int] -> [Int] -> [Int] -> [Int] -> [Int] -> [Int]
zipWith10 : ...
and show
zipWith5 (\x1 x2 x3 x4 x5 -> x1 + x2 + x3 + x4 + x5) list1 list1 list1 list1 list1
With functions as objects and our implementation there will be 6 applications going on.

Implement in:

with high input value (overflowing) for SystemF (with all optimizations), functions-as-objects+trampolines versions in Scala, Java8, and Clojure

with low input value (not yet overflowing) for SystemF (with all optimizations) + non-trampoline versions of Scala, Java8, and Clojure + fastest trampoline
Selected more complex bench

Make the simplifier work correctly with the backend

For months now we have been commenting out the simplifier in some cases to avoid issues in the backend.

While that's a momentary workaround, what really needs to be done is to make sure that the backend can process the code after simplification.

Please let `make test` run again

Seems some changes happening in the parser part, which cripple make test again. Could we agree that every time we push to the repo, at least pass all the tests?

Annotate your modules with Haddock headers

This is a task for everyone, so do it and reassign this task to the person below you alphabetically.

https://wiki.haskell.org/Programming_guidelines#File_Format

{- |
Module      :  <File name or $Header$ to be replaced automatically>
Description :  <optional short text displayed on contents page>
Copyright   :  (c) 2014-2015 HKU
License     :  BSD3

Maintainer  :  <email>
Stability   :  unstable | experimental | provisional | stable | frozen
Portability :  portable | non-portable (<reason>)

<module description starting at first column>
-}

New unboxing approach

The goal is to try the new unboxing approach. Simply put, incorporate all types (primitive types and references type into one closure class. See the code below:

package boxing;

abstract class Closure {
    long ix; // long input, or other primitive types + there should be a TAG
    Object ox; // ref input for closure
    long iout; // int output, or other primitive types + there should be a TAG
    Object oout; // ref output

    abstract void apply();
}

// Int -> Int
class Inc extends Closure {
    public void apply() { // Int -> Int
        this.iout = ix+1;
    }
}

// apply : (A -> B) -> A -> B
// apply = \f . \x . f x
class Apply extends Closure {
    Closure ap = this;

    public void apply() {
        oout = new Closure() {
                public void apply() {
                    Closure f = (Closure) ap.ox;
                    f.ix = this.ix; // set arguments, potentially could have a tag to decide which assignement to make.
                    f.ox = this.ox;
                    f.apply();
                    this.iout = f.iout; // set the outputs
                    this.oout = f.oout;
                }
            };
    }
}

}

make test2 stops after regarding `.` as a file

The below should be self-explanatory.

Running test from testsuite/tests/run-pass/
-------------------------------------
-------------------------------------
Compileation Option: [Naive]
Running simpl_mandelbrot.sf
1
Running Thunk.sf
I'm here!
Running bob1.sf
Haskell
Running intersection.sf
2
Running Apply.sf
2
Running EvenOddSelect.sf
1
Running fact.sf
3628800
Running substr.sf
bc
Running bob.sf
35
Running .
testsuite/tests/run-pass/. does not exist

And make test2 stops there.

Type variable name bug in Core's pretty printer

Pretty printing

#!haskell
let id A (x : A) = x
in
id (forall A. A -> A) id Int

in Core gives

#!haskell

(\ (a : forall A. A -> A). a (forall A. C -> C) a Int) (/\ A. \ (a : D). a)
  1. skips "B"
  2. "C" and "D" are not bound

Annotate your modules with Haddock headers

This is a task for everyone, so do it and reassign this task to the person below you alphabetically.
https://wiki.haskell.org/Programming_guidelines#File_Format

#!haskell
{- |
Module      :  <File name or $Header$ to be replaced automatically>
Description :  <optional short text displayed on contents page>
Copyright   :  (c) 2014-2015 HKU
License     :  BSD3

Maintainer  :  <email>
Stability   :  unstable | experimental | provisional | stable | frozen
Portability :  portable | non-portable (<reason>)

<module description starting at first column>
-}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.