• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..01-Sep-2021-

doc/H01-Sep-2021-1,374835

lib/H03-May-2022-

LICENSEH A D01-Sep-2021453 149

README.rstH A D01-Sep-20215.5 KiB197141

TODO.rstH A D01-Sep-20211.1 KiB4736

README.rst

1What
2====
3
4
5
6Syntax
7------
8
9* Lambdas and ternaries should be parsed but are not implemented (in
10  the evaluator)
11* Only floats are implemented, ``int`` literals are parsed as floats.
12* Octal and hexadecimal literals are not implemented
13* Srings are backed by JavaScript strings and probably behave like
14  ``unicode`` more than like ``str``
15* Slices don't work
16
17Builtins
18--------
19
20``py.js`` currently implements the following builtins:
21
22``type``
23    Restricted to creating new types, can't be used to get an object's
24    type (yet)
25
26``None``
27
28``True``
29
30``False``
31
32``NotImplemented``
33    Returned from rich comparison methods when the comparison is not
34    implemented for this combination of operands. In ``py.js``, this
35    is also the default implementation for all rich comparison methods.
36
37``issubclass``
38
39``object``
40
41``bool``
42    Does not inherit from ``int``, since ``int`` is not currently
43    implemented.
44
45``float``
46
47``str``
48
49``tuple``
50    Constructor/coercer is not implemented, only handles literals
51
52``list``
53    Same as tuple (``list`` is currently an alias for ``tuple``)
54
55``dict``
56    Implements trivial getting, setting and len, nothing beyond that.
57
58Note that most methods are probably missing from all of these.
59
60Data model protocols
61--------------------
62
63``py.js`` currently implements the following protocols (or
64sub-protocols) of the `Python 2.7 data model
65<>`_:
66
67Rich comparisons
68    Pretty much complete (including operator fallbacks), although the
69    behavior is currently undefined if an operation does not return
70    either a ``py.bool`` or ``NotImplemented``.
71
72    ``__hash__`` is supported (and used), but it should return **a
73    javascript string**. ``py.js``'s dict build on javascript objects,
74    reimplementing numeral hashing is worthless complexity at this
75    point.
76
77Boolean conversion
78    Implementing ``__nonzero__`` should work.
79
80Customizing attribute access
81    Protocols for getting and setting attributes (including new-style
82    extension) fully implemented but for ``__delattr__`` (since
83    ``del`` is a statement)
84
85Descriptor protocol
86    As with attributes, ``__delete__`` is not implemented.
87
88Callable objects
89    Work, although the handling of arguments isn't exactly nailed
90    down. For now, callables get two (javascript) arguments ``args``
91    and ``kwargs``, holding (respectively) positional and keyword
92    arguments.
93
94    Conflicts are *not* handled at this point.
95
96Collections Abstract Base Classes
97    Container is the only implemented ABC protocol (ABCs themselves
98    are not currently implemented) (well technically Callable and
99    Hashable are kind-of implemented as well)
100
101Numeric type emulation
102    Operators are implemented (but not tested), ``abs``, ``divmod``
103    and ``pow`` builtins are not implemented yet. Neither are ``oct``
104    and ``hex`` but I'm not sure we care (I'm not sure we care about
105    ``pow`` or even ``divmod`` either, for that matter)
106
107Utilities
108---------
109
110``py.js`` also provides (and exposes) a few utilities for "userland"
111implementation:
112
113``def``
114    Wraps a native javascript function into a ``py.js`` function, so
115    that it can be called from native expressions.
116
117    Does not ensure the return types are type-compatible with
118    ``py.js`` types.
119
120    When accessing instance methods, ``py.js`` automatically wraps
121    these in a variant of ``py.def``, to behave as Python's (bound)
122    methods.
123
124Why
125===
126
127Originally, to learn about Pratt parsers (which are very, very good at
128parsing expressions with lots of infix or mixfix symbols). The
129evaluator part came because "why not" and because I work on a product
130with the "feature" of transmitting Python expressions (over the wire)
131which the client is supposed to evaluate.
132
133How
134===
135
136At this point, only three steps exist in ``py.js``: tokenizing,
137parsing and evaluation. It is possible that a compilation step be
138added later (for performance reasons).
139
140To evaluate a Python expression, the caller merely needs to call
141`py.eval`_. `py.eval`_ takes a mandatory Python
142expression to evaluate (as a string) and an optional context, for the
143substitution of the free variables in the expression::
144
145    > py.eval("type in ('a', 'b', 'c') and foo", {type: 'c', foo: true});
146    true
147
148This is great for one-shot evaluation of expressions. If the
149expression will need to be repeatedly evaluated with the same
150parameters, the various parsing and evaluation steps can be performed
151separately: `py.eval`_ is really a shortcut for sequentially calling
152`py.tokenize`_, `py.parse`_ and `py.evaluate`_.
153
154API
155===
156
157.. _py.eval:
158
159``py.eval(expr[, context])``
160    "Do everything" function, to use for one-shot evaluation of a
161    Python expression: it will internally handle the tokenizing,
162    parsing and actual evaluation of the Python expression without
163    having to perform these separately.
164
165    ``expr``
166        Python expression to evaluate
167    ``context``
168        context dictionary holding the substitutions for the free
169        variables in the expression
170
171.. _py.tokenize:
172
173``py.tokenize(expr)``
174    ``expr``
175        Python expression to tokenize
176
177.. _py.parse:
178
179``py.parse(tokens)``
180    Parses a token stream and returns an abstract syntax tree of the
181    expression (if the token stream represents a valid Python
182    expression).
183
184    A parse tree is stateless and can be memoized and used multiple
185    times in separate evaluations.
186
187    ``tokens``
188         stream of tokens returned by `py.tokenize`_
189
190.. _py.evaluate:
191
192``py.evaluate(ast[, context])``
193    ``ast``
194        The output of `py.parse`_
195    ``context``
196        The evaluation context for the Python expression.
197