curimit / SugarCpp

SugarCpp is a language which can compile to C++11.
135 stars 13 forks source link

SugarCpp

SugarCpp is a programming language which compiles to readable C++11 code.

It adds lots of syntax sugar in to C++ based on the power of C++11.

SugarCpp is still under development. The C# version works OK. Now it is being re-written using SugarCpp itself(bootstrap). If you have any idea, please open a issue.

Try SugarCpp in your browser: http://curimit.com/project/SugarCpp/

SugarCpp is an experimental project, and its development is inactive.

Unit Test

Challenge the compiler on unit test page:

http://curimit.com/project/SugarCpp/unit_test.html

  1. Add new test cases.
  2. Edit/Remove exist test cases.
  3. Run all unit tests.

Features

Plugins

Sublime-Text: https://github.com/curimit/Sublime-SugarCpp

vim: https://github.com/ppwwyyxx/vim-SugarCpp

Examples

Hello world

import "stdio.h"

int main()
    printf("Hello world!")
#include "stdio.h"

int main() {
    printf("Hello world!");
}

Powerful for loop

import "cstdio"
       "cstdlib"
       "vector"

using namespace std

int main()
    for i <- 1 to 10, j <- 1 to 10, i + j == 10
        printf("%d + %d = %d\n", i, j, i + j)

    sum := 0
    for i <- 4 downto 0 by -1, i != 2, x <- a[i]
        sum += x

    // i => i * i
    // means map i into i*i
    for i <- 1 to 100, i % 3 == 0, i => i * i
        printf("%d\n", i)

    // notice the type of i can be also changed
    for i <- ["12", "21"], i => atoi(i), i => i * 2
        printf("%d\n", i)

    for x <- 0 to n, x => a[x]
        printf("%d\n", a[x])
#include "cstdio"
#include "cstdlib"
#include "vector"

using namespace std;

int main() {
    for (auto i = 1; i <= 10; ++i) {
        for (auto j = 1; j <= 10; ++j) {
            if (i + j == 10) {
                printf("%d + %d = %d\n", i, j, i + j);
            }
        }
    }
    auto sum = 0;
    for (auto i = 4; i >= 0; i = i + -1) {
        if (i != 2) {
            for (auto x : a[i]) {
                sum += x;
            }
        }
    }
    for (auto i = 1; i <= 100; ++i) {
        if (i % 3 == 0) {
            {
                auto _t_iterator = i * i;
                auto i = _t_iterator;
                printf("%d\n", i);
            }
        }
    }
    for (auto i : { "12", "21" }) {
        {
            auto _t_iterator = atoi(i);
            auto i = _t_iterator;
            {
                auto _t_iterator = i * 2;
                auto i = _t_iterator;
                printf("%d\n", i);
            }
        }
    }
    for (auto x = 0; x <= n; ++x) {
        {
            auto _t_iterator = a[x];
            auto x = _t_iterator;
            printf("%d\n", a[x]);
        }
    }
}

Multi-dimensional array

int main()
    a: int[2,3]
    a[1,2] = 2
int main() {
    int a[2][3];
    a[1][2] = 2;
}

Types

import "cstdint"
       "functional"

a: bool
b: char
c: uchar
d: schar
e: int
f: int8
g: int16
h: int32
i: int64
j: uint
k: uint8
l: uint16
m: uint32
n: uint64
o: float
p: double
q: long double

// func type
r: (int, int) -> int
s: () -> int
t: int -> ()
u: () -> ()

int main()
    a = true
#include "cstdint"
#include "functional"

bool a;
char b;
unsigned char c;
signed char d;
int e;
int8_t f;
int16_t g;
int32_t h;
int64_t i;
unsigned int j;
uint8_t k;
uint16_t l;
uint32_t m;
uint64_t n;
float o;
double p;
long double q;
std::function<int (int, int)> r;
std::function<int ()> s;
std::function<void (int)> t;
std::function<void ()> u;

int main() {
    a = true;
}

Multiple line function call

