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