This is a brief intro for using PScript. For more details see the sections below.
language. All relevant builtins, and the methods of list, dict and str
are supported. Not supported are set, slicing with steps,
imports. Other than that, most Python code should work as expected …
shine through. As a rule of thumb, the code should behave as expected
when correct, but error reporting may not be very Pythonic.
This resulted in the following two main goals:
Code produced by PScript works standalone. Any (PScript-compatible) Python snippet can be converted to JS; you don’t need another JS library to run it.
The purpose of projects like Skulpt or PyJS is to enable full Python support in the browser. This approach will always be plagued by a fundamental limitation: libraries that are not pure Python (like numpy) will not work.
PScript makes writing JS more “Pythonic”. Apart from allowing Python syntax
for loops, classes, etc, all relevant Python builtins are supported,
as well as the methods of list, dict and str. E.g. you can use
The empty list and dict evaluate to false (whereas in JS it’s
isinstance() just works (whereas JS’
Deep comparisons are supported (e.g. for
in), so you can
compare two lists or dicts, or even a structure of nested
lists/dicts. Lists can be combined with the plus operator, and lists
and strings can be repeated with the multiply (star) operator. Class
methods are bound functions.
- JavasScript has a concept of
None), as well as
undefined. Sometimes you may want to use
if x is None or x is undefined: ....
- Accessing an attribute that does not exist will not raise an
AttributeError but yield
undefined. Though this may change.
- Keys in a dictionary are implicitly converted to strings.
- Magic functions on classes (e.g. for operator overloading) do not work.
- Calling an object that starts with a capital letter is assumed to be
a class instantiation (using
new): PScript classes must start with a capital letter, and any other callables must not.
- A function can accept keyword arguments if it has a
**kwargsparameter or named arguments after
*args. Passing keywords to a function that does not handle keyword arguments might result in confusing errors.
- Divide by zero results in inf instead of raising ZeroDivisionError.
PScript is valid Python¶
Other than e.g. RapydScript, PScript is valid Python. This allows
creating modules that are a mix of real Python and PScript. You can easily
write code that runs correctly both as Python and PScript, and
be included where needed (e.g. for performance).
PScript’s compiler is written in Python. Perhaps PScript can at some point compile itself, so that it becomes possible to define PScript inside HTML documents.
There are things you can do, which you cannot do in Python:
Faster than CPython, and significantly faster than e.g. Brython.
Nevertheless, the overhead to realize the more Pythonic behavior can
have a negative impact on performance in tight loops (in comparison to
writing the JS by hand). The recommended approach is to write
RawJS) if necessary.
Using PSCRIPT_OVERLOAD to increase performance¶
To use this feature, write
PSCRIPT_OVERLOAD = False. Any code that
follows will not be subject to overloading. This parser setting can
only be used inside a function and applies only to (the scope of) that
function (i.e. not to functions defined inside that function nor any
outer scope). If needed, overloading can also be enabled again by
PSCRIPT_OVERLOAD = True.
Things that are no longer overloaded:
- The add operator (
+), so list concatenation cannot be done with
- The multiply operator (
*), so repeating a list or string cannot be done with
- The equals operator (
==), so deep comparisons of tuples/lists and dicts does not work.
- The implicit truthy operator (as e.g. used in an if-statement),
so empty tuples/lists and dicts evaluate to True. Note that functions like
any()still use the overloaded truthy.
This is an overview of the language features that PScript supports/lacks.
Not currently supported:
- import (maybe we should translate an import to
setclass (JS has no set, but we could create one?)
- slicing with steps (JS does not support this)
- Generators, i.e.
yield(not widely supported in JS)
- numbers, strings, lists, dicts (the latter become JS arrays and objects)
- operations: binary, unary, boolean, power, integer division,
- comparisons (
- tuple packing and unpacking
- basic string formatting
- slicing with start end end (though not with step)
- if-statements and single-line if-expressions
- while-loops and for-loops supporting continue, break, and else-clauses
- for-loops using
- for-loop over arrays
- for-loop over dict/object using
- function calls can have
- function defs can have default arguments and
- function calls/defs can use keyword arguments and
**kwargs, but use with care (see caveats).
- lambda expressions
- list comprehensions
- classes, with (single) inheritance, and the use of
- raising and catching exceptions, assertions
- creation of “modules”
- globals / nonlocal
withstatement (no equivalent in JS)
- double underscore name mangling
Supported Python conveniences:
- use of
selfis translated to
isinstance()Just Works (for primitive types as well as user-defined classes)
- an empty list or dict evaluates to False as in Python.
- all Python builtin functions that make sense in JS are supported: isinstance, issubclass, callable, hasattr, getattr, setattr, delattr, print, len, max, min, chr, ord, dict, list, tuple, range, pow, sum, round, int, float, str, bool, abs, divmod, all, any, enumerate, zip, reversed, sorted, filter, map.
- all methods of list, dict and str are supported (except a few string methods: encode, format_map, isprintable, maketrans).
- the default return value of a function is
- list concatenation using the plus operator, and list/str repeating using the star operator.
- deep comparisons.
- class methods are bound functions (i.e.
thisis fixed to the instance).
- functions that are defined in another function (a.k.a closures) that do not have self/this as a first argument, are bound the the same instance as the function in which it is defined.
The PScript package provides a few other “utilities” to deal with JS code, such as renaming function/class definitions, and creating JS modules (AMD, UMD, etc.).