int main()
    glVertexAttribPointer(
        attribute_coord2d, // attribute
        2,                 // number of elements per vertex, here (x,y)
        GL_FLOAT,          // the type of each element
        GL_FALSE,          // take our values as-is
        0,                 // no extra data between each position
        triangle_vertices  // pointer to the C array
    )

    test(
        1,2,3
        4,5,6
    )

    test(
        1
        2
        3)

    test(1,2
         3,4)

    test(1,2
    3,4)
int main() {
    glVertexAttribPointer(attribute_coord2d, 2, GL_FLOAT, GL_FALSE, 0, triangle_vertices);
    test(1, 2, 3, 4, 5, 6);
    test(1, 2, 3);
    test(1, 2, 3, 4);
    test(1, 2, 3, 4);
}

Multiple line string

int main()
    a = @"""
    int main() {
        printf("adf")
    }
    """

    b = "test
    it"

    c = "test
        it"
int main() {
    a = "\nint main() {\n    printf(\"adf\")\n}\n";
    b = "test\nit";
    c = "test\n    it";
}

Operator overloading

Currently support + - * /, other operators are on todo list.

Test (+) (a: const Test&, b: const Test&)
    // something

Test (/) (a: const Test&, b: const Test&)
    // something
Test operator+(const Test &a, const Test &b) {
}

Test operator/(const Test &a, const Test &b) {
}

Curried lambda functions

import "iostream"

using namespace std

void example1()
    t := 0

    plus := (x: int, y: int) --> x + y + t

    f := plus(2)
    // print 5, 6
    cout << f(3) << " " << f(4) << endl

    x := 5
    fx := plus(x)
    // print 8, 9
    cout << fx(3) << " " << fx(4) << endl

    t = 10
    // print 18, 19
    cout << fx(3) << " " << fx(4) << endl

void example2()
    t := 0

    plus := (x: int, y: int) ==> x + y + t

    f := plus(2)
    // print 5, 6
    cout << f(3) << " " << f(4) << endl

    x := 5
    fx := plus(x)
    // print 8, 9
    cout << fx(3) << " " << fx(4) << endl

    t = 10
    // print 8, 9
    cout << fx(3) << " " << fx(4) << endl

int main()
    example1()
    example2()
#include "iostream"

using namespace std;

void example1() {
    auto t = 0;
    auto plus = ([&](int x) {
        return ([&, x](int y) {
        return x + y + t;
    });
    });
    auto f = plus(2);
    cout << f(3) << " " << f(4) << endl;
    auto x = 5;
    auto fx = plus(x);
    cout << fx(3) << " " << fx(4) << endl;
    t = 10;
    cout << fx(3) << " " << fx(4) << endl;
}

void example2() {
    auto t = 0;
    auto plus = ([=](int x) {
        return ([=](int y) {
        return x + y + t;
    });
    });
    auto f = plus(2);
    cout << f(3) << " " << f(4) << endl;
    auto x = 5;
    auto fx = plus(x);
    cout << fx(3) << " " << fx(4) << endl;
    t = 10;
    cout << fx(3) << " " << fx(4) << endl;
}

int main() {
    example1();
    example2();
}

[Beta] List Generation

import "iostream"
       "cstdio"
       "vector"
       "list"
       "forward_list"
       "queue"
       "stack"
       "set"
       "unordered_set"
       "map"
       "unordered_map"
       "tuple"

using namespace std

int main()
    a := [i for i <- 1 to 10] : vector<int>

    b := [i for i <- 1 to 10] : list<int>
    c := [i for i <- 1 to 10] : forward_list<int>

    d := [i for i <- 1 to 10] : queue<int>
    e := [i for i <- 1 to 10] : deque<int>
    f := [i for i <- 1 to 10] : priority_queue<int>

    g := [i for i <- 1 to 10] : stack<int>

    h := [i for i <- 1 to 10] : set<int>
    i := [i for i <- 1 to 10] : multiset<int>
    j := [i for i <- 1 to 10] : unordered_set<int>
    k := [i for i <- 1 to 10] : unordered_multiset<int>

    l := [[i, i*i] for i <- 1 to 10] : map<int, int>
    m := [[i, i*i] for i <- 1 to 10] : multimap<int, int>
    n := [[i, i*i] for i <- 1 to 10] : unordered_map<int, int>
    o := [[i, i*i] for i <- 1 to 10] : unordered_multimap<int, int>

    // combine list generation with for loop
    printf("%d\n", i) for i <- [i * i for i <- 1 to 100, (i & 1) is 0, (i % 3) is 0] : vector<int>
