# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 2
#     language: python
#     name: python2
# ---

# + [markdown] slideshow={"slide_type": "slide"}
# # LLVM Cauldron - Wuthering Bytes 2016-09-08
#
# # Generating Python & Ruby bindings from C++
#
# ### <NAME>
# ### <EMAIL>
#
# ## https://github.com/ffig/ffig
#
# [Updated Links and API use on 2018-01-25]

# + [markdown] slideshow={"slide_type": "slide"}
# Write a C++ class out to a file in the current working directory

# + slideshow={"slide_type": "fragment"}
outputfile = "Shape.h"

# + slideshow={"slide_type": "fragment"}
# %%file $outputfile
#include <stdexcept>
#include <string>

#ifdef __clang__
  #define C_API __attribute__((annotate("GENERATE_C_API")))
#else
  #define C_API
#endif

#include <ffig/attributes.h>

struct FFIG_EXPORT Shape
{
  virtual ~Shape() = default;
  virtual double area() const = 0;
  virtual double perimeter() const = 0;
  virtual const char* name() const = 0;
} __attribute__((annotate("GENERATE_C_API")));

static const double pi = 4.0;

class Circle : public Shape
{
  const double radius_;

public:
  double area() const override
  {
    return pi * radius_ * radius_;
  }

  double perimeter() const override
  {
    return 2 * pi * radius_;
  }

  const char* name() const override
  {
    return "Circle";
  }

  Circle(double radius) : radius_(radius)
  {
    if ( radius < 0 ) 
    { 
      std::string s = "Circle radius \"" + std::to_string(radius_) + "\" must be non-negative.";
      throw std::runtime_error(s);
    }
  }
};

# + [markdown] slideshow={"slide_type": "slide"}
# Compile our header to check it's valid C++

# + slideshow={"slide_type": "fragment"} language="sh"
# clang++-3.8 -x c++ -fsyntax-only -std=c++14 -I../ffig/include Shape.h 

# + [markdown] slideshow={"slide_type": "slide"}
# Read the code using libclang

# + slideshow={"slide_type": "fragment"}
import sys
sys.path.insert(0,'..')

import ffig.clang.cindex

index = ffig.clang.cindex.Index.create()
translation_unit = index.parse(outputfile, ['-x', 'c++', '-std=c++14', '-I../ffig/include'])

# + slideshow={"slide_type": "fragment"}
import asciitree

def node_children(node):
    return (c for c in node.get_children() if c.location.file.name == outputfile)

print asciitree.draw_tree(translation_unit.cursor,
  lambda n: [c for c in node_children(n)],
  lambda n: "%s (%s)" % (n.spelling or n.displayname, str(n.kind).split(".")[1]))


# + [markdown] slideshow={"slide_type": "slide"}
# Turn the AST into some easy to manipulate Python classes

# + slideshow={"slide_type": "fragment"}
from ffig import cppmodel

# + slideshow={"slide_type": "fragment"}
model = cppmodel.Model(translation_unit)
# -

model

# + slideshow={"slide_type": "fragment"}
[f.name for f in model.functions][-5:]

# + slideshow={"slide_type": "fragment"}
[c.name for c in model.classes][-5:]

# + slideshow={"slide_type": "fragment"}
shape_class = [c for c in model.classes if c.name=='Shape'][0]

# + slideshow={"slide_type": "fragment"}
["{}::{}".format(shape_class.name,m.name) for m in shape_class.methods]

# + [markdown] slideshow={"slide_type": "slide"}
# Look at the templates the generator uses

# + slideshow={"slide_type": "fragment"}
# %cat ../ffig/templates/json.tmpl

# + [markdown] slideshow={"slide_type": "slide"}
# Run the code generator

# + slideshow={"slide_type": "fragment"} language="sh"
# cd ..
# python -m ffig -b json.tmpl rb.tmpl python -m Shape -i demos/Shape.h -o demos/

# + [markdown] slideshow={"slide_type": "fragment"}
# See what it created

# + slideshow={"slide_type": "fragment"}
# %ls

# + slideshow={"slide_type": "slide"}
# %cat Shape.json

# + [markdown] slideshow={"slide_type": "slide"}
# Build some bindings with the generated code.

# + slideshow={"slide_type": "fragment"}
# %%file CMakeLists.txt

cmake_minimum_required(VERSION 3.0)
set(CMAKE_CXX_STANDARD 14)
add_library(Shape_c SHARED Shape_c.cpp)
target_include_directories(Shape_c PRIVATE ../ffig/include)

# + slideshow={"slide_type": "fragment"} language="sh"
# cmake . 
# cmake --build .

# + slideshow={"slide_type": "slide"} language="python2"
# import shape
# c = shape.Circle(8)
#
# print "A {} with radius {} has area {}".format(c.name(), 8, c.area())

# + slideshow={"slide_type": "slide"} magic_args="pypy" language="script"
# import shape
# c = shape.Circle(8)
#
# print "A {} with radius {} has area {}".format(c.name(), 8, c.area())

# + slideshow={"slide_type": "slide"} language="ruby"
# load "Shape.rb"
# c = Circle.new(8)
#
# puts("A #{c.name()} with radius #{8} has area #{c.area()}")

StarcoderdataJupyterScriptsDedupFiltered