Skip to content

BYVoid/SugarCpp

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 

Repository files navigation

SugarCpp

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

It adds lots of syntax sugar in to C++ and is 100% equivalent C++ code.

SugarCpp is still under development. If you have any idea, please open a issue.

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

Features

Examples

Hello world

import "stdio.h"

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

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

Calculate Sum

import "stdio.h"

int main()
    sum := 0
    for i <- 1 to 10
        sum = sum + i
    printf("sum = %d\n", sum)
#include "stdio.h"

int main() {
    auto sum = 0;
    for (auto i = 1; i <= 10; ++i) {
        sum = sum + i;
    }
    printf("sum = %d\n", sum);
}

Defer and Finally

Due to 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

  • defer is fast, lightweight, the generate C++ code is highly readable. It simply insert code before return/continue/break statements. So when exception happens, the codes decleared by defer are not guarantee to be run.

  • finally is little heavier than defer. It is behaved just like the finally syntax in C# or Java. It use deconstructor to guarantee when exception happens, the codes decleared by finally will still be run.

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);
}

(Prolog? Haskell? Scala?) style for loop

import "stdio.h"

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

    sum := 0
    for i <- 10 downto 1 by -1, i != 5, x <- a[i]
        sum += x
#include "stdio.h"

int main() {
    for (auto i = 1; i <= 10; ++i) {
        for (auto j = 1; j <= 10; ++j) {
            if (i + j == 10) {
                printf("%d + %d = %d");
            }
        }
    }
    auto sum = 0;
    for (auto i = 10; i >= 1; i = i + -1) {
        if (i != 5) {
            for (auto x : a[i]) {
                sum += x;
            }
        }
    }
}

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[][] = [
    [1, 2, 3]
    [4, 5, 6]
    [7, 8, 0]
]

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

line: int[] = [1, 2, 3]
int grid[][] = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 0 } };
int list[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int line[] = { 1, 2, 3 };
Operators and Aliases
<tr>
    <td>isnt</td>
    <td>!=</td>
</tr>

<tr>
    <td>and</td>
    <td>&&</td>
</tr>

<tr>
    <td>or</td>
    <td>||</td>
</tr>
SugarCpp C++
is ==

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

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

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

    Number(T value) {
        this->value = value;
    }

    inline tuple<T> Unapply() {
        return std::make_tuple(value);
    }
};

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

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

    inline tuple<string, Expr, Expr> Unapply() {
        return std::make_tuple(op, l, r);
    }
};

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);
}

Attributes

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

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

    [private]
    x: int

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

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

class Test {
    friend class Print;

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

private:
    int x;
};

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

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& a) {
    switch (a) {
    case Sunday:
        return "Sunday";

    case Monday:
        return "Monday";

    case Tuesday:
        return "Tuesday";

    case Wednesday:
        return "Wednesday";

    case Thursday:
        return "Thursday";

    case Friday:
        return "Friday";

    case Saturday:
        return "Saturday";
    }
}

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

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

typedef u_int32 = unsigned int
typedef unsigned int u_int32;

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.
    --help -h /help /h /?       Output this help text.
    --nocode /nocode            Do not print the generated code.
    --output -o /output /o [filename]
                                Filename of output. If not specified, output
                                will be printed to standard output.
    --token /token              Output the tokens.

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

About

SugarCpp is a language which can compile to C++.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • SuperCollider 50.8%
  • C# 49.0%
  • Other 0.2%