Pythia Javascript Backend

old wiki page

PythonJS Runtime

If you include in your script the line from runtime import *, the translator will include the helper functions and builtins that emulate a subset of Python's features, builtins and data types.

Operator Overloading

To use operator overloading you need to be explicit when you are using it. You can also use with oo:

with operator_overloading:
    a = [1,2]
    a += [3,4]
    b = a + [5.6]

Examples

  • https://github.com/rusthon/Rusthon/blob/master/examples/hello_javascript.md
  • https://github.com/rusthon/Rusthon/blob/master/examples/javascript_syntax.md
  • https://github.com/rusthon/Rusthon/blob/master/examples/hello_angular.md
  • https://github.com/rusthon/Rusthon/blob/master/examples/hello_peerjs.md
  • https://github.com/rusthon/Rusthon/blob/master/examples/hello_rapydscript.md
  • https://github.com/rusthon/Rusthon/blob/master/examples/hello_threejs.md
  • https://github.com/rusthon/Rusthon/blob/master/examples/javascript_webworkers.md

Classes

    class A:
        def __init__(self, x,y,z):
            self.x = x
            self.y = y
            self.z = z

        def foo(self, w):
            return self.x + w

javascript

    A = function(x, y, z) {
      A.__init__(this, x,y,z);
    }

    A.prototype.__init__ = function(x, y, z) {
      this.x=x;
      this.y=y;
      this.z=z;
    }
    A.__init__ = function () { return A.prototype.__init__.apply(arguments[0], Array.prototype.slice.call(arguments,1)) };

    A.prototype.foo = function(w) {
      return (this.x + w);
    }
    A.foo = function () { return A.prototype.foo.apply(arguments[0], Array.prototype.slice.call(arguments,1)) };

Method Overrides

In the example above, you might be wondering why in the JavaScript translation, is the class A constructor calling A.__init__(this, x,y,z), and why is the __init__ method assigned A.prototype and then wrapped and assigned to A.__init__. This is done so that subclasses are able to override their parent's methods, but still have a way of calling them, an example that subclasses A will make this more clear.

    class B( A ):
        def __init__(self, w):
            A.__init__(self, 10, 20, 30)
            self.w = w

javascript

    B = function(w) {
      B.__init__(this, w);
    }

    B.prototype.__init__ = function(w) {
      A.__init__(this,10,20,30);
      this.w=w;
    }
    B.__init__ = function () { return B.prototype.__init__.apply(arguments[0], Array.prototype.slice.call(arguments,1)) };

    for (var n in A.prototype) {  if (!(n in B.prototype)) {    B.prototype[n] = A.prototype[n]  }};

The above output Javascript shows how the constructor for B calls B.__init__ which then calls B.prototype.__init__. B.prototype.__init__ calls A.__init__ passing this as the first argument. This emulates in JavaScript how unbound methods work in Python. When using the Dart backend, the output is different but the concept is the same - static "class methods" are created that implement the method body, the instance methods are just short stubs that call the static "class methods".

WebWorkers

Using webworkers directly, straight sucks. PythonJS hides all that shit, so you can write clear code with a syntax inspired by Golang. This syntax A <- B, sends data to A which is an instance that was spawned into the webworker-pool. This syntax N = <- A, gets data from A, note that this appears to be blocking code, but it is actually not (the transpiler transforms it into async code)


with webworker:
    class MyClass:
        def send(self, msg):
            return msg


w = spawn( MyClass() )
w <- 'hello'
w <- 'world'

a = <- w
b = <- w
print a + b

Generator Functions

Functions that use the yield keyword are generator functions. They allow you to quickly write complex iterables. PythonJS supports simple generator functions that have a single for loop, and up to three yield statements. The first yield comes before the for loop, and the final yield comes after the for loop. The compiler will translate your generator function into a simple class with state-machine. This implementation bypasses using the native JavaScript yield keyword, and ensures that your generator function can work in all web browsers.

Instances of the generator function will have a next method. Using a for loop to iterate over a generator function will automatically call its next method.

    def fib(n):
        yield 'hello'
        a, b = 0, 1
        for x in range(n):
            yield a
            a,b = b, a+b
        yield 'world'

    def test():
        for n in fib(20):
            print n

javascript

    fib = function(n) {
      this.n = n;
      this.__head_yield = "hello";
      this.__head_returned = 0;
      var __r_0;
      __r_0 = [0, 1];
      this.a = __r_0[0];
      this.b = __r_0[1];
      this.__iter_start = 0;
      this.__iter_index = 0;
      this.__iter_end = this.n;
      this.__done__ = 0;
    }

    fib.prototype.next = function() {
      if (( this.__head_returned ) == 0) {
        this.__head_returned = 1;
        return this.__head_yield;
      } else {
        if (( this.__iter_index ) < this.__iter_end) {
          __yield_return__ = this.a;
          var __r_1;
          __r_1 = [this.b, (this.a + this.b)];
          this.a = __r_1[0];
          this.b = __r_1[1];
          this.__iter_index += 1
          return __yield_return__;
        } else {
          this.__done__ = 1;
          __yield_return__ = "world";
          return __yield_return__;
        }
      }
    }

    test = function(args, kwargs) {
      var __iterator__, n;
      var n, __generator__;
      __generator__ = new fib(20);
      while(( __generator__.__done__ ) != 1) {
        n = __generator__.next();
        console.log(n);
      }
    }

Inline JavaScript

Use inline(str) to inline javascript code

    inline("var arr = new Array()")
    inline("var ob = new Object()")
    inline("ob['key'] = 'value'")
    if inline("Object.prototype.toString.call( arr ) === '[object Array]'"):
        inline("arr.push('hello world')")
        inline("arr.push( ob )")