Compiling and running
---------------------

### Overview

<table border=1 cellpadding =5>
<tr><td>Step </td><td>performed by</td></tr>
<tr>
 <td>Reading Python source</td>
 <td>function <code>brython(_debug\_mode_)</code> in __py2js.js__

If the code is in an external file, it is retrieved by an Ajax call

This function creates environment variables, including :
  
- `__BRYTHON__.$py_src` : object indexed by module names, value is the module source code
- `__BRYTHON__.debug` : debug level
- `__BRYTHON__.exception_stack` : a list of errors generated during parsing or at runtime
- `__BRYTHON__.imported` : a Javascript object, mapping imported module names to the matching module object
- `__BRYTHON__.modules` : a Javascript object, mapping module names to module objects
- `__BRYTHON__.vars` : a Javascript object, mapping module names to the dictionary of variables defined in the module

</td>
</tr>

<tr>
 <td>creation of the tree representing the Python code</td>
 <td>function <code>\_\_BRYTHON\_\_.py2js(_source,module_)</code> in __py2js.js__
  
  This function calls :
  
- `$tokenize(<i>source</i>)` : syntax analysis of the tokens in Python source code and tree building ; returns the tree root
- `transform(<i>root</i>)` : transforms the tree to prepare the conversion to Javascript (see below)
- `$add_line_num()` to add line numbers if debug mode is greater than 0
  
  The function `py2js` returns the tree root
</td>
</tr>

<tr>
 <td>generating Javascript code</td>
 <td>method `to_js()` of the tree returned by `py2js`

 This function recursively calls the method of the same name on all the syntax elements found in the tree. It returns the string holding the resulting Javascript code. If debug mode is 2, this string is printed in the browser console
 </td>
</tr>

<tr>
 <td>running Javascript code</td>
 <td>evaluation by the function `eval()`</td>
</tr>

</table>

### Files used

The script __brython.js__ is generated by compilation of several scripts :
    
- **brython\_builtins.js** : defines the object `__BRYTHON__` which acts as a gateway between Javascript native objects (`Date, RegExp, Storage...`) and Brython
- **version\_info.js** : created by the make_dist.py script, it adds information about the brython version
- **py2js.js** : performs the conversion from Python code to Javascript code
- **py\_utils.js** : utility functions (eg type conversions between Javascript and Python)
- **py\_object.js** : implements Python `object` class
- **py\_type.js** : implements Python `type` class
- **py\_builtin\_functions.js** : Python built-in functions
- **js\_objects.js** : interface to Javascript objects and constructors
- **py\_import.js** : implementation of <tt>import</tt>
- **py\_float.js**, **py\_int.js**, **py\_complex.js**, **py\_dict.js**, **py\_list.js**, **py\_string.js**, **py\_set.js** : implements the matching Python classes
- **py\_dom.js** : interaction with the HTML document (DOM)

### More on translation and running

Translation and run of a Brython script by **py2js.js** goes through the following steps :
<ol>
<li>syntax analysis and tree building

  This step relies on an automat whose state evolves with the tokens found in the source code
  
  Python code is split into tokens that can have the following types : 

- keyword
- identifier
- literal (string, integer, float)
- operator
- period (.)
- colon (:)
- semi colon (;)
- parenthesis / bracket / curly brace
- assignment (equal sign =)
- decorator (@)
- end of line

For each token, a call to the function _$transition()_ is performed, it returns a new state depending on the current state and the token

Each instruction in the source code matches a node in the tree (an instance of class _$Node_). If a line holds more than one instruction separated by  ":" (`def foo(x):return x`) or by ";" (`x=1;print(x)`), as many nodes are created for this line

Each syntax element (identifier, function call, expression, operator...) is handled by a class : see in the source code of  **py2js.js** between `function $AbstractExprCtx` and `function $UnaryCtx`

In this step, errors can be reported : 

- syntax errors
- indentation errors
- unterminated string literals
- unbalanced parenthesis / brackets / curly braces
- illegal character
- Python keyword not handled by Brython

<li>Transforming the tree

For some elements of the Python syntax, the tree representing the source code has to be modified (add branches) before starting the translation into Javascript. This is done by recursive calls to the method `transform()` from the top of the tree

For instance, in the first step the Python code `assert _condition_` yields a single branch of the tree. The second step transforms it into a branch `if not _condition_` and adds a child branch with `raise AssertionError`

The elements that must be transformed this way are : `assert`, chained (`x=y=0`) and multiple (`x,y=1,2`) assignments, `class, def, except, for, try`

This step is also used to store the variables declared by `global`

<li>Running Javascript code

At runtime the generated script can use :

- the built-in classes defined in _py\_object.js, py\_dict.js, py\_string.js, py\_list.js, py\_set.js, py\_dom.js_
- internal functions, not accessible from Python (their name always starts with $) ; most of them are defined in _$py\_utils.js_. The most important are :
- 
 - _$JS2Py_ : takes a single argument and returns :
  - the argument unchanged if it is a type handled by Brython (i.e. if it has an attribute _\_\_class\_\__)
  - an instance of DOMObject (respectively DOMEvent) if the argument is a DOM object (resp. event)
  - an instance of JSObject "wrapping" the argument in the other cases

 - _$MakeArgs_ called at the beginning of each function if its signature has at least one argument. It builds a namespace based on the function arguments, calling the function _$JS2Py_ on all arguments
 - _$class\_constructor_ is called for class definition
 - _$list\_comp_ is called for list comprehensions
 - _$lambda_ is called for anonymous functions defined by `lambda`
 - _$test\_expr_ and _$test\_item_ are used in evaluation of conditions combined by `and` or `or`

- the functions defined in the script _py\_import.js_ for management of imports

</ol>
