Skip to content

burz/cfl

master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Code

Latest commit

 

Git stats

Files

Permalink
Failed to load latest commit information.
Type
Name
Latest commit message
Commit time
 
 
src
 
 
 
 
 
 
 
 
 
 
 
 
 
 
cfl
 
 
 
 

cfl

Author: Anthony Burzillo


cfl (standing for C-based Functional Language) is a statically typed functional programming language.

Usage

To see the usage simply run ./cfl. If LLVM is already installed (can be installed by running brew install llvm or apt-get install llvm, etc.) then the usage will be

$ ./cfl
USAGE: cfl filename       :: compile the program
           -ast filename  :: print the AST of the program
           -type filename :: print the high level types of the program
           -deep filename :: print all the types of the program
           -eval filename :: evaluate the program
           -ll filename   :: print out the llvm code for the program
           -asm filename  :: print out native assembly code for the program
           -jit filename  :: evaluate the program using Just-In-Time compiling

Note that you can still run cfl without LLVM but you will not have LLVM related options like -jit or compilation.

Example

Obligatory hello world:

main = "hello world!"

Note that every cfl program must end with a main and global definitions are followed by a semicolon.

The quicksort algorithm can be written in cfl as

split x xs l r = case xs of
      []       -> (l, r)
    | (y : ys) -> let (l', r') = split x ys l r in if y <= x
        then (y : l', r')
        else (l', y : r');

quicksort x = case x of
      []       -> []
    | (y : ys) -> let (l, r) = split y ys [] []
        in quicksort l ++ y : quicksort r;

// random x is a globally defined function returning a random integer
// between 0 and x inclusive
random_list x l = if x == 0 then [] else random l : random_list (x - 1) l;

main = quicksort $ random_list 100 500

Running ./cfl -ast will output

split ::= function ~F0 -> (let rec split x = (function xs -> (function l -> (function r -> (case (xs) of [] -> ((l, r)) | (y : ys) -> ((function (l', r') -> (if (((y) < (x)) || ((y) == (x))) then (((y) : (l'), r')) else ((l', (y) : (r'))))) (((((split) (x)) (ys)) (l)) (r))))))) in ((split) (~F0)))
quicksort ::= function ~F1 -> (let rec quicksort x = (case (x) of [] -> ([]) | (y : ys) -> ((function (l, r) -> (((quicksort) (l)) ++ ((y) : ((quicksort) (r))))) (((((split) (y)) (ys)) ([])) ([])))) in ((quicksort) (~F1)))
random_list ::= function ~F2 -> (let rec random_list x = (function l -> (if ((x) == (0)) then ([]) else (((random) (l)) : (((random_list) ((x) + ((-1) * (1)))) (l))))) in ((random_list) (~F2)))
main ::= (quicksort) (((random_list) (100)) (500))

Running ./cfl -type will output

split => (Integer -> ([Integer] -> ([Integer] -> ([Integer] -> ([Integer], [Integer])))))
quicksort => ([Integer] -> [Integer])
random_list => (Integer -> (Integer -> [Integer]))
main => [Integer]

Running ./cfl -deep will output

