# Circle 

2021 - Sean Baxter - circlelang@gmail.com 

Follow me on Twitter, [@seanbax](https://www.twitter.com/seanbax), for compiler updates.

> Download the latest version: [Build 143](https://www.circle-lang.org/linux/build_143.tgz) for 64-bit Linux. 

Circle is a new C++20 compiler. It's written from scratch and designed for easy extension.

## The meta context

The most radical Circle feature is the _meta context_, which executes C++ code at compile time. Meta expression statements are evaluated at compile time. Meta for loops are _unrolled_ at compile time.

[**hello.cxx**](https://www.circle-lang.org/hello.cxx) [Compiler Explorer](https://godbolt.org/z/18E57djjq)
```cpp
#include <iostream>

int main() {
  @meta std::cout<< "Hello world compile time!\n";
  std::cout<< "Hello world runtime!\n";
}
```
```
$ circle hello.cxx
Hello world compile time!
$ ./hello
Hello world runtime!
```

Put the `@meta` token at the start of a statement to execute it at compile time. When the statement is inside a template, it will be executed at template instantiation.

[**tuple.cxx**](https://www.circle-lang.org/tuple.cxx) [Compiler Explorer](https://godbolt.org/z/1h911b8bq)
```cpp
#include <iostream>

template<typename... Ts>
struct tuple {
  // At instantiation, loop through each element in the parameter pack Ts.
  // Subscript the i'th element Ts...[i].
  // Declare a data member with name @(i): _0, _1, _2, etc.
  @meta for(int i : sizeof...(Ts))
    Ts...[i] @(i);
};

int main() {
  using MyTuple = tuple<int, char, float>;
  MyTuple my_tuple { 100, 'x', 3.14 };
  
  // Use Circle reflection to access the member names of a class object.
  // Use the pack slice operator ...[:] to convert an object into a pack.
  // Print each member name and value with a pack expansion.
  std::cout<< MyTuple.member_names<< ": "<< my_tuple...[:]<< "\n" ...;
}
```
```
$ circle tuple.cxx
$ ./tuple
_0: 100
_1: x
_2: 3.14
```

You can deploy meta control flow in any curly-brace scope: namespaces, enum-specifier, class-specifier, and function bodies. We can define a generic tuple type by looping over the template's parameter pack and depositing a data member for each element.

[**enum.cxx**](enum.cxx) [Compiler Explorer](https://godbolt.org/z/4Wo3PPMMj)
```cpp
#include <iostream>

template<typename type_t>
const char* enum_to_string(type_t e) {
  switch(e) {
    // At compile time loop through each enumerator of type_t.
    // Deposit a case statement for it.
    // Return the string spelling of its name.
    @meta for enum(type_t e2 : type_t)
      case e2:
        return type_t.string + "::" + e2.string;

    // Return a formatted string indicating an unknown enumerator.
    default:
      return type_t.string + "::unknown";
  }
}

enum class shapes_t {
  dot, circle, line, triangle, square, pentagon, hexagon, septagon, octagon
};

int main() {
  // Load up an array with enums.
  shapes_t shapes[] {
    (shapes_t)1, (shapes_t)5, (shapes_t)8, (shapes_t)10
  };

  // Print their string names.
  std::cout<< enum_to_string(shapes[:])<< "\n" ...;
}
```
```
$ circle enum.cxx && ./enum
shapes_t::circle
shapes_t::pentagon
shapes_t::octagon
shapes_t::unknown
```

Write meta-for loops inside _switch-statements_ to programmatically generate cases. The `enum_to_string` function template returns pointers to string literals containing qualified names for enumerators. This is an example of _static reflection_. There's no runtime cost to using reflection in Circle. That type information only exists at compile time, and serves to generate function and types.

## Circle parameter packs and reflection

Circle makes dozens of improvements on parameter packs. There are now many mechanisms that yield parameter packs, and the subscript `...[:]` and slice `...[begin:end:step]` operators make accessing specific pack elements easy.

[**packs.cxx**](packs.cxx) [Compiler Explorer](https://godbolt.org/z/4oqoGGWs7)
```cpp
#include <iostream>

template<typename type_t>
void print_object(const type_t& obj) {
  std::cout<< "  "<< type_t.member_names<< ": "<< obj...[:]<< "\n" ...;
}

struct obj_t {
  std::string name;
  int count;
  double cost;
};

int main() {
  obj_t objs[] {
    "Wheaties", 100, 3.49,
    "Lucky Charms", 219, 4.79,
    "Honey Smacks", 6, .99
  };

  for(int i : objs.length) {
    std::cout<< i<< ":\n";
    print_object(objs[i]);
  }
}
```
```
$ circle packs.cxx && ./packs
0:
  name: Wheaties
  count: 100
  cost: 3.49
1:
  name: Lucky Charms
  count: 219
  cost: 4.79
2:
  name: Honey Smacks
  count: 6
  cost: 0.99
```

The member trait `.member_names` returns a parameter pack of string literals spelling out the public non-static data member names of the type on the left. The `...[:]` splice operator, when applied to an object, destructures the object and returns a pack of lvalues to each non-static data member. We can print all member names and values with a simple pack expansion `...`.

[**enum2.cxx**](enum2.cxx) [Compiler Explorer](https://godbolt.org/z/Y8fW3cqeo)
```cpp
#include <iostream>

template<typename type_t>
const char* enum_to_string(type_t e) {
  return type_t.enum_values == e ...?
    type_t.string + "::" + type_t.enum_names :
    type_t.string + "::unknown";
}

enum class shapes_t {
  dot, circle, line, triangle, square, pentagon, hexagon, septagon, octagon
};

int main() {
  // Load up an array with enums.
  shapes_t shapes[] {
    (shapes_t)1, (shapes_t)5, (shapes_t)8, (shapes_t)10
  };

  // Print their string names.
  std::cout<< enum_to_string(shapes[:])<< "\n" ...;
}
```
```
$ circle enum2.cxx && ./enum2
shapes_t::circle
shapes_t::pentagon
shapes_t::octagon
shapes_t::unknown
```

Circle extends C++ with new operators that consume parameter packs, like [multi-conditional `...?:`](https://github.com/seanbaxter/circle/tree/master/conditional#multi-conditional---) and [constexpr multi-conditional `...??:`](https://github.com/seanbaxter/circle/tree/master/conditional#constexpr-multi-conditional---). This rewrite of `enum_to_string` is just a single expression. 

The `.enum_values` member trait yields a pack of enumerator prvalues. We compare each enumerator against the argument `e`, and use that as the predicate of a multi-conditional `a ...? b : c`. The first pack element `a` that evaluates true causes the operator to return the corresponding pack element from `b`. If no element of `a` evaluates true, the scalar expression `c` is returned. This is equivalent to chaining up multiple `?:` conditional operators, one for each pack element.

## Major extensions

Circle extends C++ by adding many novel language features. Here are the big ones:

* [Reflection and user-defined attributes](https://github.com/seanbaxter/circle/blob/master/reflection/README.md#circle-reflection-and-typed-enums)
* [Circle Imperative Arguments (CIA)](https://github.com/seanbaxter/circle/blob/master/imperative/README.md)
* [Member traits](https://github.com/seanbaxter/circle/blob/master/member-traits/README.md)
* [Circle conditionals](https://github.com/seanbaxter/circle/blob/master/conditional/README.md)
* [Universal member access](https://github.com/seanbaxter/circle/blob/master/universal/README.md)
* [Dynamic slices and list comprehensions](https://github.com/seanbaxter/circle/blob/master/comprehension/comprehension.md)

This is a compiler with the the capabilities I've always wanted.

## The C++ of the future

Because Circle is so easy to extend, I've gone ahead and implemented some of the most promising WG21 proposals for the C++23 timeframe.

* [P2392R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2392r1.pdf) - [Pattern matching using `is` and `as`](https://github.com/seanbaxter/circle/tree/master/pattern#pattern-matching)
* [P1938R3](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1938r3.html) - ``if consteval`
* [P1985R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p1985r1.pdf) - Universal template parameters
* [P0847R5](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0847r5.html) - Deducing this
* [P2128R5](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2128r5.pdf) - Multidimensional subscript operator
* [P0849R7](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0849r7.html) - auto(x): decay-copy in the language
* [P2041R1](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2041r1.html) - template = delete
* [P2025R2](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2025r2.html) - Guaranteed copy elision for return variables
* [P2071R0](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2071r0.html) - Named Universal Character Escapes
* [P1040R3](http://www.open-std.org/jtc1/sc22/WG21/docs/papers/2020/p1040r6.html) - [std::embed](https://github.com/seanbaxter/circle/blob/master/embed/embed.md)

Taken together, these make C++ programming experience a lot nicer!

## GPU targets

Circle's main target is 64-bit Linux. Because all modern non-Microsoft operating systems use the same [C++ ABI](https://itanium-cxx-abi.github.io/cxx-abi/abi.html), it would be easy to bring Circle to these other platforms.

But Circle supports both major GPU targets as well:
1. [Circle supports GPU compute](https://github.com/seanbaxter/circle/tree/master/cuda#cuda-on-circle) with a single-pass flavor of CUDA.
    * Use [libc and the C++ Standard Library](https://github.com/seanbaxter/circle/tree/master/cuda#improved-c-and-c-library-support-for-cuda) in device code.
    * Use [reflection and _if-target_](https://github.com/seanbaxter/circle/tree/master/cuda#reflection-and-if-target) to programmatically define the best tuning for each PTX architecture.
2. [Circle supports shader programming](https://github.com/seanbaxter/shaders#circle-c-shaders) by embedding [GLSL 4.6](https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.4.60.pdf) into C++ and emitting both SPIR-V (OpenGL and Vulkan) and DXIL (Direct3D 12) byte codes.
    * Tag functions and objects with [`spirv` attributes](https://github.com/seanbaxter/shaders#interface-attributes) to target all 12 standard shader stages.
    * Use reflection and user-defined attributes to automatically [generate interfaces](https://github.com/seanbaxter/shaders#reflection-and-attributes-for-shadertoy-development) to guide shader development.
    * Write device-portable GPGPU code with Vulkan compute, using real pointers into [physical storage buffers](https://github.com/seanbaxter/shaders#physical-storage-buffers), a powerful feature only implemented by the Circle compiler.

Circle is a heterogeneous compiler. In one translation unit, [mix x64 code, CUDA code, and shader code](https://github.com/seanbaxter/circle/tree/master/cuda#circle-as-a-heterogeneous-compiler). No tags are required. Only a single frontend pass is performed. This is the most seamless integration of CPU and GPU code of any programming language.

## Using Circle

Circle is best used locally, on any recent x86-64 Linux installation. You'll need a recent libstdc++, which should be provided by your distribution's package manager. I like libstdc++-10.2. 

> Download the latest version: [Build 143](https://www.circle-lang.org/linux/build_143.tgz) for 64-bit Linux. 

If you're on an incompatible distribution, or a different OS altogether, try running Circle through this [Dockerfile](https://www.circle-lang.org/Dockerfile).

Circle is also hosted on [Compiler Explorer](https://godbolt.org/z/zK7j8WrME), so you can use it over the web.

## Basic command-line options

* `--help` list all command-line options.
* `-S` emits an ASM file (.s).
* `-S -emit-llvm` emits a human-readable LLVM IR file (.ll).
* `-c -emit-llvm` emits a binary LLVM IR bitcode file (.bc).
* `-c` only compiles to an object file, without linking.
* `-console` prints the output (if text) to the terminal. This is very useful when paired with -S or -S -emit-llvm
* `-O0`, `-O1`, `-O2` and `-O3` are the usual optimization levels.
* `-g` generates debug info.
* `-M` names a compile-time shared object library. This enables compile-time foreign function calls to compiled code.
* `-stat` reports on files opened and lines lexed.
* `-no-demangle` prints mangled names in link errors.
* `--gcc-toolchain` point Circle at an alternate libstdc++ distribution. This is part of a gcc tarball, such as [gcc-10.2.0](https://ftp.gnu.org/gnu/gcc/gcc-10.2.0/), which includes all the binaries and headers required to compile C++ programs. This command line argument sources the libstdc++ headers and precompiled static and dynamic objects, and ignores those installed by the distribution.
* `-P2128` enable multi-dimensional subscript operator