#include "iostream"
#include "cstdio"
#include "vector"
#include "list"
#include "forward_list"
#include "queue"
#include "stack"
#include "set"
#include "unordered_set"
#include "map"
#include "unordered_map"
#include "tuple"

using namespace std;

int main() {
    auto a = ({
        vector<int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.push_back(i);
        }
        _t_return_value;
    });
    auto b = ({
        list<int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.push_back(i);
        }
        _t_return_value;
    });
    auto c = ({
        forward_list<int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.push_front(i);
        }
        _t_return_value;
    });
    auto d = ({
        queue<int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.push(i);
        }
        _t_return_value;
    });
    auto e = ({
        deque<int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.push_front(i);
        }
        _t_return_value;
    });
    auto f = ({
        priority_queue<int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.push(i);
        }
        _t_return_value;
    });
    auto g = ({
        stack<int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.push(i);
        }
        _t_return_value;
    });
    auto h = ({
        set<int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.insert(i);
        }
        _t_return_value;
    });
    auto i = ({
        multiset<int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.insert(i);
        }
        _t_return_value;
    });
    auto j = ({
        unordered_set<int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.insert(i);
        }
        _t_return_value;
    });
    auto k = ({
        unordered_multiset<int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.insert(i);
        }
        _t_return_value;
    });
    auto l = ({
        map<int, int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.insert({ i, i * i });
        }
        _t_return_value;
    });
    auto m = ({
        multimap<int, int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.insert({ i, i * i });
        }
        _t_return_value;
    });
    auto n = ({
        unordered_map<int, int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.insert({ i, i * i });
        }
        _t_return_value;
    });
    auto o = ({
        unordered_multimap<int, int> _t_return_value;
        for (auto i = 1; i <= 10; ++i) {
            _t_return_value.insert({ i, i * i });
        }
        _t_return_value;
    });
    for (auto i : ({
        vector<int> _t_return_value;
        for (auto i = 1; i <= 100; ++i) {
            if ((i & 1) == 0) {
                if ((i % 3) == 0) {
                    _t_return_value.push_back(i * i);
                }
            }
        }
        _t_return_value;
    })) {
        printf("%d\n", i);
    }
}

[Beta] Where Expression

int unit(a: Point) = Point(a.x / k, a.y / k, a.z / k) where
    k := len(a)
int unit(Point a) {
    return ({
        auto k = len(a);
        Point(a.x / k, a.y / k, a.z / k);
    });
}

[Beta] Implicit switch

int gcd(a: int, b: int) =
    | a == 0 => b
    | _      => gcd(b % a, a)
int gcd(int a, int b) {
    return ({
        decltype(b) match;
        if (a == 0) {
            match = b;
        } else {
            match = gcd(b % a, a);
        }
        match;
    });
}

Defer and Finally

Due to the fact that C++11 does not support C# style Finally syntax, it's difficult to guarantee resource be closed or pointer be deleted while exception happens.

SugarCpp provide two syntax: defer/finally

This is an example of defer

Notice it has no extra cost and does not handle exceptions.

import "fstream"

using namespace std

void foo()
    fout: ofstream("output.txt")
    defer fout.close()
    fout.write("Hello World!", 12)
    if (false)
        return

// A more complex example to show the execution order of defer
void bar()
    print("1")
    defer print("defer1")
    if true
        print("2")
        defer print("defer2")
        if true
            print("3")
            defer print("defer3")
            print("4")
            return
        print("5")
    print("6")
    return
#include "fstream"

using namespace std;

void foo() {
    ofstream fout("output.txt");
    fout.write("Hello World!", 12);
    if ((false)) {
        fout.close();
        return;
    }
    fout.close();
}