split ~>> function (~F0 :: Integer) -> (let rec (split :: (Integer -> ([Integer] -> ([Integer] -> ([Integer] -> ([Integer], [Integer])))))) (x :: Integer) = (function (xs :: [Integer]) -> (function (l :: [Integer]) -> (function (r :: [Integer]) -> (case (xs :: [Integer]) of [] -> ((l :: [Integer], r :: [Integer]) :: ([Integer], [Integer])) | ((y :: Integer) : (ys :: [Integer])) -> ((function ((l' :: [Integer], r' :: [Integer]) :: ([Integer], [Integer])) -> (if (((y :: Integer) < (x :: Integer) :: Bool) || ((y :: Integer) == (x :: Integer) :: Bool) :: Bool) then (((y :: Integer) : (l' :: [Integer]) :: [Integer], r' :: [Integer]) :: ([Integer], [Integer])) else ((l' :: [Integer], (y :: Integer) : (r' :: [Integer]) :: [Integer]) :: ([Integer], [Integer])) :: ([Integer], [Integer])) :: (([Integer], [Integer]) -> ([Integer], [Integer]))) (((((split :: (Integer -> ([Integer] -> ([Integer] -> ([Integer] -> ([Integer], [Integer])))))) (x :: Integer) :: ([Integer] -> ([Integer] -> ([Integer] -> ([Integer], [Integer]))))) (ys :: [Integer]) :: ([Integer] -> ([Integer] -> ([Integer], [Integer])))) (l :: [Integer]) :: ([Integer] -> ([Integer], [Integer]))) (r :: [Integer]) :: ([Integer], [Integer])) :: ([Integer], [Integer])) :: ([Integer], [Integer])) :: ([Integer] -> ([Integer], [Integer]))) :: ([Integer] -> ([Integer] -> ([Integer], [Integer])))) :: ([Integer] -> ([Integer] -> ([Integer] -> ([Integer], [Integer]))))) in ((split :: (Integer -> ([Integer] -> ([Integer] -> ([Integer] -> ([Integer], [Integer])))))) (~F0 :: Integer) :: ([Integer] -> ([Integer] -> ([Integer] -> ([Integer], [Integer]))))) :: ([Integer] -> ([Integer] -> ([Integer] -> ([Integer], [Integer]))))) :: (Integer -> ([Integer] -> ([Integer] -> ([Integer] -> ([Integer], [Integer])))))
quicksort ~>> function (~F1 :: [Integer]) -> (let rec (quicksort :: ([Integer] -> [Integer])) (x :: [Integer]) = (case (x :: [Integer]) of [] -> ([] :: [Integer]) | ((y :: Integer) : (ys :: [Integer])) -> ((function ((l :: [Integer], r :: [Integer]) :: ([Integer], [Integer])) -> (((quicksort :: ([Integer] -> [Integer])) (l :: [Integer]) :: [Integer]) ++ ((y :: Integer) : ((quicksort :: ([Integer] -> [Integer])) (r :: [Integer]) :: [Integer]) :: [Integer]) :: [Integer]) :: (([Integer], [Integer]) -> [Integer])) (((((split :: (Integer -> ([Integer] -> ([Integer] -> ([Integer] -> ([Integer], [Integer])))))) (y :: Integer) :: ([Integer] -> ([Integer] -> ([Integer] -> ([Integer], [Integer]))))) (ys :: [Integer]) :: ([Integer] -> ([Integer] -> ([Integer], [Integer])))) ([] :: [Integer]) :: ([Integer] -> ([Integer], [Integer]))) ([] :: [Integer]) :: ([Integer], [Integer])) :: [Integer]) :: [Integer]) in ((quicksort :: ([Integer] -> [Integer])) (~F1 :: [Integer]) :: [Integer]) :: [Integer]) :: ([Integer] -> [Integer])
random_list ~>> function (~F2 :: Integer) -> (let rec (random_list :: (Integer -> (Integer -> [Integer]))) (x :: Integer) = (function (l :: Integer) -> (if ((x :: Integer) == (0 :: Integer) :: Bool) then ([] :: [Integer]) else (((random :: (Integer -> Integer)) (l :: Integer) :: Integer) : (((random_list :: (Integer -> (Integer -> [Integer]))) ((x :: Integer) + ((-1 :: Integer) * (1 :: Integer) :: Integer) :: Integer) :: (Integer -> [Integer])) (l :: Integer) :: [Integer]) :: [Integer]) :: [Integer]) :: (Integer -> [Integer])) in ((random_list :: (Integer -> (Integer -> [Integer]))) (~F2 :: Integer) :: (Integer -> [Integer])) :: (Integer -> [Integer])) :: (Integer -> (Integer -> [Integer]))
main ~>> (quicksort :: ([Integer] -> [Integer])) (((random_list :: (Integer -> (Integer -> [Integer]))) (100 :: Integer) :: (Integer -> [Integer])) (500 :: Integer) :: [Integer]) :: [Integer]

Running ./cfl -eval or ./cfl -jit, or running ./cfl program.cfl and then ./program will output something like

[0, 1, 3, 8, 14, 15, 16, 17, 25, 32, 37, 38, 40, 46, 61, 61, 64, 77, 80, 106, 108, 110, 111, 113, 121, 127, 134, 134, 137, 144, 149, 151, 158, 160, 165, 177, 179, 180, 188, 192, 196, 200, 201, 202, 212, 216, 218, 220, 223, 230, 236, 239, 239, 244, 251, 253, 265, 269, 281, 294, 301, 304, 308, 315, 323, 332, 334, 356, 359, 372, 373, 374, 375, 375, 383, 385, 387, 392, 393, 397, 398, 399, 402, 412, 420, 425, 431, 433, 438, 440, 441, 445, 452, 454, 459, 474, 482, 488, 489, 495]

Expressions

Basic types

The basic types of cfl are bools (true or false), integers (0, 1, -1, ...), and characters ('q').

Boolean Operations

cfl allows conjunction (&&), disjunction (||), and negation (!) expressions.

Integer Operations

The operations of addition (+), subtraction (-), multiplication (*), division (/), and modulus (%) evaluate to integer values. On the other hand, the comparison operators of equality (==), inequality (!=), less-than (<), less-than-or-equal (<=), greater-than (>), and greater-than-or-equal (>=) all evaluate to boolean values.

Functional Operations

cfl allows the creation of anonymous functions via function x -> e where e is some expression, and x is the argument to the function. We can create multiple argument anonymous functions via function x -> function y -> e where x is the first argument and y is the second, etc.

To apply a function f simply use f e where e is the expression for the first argument, or f e1 e2 for the first argument e1 and second argument e2. Similary one can use f $ x to apply the entire right side of the $ to f.

Finally, one can compose two functions f . g.

g a = if a then 5 else 4;
f b = b == 5;
main = f . g $ true

If Expressions

Use if e1 then e2 else e3.

Let Expressions

cfl allows let expressions to define constants and functions (possibly recursive) via

let x = 4 in x + 54

and

let f x y = if x = 0 then 0 else y + f (x - 1) y in f 3 4

Tuple Expressions

Tuples of arbitrary size can be created via (true, false, [0], 1, [false]).

Anything but a function name can be matched to a tuple in let statements, for instance

let (x, y) = (1, 2) in x + y
let f (x, y) = x + y in f 0 1

are both valid.

List Expressions

You can create empty lists [] or lists with values [1, 2, 3, 4]. You can push values onto a list via

5 : [4, 5, 6]

You can also concatenate lists

[1, 2] ++ [3, 4]

Finally, we can match on lists via a case expression via

case e1 of [] -> e2 | (x : xs) -> e3

String Expressions

Strings are implemented as lists of characters, therefore characters can be pushed onto strings and two strings can be concatenated. To create a string one can simply write the quotation enclosed string, i.e. "hello world!".

About

a Compileable statically typed Functional programming Language

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages