{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Hello, world!\n",
    "\n",
    "As a first example, let's create a simple function in Intrepydd that prints the contents of a local array of integers. In Jupyter, we can write our Intrepydd program in a cell; to compile it, we'll need to save the contents of this cell to a file."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Prerequisites.** Before starting, note that the Intrepydd compiler depends on the following Python packages:\n",
    "\n",
    "- typed_ast\n",
    "- cppimport\n",
    "- pybind11\n",
    "\n",
    "In most Python implementations, you can install these packages by running the following [system shell command](https://ipython.readthedocs.io/en/stable/interactive/tutorial.html#system-shell-commands):"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!pip install typed_ast cppimport pybind11"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In addition, you should verify that the Intrepydd compiler is available in your environment. If you are running on our supplied environments, `pyddc` should be in your executable path; let's verify that next via another system shell command:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "!if ! [ -f \"$(which pyddc)\" ]; then echo \"Can't find the Intrepydd compiler, 'pyddc'\" ; else echo \"Found the Intrepydd compiler: $(which pyddc)\" ; fi"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Creating the Intrepydd program ###\n",
    "\n",
    "You need to store your Intrepydd code in a local file. From Jupyter, we can do so by placing that code inside a code cell, as we would with any Python code, and we can add the `%%writefile` magic at the top of the cell to tell Jupyter to write that content to a file (instead of executing it immediately).\n",
    "\n",
    "Here's an example, which defines a function called `easy_as()` and writes its contents to an Intrepydd file called `demo1.pydd`. Go ahead and run this now.\n",
    "\n",
    "> **Naming.** The name of your `.pydd` file must be a valid Python module name. That is, later you will load your Intrepydd code using a Python `import` statement; therefore, the name of the file should be a valid name for importing, i.e., here, the name `demo1` will be a valid name for the statement, `import demo1`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%writefile demo1.pydd\n",
    "# demo1.pydd\n",
    "\n",
    "def easy_as():\n",
    "    '''\n",
    "    Prints a local array of integers.\n",
    "    '''\n",
    "    a = [1,2,3]\n",
    "    for i in a:\n",
    "        print(i)\n",
    "        \n",
    "# eof"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To verify that this file is stored in the local working directory, let's issue a system shell command to list the available files. One named `demo1.pydd` should appear in this list."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!ls -al"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also verify that the written contents match what you put in the cell above, using the standard Jupyter magic command, `%pycat`:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "%pycat demo1.pydd"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Compiling ###\n",
    "\n",
    "Let's now run the Intrepydd compiler, `pyddc`, to convert this file into a static executable:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!pyddc demo1.pydd"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If everything went well, you should see a verbatim copy of your Intrepydd program as output. If there were any compilation errors, you'll see a message indicating that something went wrong.\n",
    "\n",
    "> For the end-May beta release, we'll provide pointers on how to carry out diagnostics in the event of errors.\n",
    "\n",
    "Let's re-list the contents of the current directory:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "!ls -al"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Intrepydd converts your Python-style program into a C++ program, which should appear as `demo1.cpp`. In addition, if the compilation succeeded without errors, then there will also be a binary shared library file. (The filename should have the form, `demo1.*.so` on Unix-style systems, including MacOS, or `demo1.dll` on Windows systems.)\n",
    "\n",
    "> If you know C++, you may find it intstructive to take a look at `demo1.cpp` or the compiler outputs, `gcc.out` and `gcc.err`, to get an idea of what Intrepydd can do under the hood."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Running the program ###\n",
    "\n",
    "Now for the fun part: running your first Intrepydd program!\n",
    "\n",
    "The compilation step created a new module containing your Intrepydd code. To use it, you first need to import it—as you would any Python module—and then you can call any function defined within it. The name of the module is the base name of the file (so `base.pydd` becomes a module named `base`)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import demo1\n",
    "demo1.easy_as() # Should print stuff!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(demo1.__doc__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Caveats and known limitations ###\n",
    "\n",
    "As of this v0.1 release, there is one limitation if you need to modify your Intrepydd code. Once your new module is compiled and loaded, you must terminate the kernel (`Kernel` $\\rightarrow$ `Restart`) and re-run everything for any changes to take effect."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Summary and next steps ###\n",
    "\n",
    "In short, the process of working with Intrepydd in Jupyter consists of the following steps:\n",
    "\n",
    "1. Writing your Intrepydd subprogram in its own code cell, and writing its contents to a file.\n",
    "2. Using the system shell to compile that program into a new module, which is stored locally as a dynamically loadable shared library.\n",
    "3. Importing that new module and invoking its functions.\n",
    "\n",
    "Once you think you've got the hang of these basic steps, you are ready to move on to the next demonstration."
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}