void bar() {
    print("1");
    if (true) {
        print("2");
        if (true) {
            print("3");
            print("4");
            print("defer3");
            print("defer2");
            print("defer1");
            return;
        }
        print("5");
        print("defer2");
    }
    print("6");
    print("defer1");
    return;
}
This is an example of finally

This syntax behaved like finally in Java or C# and even easier to use.

import "stdio.h"
       "functional"

using namespace std

void test()
    x := new int[100]
    finally delete(x)

    x[0] = 1
    // maybe open file failed
    // maybe divided by zero
    // anyway, an exception occurs
    // we want to avoid memory leak
    throw(0)

int main()
    try
        test()
    catch x:int
        printf("catch: %d\n", x)
#include "stdio.h"
#include "functional"

using namespace std;

void test() {
    auto x = new int[100];
    class _t_finally_0 {
    public:
        std::function<void()> finally;
        ~_t_finally_0() { finally(); }
    } _t_finally_0 = { [&]() { delete(x); } };
    x[0] = 1;
    throw(0);
}

int main() {
    try {
        test();
    } catch (int x) {
        printf("catch: %d\n", x);
    }
}

Multiple return values && Parallel assignment

import "stdio.h"
       "tuple"

using std::tuple

tuple<T, T> sort<T>(a: T, b: T)
    return a < b ? (a, b) : (b, a)

int main()
    a := 10
    b := 1
    (a, b) = sort(a, b)
    printf("%d %d\n", a, b)
    (a, b) = (b, a)
    printf("%d %d\n", a, b)
#include "stdio.h"
#include "tuple"

using std::tuple;

template <typename T>
tuple<T, T> sort(T a, T b) {
    return a < b ? std::make_tuple(a, b) : std::make_tuple(b, a);
}

int main() {
    auto a = 10;
    auto b = 1;
    std::tie(a, b) = sort(a, b);
    printf("%d %d\n", a, b);
    std::tie(a, b) = std::make_tuple(b, a);
    printf("%d %d\n", a, b);
}

Syntax sugar borrow from CoffeeScript

Existential Operator
int main()
    // ?= operator
    tree->left ?= new Node()

    // ? operator
    footprints = yeti ? "bear"
int main() {
    if (tree->left == nullptr) {
        tree->left = new Node();
    }
    footprints = yeti != nullptr ? yeti : "bear";
}
Chained Comparisons
int main()
    a = 1 <= x <= y <= 10

    b = 1 < x != 10
int main() {
    a = 1 <= x && x <= y && y <= 10;
    b = 1 < x && x != 10;
}
@ syntax represent this ponter
[public]
class Point
    x, y := 0

    void set(x: int, y: int)
        @x = x
        @y = y
class Point {
public:
    auto x = 0;
    auto y = 0;

    void set(int x, int y) {
        this->x = x;
        this->y = y;
    }
};
Suffix If/While/Until/For
import "stdio.h"
       "initializer_list"

int main()
    // suffix if
    printf("haha!") if score > 90
    return 0 if score == 0

    // suffix while/until
    buy()  while supply > demand
    sell() until supply > demand

    // suffix for
    a[i] = 0 for i <- 1 to 10, i % 2 == 0
    printf("%s\n", food) for food <- ["toast", "cheese", "wine"]

    // combine together
    a[i] = i if i % 2== 0 for i <- list
#include "stdio.h"
#include "initializer_list"

int main() {
    if (score > 90) {
        printf("haha!");
    }
    if (score == 0) {
        return 0;
    }
    while (supply > demand) {
        buy();
    }
    while (!(supply > demand)) {
        sell();
    }
    for (auto i = 1; i <= 10; ++i) {
        if (i % 2 == 0) {
            a[i] = 0;
        }
    }
    for (auto food : { "toast", "cheese", "wine" }) {
        printf("%s\n", food);
    }
    for (auto i : list) {
        if (i % 2 == 0) {
            a[i] = i;
        }
    }
}
Arrays Initialization
grid:int[3, 3] = [
    [1, 2, 3]
    [4, 5, 6]
    [7, 8, 0]
]

list: int[9] = [
    1, 2, 3
    4, 5, 6
    7, 8, 9
]

line: int[3] = [1, 2, 3]
int grid[3][3] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 0 } };
int list[9] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int line[3] = { 1, 2, 3 };
Operators and Aliases
SugarCpp C++
is ==
isnt !=
not !
and &&
or ||

C# style lambda expression

import "stdio.h"

int main()
    x := 1

    // capture by reference
    f := () -> ++x

    // capture by value
    f := () => ++x
#include "stdio.h"

int main() {
    auto x = 1;
    auto f = ([&]() { return ++x; });
    auto f = ([=]() { return ++x; });
}

Enumerated type

enum Color = RED | GREEN | BLUE
enum Color {
    RED = 0,
    GREEN,
    BLUE
};

Define new variable

// basic syntax
a := 1
a, b : int

// advanced syntax
a, b: int(1)
a, b := 1, 2
a, b := 1
auto a = 1;
int a, b;
int a(1);
int b(1);
auto a = 1;
auto b = 2;
auto a = 1;
auto b = 1;

Generic Programming

T max<T>(x: T, y: T) = x > y ? x : y
template <typename T>
T max(T x, T y) {
    return x > y ? x : y;
}

Scala style case class

case class Expr
case class Number<T>(value:T): Expr
case class ExprBin(op:string, l:Expr, r:Expr): Expr

void Test(expr: Expr*)
    // reflection get actual type.
    cout << expr->GetType() << endl

int main()
    expr: Expr
    number: Number<int>
    expr_bin: ExprBin

    Test(&expr)
    Test(&number)
    Test(&expr_bin)
class Expr {
public:
    virtual const char* GetType();
};

template <typename T>
class Number: public Expr {
public:
    T value;

    Number() = default;
    Number(T value) {
        this->value = value;
    }
    virtual const char* GetType() {
        return "Number";
    }
};

class ExprBin: public Expr {
public:
    string op;
    Expr l;
    Expr r;

    ExprBin() = default;
    ExprBin(string op, Expr l, Expr r);
    virtual const char* GetType();
};

const char* Expr::GetType() {
    return "Expr";
}

ExprBin::ExprBin(string op, Expr l, Expr r) {
    this->op = op;
    this->l = l;
    this->r = r;
}

const char* ExprBin::GetType() {
    return "ExprBin";
}

void Test(Expr *expr) {
    cout << expr->GetType() << endl;
}

int main() {
    Expr expr;
    Number<int> number;
    ExprBin expr_bin;
    Test(&expr);
    Test(&number);
    Test(&expr_bin);
}

Haskell style infix function

import "stdio.h"
       "algorithm"

using std::max

int main()
    a, b, c := 1, 2, 3
    x := a `max` b `max` c
    printf("%d\n", x)
#include "stdio.h"
#include "algorithm"

using std::max;

int main() {
    auto a = 1;
    auto b = 2;
    auto c = 3;
    auto x = max(max(a, b), c);
    printf("%d\n", x);
}

Switch case

int main()
    // switch table
    // auto break, auto add {}
    switch x
        when '0'
            i := 0
            printf("%d", i)
        when '1', '2'
            i := 4
            printf("%d", i)
        else
            printf("unknown")

    // if elsif syntax
    switch
        when 0 < i < 10
            printf("case1")
        when i <= 0
            printf("case2")
        else
            printf("else")
#include "test.h"

int main() {
    switch (x) {
    case '0':
        {
            auto i = 0;
            printf("%d", i);
            break;
        }

    case '1':
    case '2':
        {
            auto i = 4;
            printf("%d", i);
            break;
        }

    defalult:
        printf("unknown");
    }
    if (0 < i && i < 10) {
        printf("case1");
    } else if (i <= 0) {
        printf("case2");
    } else {
        printf("else");
    }
}

Attributes

1. friend, public, private, static, inline, virtual
import "stdio.h"

[friend(Print), public]
class Test
    Test(x: int) = this->x = x

    [private]
    x: int

[public]
class Print
    [inline, static]
    void print(a :Test&) = printf("%d", a.x)

    [virtual, const]
    int get() = 1

int main()
    a := Test(123)
    Print::print(a)
#include "stdio.h"

class Test {
    friend class Print;

public:
    Test(int x);

private:
    int x;
};

class Print {
public:
    inline static void print(Test &a);

    virtual int get() const;
};

Test::Test(int x) {
    this->x = x;
}

inline void Print::print(Test &a) {
    printf("%d", a.x);
}

int Print::get() const {
    return 1;
}

int main() {
    auto a = Test(123);
    Print::print(a);
}
2. FlagAttribute
[FlagAttribute]
enum MyFlags = None | Flag1 | Flag2 | Flag3 | Flag4
enum MyFlags {
    None = 0,
    Flag1 = 1,
    Flag2 = 2,
    Flag3 = 4,
    Flag4 = 8
};
3. ToString
import "stdio.h"

[ToString]
enum Day = Sunday | Monday | Tuesday | Wednesday | Thursday | Friday | Saturday

int main()
    day := Sunday
    name := day @ToString()
    printf("%s\n", name)
#include "stdio.h"

enum Day {
    Sunday = 0,
    Monday,
    Tuesday,
    Wednesday,
    Thursday,
    Friday,
    Saturday
};

const char* ToString(const Day& _t_value) {
    switch (_t_value) {
    case Sunday:
        {
            return "Sunday";
            break;
        }

    case Monday:
        {
            return "Monday";
            break;
        }

    case Tuesday:
        {
            return "Tuesday";
            break;
        }

    case Wednesday:
        {
            return "Wednesday";
            break;
        }

    case Thursday:
        {
            return "Thursday";
            break;
        }

    case Friday:
        {
            return "Friday";
            break;
        }

    case Saturday:
        {
            return "Saturday";
            break;
        }

    defalult:
        throw("Not Found");
    }
}

int main() {
    auto day = Sunday;
    auto name = ToString(day);
    printf("%s\n", name);
}

Function Type

import "iostream"
       "functional"

using namespace std

int apply(f: () -> int) = f()
int apply(f: (int, int) -> int, a: int, b: int) = f(a, b)

int main()
    a := 10
    b := 20
    ans1 := apply(() -> 100)
    cout << ans1 << endl
    ans2 := apply((a: int, b: int) -> a * b, a, b)
    cout << ans2 << endl
#include "iostream"
#include "functional"

using namespace std;

int apply(function<int ()> f) {
    return f();
}

int apply(function<int (int, int)> f, int a, int b) {
    return f(a, b);
}

int main() {
    auto a = 10;
    auto b = 20;
    auto ans1 = apply(([&]() { return 100; }));
    cout << ans1 << endl;
    auto ans2 = apply(([&](int a,int b) { return a * b; }), a, b);
    cout << ans2 << endl;
}

Namespace

namespace SugarCpp::AstNode::Expr
    class ExprBin
        Left, Right : Expr
        Op : string
namespace SugarCpp {
    namespace AstNode {
        namespace Expr {
            class ExprBin {
                Expr Left, Right;
                string Op;
            };
        }
    }
}

Typedef

type u_int32 = uint
using u_int32 = unsigned int;

Contributors

Command Line Usage

SugarCpp
Compiler Version 1.0.0
Command Line Interface Version 1.0.2

Project website: https://github.com/curimit/SugarCpp

Usage:
    sugarcpp [filename] <options>
    sugarcpp compile [filename] <compiler arguments>
    sugarcpp run [filename] <arguments>

Options:
    --ast /ast                  Output the abstract syntax tree.
    --token /token              Output the tokens.
    --help -h /help /h /?       Output this help text.
    --nocode /nocode            Do not print the generated code.
    --single /single            Translate into single cpp file.
    --output -o /output /o [output_path]
                                Path of output. If not specified, output
                                will be written into the directory
                                where your source code at.

Examples:
    Translate into C++ code
        sugarcpp code.sc
    Compile to binary by calling the default compiler
        sugarcpp compile code.sc -o code.exe
    Compile and run
        sugarcpp run code.sc