├── .gitignore
├── .gitmodules
├── .karma.js
├── .travis.yml
├── README.rst
├── build.py
├── doc
├── build-html.sh
├── environment.yml
└── source
│ ├── conf.py
│ └── index.rst
├── example
├── debugger.gif
├── hello.html
├── hello.py
├── pystone.html
└── pystone.py
├── jaspy
├── __init__.py
├── cli.py
├── converter.py
├── debugger.py
├── event.py
├── interactive.py
├── metadata.py
├── preprocessor.py
├── pydev.py
└── server.py
├── modules
├── _builtins.py
├── _thread.js
├── dom.js
├── greenlet.js
└── time.js
├── notes
└── README.rst
├── package.json
├── readthedocs.yml
├── requirements.txt
├── setup.py
├── spec
├── dict_spec.js
├── executor_spec.js
├── float_spec.js
├── javascripts
│ └── support
│ │ ├── function-bind.js
│ │ └── jasmine.yml
└── spec.js
└── src
├── __init__.js
├── base.js
├── executor.js
├── language
├── __init__.js
├── parser.js
└── tokenizer.js
└── runtime
├── __init__.js
├── base.js
├── bridge.js
├── code.js
├── constants.js
├── core
├── __init__.js
├── bytes.js
├── cell.js
├── dict.js
├── exception.js
├── float.js
├── func.js
├── generator.js
├── int.js
├── iterator.js
├── list.js
├── method.js
├── property.js
├── slice.js
├── str.js
├── traceback.js
├── tuple.js
└── wrapper.js
├── debugger.js
├── dis.js
├── execute.js
├── frame.js
├── future.js
├── module.js
├── object.js
├── python
├── __init__.js
├── bool.js
├── boot.js
├── builtins.js
├── bytes.js
├── dict.js
├── exception.js
├── float.js
├── function.js
├── generator.js
├── helpers.js
├── int.js
├── iterator.js
├── list.js
├── method.js
├── module.js
├── none.js
├── object.js
├── property.js
├── slice.js
├── str.js
├── tuple.js
├── type.js
└── wrapper.js
├── sys.js
├── threading.js
├── type.js
└── vm.js
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | playground
3 | .idea
4 | __pycache__
5 | node_modules
6 | coverage
7 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "libs/BigInteger.js"]
2 | path = libs/biginteger
3 | url = https://github.com/peterolson/BigInteger.js.git
4 | [submodule "libs/text-encoding"]
5 | path = libs/text-encoding
6 | url = https://github.com/inexorabletash/text-encoding
7 | [submodule "libs/siphash-js"]
8 | path = libs/siphash
9 | url = https://github.com/jedisct1/siphash-js.git
10 | [submodule "libs/unicode"]
11 | path = libs/unicode
12 | url = https://github.com/qsantos/unicode.js
13 |
--------------------------------------------------------------------------------
/.karma.js:
--------------------------------------------------------------------------------
1 | module.exports = function (config) {
2 | config.set({
3 | basePath: '',
4 | frameworks: ['jasmine'],
5 | files: [
6 | 'spec/javascripts/support/function-bind.js',
7 | 'build/jaspy.js',
8 | 'spec/*.js'
9 | ],
10 | browsers: ['Firefox'],
11 | singleRun: true,
12 | reporters: ['progress', 'coverage'],
13 | preprocessors: {'build/jaspy.js': ['coverage']},
14 | coverageReporter: {
15 | type: 'lcov',
16 | dir: 'coverage/',
17 | subdir: '.'
18 | },
19 | browserNoActivityTimeout: 60000
20 | });
21 | };
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 | python:
3 | - "3.5"
4 | before_install:
5 | - export DISPLAY=:99.0
6 | - sh -e /etc/init.d/xvfb start
7 | before_script:
8 | - nvm install 0.12
9 | - node --version
10 | - npm --version
11 | - nvm --version
12 | - npm install
13 | script:
14 | - npm build
15 | - npm test
16 | after_success:
17 | - cat ./coverage/lcov.info | ./node_modules/.bin/coveralls
18 | addons:
19 | firefox: latest
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | Jaspy
2 | =====
3 |
4 | |pypi| |build| |coverage| |docs| |gitter|
5 |
6 | Jaspy is a Python VM written entirely from scratch in JavaScript with some unique
7 | features. Jaspy supports multiple threads, comes with an integrated debugger which
8 | offers remote debugging and provides a flexible preprocessor based architecture.
9 | Speed is explicitly not a main goal of this project. Jaspy aims to illustrate how
10 | web programming on the client side could be done by exploring new ways.
11 |
12 |
13 | Features
14 | --------
15 | - **suspendable** interpreter with support for **threading** and greenlets
16 | - integrated **debugger** and interactive remote debugging (CLI, PyCharm, …)
17 | - **flexible** preprocessor based architecture to optimize Jaspy for your needs
18 | - easily **extensible** with native JavaScript modules (time_, dom_, …)
19 | - full support for meta-classes, builtin subclassing and operator overloading
20 | - asynchronous imports and arbitrary-length integers based on BigInteger.js_
21 |
22 | .. _BigInteger.js: https://github.com/peterolson/BigInteger.js
23 | .. _time: https://github.com/koehlma/jaspy/blob/master/modules/time.js
24 | .. _dom: https://github.com/koehlma/jaspy/blob/master/modules/dom.js
25 |
26 | Quickstart
27 | ----------
28 | Jaspy comes with an integrated development server and interactive debugger!
29 |
30 | First install the dependencies, if they are not installed already:
31 |
32 | .. code:: sh
33 |
34 | pip3 install --user -r requirements.txt
35 | pip3 install --user ptpython pygments
36 |
37 | Clone the repository and build the interpreter:
38 |
39 | .. code:: sh
40 |
41 | git clone --recursive https://github.com/koehlma/jaspy.git; cd jaspy
42 | python3 build.py # build the interpreter
43 |
44 | Switch to the example directory and start the server in interactive mode:
45 |
46 | .. code:: sh
47 |
48 | cd example
49 | PYTHONPATH=../ python3 -m jaspy.cli --interactive
50 |
51 | Visit http://localhost:8080/hello.html in your browser and click run:
52 |
53 | .. image:: https://raw.githubusercontent.com/koehlma/jaspy/master/example/debugger.gif
54 | :alt: Jaspy Screencast
55 | :align: center
56 |
57 |
58 | Alternatives
59 | ------------
60 | There are already many other Python-to-JavaScript approaches out there:
61 |
62 | - `Brython `_
63 | - `PyPy.js `_
64 | - `Skulpt `_
65 | - `Batavia `_
66 | - `Pyjs `_
67 | - …
68 |
69 | Most of them are faster than Jaspy but none of them offers the unique features of
70 | Jaspy, which are the fully suspendable interpreter with threading support, the
71 | integrated debugger and the flexible, preprocessor based architecture.
72 |
73 |
74 | Speed
75 | -----
76 | Just to get an impression how slow Jaspy really is!
77 |
78 | +-----------------------------------------------+------------------+
79 | | | pystones/second |
80 | +===============================================+==================+
81 | | Jaspy (enabled Debugger, enabled Threading) | 195 |
82 | +-----------------------------------------------+------------------+
83 | | Jaspy (disabled Debugger, enabled Threading) | 199 |
84 | +-----------------------------------------------+------------------+
85 | | Jaspy (disabled Debugger, disabled Threading) | 206 |
86 | +-----------------------------------------------+------------------+
87 | | Brython | 4184 |
88 | +-----------------------------------------------+------------------+
89 | | PyPy.js (cold) | 41425 |
90 | +-----------------------------------------------+------------------+
91 | | PyPy.js (warm) | 847457 |
92 | +-----------------------------------------------+------------------+
93 |
94 | However this is a somewhat unfair benchmark because no dom manipulation or anything
95 | else browser specific is going on. Surprisingly threading and debugging introduces nearly
96 | no overhead.
97 |
98 |
99 | State
100 | -----
101 | This project is still in an alpha state. The APIs are unstable, it is untested and not
102 | ready for productive use. Some of the features listed above are not yet implemented.
103 |
104 | I started this project in my semester break and now, as the new semester started, I have
105 | much less spare time. Therefore it might take a while until I will be able to invest much
106 | more time into it. However I very welcome all sorts of contributions.
107 |
108 |
109 | Contributions
110 | -------------
111 | If you like the ideas of Jaspy feel free to join, there are many things to do:
112 |
113 | - implement all the batteries-included-builtin stuff of Python
114 | - implement native JS modules for the DOM, JS objects and some Web APIs
115 | - improve the debugger and make it fully compatible to the PyDev protocol
116 | - implement a parser and bytecode compiler in JavaScript
117 | - complete and adjust the implementation of the Python bytecode VM
118 | - support for Apache Cordova (Jaspy for cross platform mobile applications)
119 | - implement a neat UI library on top of Jaspy (using a flexbox based grid)
120 | - implement a just-in-time compiler to speed things up
121 | - add a virtual file system (consider using: `BrowserFS `_)
122 | - … and, of course, your own great ideas and cool features
123 |
124 | Do not hesitate to contribute or ask if there is anything unclear about the code or the
125 | process of contributing in general.
126 |
127 |
128 | Structure
129 | ---------
130 |
131 | :libs: third-party dependencies
132 | :modules: bundled native JavaScript modules
133 | :src: JavaScript source files (need to be preprocessed)
134 | :jaspy: Python server, converter and remote debugger
135 |
136 |
137 | Credits
138 | -------
139 | Many thanks to the `Brython `_ project for the inspiration for
140 | many parts of code of the builtin-classes. Many thanks also to the book `“500 Lines or
141 | Less”`_ which is a good starting point if you want to know how the interpreter works.
142 |
143 | .. _`“500 Lines or Less”`: http://aosabook.org/en/500L/a-python-interpreter-written-in-python.html
144 |
145 |
146 | .. |pypi| image:: https://img.shields.io/pypi/v/jaspy.svg?style=flat-square&label=latest%20version
147 | :target: https://pypi.python.org/pypi/jaspy
148 |
149 | .. |build| image:: https://img.shields.io/travis/koehlma/jaspy/master.svg?style=flat-square&label=build
150 | :target: https://travis-ci.org/koehlma/jaspy
151 |
152 | .. |docs| image:: https://readthedocs.org/projects/jaspy/badge/?version=latest&style=flat-square
153 | :target: https://jaspy.readthedocs.org/en/latest/
154 |
155 | .. |coverage| image:: https://img.shields.io/coveralls/koehlma/jaspy/master.svg?style=flat-square
156 | :target: https://coveralls.io/github/koehlma/jaspy?branch=master
157 |
158 | .. |gitter| image:: https://img.shields.io/badge/gitter-join%20chat-1dce73.svg?style=flat-square
159 | :target: https://gitter.im/koehlma/jaspy
160 |
--------------------------------------------------------------------------------
/build.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, Maximilian Köhl
4 | #
5 | # This program is free software: you can redistribute it and/or modify it under
6 | # the terms of the GNU Lesser General Public License version 3 as published by
7 | # the Free Software Foundation.
8 | #
9 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License along
14 | # with this program. If not, see .
15 |
16 | import argparse
17 | import os
18 |
19 | from jaspy import metadata
20 | from jaspy.converter import convert
21 | from jaspy.preprocessor import process
22 |
23 |
24 | __path__ = os.path.dirname(__file__)
25 | if __path__:
26 | os.chdir(__path__)
27 |
28 |
29 | with open(os.path.join(__path__, 'modules', '_builtins.py')) as builtins:
30 | code = compile(builtins.read(), '', 'exec')
31 | source = convert(code)
32 | builtins_source = 'jaspy.module(%r, %s);' % ('_builtins', source)
33 |
34 |
35 | if __name__ == '__main__':
36 | parser = argparse.ArgumentParser()
37 |
38 | parser.add_argument('--debug', action='store_true', default=False)
39 | parser.add_argument('--debug-instructions', action='store_true', default=False)
40 | # TODO: disable DEBUG_EXCEPTIONS when production ready
41 | parser.add_argument('--debug-exceptions', action='store_true', default=True)
42 | parser.add_argument('--debug-threading', action='store_true', default=False)
43 |
44 | parser.add_argument('--exclude-bigint', action='store_true', default=False)
45 | parser.add_argument('--exclude-siphash', action='store_true', default=False)
46 |
47 | parser.add_argument('--include-encoding', action='store_true', default=False)
48 |
49 | parser.add_argument('--disable-debugger', action='store_true', default=False)
50 | parser.add_argument('--disable-threading', action='store_true', default=False)
51 |
52 | parser.add_argument('--threading-limit', type=int, default=5000)
53 |
54 | parser.add_argument('--modules', nargs='*')
55 |
56 | arguments = parser.parse_args()
57 |
58 | libs = []
59 | if not arguments.exclude_bigint:
60 | libs.append('biginteger/BigInteger.js')
61 | if not arguments.exclude_siphash:
62 | libs.append('siphash/lib/siphash.js')
63 | if arguments.include_encoding:
64 | libs.append('text-encoding/lib/encoding.js')
65 |
66 | namespace = {
67 | 'DEBUG': arguments.debug,
68 | 'DEBUG_INSTRUCTIONS': arguments.debug_instructions,
69 | 'DEBUG_EXCEPTIONS': arguments.debug_exceptions,
70 | 'DEBUG_THREADING': arguments.debug_threading,
71 |
72 | 'ENABLE_DEBUGGER': not arguments.disable_debugger,
73 | 'ENABLE_THREADING': not arguments.disable_threading,
74 |
75 | 'ENABLE_ASSERTIONS': True,
76 |
77 | 'THREADING_LIMIT': arguments.threading_limit,
78 |
79 | 'UNICODE_SUPPORT': True,
80 |
81 | 'modules': arguments.modules or [],
82 |
83 | 'metadata': metadata,
84 |
85 | 'libs': libs,
86 |
87 | '_builtins': builtins_source
88 | }
89 |
90 | if not os.path.exists('build'):
91 | os.mkdir('build')
92 |
93 | with open('build/jaspy.js', 'w') as output:
94 | output.write(process('src/__init__.js', namespace))
95 |
96 |
--------------------------------------------------------------------------------
/doc/build-html.sh:
--------------------------------------------------------------------------------
1 | #/bin/bash
2 |
3 | sphinx-build -b html source build/html
--------------------------------------------------------------------------------
/doc/environment.yml:
--------------------------------------------------------------------------------
1 | name: py35
2 | dependencies:
3 | - openssl=1.0.2g=0
4 | - pip=8.1.1=py35_0
5 | - python=3.5.1=0
6 | - readline=6.2=2
7 | - setuptools=20.3=py35_0
8 | - sqlite=3.9.2=0
9 | - tk=8.5.18=0
10 | - wheel=0.29.0=py35_0
11 | - xz=5.0.5=1
12 | - zlib=1.2.8=0
13 | - pip:
14 | - aiohttp>=0.21.5
--------------------------------------------------------------------------------
/doc/source/conf.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 |
4 | # Copyright (C) 2016, Maximilian Köhl
5 | #
6 | # This program is free software: you can redistribute it and/or modify it under
7 | # the terms of the GNU Lesser General Public License version 3 as published by
8 | # the Free Software Foundation.
9 | #
10 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY
11 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
12 | # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
13 | #
14 | # You should have received a copy of the GNU Lesser General Public License along
15 | # with this program. If not, see .
16 |
17 | import os
18 | import sys
19 |
20 | __dir__ = os.path.dirname(__file__)
21 | sys.path.insert(0, os.path.join(__dir__, '..', '..'))
22 |
23 | from jaspy import metadata
24 |
25 | extensions = [
26 | 'sphinx.ext.autodoc',
27 | 'sphinx.ext.doctest',
28 | 'sphinx.ext.intersphinx',
29 | 'sphinx.ext.todo',
30 | 'sphinx.ext.mathjax',
31 | 'sphinx.ext.viewcode',
32 | ]
33 |
34 | templates_path = ['_templates']
35 |
36 | source_suffix = '.rst'
37 |
38 | master_doc = 'index'
39 |
40 | project = 'Jaspy'
41 | copyright = '2016, Maximilian Köhl'
42 | author = 'Maximilian Köhl'
43 |
44 | version = metadata.__version__
45 | release = metadata.__version__
46 |
47 | language = None
48 |
49 | exclude_patterns = []
50 |
51 | pygments_style = 'sphinx'
52 |
53 | todo_include_todos = False
54 |
55 | html_static_path = ['_static']
56 |
57 | intersphinx_mapping = {'python': ('https://docs.python.org/3.5', None)}
58 |
--------------------------------------------------------------------------------
/doc/source/index.rst:
--------------------------------------------------------------------------------
1 | .. currentmodule:: jaspy
2 |
3 | Jaspy Documentation
4 | ===================
5 |
6 |
7 | Indices and tables
8 | ==================
9 |
10 | * :ref:`genindex`
11 | * :ref:`modindex`
12 | * :ref:`search`
13 |
14 |
--------------------------------------------------------------------------------
/example/debugger.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/koehlma/jaspy/585c11d135f565c8a19f34f9e2fb6eeb22328405/example/debugger.gif
--------------------------------------------------------------------------------
/example/hello.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Jaspy — Hello!
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/example/hello.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, Maximilian Köhl
4 | #
5 | # This program is free software: you can redistribute it and/or modify it under
6 | # the terms of the GNU Lesser General Public License version 3 as published by
7 | # the Free Software Foundation.
8 | #
9 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License along
14 | # with this program. If not, see .
15 |
16 | import sys
17 | import time
18 |
19 | import _thread
20 |
21 | import dom
22 |
23 |
24 | # command line arguments
25 | print('command line arguments:')
26 | print(sys.argv)
27 |
28 | print('Hello ', sys.argv[1])
29 |
30 |
31 | for x in ['abc', 1, 2, True, None]:
32 | print(x)
33 |
34 |
35 | # dom manipulation
36 | p = dom.Element('p')
37 | p.text = 'Hello ' + sys.argv[1]
38 | p.css('background', 'black')
39 | p.css('color', 'white')
40 |
41 | dom.get_body().append(p)
42 |
43 |
44 | # exceptions
45 | def recursion(level=10):
46 | if level < 0:
47 | raise Exception('example exception')
48 | else:
49 | recursion(level - 1)
50 |
51 | try:
52 | recursion()
53 | except Exception:
54 | print('exception caught!')
55 |
56 |
57 | # event listeners
58 | def on_click(element):
59 | print('click on element', element)
60 |
61 |
62 | button = dom.Element('button')
63 | button.text = 'Click Me!'
64 | button.register_listener('click', on_click)
65 | button.css('background', 'white')
66 | button.css('color', 'black')
67 |
68 | dom.get_body().append(button)
69 |
70 | print(hash('abc'))
71 |
72 | print(any([0, False, None]))
73 |
74 | for x, y in zip([1, 2, 3], ('a', 'b', 'c')):
75 | print('zip', x, y)
76 |
77 | print(sum([1, 2, 4]))
78 | print([item for item in enumerate(('a', 'b', 'c'))])
79 |
80 | example_dict = {
81 | '123': 'abc',
82 | 123: 'xyz'
83 | }
84 |
85 | if example_dict['123'] == 'abc' and example_dict[123] == 'xyz':
86 | for key, value in example_dict.items():
87 | print(key, value)
88 | if 123 in example_dict and True not in example_dict:
89 | del example_dict['123']
90 | try:
91 | print('Error:', example_dict['123'])
92 | except KeyError:
93 | print('Dictionaries are working!')
94 |
95 |
96 | # multiple threads
97 | def button_animation():
98 | state = True
99 | while True:
100 | # this also works without time sleep because jaspy provides preemptive
101 | # multitasking but it would produce an enormous load
102 | time.sleep(0.5)
103 | if state:
104 | button.css('background', 'black')
105 | button.css('color', 'white')
106 | state = False
107 | else:
108 | button.css('background', 'white')
109 | button.css('color', 'black')
110 | state = True
111 |
112 |
113 | thread = _thread.start_new_thread(button_animation)
114 |
--------------------------------------------------------------------------------
/example/pystone.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Jaspy — PyStone
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/jaspy/__init__.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, Maximilian Köhl
4 | #
5 | # This program is free software: you can redistribute it and/or modify it under
6 | # the terms of the GNU Lesser General Public License version 3 as published by
7 | # the Free Software Foundation.
8 | #
9 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License along
14 | # with this program. If not, see .
15 |
16 | from .server import Server
17 |
--------------------------------------------------------------------------------
/jaspy/converter.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, Maximilian Köhl
4 | #
5 | # This program is free software: you can redistribute it and/or modify it under
6 | # the terms of the GNU Lesser General Public License version 3 as published by
7 | # the Free Software Foundation.
8 | #
9 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License along
14 | # with this program. If not, see .
15 |
16 | import argparse
17 | import dis
18 | import os.path
19 | import types
20 |
21 |
22 | def convert(const):
23 | js = []
24 | if const is None or isinstance(const, bool):
25 | js.append('jaspy.%r' % const)
26 | elif isinstance(const, int):
27 | js.append('jaspy.Int.pack(%r)' % const)
28 | elif isinstance(const, float):
29 | js.append('jaspy.Float.pack(%r)' % const)
30 | elif isinstance(const, str):
31 | js.append('jaspy.Str.pack(%r)' % const)
32 | elif isinstance(const, bytes):
33 | js.append('jaspy.pack_bytes(%r)' % ', '.join(map(int, const)))
34 | elif isinstance(const, tuple):
35 | js.append('jaspy.pack_tuple([%s])' % ', '.join(map(convert, const)))
36 | elif isinstance(const, types.CodeType):
37 | js.append('(new jaspy.PythonCode(%s, {' % repr(const.co_code)[1:])
38 | js.append('name: %r,' % const.co_name)
39 | js.append('filename: %r,' % const.co_filename)
40 | js.append('constants: [%s],' % ', '.join(map(convert, const.co_consts)))
41 | js.append('flags: %r,' % const.co_flags)
42 | js.append('names: [%s],' % ', '.join(map(repr, const.co_names)))
43 | js.append('stacksize: %r,' % const.co_stacksize)
44 | js.append('argcount: %r,' % const.co_argcount)
45 | js.append('kwargcount: %r,' % const.co_kwonlyargcount)
46 | js.append('varnames: [%s],' % ', '.join(map(repr, const.co_varnames)))
47 | js.append('freevars: [%s],' % ', '.join(map(repr, const.co_freevars)))
48 | js.append('cellvars: [%s],' % ', '.join(map(repr, const.co_cellvars)))
49 | js.append('firstline: %r,' % const.co_firstlineno)
50 | js.append('lnotab: \'%s\'' % repr(const.co_lnotab)[2:-1])
51 | js.append('}))')
52 | else:
53 | raise TypeError('invalid type of constant', const)
54 | return '(' + ''.join(js) + ')'
55 |
56 |
57 | def disassemble(const):
58 | dis.dis(const)
59 | for const in const.co_consts:
60 | if isinstance(const, types.CodeType):
61 | disassemble(const)
62 |
63 |
64 | def compile_and_convert(filename):
65 | with open(filename, 'r') as source_file:
66 | source = source_file.read()
67 | code = compile(source, filename, 'exec')
68 | return convert(code)
69 |
70 |
71 | def main():
72 | parser = argparse.ArgumentParser()
73 | parser.add_argument('module', type=argparse.FileType('r'))
74 | parser.add_argument('--debug', default=False, action='store_true')
75 |
76 | arguments = parser.parse_args()
77 |
78 | filename = os.path.basename(arguments.module.name)
79 | code = compile(arguments.module.read(), filename, 'exec')
80 | source = convert(code)
81 | name = os.path.basename(arguments.module.name).partition('.')[0]
82 |
83 | with open(arguments.module.name + '.js', 'w') as output:
84 | output.write('jaspy.module(%r, %s);' % (name, source))
85 |
86 | if arguments.debug:
87 | disassemble(code)
88 |
89 |
90 | if __name__ == '__main__':
91 | main()
92 |
--------------------------------------------------------------------------------
/jaspy/debugger.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, Maximilian Köhl
4 | #
5 | # This program is free software: you can redistribute it and/or modify it under
6 | # the terms of the GNU Lesser General Public License version 3 as published by
7 | # the Free Software Foundation.
8 | #
9 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License along
14 | # with this program. If not, see .
15 |
16 | import asyncio
17 | import enum
18 | import itertools
19 | import json
20 |
21 | import aiohttp
22 |
23 | from . import converter
24 | from .event import Event
25 |
26 |
27 | class Commands(enum.Enum):
28 | RUN = 'run'
29 |
30 | THREAD_SUSPEND = 'suspend_thread'
31 | THREAD_RESUME = 'resume_thread'
32 | THREAD_KILL = 'kill_thread'
33 |
34 | STEP_OVER = 'step_over'
35 | STEP_INTO = 'step_into'
36 | STEP_OUT = 'step_out'
37 |
38 | GET_THREADS = 'get_threads'
39 | GET_LOCALS = 'get_locals'
40 |
41 | ADD_BREAK = 'add_break'
42 | REMOVE_BREAK = 'remove_break'
43 |
44 | RUN_IN_FRAME = 'run_in_frame'
45 | RUN_IN_THREAD = 'run_in_thread'
46 |
47 | ADD_EXCEPTION_BREAK = 'add_exception_break'
48 | REMOVE_EXCEPTION_BREAK = 'remove_exception_break'
49 |
50 | JS_EVAL = 'js_eval'
51 | JS_DEBUGGER = 'js_debugger'
52 |
53 | def make(self, sequence_number, *arguments):
54 | return json.dumps({'cmd': self.value, 'seq': sequence_number, 'args': arguments})
55 |
56 |
57 | class Events(enum.Enum):
58 | HELLO = 'hello'
59 |
60 | SUCCESS = 'success'
61 | ERROR = 'error'
62 |
63 | RUNNING = 'running'
64 |
65 | THREAD_CREATED = 'thread_created'
66 | THREAD_SUSPENDED = 'thread_suspended'
67 | THREAD_RESUMED = 'thread_resumed'
68 | THREAD_FINISHED = 'thread_finished'
69 |
70 | BREAK_ADDED = 'break_added'
71 | BREAK_REMOVED = 'break_removed'
72 |
73 | EXCEPTION_BREAK_ADDED = 'exception_break_added'
74 | EXCEPTION_BREAK_REMOVED = 'exception_break_removed'
75 |
76 | THREADS = 'threads'
77 | LOCALS = 'locals'
78 |
79 | CONSOLE_LOG = 'console_log'
80 | CONSOLE_ERROR = 'console_error'
81 |
82 |
83 | sessions = []
84 |
85 | session_created = Event()
86 | session_closed = Event()
87 |
88 |
89 | class Debugger:
90 | def __init__(self, websocket):
91 | self.websocket = websocket
92 |
93 | self.on_hello = Event()
94 |
95 | self.on_success = Event()
96 | self.on_error = Event()
97 |
98 | self.on_running = Event()
99 |
100 | self.on_thread_created = Event()
101 | self.on_thread_suspended = Event()
102 | self.on_thread_resumed = Event()
103 | self.on_thread_finished = Event()
104 |
105 | self.on_break_added = Event()
106 | self.on_break_removed = Event()
107 |
108 | self.on_exception_break_added = Event()
109 | self.on_exception_break_removed = Event()
110 |
111 | self.on_threads = Event()
112 | self.on_locals = Event()
113 |
114 | self.on_console_log = Event()
115 | self.on_console_error = Event()
116 |
117 | self.events = {
118 | Events.HELLO: self.on_hello,
119 |
120 | Events.SUCCESS: self.on_success,
121 | Events.ERROR: self.on_error,
122 |
123 | Events.RUNNING: self.on_running,
124 |
125 | Events.THREAD_CREATED: self.on_thread_created,
126 | Events.THREAD_SUSPENDED: self.on_thread_suspended,
127 | Events.THREAD_RESUMED: self.on_thread_resumed,
128 | Events.THREAD_FINISHED: self.on_thread_finished,
129 |
130 | Events.BREAK_ADDED: self.on_break_added,
131 | Events.BREAK_REMOVED: self.on_break_removed,
132 |
133 | Events.EXCEPTION_BREAK_ADDED: self.on_exception_break_added,
134 | Events.EXCEPTION_BREAK_REMOVED: self.on_exception_break_added,
135 |
136 | Events.THREADS: self.on_threads,
137 | Events.LOCALS: self.on_locals,
138 |
139 | Events.CONSOLE_LOG: self.on_console_log,
140 | Events.CONSOLE_ERROR: self.on_console_error
141 | }
142 |
143 | self.pending = {}
144 |
145 | self.sequence_counter = itertools.count(1, 2)
146 |
147 | def send(self, command, *arguments, sequence_number=None):
148 | if sequence_number is None:
149 | sequence_number = next(self.sequence_counter)
150 | self.websocket.send_str(command.make(sequence_number, *arguments))
151 | return sequence_number
152 |
153 | def run(self):
154 | self.send(Commands.RUN)
155 |
156 | def suspend_thread(self, thread_id):
157 | self.send(Commands.THREAD_SUSPEND, thread_id)
158 |
159 | def resume_thread(self, thread_id):
160 | self.send(Commands.THREAD_RESUME, thread_id)
161 |
162 | def kill_thread(self, thread_id):
163 | self.send(Commands.THREAD_KILL, thread_id)
164 |
165 | def step_over(self, thread_id):
166 | self.send(Commands.STEP_OVER, thread_id)
167 |
168 | def step_into(self, thread_id):
169 | self.send(Commands.STEP_INTO, thread_id)
170 |
171 | def step_out(self, thread_id):
172 | self.send(Commands.STEP_OUT, thread_id)
173 |
174 | def get_threads(self):
175 | self.send(Commands.GET_THREADS)
176 |
177 | def add_break(self, filename, line, condition=None, expression=None):
178 | self.send(Commands.ADD_BREAK, filename, line, condition, expression)
179 |
180 | def remove_break(self, filename, line):
181 | self.send(Commands.REMOVE_BREAK, filename, line)
182 |
183 | def add_exception_break(self, name, on_termination=False, on_raise=True):
184 | self.send(Commands.ADD_EXCEPTION_BREAK, name, on_termination, on_raise)
185 |
186 | def remove_exception_break(self, name):
187 | self.send(Commands.REMOVE_EXCEPTION_BREAK, name)
188 |
189 | def js_eval(self, source):
190 | self.send(Commands.JS_EVAL, source)
191 |
192 | def js_debugger(self):
193 | self.send(Commands.JS_DEBUGGER)
194 |
195 | def exec_in_frame(self, thread_id, frame_id, source):
196 | code = converter.convert(compile(source, '', 'exec'))
197 | return self.send(Commands.RUN_IN_FRAME, thread_id, frame_id, code)
198 |
199 | def eval_in_frame(self, thread_id, frame_id, source):
200 | code = converter.convert(compile(source, '', 'eval'))
201 | return self.send(Commands.RUN_IN_FRAME, thread_id, frame_id, code)
202 |
203 | def run_in_thread(self, source):
204 | code = converter.convert(compile(source, '', 'exec'))
205 | return self.send(Commands.RUN_IN_THREAD, code)
206 |
207 | def get_locals(self, thread_id, frame_id):
208 | seq = self.send(Commands.GET_LOCALS, thread_id, frame_id)
209 | self.pending[seq] = Event()
210 | return self.pending[seq]
211 |
212 | async def debug(self):
213 | sessions.append(self)
214 | try:
215 | session_created.emit(self)
216 | async for message in self.websocket:
217 | if message.tp == aiohttp.MsgType.text:
218 | data = json.loads(message.data)
219 | seq = int(data['seq'])
220 | if seq in self.pending:
221 | self.pending[seq].emit(data['event'], data['args'])
222 | del self.pending[seq]
223 | event = self.events[Events(data['event'])]
224 | event.emit(self, seq, *data['args'])
225 | finally:
226 | sessions.remove(self)
227 | session_closed.emit(self)
228 |
--------------------------------------------------------------------------------
/jaspy/event.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, Maximilian Köhl
4 | #
5 | # This program is free software: you can redistribute it and/or modify it under
6 | # the terms of the GNU Lesser General Public License version 3 as published by
7 | # the Free Software Foundation.
8 | #
9 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License along
14 | # with this program. If not, see .
15 |
16 |
17 | class Event:
18 | def __init__(self):
19 | self.listeners = []
20 |
21 | def __iadd__(self, listener):
22 | self.listeners.append(listener)
23 | return self
24 |
25 | def __isub__(self, listener):
26 | self.listeners.remove(listener)
27 | return self
28 |
29 | def emit(self, *arguments, **keywords):
30 | for listener in self.listeners:
31 | listener(*arguments, **keywords)
32 |
--------------------------------------------------------------------------------
/jaspy/interactive.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, Maximilian Köhl
4 | #
5 | # This program is free software: you can redistribute it and/or modify it under
6 | # the terms of the GNU Lesser General Public License version 3 as published by
7 | # the Free Software Foundation.
8 | #
9 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License along
14 | # with this program. If not, see .
15 |
16 | import asyncio
17 | import os
18 |
19 | from pygments.token import Token
20 |
21 | from prompt_toolkit.styles import style_from_dict
22 | from prompt_toolkit.shortcuts import print_tokens
23 |
24 | from ptpython.repl import embed
25 |
26 | from . import debugger
27 |
28 |
29 | INFO = Token.Info
30 | SUCCESS = Token.Success
31 | WARNING = Token.Warning
32 | ERROR = Token.Error
33 |
34 | style = style_from_dict({
35 | Token.Info: '#5555FF',
36 | Token.Success: '#00FF00',
37 | Token.Warning: '#FF5500',
38 | Token.Error: '#FF0000',
39 | Token.Trace: '#888888',
40 | Token.Variable: '#FF8888'
41 | }, include_defaults=True)
42 |
43 |
44 | FRAME_TEMPLATE = ('| Frame {} [{name}]:{linesep}'
45 | '| File: {file}{linesep}'
46 | '| Line: {line}{linesep}')
47 |
48 | VARIABLE_HEADER = 'Received variable {} from thread {} frame {}!'
49 |
50 |
51 | def format_variable_path(path):
52 | if not path:
53 | return ''
54 | parts = []
55 | for component in path:
56 | if isinstance(component, str):
57 | if parts: parts.append('.')
58 | parts.append(component)
59 | else:
60 | parts.append('[' + str(component) + ']')
61 | return ''.join(parts)
62 |
63 |
64 | class InteractiveConsole:
65 | def __init__(self, server, history=os.path.expanduser('~/.jaspy.history')):
66 | self.server = server
67 | self.namespace = {'sessions': debugger.sessions}
68 | self.history = history
69 | self.cli = None
70 | self.running = False
71 |
72 | debugger.session_created += self.on_session_created
73 | debugger.session_closed += self.on_session_closed
74 |
75 | self.server.on_running += self.on_server_running
76 |
77 | def start(self):
78 | self.running = True
79 |
80 | coroutine = embed(self.namespace, self.namespace, title='Jaspy Console',
81 | patch_stdout=True, history_filename=self.history,
82 | return_asyncio_coroutine=True)
83 |
84 | # HACK: nasty hack to gain access to the command line interface wrapper
85 | self.cli = coroutine.gi_frame.f_locals['cli']
86 |
87 | future = asyncio.ensure_future(coroutine)
88 | future.add_done_callback(self.on_closed)
89 | return future
90 |
91 | def print_tokens(self, tokens):
92 | if self.running:
93 | def printer():
94 | print_tokens(tokens, style=style)
95 | self.cli.run_in_terminal(printer)
96 |
97 | def print_message(self, message, kind=SUCCESS):
98 | self.print_tokens([(kind, '<<< ' + message + os.linesep)])
99 |
100 | def on_closed(self, future):
101 | self.running = False
102 |
103 | def on_server_running(self, server):
104 | msg = 'Sever is running on http://{}:{}/!'.format(server.host, server.port)
105 | self.print_message(msg, INFO)
106 |
107 | def on_session_created(self, session):
108 | self.print_message('Remote debugging session created!')
109 | self.print_message('debugger = {}'.format(session), INFO)
110 |
111 | self.namespace['debugger'] = session
112 |
113 | session.on_error += self.on_error
114 | session.on_success += self.on_success
115 |
116 | session.on_running += self.on_running
117 |
118 | session.on_thread_suspended += self.on_thread_suspended
119 |
120 | session.on_locals += self.on_locals
121 |
122 | session.on_console_log += self.on_console_log
123 | session.on_console_error += self.on_console_error
124 |
125 | def on_session_closed(self, session):
126 | self.print_message('Remote debugging session closed!', WARNING)
127 |
128 | def on_thread_suspended(self, session, seq, thread_id, frames):
129 | self.print_message('Thread {} has been suspended!'.format(thread_id))
130 | tokens = [(Token.Trace, '| Traceback (most recent call first):' + os.linesep)]
131 | self.print_tokens(tokens)
132 | for index, frame in enumerate(frames):
133 | message = FRAME_TEMPLATE.format(index, linesep=os.linesep, **frame)
134 | self.print_tokens([(Token.Trace, message)])
135 |
136 | def on_error(self, session, seq, message):
137 | self.print_message('Error: ' + message, ERROR)
138 |
139 | def on_success(self, session, seq, message):
140 | self.print_message('Success: ' + message, SUCCESS)
141 |
142 | def on_running(self, session, seq, module_name, argv):
143 | self.print_message('Program is running!')
144 |
145 | def on_variable(self, session, seq, thread_id, frame_id, path, result):
146 | header = VARIABLE_HEADER.format(format_variable_path(path), thread_id, frame_id)
147 | self.print_message(header)
148 | tokens = []
149 | for name in sorted(result.keys()):
150 | info = result[name]
151 | tokens.extend([
152 | (Token.Trace, '| '),
153 | (Token.Variable, name),
154 | (Token.Normal, ' = '),
155 | (Token.Trace, '{%s} ' % info['type']),
156 | (Token.Normal, info['value'] + os.linesep)
157 | ])
158 | self.print_tokens(tokens)
159 |
160 | def on_console_log(self, session, seq, *strings):
161 | self.print_tokens([(Token.Trace, ' '.join(strings) + os.linesep)])
162 |
163 | def on_console_error(self, session, seq, *strings):
164 | self.print_tokens([(Token.Warning, ' '.join(strings) + os.linesep)])
165 |
166 | def on_locals(self, session, seq, result):
167 | self.print_message('Received local frame variables!')
168 | tokens = []
169 | for name in sorted(result.keys()):
170 | info = result[name]
171 | tokens.extend([
172 | (Token.Trace, '| '),
173 | (Token.Variable, name),
174 | (Token.Normal, ' = '),
175 | (Token.Trace, '{%s} ' % info['type']),
176 | (Token.Normal, info['value'] + os.linesep)
177 | ])
178 | self.print_tokens(tokens)
179 |
180 |
181 |
--------------------------------------------------------------------------------
/jaspy/metadata.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, Maximilian Köhl
4 | #
5 | # This program is free software: you can redistribute it and/or modify it under
6 | # the terms of the GNU Lesser General Public License version 3 as published by
7 | # the Free Software Foundation.
8 | #
9 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License along
14 | # with this program. If not, see .
15 |
16 | __version_info__ = (0, 1, 0, 'dev0', 0)
17 |
18 | __version__ = '0.1.0.dev0'
19 | __project__ = 'Jaspy Python Interpreter'
20 | __author__ = 'Maximilian Köhl'
21 | __email__ = 'mail@koehlma.de'
22 |
--------------------------------------------------------------------------------
/jaspy/server.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, Maximilian Köhl
4 | #
5 | # This program is free software: you can redistribute it and/or modify it under
6 | # the terms of the GNU Lesser General Public License version 3 as published by
7 | # the Free Software Foundation.
8 | #
9 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License along
14 | # with this program. If not, see .
15 |
16 | import os.path
17 |
18 | import aiohttp
19 | import aiohttp.web
20 |
21 | from .event import Event
22 | from .debugger import Debugger
23 | from .converter import compile_and_convert
24 |
25 |
26 | class Server:
27 | def __init__(self, jaspy_js, modules_dir, host='localhost', port=8080, root_dir='.'):
28 | self.jaspy_js = jaspy_js
29 | self.modules_dir = modules_dir
30 |
31 | self.host = host
32 | self.port = port
33 |
34 | self.root_dir = root_dir
35 |
36 | self.application = aiohttp.web.Application()
37 | self.application.on_shutdown.append(self.on_shutdown)
38 |
39 | self.router = self.application.router
40 | self.router.add_route('GET', '/debugger', self.debugger)
41 | self.router.add_route('GET', '/load/{name}', self.load)
42 | self.router.add_route('GET', '/jaspy.js', self.jaspy)
43 | self.router.add_static('/modules', self.modules_dir)
44 | self.router.add_static('/', self.root_dir)
45 |
46 | self.on_running = Event()
47 |
48 | self.connections = []
49 |
50 | async def on_shutdown(self, application):
51 | for websocket in self.connections:
52 | await websocket.close(message='Server Shutdown')
53 |
54 | async def debugger(self, request):
55 | websocket = aiohttp.web.WebSocketResponse()
56 | self.connections.append(websocket)
57 | try:
58 | await websocket.prepare(request)
59 | debugger = Debugger(websocket)
60 | await debugger.debug()
61 | finally:
62 | self.connections.remove(websocket)
63 | return websocket
64 |
65 | async def load(self, request):
66 | name = request.match_info['name']
67 | url = os.path.join(self.root_dir, '/'.join(name.split('.')))
68 | if os.path.isdir(url):
69 | url = os.path.join(url, '__init__.py')
70 | else:
71 | url = '{}.py'.format(url)
72 | source = compile_and_convert(url)
73 | text = 'jaspy.module(%r, %s);' % (name, source)
74 | return aiohttp.web.Response(text=text, content_type='application/javascript')
75 |
76 | def jaspy(self, request):
77 | with open(self.jaspy_js, 'r') as jaspy_js_file:
78 | text = jaspy_js_file.read()
79 | return aiohttp.web.Response(text=text, content_type='application/javascript')
80 |
81 | def run(self):
82 | aiohttp.web.run_app(self.application, host=self.host, port=self.port,
83 | shutdown_timeout=5,
84 | print=lambda *_: self.on_running.emit(self))
85 |
86 | def shutdown(self):
87 | self.application.shutdown()
88 |
--------------------------------------------------------------------------------
/modules/_builtins.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, Maximilian Köhl
4 | #
5 | # This program is free software: you can redistribute it and/or modify it under
6 | # the terms of the GNU Lesser General Public License version 3 as published by
7 | # the Free Software Foundation.
8 | #
9 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License along
14 | # with this program. If not, see .
15 |
16 | """
17 | Implementation of non-trivial Python builtin functions.
18 |
19 | https://docs.python.org/3/library/functions.html
20 | """
21 |
22 |
23 | NULL = object()
24 |
25 |
26 | def all(iterable):
27 | for element in iterable:
28 | if not element:
29 | return False
30 | return True
31 |
32 |
33 | def any(iterable):
34 | for element in iterable:
35 | if element:
36 | return True
37 | return False
38 |
39 |
40 | def next(iterator, default=NULL):
41 | if default is NULL:
42 | return iterator.__next__()
43 | else:
44 | try:
45 | return iterator.__next__()
46 | except StopIteration:
47 | return default
48 |
49 |
50 | def _counter(start=0):
51 | while True:
52 | yield start
53 | start += 1
54 |
55 |
56 | def enumerate(iterable, start=0):
57 | return zip(_counter(start), iterable)
58 |
59 |
60 | def filter(function, iterable):
61 | if function is None:
62 | return (item for item in iterable if item)
63 | else:
64 | return (item for item in iterable if function(item))
65 |
66 |
67 | def map(function, *iterables):
68 | return (function(*args) for args in zip(*iterables))
69 |
70 |
71 | def pow(x, y, z=None):
72 | return x ** y if z is None else (x ** y) % z
73 |
74 |
75 | def sum(iterable, start=0):
76 | for item in iterable:
77 | start += item
78 | return start
79 |
80 |
81 | def zip(*iterables):
82 | iterators = [iter(iterable) for iterable in iterables]
83 | while iterators:
84 | result = []
85 | for iterator in iterators:
86 | try:
87 | result.append(iterator.__next__())
88 | except StopIteration:
89 | return
90 | yield tuple(result)
91 |
--------------------------------------------------------------------------------
/modules/_thread.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | jaspy.module('_thread', function ($, module) {
17 | module.$def('start_new_thread', function (target, args, kwargs) {
18 | var frame = $.vm.frame;
19 | var new_frame = $.call(target, args, kwargs);
20 | new_frame.thread = new $.Thread(new_frame);
21 | new_frame.back = null;
22 | new_frame.thread.enqueue();
23 | $.vm.frame = frame;
24 | }, ['target', '*args', '**kwargs']);
25 |
26 |
27 | var LockType = module.$class('LockType');
28 |
29 | LockType.$def('__exit__', function (self, exc_type, exc_value, exc_tb) {
30 | LockType.check(self);
31 | self.lock.release();
32 | return $.False;
33 | }, ['exc_type', 'exc_value', 'exc_tb']);
34 |
35 | LockType.$def('acquire', function (self, state, frame) {
36 | LockType.check(self);
37 | switch (state) {
38 | case 0:
39 | if (self.lock.acquire()) {
40 | return $.True;
41 | } else {
42 | $.threading.drop();
43 | return 1;
44 | }
45 | case 1:
46 | return $.True;
47 | }
48 | });
49 |
50 | LockType.$def('release', function (self) {
51 | LockType.check(self);
52 | self.lock.release();
53 | });
54 |
55 | LockType.$def('locked', function (self) {
56 | LockType.check(self);
57 | return self.lock.locked() ? $.True : $.False;
58 | });
59 |
60 | LockType.$def_alias('acquire', '__enter__');
61 |
62 |
63 |
64 |
65 |
66 | module.$def('allocate_lock', function () {
67 | var lock = LockType.make();
68 | lock.lock = new $.Lock();
69 | return lock;
70 | });
71 |
72 |
73 |
74 | });
75 |
--------------------------------------------------------------------------------
/modules/dom.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | jaspy.module('dom', function ($, module, builtins) {
17 | var MetaElement = module.$class('MetaElement', [builtins.type]);
18 | var Element = module.$class('Element', [builtins.object], MetaElement);
19 |
20 |
21 | Element.$def('__new__', function (cls, tag) {
22 | Element.check_subclass(cls);
23 | var self = new $.PyObject(cls);
24 | self.element = document.createElement($.Str.unpack(tag, 'div'));
25 | self.element.__element__ = self;
26 | return self;
27 | }, ['tag'], {defaults: {'tag': builtins.None}});
28 |
29 | Element.$def('__str__', function (self) {
30 | Element.check(self);
31 | return $.Str.pack('<' + self.element.nodeName.toLowerCase() + ' element at 0x' + self.get_address() + '>');
32 | });
33 |
34 | Element.$def('__getitem__', function (self, name) {
35 | Element.check(self);
36 | return $.Str.pack(self.element.getAttribute($.Str.unpack(name)));
37 | }, ['name']);
38 |
39 | Element.$def('__setitem__', function (self, name, value) {
40 | Element.check(self);
41 | self.element.setAttribute($.Str.unpack(name), $.Str.unpack(value));
42 | }, ['name', 'value']);
43 |
44 | Element.$def('__getattr__', function (self, name) {
45 | Element.check(self);
46 | var child = new $.PyObject(Element);
47 | child.element = document.createElement($.Str.unpack(name, 'div'));
48 | child.element.__element__ = self;
49 | self.element.appendChild(child.element);
50 | return child;
51 | }, ['name']);
52 |
53 | Element.$def_property('text', function (self) {
54 | Element.check(self);
55 | return $.Str.pack(self.element.textContent);
56 | }, function (self, value) {
57 | Element.check(self);
58 | self.element.textContent = $.Str.unpack(value);
59 | });
60 |
61 | Element.$def_property('html', function (self) {
62 | Element.check(self);
63 | return $.Str.pack(self.element.innerHTML);
64 | }, function (self, value) {
65 | Element.check(self);
66 | self.element.innerHTML = $.Str.unpack(value);
67 | });
68 |
69 | Element.$def('css', function (self, name, value) {
70 | Element.check(self);
71 | if (value === builtins.NotImplemented) {
72 | return $.Str.pack(self.element.style[$.Str.unpack(name)]);
73 | } else {
74 | self.element.style[$.Str.unpack(name)] = $.Str.unpack(value, '');
75 | }
76 | }, ['name', 'value'], {defaults: {'value': builtins.NotImplemented}});
77 |
78 | Element.$def('append', function (self, other) {
79 | Element.check(self);
80 | Element.check(other);
81 | self.element.appendChild(other.element);
82 | }, ['other']);
83 |
84 |
85 | module.$def('get_body', function () {
86 | if (document.body) {
87 | if (document.body.__element__) {
88 | return document.body.__element__;
89 | }
90 | var element = new $.PyObject(Element);
91 | element.element = document.body;
92 | document.body.__element__ = element;
93 | return element;
94 | } else {
95 | $.raise(builtins.ValueError, 'unable to load body from dom');
96 | }
97 | });
98 |
99 |
100 | Element.$def('register_listener', function (self, name, callback) {
101 | Element.check(self);
102 | var element = self.element;
103 | element.addEventListener($.Str.unpack(name), function (event) {
104 | $.resume(callback, [self], {});
105 | });
106 | }, ['name', 'resume']);
107 |
108 |
109 |
110 |
111 | module.$def('set_interval', function (interval, callback) {
112 | var handle = $.Int.pack(setInterval(function () {
113 | $.resume(callback, [handle], {});
114 | }, $.Int.unpack(interval)));
115 | return handle;
116 | }, ['interval', 'resume']);
117 |
118 | }, ['builtins']);
--------------------------------------------------------------------------------
/modules/greenlet.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | jaspy.module('greenlet', function ($, module, builtins) {
17 | var Greenlet = module.$class('greenlet');
18 | var GreenletExit = module.$class('GreenletExit', [builtins.Exception]);
19 |
20 |
21 | var current = new $.PyObject(Greenlet);
22 | current.started = true;
23 | current.bottom = {back: null};
24 |
25 | Greenlet.$def('__new__', function (cls, run) {
26 | Greenlet.check_subclass(cls);
27 | var self = new $.PyObject(cls);
28 | self.run = run;
29 | self.started = false;
30 | self.setattr('parent', current);
31 | return self;
32 | }, ['run']);
33 |
34 | Greenlet.$def('switch', function (self, state, frame) {
35 | Greenlet.check(self);
36 | if (self.started) {
37 | switch (state) {
38 | case 0:
39 | current.top = frame;
40 | $.vm.frame = self.top;
41 | current = self;
42 | current.bottom.back = frame;
43 | return 1;
44 | case 1:
45 | return;
46 | }
47 | } else {
48 | current.top = frame;
49 | current = self;
50 | self.started = true;
51 | if (self.bottom = $.call(self.run)) {
52 | self.bottom.back = null;
53 | return 1;
54 | }
55 | }
56 | });
57 |
58 | module.$def('getcurrent', function () {
59 | return current;
60 | });
61 |
62 | }, ['builtins']);
--------------------------------------------------------------------------------
/modules/time.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | jaspy.module('time', function ($, module, builtins) {
17 | module.$def('sleep', function (seconds, state, frame) {
18 | switch (state) {
19 | case 0:
20 | setTimeout(function () {
21 | $.resume(frame);
22 | }, $.Float.unpack(seconds) * 1000);
23 | $.suspend();
24 | return 1;
25 | case 1:
26 | break;
27 | }
28 | }, ['seconds']);
29 |
30 | module.$def('time', function () {
31 | return $.Float.pack((new Date()).getTime() / 1000);
32 | });
33 | }, ['builtins']);
34 |
--------------------------------------------------------------------------------
/notes/README.rst:
--------------------------------------------------------------------------------
1 | Notes
2 | =====
3 |
4 | This directory contains some notes about Jaspy.
5 |
6 |
7 | Execution Model
8 | ===============
9 | There are two different execution modes — synchronous and asynchronous.
10 |
11 | Example:
12 |
13 | Dict.set called in synchronous mode finishes execution and might call python code.
14 |
15 | Dict.set called in asynchronous mode returns a coroutine which should be yielded.
16 |
17 | This way it is possible to write function which work when called from JavaScript directly
18 | but also allow the Python interpreter to provide features like threading. When using the
19 | asm.js or speedy backend the interpreter is also in synchronous mode which allows to call
20 | Python code. Greenlets, debugging and threading and all other features which require the
21 | interpreter to be suspendable only work in asynchronous mode.
22 |
23 | Asynchronous functions have to be decorated using the coroutine decorator.
24 |
25 | Example:
26 |
27 | .. code:: javascript
28 |
29 | Dict.set = coroutine(function (self, key, value) {
30 | var hash = yield key.hash();
31 | // do insertion
32 | });
33 |
34 |
35 | Synchronous Mode:
36 |
37 | .. code:: javascript
38 |
39 | Dict.set(key, value) // blocks
40 |
41 | Asynchronous Mode:
42 |
43 | .. code:: javascript
44 |
45 | yield Dict.set(key, value) // blocks
46 | Dict.set(key, value) // is non-blocking
47 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "jaspy",
3 | "version": "0.0.4",
4 | "description": "a Python VM written entirely from scratch in JavaScript with some unique features",
5 | "main": "jaspy.js",
6 | "directories": {
7 | "example": "example"
8 | },
9 | "scripts": {
10 | "test": "node_modules/.bin/karma start .karma.js",
11 | "build": "python3 build.py",
12 | "prepublish": "python3 build.py && cp build/jaspy.js .",
13 | "publish": "rm -f jaspy.js",
14 | "start": "cd example && PYTHONPATH=../ python3 -m jaspy.cli --interactive --jaspy-js ../jaspy.js"
15 | },
16 | "repository": {
17 | "type": "git",
18 | "url": "git+https://github.com/koehlma/jaspy.git"
19 | },
20 | "keywords": [
21 | "python",
22 | "interpreter"
23 | ],
24 | "devDependencies": {
25 | "coveralls": "^2.11.4",
26 | "jasmine": "2.1.x",
27 | "jasmine-core": "^2.3.4",
28 | "karma": "^0.13.3",
29 | "karma-coverage": "^0.4.2",
30 | "karma-firefox-launcher": "^1.0.0",
31 | "karma-jasmine": "^0.3.6"
32 | },
33 | "author": "Maximilian Köhl ",
34 | "license": "LGPL-3.0",
35 | "bugs": {
36 | "url": "https://github.com/koehlma/jaspy/issues"
37 | },
38 | "homepage": "https://github.com/koehlma/jaspy#readme"
39 | }
40 |
--------------------------------------------------------------------------------
/readthedocs.yml:
--------------------------------------------------------------------------------
1 | conda:
2 | file: doc/environment.yml
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiohttp
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Copyright (C) 2016, Maximilian Köhl
4 | #
5 | # This program is free software: you can redistribute it and/or modify it under
6 | # the terms of the GNU Lesser General Public License version 3 as published by
7 | # the Free Software Foundation.
8 | #
9 | # This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | # PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 | #
13 | # You should have received a copy of the GNU Lesser General Public License along
14 | # with this program. If not, see .
15 |
16 | import os
17 |
18 | from distutils.core import setup
19 |
20 |
21 | LICENSE = 'License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3)'
22 |
23 | with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme:
24 | long_description = readme.read()
25 |
26 |
27 | setup(
28 | name='jaspy',
29 | version='0.1.0dev',
30 | description='Python interpreter in JavaScript',
31 | long_description=long_description,
32 | author='Maximilian Köhl',
33 | author_email='mail@koehlma.de',
34 | url='https://github.com/koehlma/jaspy',
35 | license='LGPLv3',
36 | scripts=['build'],
37 | packages=['jaspy'],
38 | extras_require={
39 | 'interactive remote console': ['ptpython', 'pygments']
40 | },
41 | classifiers=[
42 | 'Development Status :: 2 - Pre-Alpha',
43 | 'Intended Audience :: Developers',
44 | LICENSE,
45 | 'Operating System :: OS Independent',
46 | 'Programming Language :: Python :: 3',
47 | 'Environment :: Web Environment',
48 | 'Topic :: Internet',
49 | 'Topic :: Internet :: WWW/HTTP :: Browsers',
50 | ]
51 | )
52 |
--------------------------------------------------------------------------------
/spec/dict_spec.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | describe('Dict', function () {
18 | it('operations', function () {
19 | var dict = new jaspy.Dict();
20 |
21 | dict.set('abc', 42);
22 | expect(dict.get('abc')).toBe(42);
23 | dict.set('abc', 31415);
24 | expect(dict.pop('abc')).toBe(31415);
25 |
26 | expect(dict.get('abc')).toBe(undefined);
27 | expect(dict.get('abc', 123)).toBe(123);
28 | });
29 |
30 | it('entries', function () {
31 | var dict = new jaspy.Dict();
32 |
33 | expect(dict.entries().length, 0);
34 |
35 | dict.set('abc', 42);
36 | dict.set('abc', 31415);
37 |
38 | expect(dict.entries().length, 1);
39 | expect(dict.entries()[0].key.equals('abc')).toBe(jaspy.True);
40 | expect(dict.entries()[0].value).toBe(31415);
41 | });
42 |
43 | it('size', function () {
44 | var dict = new jaspy.Dict();
45 |
46 | expect(dict.size).toBe(0);
47 |
48 | dict.set('abc', 42);
49 | dict.set('abc', 31415);
50 | dict.set('xyz', 4242);
51 |
52 | expect(dict.size).toBe(2);
53 |
54 | dict.pop('abc');
55 |
56 | expect(dict.size).toBe(1);
57 |
58 | dict.pop('xyz');
59 |
60 | expect(dict.size).toBe(0);
61 | })
62 | });
--------------------------------------------------------------------------------
/spec/executor_spec.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | describe('Executor', function () {
18 | it('faculty', function () {
19 | var $ = jaspy;
20 |
21 | var fac = $._(function* (n) {
22 | return n > 1 ? n * (yield fac(n - 1)) : 1;
23 | });
24 |
25 | expect(fac(10)).toBe(3628800);
26 |
27 | var thread = new $.Microthread(fac, 10);
28 | expect(thread.run()).toBe(3628800);
29 | });
30 |
31 | it('suspension', function () {
32 | var $ = jaspy;
33 |
34 | var test = $._(function* () {
35 | var value = yield new $.Suspension();
36 | return value;
37 | });
38 |
39 | var thread = new $.Microthread(test);
40 | var suspension = thread.run();
41 | expect(suspension instanceof $.Suspension).toBeTruthy();
42 | suspension.set_result(42);
43 | expect(thread.run(suspension)).toBe(42);
44 |
45 | expect(function () { test(); }).toThrowError(/ExecutorError/);
46 | });
47 | });
--------------------------------------------------------------------------------
/spec/float_spec.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Matthias Heerde
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | describe('jaspy.Float', function () {
18 | it('unpack', function () {
19 | expect(jaspy.Float.unpack(42.42)).toBe(42.42);
20 | expect(jaspy.Float.unpack(new jaspy.Int(42))).toBe(42);
21 | expect(function () { jaspy.Float.unpack(jaspy.None); }).toThrowError(/TypeError/);
22 | expect(function () { jaspy.Float.unpack(new jaspy.Str('42.42')); }).toThrowError(/TypeError/);
23 | expect(jaspy.Float.unpack(jaspy.None, 42.42)).toBe(42.42);
24 | });
25 |
26 | it('equals', function() {
27 | expect((new jaspy.Float(42)).equals(42)).toBe(jaspy.True);
28 | expect((new jaspy.Float(42)).equals((new jaspy.Int(42)))).toBe(jaspy.True);
29 | expect((new jaspy.Float(42)).equals((new jaspy.Float(42)))).toBe(jaspy.True);
30 | });
31 |
32 | it('add', function () {
33 | expect(((new jaspy.Float(21)).add(21)).equals(42)).toBe(jaspy.True);
34 | expect(((new jaspy.Float(21)).add(new jaspy.Float(21))).equals(42)).toBe(jaspy.True);
35 | expect(((new jaspy.Float(21)).add(new jaspy.Float(21))).equals(new jaspy.Float(42))).toBe(jaspy.True);
36 | });
37 |
38 | it('is_integer', function () {
39 | expect((new jaspy.Float(42.42)).is_integer()).toBe(jaspy.False);
40 | })
41 | });
--------------------------------------------------------------------------------
/spec/javascripts/support/function-bind.js:
--------------------------------------------------------------------------------
1 | Function.prototype.bind = Function.prototype.bind || function (bind_to) {
2 | var func = this;
3 | return function () {
4 | return func.apply(bind_to, arguments);
5 | };
6 | };
7 |
--------------------------------------------------------------------------------
/spec/javascripts/support/jasmine.yml:
--------------------------------------------------------------------------------
1 | src_files:
2 | - build/jaspy.js
3 |
4 | spec_files:
5 | - "**/*[Ss]pec.js"
6 |
7 | spec_dir: spec/
8 |
--------------------------------------------------------------------------------
/spec/spec.js:
--------------------------------------------------------------------------------
1 | describe('Jaspy', function () {
2 | it('test case 1', function () {
3 | expect(true).toBe(true);
4 | })
5 | });
--------------------------------------------------------------------------------
/src/__init__.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | /**
18 | * Welcome to the source code of Jaspy!
19 | * ====================================
20 | * Warning: Python interpreter under construction!
21 | *
22 | * So you like to learn how Jaspy works under the hood? You have made the first important
23 | * step — you are reading the source code of Jaspy. In case you only want to use Jaspy you
24 | * probably should instead read the user documentation [1]_.
25 | *
26 | * The in-source documentation is more or less a loose bunch of thoughts, ideas, and other
27 | * stuff than well-structured and well-conceived. However I will try to explain the rough
28 | * ideas and concepts behind the implementation.
29 | *
30 | * .. [1] https://jaspy.readthedocs.io/en/latest/
31 | *
32 | *
33 | * Motivation
34 | * ----------
35 | * Why should one come up with yet another Python-JavaScript-Thingamajig? Just to give you
36 | * a few examples why this might be a good idea:
37 | *
38 | * - First of all programming is fun, so why not?
39 | * - Learn how to build an interpreter and the corresponding runtime environment.
40 | * - Get a better and deep understanding of the Python programming language.
41 | * - Experiment with web technologies and see what is possible.
42 | * - Learn JavaScript although your really do not want to. ;)
43 | *
44 | * However I do not want to reinvent the wheel, therefore Jaspy is also an experiment on
45 | * how to implement various features others are not offering. This includes threading, a
46 | * built-in debugger, Greenlets, blocking IO, and other features.
47 | */
48 |
49 |
50 | // << for lib in libs
51 | // #include '../libs/' + lib
52 | // >>
53 |
54 |
55 | var jaspy = {};
56 |
57 |
58 | (function () {
59 | var $ = jaspy;
60 |
61 | // #include 'base.js'
62 | // #include 'executor.js'
63 | })();
64 |
65 |
66 | // #include 'runtime/__init__.js'
67 | // #include 'language/__init__.js'
68 |
69 | // #include 'runtime/sys.js'
70 |
71 | /* {{ _builtins }} */
72 |
73 | jaspy.main(jaspy.get_module('_builtins'), [], true);
74 | jaspy.update(jaspy.builtins, jaspy.get_module('_builtins').__dict__);
75 | jaspy.builtins['__name__'] = 'builtins';
76 |
77 | // << if ENABLE_THREADING
78 | // #include '../modules/_thread.js'
79 | // >>
80 |
81 | // << for module in modules
82 | // #include '../modules/' + module + '.js'
83 | // >>
84 |
--------------------------------------------------------------------------------
/src/base.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | $.update = function (target, source) {
18 | var name, value;
19 | for (name in source) {
20 | if (source.hasOwnProperty(name)) {
21 | target[name] = source[name];
22 | }
23 | }
24 | };
25 |
26 |
27 | $.error = function (message, type) {
28 | throw new Error((type || '[Fatal Error]') + ' ' + (message || 'Fatal interpreter error, unable to recover!'));
29 | };
30 |
31 |
32 | $.assert = function (condition, message) {
33 | if (!condition) {
34 | $.error(message, '[Assertion Failed]');
35 | }
36 | };
37 |
38 |
39 | $.raise = function (exc_type, exc_value, exc_traceback) {
40 | if (exc_value) {
41 | console.error('Exception: ' + exc_value);
42 | }
43 | $.error('Exception raised before interpreter has been fully initialized!');
44 | };
45 |
46 |
47 | $.Class = function (attributes, superclass) {
48 | var constructor = attributes.constructor;
49 | if (superclass) {
50 | constructor.prototype = Object.create(superclass.prototype);
51 | }
52 | $.update(constructor.prototype, attributes);
53 | constructor.superclass = superclass;
54 | constructor.extend = function (attributes) {
55 | return $.Class(attributes, constructor);
56 | };
57 | return constructor;
58 | };
59 |
60 | $.Class.extend = function (attributes) {
61 | return $.Class(attributes);
62 | };
63 |
--------------------------------------------------------------------------------
/src/language/__init__.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | /**
17 | * use node.js for offline compilation...
18 | *
19 | * - Tokenizer
20 | * - Parser
21 | * - Backends
22 | * - Bytecode (needs VM)
23 | * - Speedy (only needs Runtime, no Threading, Debugging, Greenlets and IO)
24 | * - ASM.js (needs neither VM nor Runtime)
25 | *
26 | * Requires: base, runtime
27 | */
28 |
29 |
30 | jaspy.language = (function () {
31 | var $ = jaspy;
32 |
33 | // #include 'tokenizer.js'
34 | // #include 'parser.js'
35 |
36 | return {
37 | tokenize: tokenizer.tokenize
38 | }
39 | })();
--------------------------------------------------------------------------------
/src/language/parser.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
--------------------------------------------------------------------------------
/src/runtime/__init__.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | jaspy.runtime = (function () {
18 | var $ = jaspy;
19 | var _ = $._;
20 |
21 | // << if ENABLE_DEBUGGER
22 | console.info('Jaspy Python Interpreter\nDebugging Mode!');
23 | // >>
24 |
25 | // #include 'constants.js'
26 | // #include 'base.js'
27 |
28 | // #include 'future.js'
29 |
30 | // #include 'object.js'
31 | // #include 'type.js'
32 |
33 | // #include 'core/__init__.js'
34 |
35 | // #include 'code.js'
36 | // #include 'module.js'
37 |
38 | // #include 'bridge.js'
39 |
40 | // #include 'python/__init__.js'
41 |
42 | // #include 'dis.js'
43 |
44 | // #include 'frame.js'
45 | // #include 'execute.js'
46 | // #include 'vm.js'
47 |
48 | // << if ENABLE_THREADING
49 | // #include 'threading.js'
50 | // >>
51 |
52 | // << if ENABLE_DEBUGGER
53 | // #include 'debugger.js'
54 | // >>
55 | })();
56 |
--------------------------------------------------------------------------------
/src/runtime/base.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var Integer = bigInt;
18 |
19 |
20 | var SIPHASH_KEY = [Math.random() * Math.pow(2, 32) >>> 0,
21 | Math.random() * Math.pow(2, 32) >>> 0,
22 | Math.random() * Math.pow(2, 32) >>> 0,
23 | Math.random() * Math.pow(2, 32) >>> 0];
24 |
25 | function siphash(string) {
26 | var hash = SipHash.hash(SIPHASH_KEY, Str.unpack(string));
27 | return new Int(Integer(hash.h).shiftLeft(32).or(hash.l));
28 | }
29 |
30 |
31 | function error(message) {
32 | throw new Error('[FATAL ERROR] ' + (message || 'fatal interpreter error'));
33 | }
34 |
35 | function raise(exc_type, exc_value, exc_tb) {
36 | error('exception occurred before jaspy has been fully initialized');
37 | }
38 |
39 | function assert(condition, message) {
40 | if (!condition) {
41 | error(message || 'assertion failed');
42 | }
43 | }
44 |
45 | function update(target, source) {
46 | var name, value;
47 | for (name in source) {
48 | if (source.hasOwnProperty(name)) {
49 | target[name] = source[name];
50 | }
51 | }
52 | }
53 |
54 |
55 | function Class(attributes, superclass) {
56 | var constructor = attributes.constructor;
57 | if (superclass) {
58 | constructor.prototype = Object.create(superclass.prototype);
59 | }
60 | update(constructor.prototype, attributes);
61 | constructor.superclass = superclass;
62 | constructor.extend = function (attributes) {
63 | return Class(attributes, constructor);
64 | };
65 | return constructor;
66 | }
67 |
68 | Class.extend = function (attributes) {
69 | return Class(attributes);
70 | };
71 |
72 |
73 | function $Class(name, attributes, bases, superclass) {
74 | var constructor = Class(attributes, superclass || PyObject);
75 | constructor.cls = $class(name, bases);
76 | constructor.check = function (object) {
77 | if (!(object instanceof constructor)) {
78 | raise(TypeError, 'expected ' + name);
79 | }
80 | };
81 | constructor.$def = constructor.cls.$def.bind(constructor.cls);
82 |
83 | constructor.$map = function (name, spec, options) {
84 | var args, index;
85 | options = options || {};
86 | options.simple = true;
87 | spec = spec || [];
88 | args = new Array(spec.length);
89 | for (index = 0; index < spec.length; index++) {
90 | args[index] = ('arg' + index);
91 | }
92 | var source = "" +
93 | "(function (" + (['self'].concat(args)).join(', ') + ") {" +
94 | " if (!(self instanceof constructor)) {" +
95 | " raise(TypeError, 'invalid type of self in native method call');" +
96 | " }" +
97 | " return self." + name + "(" + args.join(', ') + ");" +
98 | "})";
99 | constructor.cls.$def(name, eval(source), spec, options);
100 | };
101 | constructor.extend = function (name, attributes, bases) {
102 | bases = bases || [];
103 | bases.push(constructor.cls);
104 | return $Class(name, attributes, bases, constructor);
105 | };
106 | return constructor;
107 | }
108 |
109 |
110 | $.Integer = Integer;
111 |
112 | $.siphash = siphash;
113 |
114 | $.error = error;
115 | $.raise = raise;
116 | $.assert = assert;
117 | $.assign = update;
118 |
119 | $.update = update;
120 |
121 | $.Class = Class;
122 |
--------------------------------------------------------------------------------
/src/runtime/bridge.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | function pack_bool(boolean) {
17 | return boolean ? True : False;
18 | }
19 |
20 | function pack_bytes(array) {
21 | return new Bytes(array);
22 | }
23 |
24 | function pack_tuple(array) {
25 | return new Tuple(array);
26 | }
27 |
28 | function pack_object(object) {
29 | return new PyJSObject(object);
30 | }
31 |
32 | function pack_array(array) {
33 | return new PyJSArray(array);
34 | }
35 |
36 | function pack_function(func) {
37 | return new PyJSFunction(func);
38 | }
39 |
40 | function pack_error(error) {
41 | return make_exception(JSError, '[' + error.name + '] ' + error.message);
42 | }
43 |
44 | function pack(object) {
45 | if (object == undefined) {
46 | return None;
47 | }
48 | if (object instanceof PyObject) {
49 | return object;
50 | } else if (typeof object == 'string') {
51 | return Str.pack(object);
52 | } else if (typeof object == 'number') {
53 | if (Number.isInteger(object)) {
54 | return Int.pack(object);
55 | } else {
56 | return Float.pack(object);
57 | }
58 | } else if (typeof object == 'boolean') {
59 | return pack_bool(object);
60 | } else if (typeof object == 'function') {
61 | return pack_function(object);
62 | } else if (object instanceof Array) {
63 | return pack_array(object);
64 | } else if (object instanceof Object) {
65 | return pack_object(object);
66 | } else {
67 | raise(TypeError, 'unable to pack native object');
68 | }
69 | }
70 |
71 | function unpack_bool(object, fallback) {
72 | if ((object === None || !object) && fallback) {
73 | return fallback;
74 | }
75 | if (!(object.__class__ === py_bool)) {
76 | raise(TypeError, 'unable to unpack to_bool from object');
77 | }
78 | return object === True;
79 | }
80 |
81 | function unpack_bytes(object, fallback) {
82 | if ((object === None || !object) && fallback) {
83 | return fallback;
84 | }
85 | if (!(object instanceof Bytes)) {
86 | raise(TypeError, 'unable to unpack bytes from object');
87 | }
88 | return object.array;
89 | }
90 |
91 | function unpack_tuple(object, fallback) {
92 | if ((object === None || !object) && fallback) {
93 | return fallback;
94 | }
95 | if (!(object instanceof Tuple)) {
96 | raise(TypeError, 'unable to unpack tuple from object');
97 | }
98 | return object.array;
99 | }
100 |
101 | function unpack_object(object, fallback) {
102 | if ((object === None || !object) && fallback) {
103 | return fallback;
104 | }
105 | if (!(object instanceof PyJSObject)) {
106 | raise(TypeError, 'unable to unpack js object');
107 | }
108 | return object.object;
109 | }
110 |
111 | function unpack_array(object, fallback) {
112 | if ((object === None || !object) && fallback) {
113 | return fallback;
114 | }
115 | if (!(object instanceof PyJSArray)) {
116 | raise(TypeError, 'unable to unpack js array');
117 | }
118 | return object.array;
119 | }
120 |
121 | function unpack_function(object, fallback) {
122 | if ((object === None || !object) && fallback) {
123 | return fallback;
124 | }
125 | if (!(object instanceof PyJSFunction)) {
126 | raise(TypeError, 'unable to unpack js function');
127 | }
128 | return object.func;
129 | }
130 |
131 | function unpack(object, fallback) {
132 | if ((object === None || !object) && fallback) {
133 | return fallback;
134 | }
135 | if (!(object instanceof PyObject)) {
136 | raise(TypeError, 'object to unpack is not a python object');
137 | }
138 | if (object.__class__ === py_bool) {
139 | return unpack_bool(object);
140 | } else if (object === None) {
141 | return null;
142 | } else if (object instanceof Int) {
143 | return Int.unpack(object);
144 | } else if (object instanceof Float) {
145 | return Float.unpack(object);
146 | } else if (object instanceof Str) {
147 | return Str.unpack(object);
148 | } else if (object instanceof Bytes) {
149 | return unpack_bytes(object);
150 | } else if (object instanceof Tuple) {
151 | return unpack_tuple(object);
152 | } else if (object instanceof PyJSObject) {
153 | return unpack_object(object);
154 | } else if (object instanceof PyJSArray) {
155 | return unpack_array(object);
156 | } else if (object instanceof PyJSFunction) {
157 | return unpack_function(object);
158 | } else {
159 | raise(TypeError, 'unable to unpack native value from object');
160 | }
161 | }
162 |
163 |
164 |
165 | $.pack_bool = pack_bool;
166 | $.pack_bytes = pack_bytes;
167 | $.pack_tuple = pack_tuple;
168 | $.pack_object = pack_object;
169 | $.pack_array = pack_array;
170 | $.pack_function = pack_function;
171 | $.pack_error = pack_error;
172 |
173 |
174 | $.unpack_bool = unpack_bool;
175 | $.unpack_bytes = unpack_bytes;
176 | $.unpack_tuple = unpack_tuple;
177 | $.unpack_object = unpack_object;
178 | $.unpack_array = unpack_array;
179 | $.unpack_function = unpack_function;
180 |
181 | $.pack = pack;
182 | $.unpack = unpack;
183 |
184 | var Bool = {
185 | pack: pack_bool,
186 | unpack: unpack_bool
187 | };
188 |
--------------------------------------------------------------------------------
/src/runtime/constants.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | var TRACEBACK_ON_EXCEPTION = true;
17 |
18 | var CODE_FLAGS = {
19 | OPTIMIZED: 1 << 0,
20 | NEWLOCALS: 1 << 1,
21 | NESTED: 1 << 4,
22 | GENERATOR: 1 << 5,
23 | NOFREE: 1 << 6,
24 |
25 | STAR_ARGS: 1 << 2,
26 | STAR_KWARGS: 1 << 3,
27 |
28 | PYTHON: 1 << 10,
29 | NATIVE: 1 << 11
30 | };
31 |
32 | var BLOCK_TYPES = {
33 | BASE: 0,
34 | LOOP: 1,
35 | EXCEPT: 2,
36 | FINALLY: 3
37 | };
38 |
39 | var CAUSES = {
40 | RETURN: 0,
41 | EXCEPTION: 1,
42 | BREAK: 2,
43 | CONTINUE: 3,
44 | YIELD: 4,
45 | RUN: 5
46 | };
47 |
48 | var COMPARE_OPS = {
49 | LT: 0,
50 | LE: 1,
51 | EQ: 2,
52 | NE: 3,
53 | GT: 4,
54 | GE: 5,
55 | IN: 6,
56 | NIN: 7,
57 | IS: 8,
58 | NIS: 9,
59 | EXC: 10
60 | };
61 |
62 | var COMPARE_SLOTS = [
63 | '__lt__',
64 | '__le__',
65 | '__eq__',
66 | '__ne__',
67 | '__gt__',
68 | '__ge__',
69 | '__contains__',
70 | '__contains__'
71 | ];
72 |
73 | var OPCODES = {
74 | BEFORE_ASYNC_WITH: 52,
75 | BINARY_ADD: 23,
76 | BINARY_AND: 64,
77 | BINARY_FLOOR_DIVIDE: 26,
78 | BINARY_LSHIFT: 62,
79 | BINARY_MATRIX_MULTIPLY: 16,
80 | BINARY_MODULO: 22,
81 | BINARY_MULTIPLY: 20,
82 | BINARY_OR: 66,
83 | BINARY_POWER: 19,
84 | BINARY_RSHIFT: 63,
85 | BINARY_SUBSCR: 25,
86 | BINARY_SUBTRACT: 24,
87 | BINARY_TRUE_DIVIDE: 27,
88 | BINARY_XOR: 65,
89 | BREAK_LOOP: 80,
90 | BUILD_LIST: 103,
91 | BUILD_LIST_UNPACK: 149,
92 | BUILD_MAP: 105,
93 | BUILD_MAP_UNPACK: 150,
94 | BUILD_MAP_UNPACK_WITH_CALL: 151,
95 | BUILD_SET: 104,
96 | BUILD_SET_UNPACK: 153,
97 | BUILD_SLICE: 133,
98 | BUILD_TUPLE: 102,
99 | BUILD_TUPLE_UNPACK: 152,
100 | CALL_FUNCTION: 131,
101 | CALL_FUNCTION_KW: 141,
102 | CALL_FUNCTION_VAR: 140,
103 | CALL_FUNCTION_VAR_KW: 142,
104 | COMPARE_OP: 107,
105 | CONTINUE_LOOP: 119,
106 | DELETE_ATTR: 96,
107 | DELETE_DEREF: 138,
108 | DELETE_FAST: 126,
109 | DELETE_GLOBAL: 98,
110 | DELETE_NAME: 91,
111 | DELETE_SUBSCR: 61,
112 | DUP_TOP: 4,
113 | DUP_TOP_TWO: 5,
114 | END_FINALLY: 88,
115 | EXTENDED_ARG: 144,
116 | FOR_ITER: 93,
117 | GET_AITER: 50,
118 | GET_ANEXT: 51,
119 | GET_AWAITABLE: 73,
120 | GET_ITER: 68,
121 | GET_YIELD_FROM_ITER: 69,
122 | IMPORT_FROM: 109,
123 | IMPORT_NAME: 108,
124 | IMPORT_STAR: 84,
125 | INPLACE_ADD: 55,
126 | INPLACE_AND: 77,
127 | INPLACE_FLOOR_DIVIDE: 28,
128 | INPLACE_LSHIFT: 75,
129 | INPLACE_MATRIX_MULTIPLY: 17,
130 | INPLACE_MODULO: 59,
131 | INPLACE_MULTIPLY: 57,
132 | INPLACE_OR: 79,
133 | INPLACE_POWER: 67,
134 | INPLACE_RSHIFT: 76,
135 | INPLACE_SUBTRACT: 56,
136 | INPLACE_TRUE_DIVIDE: 29,
137 | INPLACE_XOR: 78,
138 | JUMP_ABSOLUTE: 113,
139 | JUMP_FORWARD: 110,
140 | JUMP_IF_FALSE_OR_POP: 111,
141 | JUMP_IF_TRUE_OR_POP: 112,
142 | LIST_APPEND: 145,
143 | LOAD_ATTR: 106,
144 | LOAD_BUILD_CLASS: 71,
145 | LOAD_CLASSDEREF: 148,
146 | LOAD_CLOSURE: 135,
147 | LOAD_CONST: 100,
148 | LOAD_DEREF: 136,
149 | LOAD_FAST: 124,
150 | LOAD_GLOBAL: 116,
151 | LOAD_NAME: 101,
152 | MAKE_CLOSURE: 134,
153 | MAKE_FUNCTION: 132,
154 | MAP_ADD: 147,
155 | NOP: 9,
156 | POP_BLOCK: 87,
157 | POP_EXCEPT: 89,
158 | POP_JUMP_IF_FALSE: 114,
159 | POP_JUMP_IF_TRUE: 115,
160 | POP_TOP: 1,
161 | PRINT_EXPR: 70,
162 | RAISE_VARARGS: 130,
163 | RETURN_VALUE: 83,
164 | ROT_THREE: 3,
165 | ROT_TWO: 2,
166 | SETUP_ASYNC_WITH: 154,
167 | SETUP_EXCEPT: 121,
168 | SETUP_FINALLY: 122,
169 | SETUP_LOOP: 120,
170 | SETUP_WITH: 143,
171 | SET_ADD: 146,
172 | STORE_ATTR: 95,
173 | STORE_DEREF: 137,
174 | STORE_FAST: 125,
175 | STORE_GLOBAL: 97,
176 | STORE_NAME: 90,
177 | STORE_SUBSCR: 60,
178 | UNARY_INVERT: 15,
179 | UNARY_NEGATIVE: 11,
180 | UNARY_NOT: 12,
181 | UNARY_POSITIVE: 10,
182 | UNPACK_EX: 94,
183 | UNPACK_SEQUENCE: 92,
184 | WITH_CLEANUP_FINISH: 82,
185 | WITH_CLEANUP_START: 81,
186 | YIELD_FROM: 72,
187 | YIELD_VALUE: 86
188 | };
189 |
190 | var OPCODES_ARGUMENT = 90;
191 |
192 | var OPCODES_EXTRA = new Array(255);
193 |
194 | OPCODES_EXTRA[OPCODES.UNARY_POSITIVE] = '__pos__';
195 | OPCODES_EXTRA[OPCODES.UNARY_NEGATIVE] = '__neg__';
196 | OPCODES_EXTRA[OPCODES.UNARY_NOT] = '__not__';
197 | OPCODES_EXTRA[OPCODES.UNARY_INVERT] = '__invert__';
198 | OPCODES_EXTRA[OPCODES.GET_ITER] = '__iter__';
199 | OPCODES_EXTRA[OPCODES.GET_YIELD_FROM_ITER] = '__iter__';
200 |
201 | OPCODES_EXTRA[OPCODES.BINARY_POWER] = 'pow';
202 | OPCODES_EXTRA[OPCODES.BINARY_MULTIPLY] = 'mul';
203 | OPCODES_EXTRA[OPCODES.BINARY_MATRIX_MULTIPLY] = 'matmul';
204 | OPCODES_EXTRA[OPCODES.BINARY_FLOOR_DIVIDE] = 'floordiv';
205 | OPCODES_EXTRA[OPCODES.BINARY_TRUE_DIVIDE] = 'truediv';
206 | OPCODES_EXTRA[OPCODES.BINARY_MODULO] = 'mod';
207 | OPCODES_EXTRA[OPCODES.BINARY_ADD] = 'add';
208 | OPCODES_EXTRA[OPCODES.BINARY_SUBTRACT] = 'sub';
209 | OPCODES_EXTRA[OPCODES.BINARY_SUBSCR] = 'getitem';
210 | OPCODES_EXTRA[OPCODES.BINARY_LSHIFT] = 'lshift';
211 | OPCODES_EXTRA[OPCODES.BINARY_RSHIFT] = 'rshift';
212 | OPCODES_EXTRA[OPCODES.BINARY_AND] = 'and';
213 | OPCODES_EXTRA[OPCODES.BINARY_XOR] = 'xor';
214 | OPCODES_EXTRA[OPCODES.BINARY_OR] = 'or';
215 |
216 | OPCODES_EXTRA[OPCODES.INPLACE_POWER] = '__ipow__';
217 | OPCODES_EXTRA[OPCODES.INPLACE_MULTIPLY] = '__imul__';
218 | OPCODES_EXTRA[OPCODES.INPLACE_MATRIX_MULTIPLY] = '__imatmul__';
219 | OPCODES_EXTRA[OPCODES.INPLACE_FLOOR_DIVIDE] = '__ifloordiv__';
220 | OPCODES_EXTRA[OPCODES.INPLACE_TRUE_DIVIDE] = '__itruediv__';
221 | OPCODES_EXTRA[OPCODES.INPLACE_MODULO] = '__imod__';
222 | OPCODES_EXTRA[OPCODES.INPLACE_ADD] = '__iadd__';
223 | OPCODES_EXTRA[OPCODES.INPLACE_SUBTRACT] = '__isub__';
224 | OPCODES_EXTRA[OPCODES.INPLACE_LSHIFT] = '__ilshift__';
225 | OPCODES_EXTRA[OPCODES.INPLACE_RSHIFT] = '__irshift__';
226 | OPCODES_EXTRA[OPCODES.INPLACE_AND] = '__iand__';
227 | OPCODES_EXTRA[OPCODES.INPLACE_XOR] = '__ixor__';
228 | OPCODES_EXTRA[OPCODES.INPLACE_OR] = '__ior__';
229 | OPCODES_EXTRA[OPCODES.DELETE_SUBSCR] = '__delitem__';
230 |
231 | OPCODES_EXTRA[OPCODES.STORE_SUBSCR] = '__setitem__';
232 |
233 | OPCODES_EXTRA[OPCODES.SETUP_LOOP] = BLOCK_TYPES.LOOP;
234 | OPCODES_EXTRA[OPCODES.SETUP_EXCEPT] = BLOCK_TYPES.EXCEPT;
235 | OPCODES_EXTRA[OPCODES.SETUP_FINALLY] = BLOCK_TYPES.FINALLY;
236 |
--------------------------------------------------------------------------------
/src/runtime/core/__init__.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var py_object = PyType.native('object', []);
18 | var py_type = PyType.native('type', [py_object]);
19 |
20 | py_object.__class__ = py_type;
21 | py_type.__class__ = py_type;
22 |
23 |
24 | // #include 'iterator.js'
25 |
26 | // #include 'dict.js'
27 |
28 | // #include 'int.js'
29 |
30 | // #include 'float.js'
31 |
32 | // #include 'str.js'
33 | // #include 'bytes.js'
34 |
35 | // #include 'tuple.js'
36 | // #include 'list.js'
37 |
38 | // #include 'cell.js'
39 |
40 | // #include 'wrapper.js'
41 |
42 | // #include 'func.js'
43 | // #include 'generator.js'
44 | // #include 'method.js'
45 |
46 | // #include 'property.js'
47 |
48 | // #include 'slice.js'
49 |
50 | // #include 'exception.js'
51 | // #include 'traceback.js'
52 |
--------------------------------------------------------------------------------
/src/runtime/core/bytes.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var SINGLE_QUOTES_CODE = 39;
18 | var DOUBLE_QUOTES_CODE = 34;
19 |
20 |
21 | var Bytes = $Class('bytes', {
22 | constructor: function (array, cls) {
23 | if (!(array instanceof Uint8Array)) {
24 | raise(TypeError, 'invalid type of native bytes initializer');
25 | }
26 | PyObject.call(this, cls || Bytes.cls);
27 | this.array = array;
28 | },
29 |
30 | bool: function () {
31 | return this.array.length != 0;
32 | },
33 |
34 | get: function (offset) {
35 | return this.array[offset];
36 | },
37 |
38 | str: function () {
39 | var index;
40 | var result = [];
41 | // TODO: improve performance
42 | for (index = 0; index < this.array.length; index++) {
43 | result.push(String.fromCharCode(this.array[index]));
44 | }
45 | return new Str(result.join(''));
46 | },
47 |
48 | __repr__: function () {
49 | return new Str('b' + this.str().repr().value);
50 | },
51 |
52 | __hash__: function () {
53 | return siphash(this.str());
54 | },
55 |
56 | decode: function (encoding) {
57 | var decoder, result;
58 | if (!TextDecoder) {
59 | // Polyfill: https://github.com/inexorabletash/text-encoding
60 | raise(RuntimeError, 'browser does not support decoding, please enable the polyfill');
61 | }
62 | try {
63 | decoder = new TextDecoder(encoding || 'utf-8', {fatal: true});
64 | } catch (error) {
65 | raise(LookupError, 'unknown encoding: ' + encoding);
66 | }
67 | try {
68 | result = decoder.decode(this.array);
69 | } catch (error) {
70 | raise(UnicodeDecodeError, 'unable to decode bytes object, data is not valid');
71 | }
72 | return result;
73 | }
74 | });
75 |
76 | Bytes.prototype.toString = Bytes.prototype.repr;
77 |
78 |
79 | $.Bytes = Bytes;
80 |
--------------------------------------------------------------------------------
/src/runtime/core/cell.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var Cell = $Class('cell', {
18 | constructor: function (object) {
19 | PyObject.call(this, Cell.cls);
20 | this.set(object || None);
21 | },
22 |
23 | set: function (object) {
24 | if (!(object instanceof PyObject)) {
25 | raise(TypeError, 'only python objects can be stored in a cell');
26 | }
27 | this.object = object;
28 | },
29 |
30 | get: function () {
31 | return this.object;
32 | }
33 | });
34 |
35 |
36 | $.Cell = Cell;
37 |
--------------------------------------------------------------------------------
/src/runtime/core/dict.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var DICT_ITERATOR_TYPES = {
18 | KEYS: 0,
19 | VALUES: 1,
20 | ITEMS: 2
21 | };
22 |
23 |
24 | var Dict = $Class('dict', {
25 | constructor: function (table, cls) {
26 | PyObject.call(this, cls || Dict.cls);
27 | if (!issubclass(this.__class__, Dict.cls)) {
28 | raise(TypeError, 'unable to create dict with non dict subclass');
29 | }
30 | this.table = table || {};
31 | this.size = 0;
32 | if (!(this.table instanceof Object)) {
33 | raise(TypeError, 'invalid type of native dict initializer');
34 | }
35 | },
36 |
37 | get: function (str_key, fallback) {
38 | if (str_key instanceof Str) {
39 | str_key = str_key.value;
40 | } else if (typeof str_key != 'string') {
41 | raise(TypeError, 'invalid native dict key type');
42 | }
43 | var hash = siphash(str_key);
44 | var entry = this.table[hash];
45 | while (entry) {
46 | if (entry.key instanceof Str && entry.key.value == str_key) {
47 | return entry.value;
48 | }
49 | entry = entry.next;
50 | }
51 | return fallback;
52 | },
53 |
54 | set: function (str_key, value) {
55 | if (str_key instanceof Str) {
56 | str_key = str_key.value;
57 | } else if (typeof str_key != 'string') {
58 | raise(TypeError, 'invalid native dict key type');
59 | }
60 | var hash = siphash(str_key);
61 | var entry = this.table[hash];
62 | while (entry) {
63 | if (entry.key instanceof Str && entry.key.value == str_key) {
64 | entry.value = value;
65 | return;
66 | }
67 | entry = entry.next;
68 | }
69 | this.table[hash] = new Dict.Entry(new Str(str_key), value, this.table[hash]);
70 | this.size++;
71 | },
72 |
73 | pop: function (str_key) {
74 | var hash, entry, previous;
75 | if (str_key instanceof Str) {
76 | str_key = str_key.value;
77 | } else if (typeof str_key != 'string') {
78 | raise(TypeError, 'invalid native dict key type');
79 | }
80 | hash = siphash(str_key);
81 | entry = this.table[hash];
82 | while (entry) {
83 | if (entry.key instanceof Str && entry.key.value == str_key) {
84 | if (previous) {
85 | previous.next = entry.next;
86 | } else if (entry.next) {
87 | this.table[hash] = entry.next;
88 | } else {
89 | delete this.table[hash];
90 | }
91 | this.size--;
92 | return entry.value;
93 | }
94 | previous = entry;
95 | entry = entry.next;
96 | }
97 | },
98 |
99 | entries: function () {
100 | var hash, entry;
101 | var entries = [];
102 | for (hash in this.table) {
103 | if (this.table.hasOwnProperty(hash)) {
104 | entry = this.table[hash];
105 | while (entry) {
106 | entries.push(entry);
107 | entry = entry.next;
108 | }
109 | }
110 | }
111 | return entries;
112 | },
113 |
114 | keys: function () {
115 | return new Dict.Keys(this);
116 | },
117 |
118 | values: function () {
119 | return new Dict.Values(this);
120 | },
121 |
122 | items: function () {
123 | return new Dict.Items(this);
124 | },
125 |
126 | copy: function () {
127 | var hash, entry;
128 | var dict = new Dict();
129 | dict.size = this.size;
130 | for (hash in this.table) {
131 | if (this.table.hasOwnProperty(hash)) {
132 | entry = this.table[hash];
133 | while (entry) {
134 | dict.table[hash] = new Dict.Entry(entry.key, entry.value, dict.table[hash]);
135 | entry = entry.next;
136 | }
137 | }
138 | }
139 | return dict;
140 | },
141 |
142 | clear: function () {
143 | this.table = {};
144 | this.size = 0;
145 | },
146 |
147 | __len__: function () {
148 | return new Int(this.size);
149 | },
150 |
151 | __hash__: function () {
152 | return Int.MINUSONE;
153 | }
154 | });
155 |
156 |
157 | Dict.Entry = Class({
158 | constructor: function (key, value, next) {
159 | this.key = key;
160 | this.value = value;
161 | this.next = next;
162 | }
163 | });
164 |
165 |
166 | Dict.Iterator = Iterator.extend('dict_iterator', {
167 | constructor: function (dict, type) {
168 | PyObject.call(this, Dict.Iterator.cls);
169 | this.entries = dict.entries();
170 | this.position = 0;
171 | this.type = type;
172 | },
173 |
174 | next: function () {
175 | var entry;
176 | if (entry = this.entries[this.position++]) {
177 | switch (this.type) {
178 | case DICT_ITERATOR_TYPES.KEYS:
179 | return entry.key;
180 | case DICT_ITERATOR_TYPES.VALUES:
181 | return entry.value;
182 | case DICT_ITERATOR_TYPES.ITEMS:
183 | return new Tuple([entry.key, entry.value]);
184 | }
185 | }
186 | }
187 | });
188 |
189 |
190 | Dict.Keys = $Class('dict_keys', {
191 | constructor: function (dict) {
192 | PyObject.call(this, Dict.Values.cls);
193 | this.dict = dict;
194 | },
195 |
196 | __len__: function () {
197 | return this.dict.size;
198 | },
199 |
200 | __iter__: function () {
201 | return new Dict.Iterator(this.dict, DICT_ITERATOR_TYPES.KEYS);
202 | }
203 | });
204 |
205 |
206 | Dict.Values = $Class('dict_values', {
207 | constructor: function (dict) {
208 | PyObject.call(this, Dict.Values.cls);
209 | this.dict = dict;
210 | },
211 |
212 | __len__: function () {
213 | return this.dict.size;
214 | },
215 |
216 | __iter__: function () {
217 | return new Dict.Iterator(this.dict, DICT_ITERATOR_TYPES.VALUES);
218 | }
219 | });
220 |
221 |
222 | Dict.Items = $Class('dict_items', {
223 | constructor: function (dict) {
224 | PyObject.call(this, Dict.Items.cls);
225 | this.dict = dict;
226 | },
227 |
228 | __len__: function () {
229 | return this.dict.size;
230 | },
231 |
232 | __iter__: function () {
233 | return new Dict.Iterator(this.dict, DICT_ITERATOR_TYPES.ITEMS);
234 | }
235 | });
236 |
237 |
238 |
239 | $.Dict = Dict;
240 |
--------------------------------------------------------------------------------
/src/runtime/core/exception.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var Exception = $Class('BaseException', {
18 | constructor: function (args, cls) {
19 | PyObject.call(this, cls || Exception.cls);
20 | this.args = args;
21 | }
22 | });
23 |
24 |
25 | function make_exception(cls, message) {
26 | var exc_value = new PyObject(cls, {});
27 | exc_value.__dict__['args'] = pack_tuple([Str.pack(message)]);
28 | return exc_value;
29 | }
30 |
31 |
32 |
33 |
34 | function format_exception(exc_value) {
35 | var string = [];
36 | if (exc_value.traceback) {
37 | string.push(format_traceback(exc_value.traceback));
38 | }
39 | if (exc_value.getattr('args') instanceof Tuple && exc_value.getattr('args').array[0] instanceof Str) {
40 | string.push(exc_value.__class__.name + ': ' + exc_value.getattr('args').array[0]);
41 | } else {
42 | string.push(exc_value.__class__.name);
43 | }
44 | return string.join('\n');
45 | }
46 |
47 | function print_exception(exc_value) {
48 | console.error(format_exception(exc_value));
49 | }
50 |
51 | $.Exception = Exception;
52 |
--------------------------------------------------------------------------------
/src/runtime/core/float.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | * Copyright (C) 2016, Matthias Heerde
4 | *
5 | * This program is free software: you can redistribute it and/or modify it under
6 | * the terms of the GNU Lesser General Public License version 3 as published by
7 | * the Free Software Foundation.
8 | *
9 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
10 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
12 | *
13 | * You should have received a copy of the GNU Lesser General Public License along
14 | * with this program. If not, see .
15 | */
16 |
17 |
18 | var Float = $Class('float', {
19 | constructor: function (value, cls) {
20 | if (!(typeof value == 'number')) {
21 | raise(TypeError, 'invalid type of native float initializer');
22 | }
23 | PyObject.call(this, cls || Float.cls);
24 | this.value = value;
25 | },
26 |
27 | __abs__: function () {
28 | return new Float(Math.abs(this.value));
29 | },
30 |
31 | to_number: function () {
32 | return this.value;
33 | },
34 |
35 | equals: function(other) {
36 | other = Float.unpack(other);
37 | return this.value == other ? True : False;
38 | },
39 |
40 | add: function(other) {
41 | other = Float.unpack(other);
42 | return new Float(this.value + other);
43 | },
44 |
45 | is_integer: function() {
46 | return Math.floor(this.value) == this.value ? True : False;
47 | },
48 |
49 | as_integer_ratio: function() {
50 | if (this.value == Number.POSITIVE_INFINITY || this.value == Number.NEGATIVE_INFINITY) {
51 | raise(OverflowError, 'Cannot pass infinity to float.as_integer_ratio.');
52 | }
53 | if (!Number.isFinite(this.value)) {
54 | raise(ValueError, 'Cannot pass NaN to float.as_integer_ratio.');
55 | }
56 | raise(NotImplemented);
57 | }
58 | });
59 |
60 | Float.pack = function (value) {
61 | return new Float(value);
62 | };
63 |
64 |
65 | Float.unpack = function (object, fallback) {
66 | if ((object === None || !object) && fallback != undefined) {
67 | return fallback;
68 | }
69 | if (typeof object == 'number') {
70 | return object;
71 | }
72 | if (!(object instanceof Int) && !(object instanceof Float)) {
73 | raise(TypeError, 'unable to unpack number from object');
74 | }
75 | return object.to_number();
76 | };
77 |
78 | $.Float = Float;
79 |
--------------------------------------------------------------------------------
/src/runtime/core/func.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var Func = $Class('function', {
18 | constructor: function (name, code, options, cls) {
19 | PyObject.call(this, cls || Func.cls);
20 |
21 | this.name = name;
22 | this.code = code;
23 |
24 | this.qualname = options.qualname || this.name;
25 | this.doc = options.doc || '';
26 | this.module = options.module || 'builtins';
27 | this.defaults = options.defaults || null;
28 | this.closure = options.closure || null;
29 | this.globals = options.globals || null;
30 | }
31 | });
32 |
33 |
34 | function $def(func, signature, options) {
35 | options = options || {};
36 | var name = options.name || '';
37 | var code = new NativeCode(func, options, signature);
38 | return new Func(name, code, options);
39 | }
40 |
41 | $.Func = Func;
42 |
43 | $.$def = $def;
44 |
--------------------------------------------------------------------------------
/src/runtime/core/generator.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var Generator = $Class('generator', {
18 | constructor: function (code, frame) {
19 | PyObject.call(this, Generator.cls);
20 | this.code = code;
21 | this.frame = frame;
22 | }
23 | });
24 |
25 |
26 | $.Generator = Generator;
27 |
--------------------------------------------------------------------------------
/src/runtime/core/int.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | var Int = $Class('int', {
17 | constructor: function (value, cls) {
18 | PyObject.call(this, cls || Int.cls);
19 | try {
20 | this.value = bigInt(value);
21 | } catch (error) {
22 | raise(TypeError, 'invalid type of native int initializer');
23 | }
24 | },
25 |
26 | toString: function () {
27 | return this.value.toString();
28 | },
29 |
30 | valueOf: function () {
31 | return this.number();
32 | },
33 |
34 | to_bool: function () {
35 | return this.value.neq(0);
36 | },
37 |
38 | to_string: function () {
39 | return this.value.toString();
40 | },
41 |
42 | is: function (other) {
43 | if (other instanceof Int) {
44 | return this.value.eq(other.value);
45 | }
46 | return false;
47 | },
48 |
49 | to_number: function () {
50 | var number = this.value.toJSNumber();
51 | if (number == Infinity || number == -Infinity) {
52 | raise(OverflowError, 'int too large to convert to float');
53 | }
54 | return number;
55 | },
56 |
57 | float: function () {
58 | return new Float(this.to_number());
59 | },
60 |
61 |
62 | __abs__: function () {
63 | return new Int(this.value.abs());
64 | },
65 |
66 | __pos__: function () {
67 | return this;
68 | },
69 |
70 | __neg__: function () {
71 | return new Int(this.value.negate());
72 | },
73 |
74 | __invert__: function () {
75 | return new Int(this.value.not());
76 | },
77 |
78 | __add__: function (other) {
79 | return new Int(this.value.add(other.value));
80 | },
81 |
82 | __sub__: function (other) {
83 | return new Int(this.value.subtract(other.value));
84 | },
85 |
86 | __pow__: function (other) {
87 | if (other < 0) {
88 | return Float.pack(Math.pow(this.to_number(), other.to_number()));
89 | }
90 | return new Int(this.value.pow(other.value));
91 | },
92 |
93 | __mul__: function (other) {
94 | return new Int(this.value.multiply(other.value));
95 | },
96 |
97 | __floordiv__: function (other) {
98 | return new Int(this.value.divide(other.value));
99 | },
100 |
101 | __truediv__: function (other) {
102 | return Float.pack(this.to_number() / other.to_number());
103 | },
104 |
105 | __mod__: function (other) {
106 | if (!this.value.sign && other.value.sign) {
107 | return new Int(this.value.mod(other.value).substract(other.value));
108 | } else if (this.value.sign && !other.value.sign) {
109 | return new Int(other.value.substract(this.value.mod(other.value)));
110 | }
111 | return new Int(this.value.mod(other.value));
112 | },
113 |
114 | __lshift__: function (other) {
115 | return new Int(this.value.shiftLeft(other.value));
116 | },
117 |
118 |
119 | __rshift__: function (other) {
120 | return new Int(this.value.shiftRight(other.value));
121 | },
122 |
123 | __and__: function (other) {
124 | return new Int(this.value.and(other.value));
125 | },
126 |
127 | __xor__: function (other) {
128 | return new Int(this.value.xor(other.value));
129 | },
130 |
131 | __or__: function (other) {
132 | return new Int(this.value.or(other.value));
133 | },
134 |
135 | __lt__: function (other) {
136 | return this.value.lt(other.value);
137 | },
138 |
139 | __le__: function (other) {
140 | return this.value.leq(other.value);
141 | },
142 |
143 | __eq__: function (other) {
144 | if (!(other instanceof Int)) {
145 | return false;
146 | }
147 | return this.value.eq(other.value);
148 | },
149 |
150 | __ne__: function (other) {
151 | return this.value.neq(other.value);
152 | },
153 |
154 | __gt__: function (other) {
155 | return this.value.gt(other.value);
156 | },
157 |
158 | __ge__: function (other) {
159 | return this.value.geq(other.value);
160 | },
161 |
162 | __hash__: function () {
163 | if (this.value.eq(-1)) {
164 | return Int.pack(-2);
165 | } else {
166 | return this;
167 | }
168 | }
169 | });
170 |
171 |
172 | Int.parse = function (string, base) {
173 | if (base instanceof Int) {
174 | return new Int(bigInt(string, base.value));
175 | }
176 | raise(TypeError, 'invalid type of integer base');
177 | };
178 |
179 | Int.unpack = function (object, fallback) {
180 | if ((object === None || object == undefined) && fallback != undefined) {
181 | return fallback;
182 | }
183 | if (object instanceof Int) {
184 | return object.to_number();
185 | } else if (typeof object == 'number') {
186 | return object | 0;
187 | } else {
188 | raise(TypeError, 'unable to unpack integer from object');
189 | }
190 | };
191 |
192 | Int.pack = function (value) {
193 | return new Int(value);
194 | };
195 |
196 | Int.ZERO = new Int(0);
197 | Int.ONE = new Int(1);
198 | Int.MINUSONE = new Int(-1);
199 |
200 | $.Int = Int;
201 |
--------------------------------------------------------------------------------
/src/runtime/core/iterator.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var Iterator = $Class('iterator', {
18 | constructor: function (cls) {
19 | PyObject.call(this, cls);
20 | },
21 |
22 | next: function () {
23 | raise(NotImplemented, 'next not implemented by native iterator');
24 | },
25 |
26 | __next__: function () {
27 | var value = this.next();
28 | if (!value) {
29 | raise(StopIteration);
30 | }
31 | return value;
32 | },
33 |
34 | __iter__: function () {
35 | return this;
36 | }
37 | });
38 |
39 |
40 | $.Iterator = Iterator;
41 |
--------------------------------------------------------------------------------
/src/runtime/core/list.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var List = $Class('list', {
18 | constructor: function (initializer, size, cls) {
19 | PyObject.call(this, cls || List.cls);
20 | this.value = new Array(4);
21 | if (initializer) {
22 | if (!(initializer instanceof Array)) {
23 | raise(TypeError, 'invalid type of list initializer');
24 | }
25 | this.size = initializer.length;
26 | } else {
27 | this.size = size || 0;
28 | }
29 | this.grow();
30 | if (initializer) {
31 | for (var index = 0; index < initializer.length; index++) {
32 | this.value[index] = initializer[index];
33 | }
34 | }
35 | },
36 |
37 | check: function (index) {
38 | if (index < 0) {
39 | index = this.size - index;
40 | }
41 | if (index < 0 || index > this.size - 1) {
42 | raise(IndexError, 'index out of range');
43 | }
44 | return index;
45 | },
46 |
47 | grow: function () {
48 | while (this.value.length <= this.size) {
49 | var length = this.value.length * 2;
50 | while (length <= this.size) {
51 | length *= 2;
52 | }
53 | this.value.length = length;
54 | }
55 | },
56 |
57 | shrink: function () {
58 | if (this.value.length > 4 && this.value.length / 4 >= this.size) {
59 | var length = this.value.length / 2;
60 | while (length / 4 >= this.size && length > 4) {
61 | length /= 2;
62 | }
63 | this.value.length = length;
64 | }
65 | },
66 |
67 | get: function (index) {
68 | index = this.check(index);
69 | return this.value[index] || None;
70 | },
71 |
72 | set: function (index, item) {
73 | index = this.check(index);
74 | return this.value[index] = item;
75 | },
76 |
77 | append: function (item) {
78 | this.size++;
79 | this.grow();
80 | this.value[this.size - 1] = item;
81 | return item;
82 | },
83 |
84 | pop: function (index) {
85 | index = this.check(index);
86 | this.size--;
87 | if (index == null) {
88 | index = this.size;
89 | }
90 | var item = this.value[index];
91 | for (; index < this.size; index++) {
92 | this.value[index] = this.value[index + 1];
93 | }
94 | this.value[index] = null;
95 | this.shrink();
96 | return item;
97 | },
98 |
99 | clear: function () {
100 | this.value = new Array(4);
101 | this.size = 0;
102 | },
103 |
104 | slice: function (start, stop, step) {
105 | var index, list = new List();
106 | if (start == undefined) {
107 | start = 0;
108 | } else if (start < 0) {
109 | start = this.size + start;
110 | }
111 | if (stop == undefined) {
112 | stop = this.size;
113 | } else if (stop < 0) {
114 | stop = this.size + stop;
115 | }
116 | step = step || 1;
117 | if (step > 0) {
118 | if (start < 0) {
119 | start = 0;
120 | }
121 | if (stop > this.size) {
122 | stop = this.size;
123 | }
124 | for (index = start; index < stop; index += step) {
125 | list.append(this.value[index]);
126 | }
127 | } else if (step < 0) {
128 | if (start >= this.size) {
129 | start = this.size - 1;
130 | }
131 | if (stop < 0) {
132 | stop = 0;
133 | }
134 | for (index = start; index > stop; index += step) {
135 | list.append(this.value[index]);
136 | }
137 | } else {
138 | raise(ValueError, 'slice step cannot be zero')
139 | }
140 | return list;
141 | },
142 |
143 | concat: function (list_or_array) {
144 | var list, index, size;
145 | if (list_or_array instanceof List) {
146 | size = list_or_array.size;
147 | list_or_array = list_or_array.value;
148 | } else if (list_or_array instanceof Array) {
149 | size = list_or_array.length;
150 | } else {
151 | raise(TypeError, 'invalid type of concatenation object');
152 | }
153 | list = new List(null, this.size + size);
154 | for (index = 0; index < this.size; index++) {
155 | list.value[index] = this.value[index];
156 | }
157 | for (index = 0; index < size; index++) {
158 | list.value[index + this.size] = list_or_array[index];
159 | }
160 | return list;
161 | },
162 |
163 | copy: function () {
164 | return this.concat([]);
165 | },
166 |
167 | __iter__: function () {
168 | return new List.Iterator(this);
169 | },
170 |
171 | __len__: function () {
172 | return new Int(this.size);
173 | },
174 |
175 | __hash__: function () {
176 | return Int.MINUSONE;
177 | },
178 |
179 | __mul__: function (other) {
180 | if (!(other instanceof Int)) {
181 | raise(UnsupportedOperation, 'unsupported operation')
182 | }
183 | var result = new List();
184 | var iterations = Int.unpack(other);
185 | for (var iteration = 0; iteration < iterations; iteration++) {
186 | for (var index = 0; index < this.size; index++) {
187 | result.append(this.value[index]);
188 | }
189 | }
190 | return result;
191 | }
192 | });
193 |
194 |
195 | List.Iterator = Iterator.extend('list_iterator', {
196 | constructor: function (list) {
197 | Iterator.call(this, List.Iterator.cls);
198 | this.list = list;
199 | this.position = 0;
200 | },
201 |
202 | next: function () {
203 | if (this.position < this.list.size) {
204 | return this.list.value[this.position++];
205 | }
206 | }
207 | });
208 |
209 |
210 | $.List = List;
211 |
--------------------------------------------------------------------------------
/src/runtime/core/method.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var Method = $Class('method', {
18 | constructor: function (self, func) {
19 | PyObject.call(this, Method.cls);
20 | this.self = self;
21 | this.func = func;
22 | }
23 | });
24 |
25 |
--------------------------------------------------------------------------------
/src/runtime/core/property.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var Property = $Class('property', {
18 | constructor: function (getter, setter) {
19 | PyObject.call(this, Property.cls, {
20 | 'fget': getter || None,
21 | 'fset': setter || None
22 | });
23 | this.getter = getter;
24 | this.setter = setter;
25 | }
26 | });
27 |
28 | function new_property(getter, setter) {
29 | return new Property(getter, setter);
30 | }
31 |
--------------------------------------------------------------------------------
/src/runtime/core/slice.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var Slice = $Class('slice', {
18 | constructor: function (start, stop, step) {
19 | // TODO: check step
20 |
21 | PyObject.call(this, Slice.cls);
22 |
23 | this.start = start;
24 | this.stop = stop;
25 | this.step = step || None;
26 | },
27 |
28 | normalize: function (length) {
29 | var start, stop, step;
30 | length = Int.unpack(length);
31 | step = Int.unpack(this.step, 1);
32 | if (step == 0) {
33 | raise(ValueError, 'slice step must not be zero');
34 | }
35 | start = Int.unpack(this.start, 0);
36 | stop = Int.unpack(this.stop, length);
37 | if (start < 0) {
38 | start += length;
39 | }
40 | if (stop < 0) {
41 | stop += length;
42 | }
43 | return new Slice(Math.max(0, start), Math.min(stop, length), step);
44 | }
45 |
46 | });
47 |
48 |
49 | function new_slice(start, stop, step) {
50 | return new Slice(start, stop, step);
51 | }
52 |
53 | $.Slice = Slice;
54 |
--------------------------------------------------------------------------------
/src/runtime/core/traceback.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var Traceback = $Class('traceback', {
18 | constructor: function (frame, position, line, next) {
19 | PyObject.call(this, Traceback.cls);
20 | this.frame = frame;
21 | this.position = position;
22 | this.line = line;
23 | this.next = next || None;
24 | }
25 | });
26 |
27 |
28 | function format_traceback(traceback) {
29 | var string = ['Traceback (most recent call last):'];
30 | while (traceback && traceback != None) {
31 | string.push(' File \'' + traceback.frame.code.filename + '\', line ' + traceback.line + ', in ' + traceback.frame.code.name);
32 | traceback = traceback.next;
33 | }
34 | return string.join('\n');
35 | }
36 |
37 | function print_traceback(traceback) {
38 | console.error(format_traceback(traceback));
39 | }
40 |
41 |
42 | $.Traceback = Traceback;
43 |
--------------------------------------------------------------------------------
/src/runtime/core/tuple.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var Tuple = $Class('tuple', {
18 | constructor: function (array, cls) {
19 | if (array instanceof Tuple) {
20 | array = array.array;
21 | }
22 | if (!(array instanceof Array)) {
23 | raise(TypeError, 'invalid type of native tuple initializer');
24 | }
25 | PyObject.call(this, cls || Tuple.cls);
26 | this.array = array;
27 | Object.freeze(this.array);
28 | },
29 |
30 | get: function (index) {
31 | return this.array[index];
32 | },
33 |
34 | len: function () {
35 | return this.array.length;
36 | },
37 |
38 | __iter__: function () {
39 | return new Tuple.Iterator(this);
40 | }
41 | });
42 |
43 |
44 | Tuple.Iterator = Iterator.extend('tuple_iterator', {
45 | constructor: function (tuple) {
46 | PyObject.call(this, Tuple.Iterator.cls);
47 | this.tuple = tuple;
48 | this.position = 0;
49 | },
50 |
51 | next: function () {
52 | if (this.position < this.tuple.array.length) {
53 | return this.tuple.array[this.position++];
54 | }
55 | }
56 | });
57 |
58 | Tuple.unpack = function (object, fallback) {
59 | if ((object === None || !object) && fallback !== undefined) {
60 | return fallback;
61 | }
62 | if (object instanceof Tuple) {
63 | return object.array;
64 | } else if (Array.isArray(object)) {
65 | return object;
66 | } else {
67 | raise(TypeError, 'unable to unpack array from object');
68 | }
69 | };
70 |
71 | Tuple.EMPTY = new Tuple([]);
72 |
73 | $.Tuple = Tuple;
74 |
--------------------------------------------------------------------------------
/src/runtime/core/wrapper.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var PyJSObject = PyObject.extend({
18 | constructor: function (object, cls) {
19 | if (!(object instanceof Object)) {
20 | raise(TypeError, 'invalid type of native object initializer');
21 | }
22 | PyObject.call(this, cls || py_js_object);
23 | this.object = object;
24 | },
25 |
26 | primitive: function () {
27 | return this.object;
28 | }
29 | });
30 |
31 |
32 | var PyJSArray = PyObject.extend({
33 | constructor: function (array, cls) {
34 | if (!(array instanceof Array)) {
35 | raise(TypeError, 'invalid type of native array initializer');
36 | }
37 | PyObject.call(this, cls || py_js_array);
38 | this.array = array;
39 | },
40 |
41 | primitive: function () {
42 | return this.array;
43 | }
44 | });
45 |
46 |
47 | var PyJSFunction = PyObject.extend({
48 | constructor: function (func, cls) {
49 | if (typeof func != 'function') {
50 | raise(TypeError, 'invalid type of native function initializer');
51 | }
52 | PyObject.call(this, cls || py_js_function);
53 | this.func = func;
54 | },
55 |
56 | primitive: function () {
57 | return this.func;
58 | }
59 | });
60 |
61 |
62 | $.PyJSObject = PyJSObject;
63 | $.PyJSArray = PyJSArray;
64 | $.PyJSFunction = PyJSFunction;
65 |
--------------------------------------------------------------------------------
/src/runtime/dis.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | function disassemble(code) {
17 | var instruction, opcode, high, low, argument, index;
18 |
19 | var instructions = [];
20 | var table = {};
21 | var position = 0;
22 |
23 | while (position < code.bytecode.length) {
24 | instruction = {start: position};
25 | table[position] = instruction;
26 |
27 | opcode = code.bytecode.charCodeAt(position++);
28 | if (opcode >= OPCODES_ARGUMENT) {
29 | low = code.bytecode.charCodeAt(position++);
30 | high = code.bytecode.charCodeAt(position++);
31 | argument = high << 8 | low;
32 | }
33 | if (opcode === OPCODES.EXTENDED_ARG) {
34 | opcode = code.bytecode.charCodeAt(position++);
35 | low = code.bytecode.charCodeAt(position++);
36 | high = code.bytecode.charCodeAt(position++);
37 | argument = (argument << 16) | (high << 8) | low;
38 | }
39 | instruction.position = instructions.length;
40 | instruction.end = position;
41 | instruction.opcode = opcode;
42 | instruction.argument = argument;
43 | instructions.push(instruction);
44 | }
45 |
46 | for (index = 0; index < instructions.length; index++) {
47 | instruction = instructions[index];
48 | switch (instruction.opcode) {
49 | case OPCODES.JUMP_FORWARD:
50 | instruction.opcode = OPCODES.JUMP_ABSOLUTE;
51 | case OPCODES.FOR_ITER:
52 | case OPCODES.SETUP_EXCEPT:
53 | case OPCODES.SETUP_FINALLY:
54 | case OPCODES.SETUP_LOOP:
55 | case OPCODES.SETUP_WITH:
56 | instruction.target = table[instruction.end + instruction.argument].position;
57 | break;
58 |
59 | case OPCODES.JUMP_IF_FALSE_OR_POP:
60 | case OPCODES.JUMP_IF_TRUE_OR_POP:
61 | case OPCODES.POP_JUMP_IF_FALSE:
62 | case OPCODES.POP_JUMP_IF_TRUE:
63 | case OPCODES.JUMP_ABSOLUTE:
64 | instruction.target = table[instruction.argument].position;
65 | break;
66 | }
67 | }
68 |
69 | return instructions;
70 | }
71 |
72 |
73 | $.disassemble = disassemble;
74 |
--------------------------------------------------------------------------------
/src/runtime/future.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var Future = Class.extend({
18 | constructor: function () {
19 | this.result = null;
20 |
21 | this.success = false;
22 | this.error = false;
23 |
24 | this.callbacks = [];
25 | },
26 |
27 | done: function (callback) {
28 | if (this.error || this.success) {
29 | callback(this);
30 | } else {
31 | this.callbacks.push(callback);
32 | }
33 | },
34 |
35 | run_callbacks: function () {
36 | for (var index = 0; index < this.callbacks.length; index++) {
37 | this.callbacks[index](this)
38 | }
39 | },
40 |
41 | set_result: function (result) {
42 | this.result = result;
43 | this.success = true;
44 | this.run_callbacks();
45 | },
46 |
47 | set_exception: function (exception) {
48 | this.result = exception;
49 | this.error = true;
50 | this.run_callbacks();
51 | }
52 | });
53 |
54 |
55 | $.Future = Future;
56 |
--------------------------------------------------------------------------------
/src/runtime/module.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | var modules = {};
17 | var pending = {};
18 |
19 | function get_module(name) {
20 | if (name in modules) {
21 | return modules[name];
22 | } else {
23 | raise(ImportError, 'no module named \'' + name + '\'');
24 | }
25 | }
26 |
27 | function get_namespace(name) {
28 | return get_module(name).__dict__;
29 | }
30 |
31 | function register_module(name, module) {
32 | modules[name] = module;
33 | module.__dict__['__name__'] = Str.pack(name);
34 | }
35 |
36 | function unregister_module(name) {
37 | delete modules[name];
38 | }
39 |
40 |
41 | var Module = Class.extend({
42 | constructor: function (name, depends) {
43 | this.name = name;
44 | this.depends = depends || [];
45 | this.__dict__ = {};
46 | if (this.name) {
47 | register_module(this.name, this);
48 | }
49 | this.wrapper = null;
50 | }
51 | });
52 |
53 |
54 | var PythonModule = Module.extend({
55 | constructor: function (name, code, depends) {
56 | Module.call(this, name, depends);
57 | this.code = code;
58 | this.frame = null;
59 | }
60 | });
61 |
62 |
63 | var NativeModule = Module.extend({
64 | constructor: function (name, func, depends) {
65 | Module.call(this, name, depends);
66 | this.func = func;
67 | if (func) {
68 | func.apply(null, [jaspy, this].concat(this.depends.map(get_namespace)));
69 | }
70 | },
71 |
72 | $def: function (name, func, signature, options) {
73 | options = options || {};
74 | signature = signature || [];
75 | options.module = this.name;
76 | options.name = name;
77 | options.qualname = name;
78 | options.simple = func.length == signature.length;
79 | this.__dict__[name] = $def(func, signature, options);
80 | return this.__dict__[name];
81 | },
82 |
83 | $set: function (name, value) {
84 | this.__dict__[name] = value;
85 | return this.__dict__[name];
86 | },
87 |
88 | $class: function (name, bases, mcs) {
89 | this.__dict__[name] = PyType.native(name, bases, null, mcs);
90 | return this.__dict__[name];
91 | }
92 | });
93 |
94 | function module(name, initializer, depends) {
95 | if (typeof initializer == 'function') {
96 | return new NativeModule(name, initializer, depends);
97 | } else if (initializer instanceof PythonCode) {
98 | return new PythonModule(name, initializer, depends);
99 | } else {
100 | throw new Error('invalid type of code or function');
101 | }
102 | }
103 |
104 |
105 | $.get_module = get_module;
106 | $.get_namespace = get_namespace;
107 |
108 | $.module = module;
109 |
110 | $.modules = modules;
111 |
--------------------------------------------------------------------------------
/src/runtime/object.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var object_id_counter = 0;
18 |
19 | /**
20 | * Python Object
21 | * =============
22 | * Base class of all Python objects.
23 | *
24 | * __class___: PyType
25 | * Type of the Python object.
26 | *
27 | * __addr__: null | JS.Number
28 | * Virtual memory address of the object.
29 | *
30 | * __dict__: Dict | JS.Object
31 | * Mapping containing instance attributes.
32 | */
33 | var PyObject = Class.extend({
34 | constructor: function (cls, dict) {
35 | this.__class__ = cls;
36 | this.__addr__ = null;
37 | this.__dict__ = dict === undefined ? {} : dict;
38 | },
39 |
40 | get_id: function () {
41 | if (this.__addr__ === null) {
42 | this.__addr__ = object_id_counter++;
43 | }
44 | return this.__addr__;
45 | },
46 |
47 | get_address: function () {
48 | return ('0000000000000' + this.get_id().toString(16)).substr(-13);
49 | },
50 |
51 | call: function (name, args, kwargs) {
52 | var method = this.__class__.lookup(name);
53 | if (method) {
54 | if (isinstance(method, py_classmethod)) {
55 | return call(method.func, [this.__class__].concat(args || []), kwargs);
56 | } else if (isinstance(method, py_staticmethod)) {
57 | return call(method.func, args, kwargs);
58 | } else if (name == '__new__') {
59 | return call(method, [this.__class__].concat(args || []), kwargs);
60 | }
61 | return call(method, [this].concat(args || []), kwargs);
62 | } else {
63 | vm.return_value = null;
64 | vm.last_exception = METHOD_NOT_FOUND;
65 | return false;
66 | }
67 | },
68 |
69 | setattr: function (name, value) {
70 | if (!this.__dict__) {
71 | raise(TypeError, 'object does not support attribute access');
72 | }
73 | if (name instanceof Str) {
74 | name = name.value;
75 | } else if (typeof name != 'string') {
76 | raise(TypeError, 'native attribute name must be a string');
77 | }
78 | if (this.__dict__ instanceof Dict) {
79 | return this.__dict__.set(name, value);
80 | } else {
81 | this.__dict__[name] = value;
82 | }
83 | },
84 |
85 | getattr: function (name) {
86 | if (!this.__dict__) {
87 | raise(TypeError, 'object does not support attribute access');
88 | }
89 | if (name instanceof Str) {
90 | name = name.value;
91 | } else if (typeof name != 'string') {
92 | raise(TypeError, 'native attribute name must be a string');
93 | }
94 | if (this.__dict__ instanceof Dict) {
95 | return this.__dict__.get(name);
96 | } else {
97 | return this.__dict__[name];
98 | }
99 | },
100 |
101 | is: function (other) {
102 | return this === other;
103 | },
104 |
105 |
106 | /* low level implicit conversions */
107 |
108 | to_bool: function () {
109 | return true;
110 | },
111 |
112 | to_number: function () {
113 | raise(TypeError, 'unable to convert object to native number implicitly');
114 | },
115 |
116 | to_string: function () {
117 | raise(TypeError, 'unable to convert object to native string implicitly');
118 | },
119 |
120 |
121 | /* expose special methods to native code */
122 |
123 | repr: function () {
124 | return this.__repr__();
125 | },
126 |
127 | str: function () {
128 | return this.__str__();
129 | },
130 |
131 | len: function () {
132 | return this.__len__();
133 | },
134 |
135 | iter: function () {
136 | return this.__iter__();
137 | },
138 |
139 | add: function (other) {
140 | return this.__add__(other);
141 | },
142 |
143 | sub: function (other) {
144 | return this.__sub__(other);
145 | },
146 |
147 | mul: function (other) {
148 | return this.__mul__(other);
149 | },
150 |
151 | truediv: function (other) {
152 | return this.__truediv__(other);
153 | },
154 |
155 | floordiv: function (other) {
156 | return this.__floordiv__(other);
157 | },
158 |
159 | mod: function (other) {
160 | return this.__mod__(other);
161 | },
162 |
163 | divmod: function (other) {
164 | return this.__divmod__(other);
165 | },
166 |
167 | lshift: function (other) {
168 | return this.__lshift__(other);
169 | },
170 |
171 | rshift: function (other) {
172 | return this.__rshift__(other);
173 | },
174 |
175 | and: function (other) {
176 | return this.__and__(other);
177 | },
178 |
179 | xor: function (other) {
180 | return this.__xor__(other);
181 | },
182 |
183 | or: function (other) {
184 | return this.__or__(other);
185 | },
186 |
187 | neg: function () {
188 | return this.__neg__();
189 | },
190 |
191 | pos: function () {
192 | return this.__pos__();
193 | },
194 |
195 | abs: function () {
196 | return this.__abs__();
197 | },
198 |
199 | invert: function () {
200 | return this.__invert__();
201 | },
202 |
203 | hash: function () {
204 | return this.__hash__();
205 | },
206 |
207 | eq: function (other) {
208 | return this.__eq__(other);
209 | },
210 |
211 | ne: function (other) {
212 | return this.__ne__(other);
213 | },
214 |
215 | gt: function (other) {
216 | return this.__gt__(other);
217 | },
218 |
219 | ge: function (other) {
220 | return this.__ge__(other);
221 | },
222 |
223 | lt: function (other) {
224 | return this.__lt__(other);
225 | },
226 |
227 | le: function (other) {
228 | return this.__le__(other);
229 | },
230 |
231 |
232 | /* special methods */
233 |
234 | __repr__: function () {
235 | return '<' + this.__class__.name + ' object at 0x' + this.get_address() + '>';
236 | },
237 |
238 | __str__: function () {
239 | return this.__repr__();
240 | },
241 |
242 | __hash__: function () {
243 | return siphash(this.get_address());
244 | }
245 | });
246 |
247 | PyObject.prototype.toString = PyObject.prototype.repr;
248 |
249 |
250 | function isinstance(object, cls) {
251 | var index;
252 | for (index = 0; index < object.__class__.mro.length; index++) {
253 | if (object.__class__.mro[index] === cls) {
254 | return true;
255 | }
256 | }
257 | return false;
258 | }
259 |
260 |
261 | $.PyObject = PyObject;
262 |
263 | $.isinstance = isinstance;
264 |
--------------------------------------------------------------------------------
/src/runtime/python/__init__.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | // #include 'boot.js'
17 |
18 | // #include 'object.js'
19 | // #include 'type.js'
20 | // #include 'dict.js'
21 | // #include 'int.js'
22 | // #include 'bool.js'
23 | // #include 'float.js'
24 | // #include 'str.js'
25 | // #include 'bytes.js'
26 | // #include 'list.js'
27 | // #include 'function.js'
28 | // #include 'generator.js'
29 | // #include 'method.js'
30 | // #include 'property.js'
31 | // #include 'slice.js'
32 | // #include 'module.js'
33 | // #include 'none.js'
34 | // #include 'exception.js'
35 | // #include 'iterator.js'
36 |
37 | // #include 'tuple.js'
38 |
39 | // #include 'builtins.js'
40 |
41 | // #include 'helpers.js'
42 |
43 | // #include 'wrapper.js'
44 |
--------------------------------------------------------------------------------
/src/runtime/python/bool.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | var TRUE_STR = Str.pack('True');
17 | var FALSE_STR = Str.pack('False');
18 |
19 | py_bool.$def('__new__', function (cls, initializer, state, frame) {
20 | switch (state) {
21 | case 0:
22 | // FIXME: subclassing bool is not allowed
23 | if (!(issubclass(cls, py_bool))) {
24 | raise(TypeError, 'class is not an subclass of to_bool');
25 | }
26 | if (initializer.call('__bool__')) {
27 | return 1;
28 | }
29 | case 1:
30 | if (except(MethodNotFoundError)) {
31 | if (initializer.call('__len__')) {
32 | return 2;
33 | }
34 | } else {
35 | if (vm.return_value && vm.return_value.__class__ !== py_bool) {
36 | raise(TypeError, '__bool__ should return bool');
37 | }
38 | return vm.return_value;
39 | }
40 | case 2:
41 | if (except(MethodNotFoundError)) {
42 | return True;
43 | } else if (vm.return_value) {
44 | // FIXME: create object of class cls
45 | return vm.return_value.ne(False) ? True : False;
46 | }
47 | }
48 | }, ['initializer'], {defaults: {initializer: False}});
49 |
50 | py_bool.$def('__str__', function (self) {
51 | return self.ne(False) ? TRUE_STR : FALSE_STR;
52 | });
53 |
--------------------------------------------------------------------------------
/src/runtime/python/boot.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | var py_bool = PyType.native('to_bool', [Int.cls]);
18 |
19 | var py_js_object = PyType.native('JSObject');
20 | var py_js_array = PyType.native('JSArray', [py_js_object]);
21 | var py_js_function = PyType.native('JSFunction', [py_js_object]);
22 |
23 | var py_traceback = PyType.native('traceback');
24 |
25 | var py_set = PyType.native('set');
26 | var py_frozenset = PyType.native('frozenset');
27 |
28 | var py_classmethod = PyType.native('classmethod');
29 | var py_staticmethod = PyType.native('staticmethod');
30 |
31 | var py_module = PyType.native('ModuleType');
32 |
33 | var None = new PyObject(PyType.native('NoneType'));
34 | var NotImplemented = new PyObject(PyType.native('NotImplemented'));
35 | var Ellipsis = new PyObject(PyType.native('Ellipsis'));
36 |
37 | var False = new Int(0, py_bool);
38 | var True = new Int(1, py_bool);
39 |
40 | var py_base_exception = PyType.native('BaseException');
41 | var py_exception = new PyType('Exception', [py_base_exception]);
42 | var ValueError = new PyType('ValueError', [py_exception]);
43 | var ArithmeticError = new PyType('ArithmeticError', [py_exception]);
44 | var LookupError = new PyType('LookupError', [py_exception]);
45 | var RuntimeError = new PyType('RuntimeError', [py_exception]);
46 | var BufferError = new PyType('BufferError', [py_exception]);
47 | var AssertionError = new PyType('AssertionError', [py_exception]);
48 | var AttributeError = new PyType('AttributeError', [py_exception]);
49 | var EOFError = new PyType('EOFError', [py_exception]);
50 | var FloatingPointError = new PyType('FloatingPointError', [ArithmeticError]);
51 | var GeneratorExit = new PyType('GeneratorExit', [py_base_exception]);
52 | var ImportError = new PyType('ImportError', [py_exception]);
53 | var IndexError = new PyType('IndexError', [LookupError]);
54 | var KeyError = new PyType('KeyError', [py_exception]);
55 | var KeyboardInterrupt = new PyType('KeyboardInterrupt', [py_base_exception]);
56 | var MemoryError = new PyType('MemoryError', [py_exception]);
57 | var NameError = new PyType('NameError', [py_exception]);
58 | var NotImplementedError = new PyType('NotImplementedError', [RuntimeError]);
59 | var OSError = new PyType('OSError', [py_exception]);
60 | var OverflowError = new PyType('OverflowError', [py_exception]);
61 | var RecursionError = new PyType('RecursionError', [RuntimeError]);
62 | var ReferenceError = new PyType('ReferenceError', [py_exception]);
63 | var StopIteration = new PyType('StopIteration', [py_exception]);
64 | var SyntaxError = new PyType('SyntaxError', [py_exception]);
65 | var IndentationError = new PyType('IndentationError', [SyntaxError]);
66 | var TabError = new PyType('TabError', [IndentationError]);
67 | var SystemError = new PyType('SystemError', [py_exception]);
68 | var SystemExit = new PyType('SystemExit', [py_base_exception]);
69 | var TypeError = new PyType('TypeError', [py_exception]);
70 | var UnboundLocalError = new PyType('UnboundLocalError', [NameError]);
71 | var UnicodeError = new PyType('UnicodeError', [ValueError]);
72 | var UnicodeEncodeError = new PyType('UnicodeEncodeError', [UnicodeError]);
73 | var UnicodeDecodeError = new PyType('UnicodeDecodeError', [UnicodeError]);
74 | var UnicodeTranslateError = new PyType('UnicodeTranslateError', [UnicodeError]);
75 | var ZeroDivisionError = new PyType('ZeroDivisionError', [ArithmeticError]);
76 | var EnvironmentError = OSError;
77 | var IOError = OSError;
78 |
79 | var BlockingIOError = new PyType('BlockingIOError', [OSError]);
80 | var ChildProcessError = new PyType('ChildProcessError', [OSError]);
81 | var BrokenPipeError = new PyType('BrokenPipeError', [OSError]);
82 | var ConnectionError = new PyType('ConnectionError', [OSError]);
83 | var ConnectionAbortedError = new PyType('ConnectionAbortedError', [ConnectionError]);
84 | var ConnectionRefusedError = new PyType('ConnectionRefusedError', [ConnectionError]);
85 | var ConnectionResetError = new PyType('ConnectionResetError', [ConnectionError]);
86 | var FileExistsError = new PyType('FileExistsError', [OSError]);
87 | var FileNotFoundError = new PyType('FileNotFoundError', [OSError]);
88 | var InterruptedError = new PyType('InterruptedError', [OSError]);
89 | var IsADirectoryError = new PyType('IsADirectoryError', [OSError]);
90 | var NotADirectoryError = new PyType('NotADirectoryError', [OSError]);
91 | var PermissionError = new PyType('PermissionError', [OSError]);
92 | var ProcessLookupError = new PyType('ProcessLookupError', [OSError]);
93 | var TimeoutError = new PyType('TimeoutError', [OSError]);
94 |
95 | var MethodNotFoundError = new PyType('MethodNotFoundError', [TypeError]);
96 | var METHOD_NOT_FOUND = {
97 | exc_type: MethodNotFoundError,
98 | exc_value: make_exception(MethodNotFoundError, 'method not found'),
99 | exc_tb: None
100 | };
101 |
102 | var UnpackError = new PyType('UnpackError', [TypeError]);
103 | var PackError = new PyType('PackError', [TypeError]);
104 |
105 | var ExecutorError = new PyType('ExecutorError', [RuntimeError]);
106 |
107 | var JSError = new PyType('JSError', [py_exception]);
108 |
109 | var ZERO = new Int(0);
110 | var ONE = new Int(1);
111 |
112 | var EMPTY_TUPLE = new Tuple([]);
113 |
114 | $.ExecutorError = ExecutorError;
115 |
--------------------------------------------------------------------------------
/src/runtime/python/bytes.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | Bytes.cls.$def('decode', function (self, encoding) {
17 | Bytes.__class__.check(self);
18 | return Str.pack(self.decode(Str.unpack(encoding)));
19 | }, ['encoding'], {defaults: {'encoding': None}});
20 |
21 |
22 | Bytes.$map('__hash__');
23 |
--------------------------------------------------------------------------------
/src/runtime/python/exception.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | py_base_exception.$def('__new__', function (cls, args) {
17 | py_base_exception.check_subclass(cls);
18 | return new PyObject(cls, {'args': pack_tuple(args)})
19 | }, ['*args']);
20 |
21 | py_exception.$def('__init__', function (self, args) {
22 | self.setattr('args', pack_tuple(args));
23 | }, ['*args']);
--------------------------------------------------------------------------------
/src/runtime/python/float.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | Float.cls.$def('__new__', function (cls, initializer, state, frame) {
17 | switch (state) {
18 | case 0:
19 | if (!(subclass(cls, Float.cls))) {
20 | raise(TypeError, 'class is not an subclass of float');
21 | }
22 | if (initializer instanceof Int || initializer instanceof Float) {
23 | if (initializer.__class__ == cls) {
24 | return initializer;
25 | } else {
26 | return Int.pack(initializer.value, cls);
27 | }
28 | }
29 | if (initializer instanceof Str) {
30 | return Float.pack(parseFloat(initializer.value));
31 | }
32 | if (initializer.call('__float__')) {
33 | return 1;
34 | }
35 | case 1:
36 | if (except(MethodNotFoundError)) {
37 | raise(TypeError, 'invalid type of int initializer');
38 | } else if (vm.return_value) {
39 | return vm.return_value;
40 | }
41 | break;
42 | }
43 | }, ['initializer'], {defaults: {initializer: Float.pack(0)}});
44 |
45 | Float.cls.$def('__str__', function (self) {
46 | return Str.pack(Float.unpack(self).toString());
47 | });
48 |
49 | Float.cls.$def('__neg__', function (self) {
50 | return Float.pack(-Float.unpack(self));
51 | });
52 |
53 | Float.cls.$def('__pos__', function (self) {
54 | return self;
55 | });
56 |
57 | Float.cls.$def('__lt__', function (self, other) {
58 | return Float.unpack(self) < Float.unpack(other) ? True : False;
59 | }, ['other']);
60 |
61 | Float.cls.$def('__le__', function (self, other) {
62 | return Float.unpack(self) <= Float.unpack(other) ? True : False;
63 | }, ['other']);
64 |
65 | Float.cls.$def('__eq__', function (self, other) {
66 | return Float.unpack(self) == Float.unpack(other) ? True : False;
67 | }, ['other']);
68 |
69 | Float.cls.$def('__ne__', function (self, other) {
70 | return Float.unpack(self) != Float.unpack(other) ? True : False;
71 | }, ['other']);
72 |
73 | Float.cls.$def('__gt__', function (self, other) {
74 | return Float.unpack(self) > Float.unpack(other) ? True : False;
75 | }, ['other']);
76 |
77 | Float.cls.$def('__ge__', function (self, other) {
78 | return Float.unpack(self) <= Float.unpack(other) ? True : False;
79 | }, ['other']);
80 |
81 | Float.cls.$def('__pow__', function (self, other) {
82 | return Float.pack(Math.pow(Float.unpack(self), Float.unpack(other)));
83 | }, ['other']);
84 | Float.cls.$def_alias('__pow__', '__ipow__');
85 | Float.cls.$def_alias('__pow__', '__rpow__');
86 |
87 | Float.cls.$def('__mul__', function (self, other) {
88 | return Float.pack(Float.unpack(self) * Float.unpack(other));
89 | }, ['other']);
90 | Float.cls.$def_alias('__mul__', '__imul__');
91 | Float.cls.$def_alias('__mul__', '__rmul__');
92 |
93 | Float.cls.$def('__floordiv__', function (self, other) {
94 | return Int.pack(Math.floor(Float.unpack(self) / Float.unpack(other)));
95 | }, ['other']);
96 | Float.cls.$def_alias('__floordiv__', '__ifloordiv__');
97 | Float.cls.$def_alias('__floordiv__', '__rfloordiv__');
98 |
99 | Float.cls.$def('__truediv__', function (self, other) {
100 | return Float.pack(Float.unpack(self) / Float.unpack(other));
101 | }, ['other']);
102 | Float.cls.$def_alias('__truediv__', '__itruediv__');
103 | Float.cls.$def_alias('__truediv__', '__rtruediv__');
104 |
105 | Float.cls.$def('__mod__', function (self, other) {
106 | return Float.pack(Float.unpack(self) % Float.unpack(other));
107 | }, ['other']);
108 | Float.cls.$def_alias('__mod__', '__imod__');
109 | Float.cls.$def_alias('__mod__', '__rmod__');
110 |
111 | Float.cls.$def('__add__', function (self, other) {
112 | return Float.pack(Float.unpack(self) + Float.unpack(other));
113 | }, ['other']);
114 | Float.cls.$def_alias('__add__', '__iadd__');
115 | Float.cls.$def_alias('__add__', '__radd__');
116 |
117 | Float.cls.$def('__sub__', function (self, other) {
118 | return Float.pack(Float.unpack(self) - Float.unpack(other));
119 | }, ['other']);
120 | Float.cls.$def_alias('__sub__', '__isub__');
121 | Float.cls.$def_alias('__sub__', '__rsub__');
122 |
123 |
124 | Float.$map('__abs__');
125 |
--------------------------------------------------------------------------------
/src/runtime/python/function.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | Func.cls.$def('__get__', function (self, instance, owner) {
17 | return new Method(instance, self);
18 | }, ['instance', 'owner']);
--------------------------------------------------------------------------------
/src/runtime/python/generator.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | Generator.cls.$def('__iter__', function (self) {
17 | return self;
18 | });
19 |
20 | Generator.cls.$def('__next__', function (self, state, frame) {
21 | switch (state) {
22 | case 0:
23 | Generator.cls.check(self);
24 | self.running = true;
25 | self.frame.back = frame;
26 | vm.frame = self.frame;
27 | vm.return_value = None;
28 | return 1;
29 | case 1:
30 | if (self.frame.why == CAUSES.YIELD) {
31 | return vm.return_value;
32 | } else if (self.frame.why == CAUSES.RETURN) {
33 | raise(StopIteration, new PyObject(StopIteration, {'args': pack_tuple([vm.return_value])}));
34 | }
35 | }
36 | });
--------------------------------------------------------------------------------
/src/runtime/python/helpers.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | var unpack_sequence = $def(function (sequence, limit, state, frame) {
17 | while (true) {
18 | switch (state) {
19 | case 0:
20 | frame.result = [];
21 | frame.limit = Int.unpack(limit, Infinity);
22 | if (sequence.__class__.lookup('__next__')) {
23 | frame.iterator = sequence;
24 | state = 2;
25 | break;
26 | }
27 | if (sequence.call('__iter__')) {
28 | return 1;
29 | }
30 | case 1:
31 | if (!vm.return_value) {
32 | if (except(MethodNotFoundError)) {
33 | raise(TypeError, 'object does not support the iterable protocol');
34 | }
35 | return;
36 | }
37 | frame.iterator = vm.return_value;
38 | case 2:
39 | if (frame.iterator.call('__next__')) {
40 | return 3;
41 | }
42 | case 3:
43 | if (!vm.return_value) {
44 | if (except(StopIteration)) {
45 | state = 4;
46 | break;
47 | } else if (except(MethodNotFoundError)) {
48 | raise(TypeError, 'object does not support the iterable protocol');
49 | }
50 | return;
51 | }
52 | frame.result.push(vm.return_value);
53 | if (frame.result.length > frame.limit) {
54 | raise(ValueError, 'too many values to unpack (expected ' + frame.limit + ')');
55 | }
56 | state = 2;
57 | break;
58 | case 4:
59 | return pack_tuple(frame.result);
60 | }
61 | }
62 | }, ['sequence', 'limit'], {name: 'unpack_sequence', defaults: {'limit': None}});
63 |
--------------------------------------------------------------------------------
/src/runtime/python/int.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | Int.cls.$def('__new__', function (cls, initializer, base, state, frame) {
17 | switch (state) {
18 | case 0:
19 | if (!(issubclass(cls, Int.cls))) {
20 | raise(TypeError, 'class is not an subclass of int');
21 | }
22 | if (initializer instanceof Float) {
23 | return Int.pack(Math.floor(initializer.value), cls);
24 | }
25 | if (initializer instanceof Int) {
26 | if (initializer.__class__ == cls) {
27 | return initializer;
28 | } else {
29 | return Int.pack(initializer.value, cls);
30 | }
31 | }
32 | if (initializer instanceof Str) {
33 | return Int.parse(initializer.value, base);
34 | }
35 | if (initializer.call('__int__')) {
36 | return 1;
37 | }
38 | case 1:
39 | if (except(MethodNotFoundError)) {
40 | raise(TypeError, 'invalid type of int initializer');
41 | } else if (vm.return_value) {
42 | return vm.return_value;
43 | }
44 | break;
45 | }
46 | }, ['initializer', 'base'], {defaults: {initializer: Int.pack(0), base: Int.pack(10)}});
47 |
48 | Int.cls.$def('__str__', function (self) {
49 | return Str.pack(self.toString());
50 | });
51 |
52 | Int.cls.$def_alias('__str__', '__repr__');
53 |
54 |
55 | Int.cls.$def('__bool__', function (self) {
56 | return pack_bool(self.ne(False));
57 | });
58 |
59 | Int.$def('__not__', function (self) {
60 | return pack_bool(!self.ne(False));
61 | });
62 |
63 | Int.cls.$def('__neg__', function (self) {
64 | return self.neg();
65 | });
66 |
67 | Int.cls.$def('__pos__', function (self) {
68 | return self;
69 | });
70 |
71 | Int.cls.$def('__lt__', function (self, other) {
72 | return pack_bool(self.lt(other));
73 | }, ['other']);
74 |
75 | Int.cls.$def('__le__', function (self, other) {
76 | return pack_bool(self.le(other));
77 | }, ['other']);
78 |
79 | Int.cls.$def('__eq__', function (self, other) {
80 | return pack_bool(self.eq(other));
81 | }, ['other']);
82 |
83 | Int.cls.$def('__ne__', function (self, other) {
84 | return pack_bool(self.ne(other));
85 | }, ['other']);
86 |
87 | Int.cls.$def('__gt__', function (self, other) {
88 | return pack_bool(self.gt(other));
89 | }, ['other']);
90 |
91 | Int.cls.$def('__ge__', function (self, other) {
92 | return pack_bool(self.ge(other));
93 | }, ['other']);
94 |
95 | Int.cls.$def('__pow__', function (self, other) {
96 | return self.pow(other);
97 | }, ['other']);
98 | Int.cls.$def_alias('__pow__', '__ipow__');
99 | Int.cls.$def_alias('__pow__', '__rpow__');
100 |
101 | Int.cls.$def('__mul__', function (self, other) {
102 | return self.mul(other);
103 | }, ['other']);
104 | Int.cls.$def_alias('__mul__', '__imul__');
105 | Int.cls.$def_alias('__mul__', '__rmul__');
106 |
107 | Int.cls.$def('__floordiv__', function (self, other) {
108 | return self.floordiv(other);
109 | }, ['other']);
110 | Int.cls.$def_alias('__floordiv__', '__ifloordiv__');
111 | Int.cls.$def_alias('__floordiv__', '__rfloordiv__');
112 |
113 | Int.cls.$def('__truediv__', function (self, other) {
114 | return self.truediv(other);
115 | }, ['other']);
116 | Int.cls.$def_alias('__truediv__', '__itruediv__');
117 | Int.cls.$def_alias('__truediv__', '__rtruediv__');
118 |
119 | Int.cls.$def('__mod__', function (self, other) {
120 | return self.mod(other);
121 | }, ['other']);
122 | Int.cls.$def_alias('__mod__', '__imod__');
123 | Int.cls.$def_alias('__mod__', '__rmod__');
124 |
125 | Int.cls.$def('__add__', function (self, other) {
126 | return self.add(other);
127 | }, ['other']);
128 | Int.cls.$def_alias('__add__', '__iadd__');
129 | Int.cls.$def_alias('__add__', '__radd__');
130 |
131 | Int.cls.$def('__sub__', function (self, other) {
132 | return self.sub(other);
133 | }, ['other']);
134 | Int.cls.$def_alias('__sub__', '__isub__');
135 | Int.cls.$def_alias('__sub__', '__rsub__');
136 |
137 | Int.cls.$def('__lshift__', function (self, other) {
138 | return self.lshift(other);
139 | }, ['other']);
140 | Int.cls.$def_alias('__lshift__', '__ilshift__');
141 | Int.cls.$def_alias('__lshift__', '__rlshift__');
142 |
143 | Int.cls.$def('__rshift__', function (self, other) {
144 | return self.rshift(other);
145 | }, ['other']);
146 | Int.cls.$def_alias('__rshift__', '__irshift__');
147 | Int.cls.$def_alias('__rshift__', '__rrshift__');
148 |
149 | Int.cls.$def('__and__', function (self, other) {
150 | return self.and(other);
151 | }, ['other']);
152 | Int.cls.$def_alias('__and__', '__iand__');
153 | Int.cls.$def_alias('__and__', '__rand__');
154 |
155 | Int.cls.$def('__xor__', function (self, other) {
156 | return self.xor(other);
157 | }, ['other']);
158 | Int.cls.$def_alias('__xor__', '__ixor__');
159 | Int.cls.$def_alias('__xor__', '__rxor__');
160 |
161 | Int.cls.$def('__or__', function (self, other) {
162 | return self.or(other);
163 | }, ['other']);
164 | Int.cls.$def_alias('__or__', '__ior__');
165 | Int.cls.$def_alias('__or__', '__ror__');
166 |
167 |
168 | Int.$map('__abs__');
169 | Int.$map('__hash__');
170 |
--------------------------------------------------------------------------------
/src/runtime/python/iterator.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | Iterator.$map('__iter__');
18 | Iterator.$map('__next__');
19 |
--------------------------------------------------------------------------------
/src/runtime/python/list.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | List.cls.$def('__repr__', function (self, state, frame) {
17 | while (true) {
18 | switch (state) {
19 | case 0:
20 | List.cls.check(self);
21 | frame.parts = new Array(self.size);
22 | frame.index = 0;
23 | case 1:
24 | if (frame.index < self.size) {
25 | if (self.get(frame.index).call('__repr__')) {
26 | return 2;
27 | }
28 | } else {
29 | state = 3;
30 | break;
31 | }
32 | case 2:
33 | if (!vm.return_value) {
34 | return;
35 | }
36 | frame.parts[frame.index] = vm.return_value.toString();
37 | frame.index++;
38 | state = 1;
39 | break;
40 | case 3:
41 | return Str.pack('[' + frame.parts.join(', ') + ']');
42 | }
43 | }
44 | });
45 |
46 |
47 | List.$map('append', ['item']);
48 |
49 |
50 | List.cls.$def('__getitem__', function (self, index_or_slice) {
51 | List.cls.check(self);
52 | // TODO: do conversion with __index__ and support slice
53 | if (index_or_slice instanceof Slice) {
54 | var start = Int.unpack(index_or_slice.start, 0);
55 | var stop = Int.unpack(index_or_slice.stop, self.value.length);
56 | var step = Int.unpack(index_or_slice.step, 1);
57 | return self.slice(start, stop, step);
58 | } else {
59 | return self.get(Int.unpack(index_or_slice));
60 | }
61 | }, ['index_or_slice']);
62 |
63 | List.cls.$def('__setitem__', function (self, index_or_slice, item) {
64 | List.cls.check(self);
65 | return self.set(Int.unpack(index_or_slice), item);
66 | }, ['index_or_slice', 'item']);
67 |
68 |
69 | List.$map('__iter__');
70 | List.$map('__len__');
71 |
72 | List.$map('__mul__', ['other']);
73 |
--------------------------------------------------------------------------------
/src/runtime/python/method.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | Method.$def('__repr__', function (self, state, frame) {
18 | switch (state) {
19 | case 0:
20 | if (self.self.call('__repr__')) {
21 | return 1;
22 | }
23 | case 1:
24 | if (vm.return_value) {
25 | return new Str('');
26 | }
27 | }
28 | });
29 |
30 | py_classmethod.$def('__init__', function (self, func) {
31 | self.setattr('__func__', func);
32 | }, ['func']);
33 |
34 | py_classmethod.$def('__get__', function (self, instance, owner) {
35 | return new Method(self.getattr('__func__'), owner);
36 | }, ['instance', 'owner']);
--------------------------------------------------------------------------------
/src/runtime/python/module.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | function PyModule(namespace) {
17 | PyObject.call(this, py_module, namespace);
18 | }
19 |
20 | PyModule.prototype = new PyObject;
21 |
--------------------------------------------------------------------------------
/src/runtime/python/none.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | var NONE_STR = Str.pack('None');
17 |
18 | None.__class__.$def('__new__', function (cls) {
19 | return None;
20 | });
21 |
22 | None.__class__.$def('__repr__', function (self) {
23 | return NONE_STR;
24 | });
25 |
26 | None.__class__.$def('__bool__', function (self) {
27 | return False;
28 | });
29 |
--------------------------------------------------------------------------------
/src/runtime/python/object.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | py_object.$def('__new__', function (cls, args, kwargs) {
17 | if (!(cls instanceof PyType)) {
18 | raise(TypeError, 'object.__new__(X): X is not a type object');
19 | }
20 | if (cls.native !== py_object) {
21 | raise(TypeError, 'object.__new__() is not safe, use ' + cls.native.name + '.__new__()');
22 | }
23 | return new PyObject(cls, {});
24 | }, ['*args', '**kwargs']);
25 |
26 | py_object.$def('__getattribute__', function (self, name, state, frame) {
27 | var value;
28 | switch (state) {
29 | case 0:
30 | name = Str.unpack(name);
31 | value = self.__dict__ ? self.getattr(name) : null;
32 | if (!value) {
33 | value = self.__class__.lookup(name);
34 | if (value) {
35 | if (value.call('__get__', [self, self.__class__])) {
36 | return 1;
37 | }
38 | } else {
39 | raise(AttributeError, '\'' + self.__class__.name + '\' object has no attribute \'' + name + '\'');
40 | }
41 | } else {
42 | return value;
43 | }
44 | case 1:
45 | if (except(MethodNotFoundError)) {
46 | return value;
47 | } else if (vm.return_value) {
48 | return vm.return_value
49 | } else {
50 | return null;
51 | }
52 | }
53 | }, ['name']);
54 |
55 | py_object.$def('__setattr__', function (self, name, item, state, frame) {
56 | var descriptor;
57 | switch (state) {
58 | case 0:
59 | descriptor = self.__class__.lookup(name);
60 | if (descriptor && descriptor.__class__.lookup('__set__')) {
61 | if (descriptor.call('__set__', [self, item])) {
62 | return 1;
63 | }
64 | } else {
65 | self.setattr(name, item);
66 | return null;
67 | }
68 | case 1:
69 | return null;
70 | }
71 | }, ['name', 'item']);
72 |
73 | py_object.$def('__repr__', function (self) {
74 | var module = self.__class__.getattr('__module__');
75 | if (module instanceof Str) {
76 | return Str.pack('<' + module.value + '.' + self.__class__.name + ' object at 0x' + self.get_address() + '>');
77 | } else {
78 | return Str.pack('<' + self.__class__.name + ' object at 0x' + self.get_address() + '>');
79 | }
80 | });
81 |
82 | py_object.$def('__str__', function (self, state, frame) {
83 | switch (state) {
84 | case 0:
85 | if (self.call('__repr__')) {
86 | return 1;
87 | }
88 | case 1:
89 | return vm.return_value;
90 | }
91 | });
92 |
93 | py_object.$def('__hash__', function (self) {
94 | return Str.pack('object: ' + self.get_address());
95 | });
96 |
97 | py_object.$def('__eq__', function (self, other) {
98 | return self === other ? True : False;
99 | }, ['other']);
100 |
101 | py_object.$def_property('__class__', function (self) {
102 | return self.__class__;
103 | }, function (self, value) {
104 | if (!(value instanceof PyType) || value.native != py_object) {
105 | raise(TypeError, 'invalid type of \'value\' argument');
106 | }
107 | if (self instanceof PyType || self.__class__.native != py_object) {
108 | raise(TypeError, 'object does not support class assignment');
109 | }
110 | self.__class__ = value;
111 | });
112 |
--------------------------------------------------------------------------------
/src/runtime/python/property.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | Property.cls.$def('__get__', function (self, instance, owner, state, frame) {
17 | switch (state) {
18 | case 0:
19 | if (call(self.getattr('fget'), [instance])) {
20 | return 1;
21 | }
22 | case 1:
23 | return vm.return_value;
24 | }
25 | }, ['instance', 'owner']);
26 |
27 | Property.cls.$def('__set__', function (self, instance, value, state, frame) {
28 | switch (state) {
29 | case 0:
30 | if (call(self.getattr('fset'), [instance, value])) {
31 | return 1;
32 | }
33 | case 1:
34 | break;
35 | }
36 | }, ['instance', 'value']);
--------------------------------------------------------------------------------
/src/runtime/python/slice.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | Slice.cls.$def('__repr__', function (self, state, frame) {
17 | switch (state) {
18 | case 0:
19 | Slice.cls.check(self);
20 | frame.result = 'slice(';
21 | if (self.start.call('__repr__')) {
22 | return 1;
23 | }
24 | case 1:
25 | if (!vm.return_value) {
26 | return;
27 | }
28 | frame.result += Str.unpack(vm.return_value) + ', ';
29 | if (self.stop.call('__repr__')) {
30 | return 2;
31 | }
32 | case 2:
33 | if (!vm.return_value) {
34 | return;
35 | }
36 | frame.result += Str.unpack(vm.return_value) + ', ';
37 | if (self.step.call('__repr__')) {
38 | return 3;
39 | }
40 | case 3:
41 | if (!vm.return_value) {
42 | return;
43 | }
44 | frame.result += Str.unpack(vm.return_value) + ')';
45 | return Str.pack(frame.result);
46 | }
47 | });
48 |
--------------------------------------------------------------------------------
/src/runtime/python/str.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | Str.$def('__new__', function (cls, initializer, state, frame) {
18 | switch (state) {
19 | case 0:
20 | if (!issubclass(cls, Str.cls)) {
21 | raise(TypeError, 'class is not an subclass of str');
22 | }
23 | if (initializer instanceof Str) {
24 | if (initializer.__class__ == cls) {
25 | return initializer;
26 | } else {
27 | return Str.pack(initializer.value, cls);
28 | }
29 | }
30 | if (initializer.call('__str__')) {
31 | return 1;
32 | }
33 | case 1:
34 | if (except(MethodNotFoundError)) {
35 | raise(TypeError, 'invalid type of str initializer');
36 | } else if (vm.return_value) {
37 | return vm.return_value;
38 | }
39 | break;
40 | }
41 | }, ['initializer']);
42 |
43 | Str.$def('__str__', function (self) {
44 | return self;
45 | });
46 |
47 |
48 |
49 | Str.$def('__len__', function (self) {
50 | Str.cls.check(self);
51 | return Int.pack(self.value.length);
52 | });
53 |
54 |
55 |
56 |
57 |
58 | Str.cls.$def_alias('__add__', '__iadd__');
59 | Str.cls.$def_alias('__add__', '__radd__');
60 |
61 |
62 | Str.$map('__repr__');
63 | Str.$map('__hash__');
64 |
65 | Str.$def('__eq__', function (self, other) {
66 | return pack_bool(self.eq(other));
67 | }, ['other']);
68 |
69 | Str.$def('__ne__', function (self, other) {
70 | return pack_bool(!self.eq(other));
71 | }, ['other']);
72 |
73 | Str.$def('__ge__', function (self, other) {
74 | return pack_bool(self.ge(other));
75 | }, ['other']);
76 |
77 | Str.$def('__gt__', function (self, other) {
78 | return pack_bool(self.gt(other));
79 | }, ['other']);
80 |
81 | Str.$def('__le__', function (self, other) {
82 | return pack_bool(self.le(other));
83 | }, ['other']);
84 |
85 | Str.$def('__lt__', function (self, other) {
86 | return pack_bool(self.lt(other));
87 | }, ['other']);
88 |
89 | Str.$map('__getitem__', ['index']);
90 |
91 | Str.$map('__add__', ['other']);
92 |
93 | Str.$map('capitalize');
94 | Str.$map('casefold');
95 | Str.$map('center', ['width', 'fillchar'], {defaults: {'fillchar': None}});
96 | Str.$map('count', ['sub', 'start', 'end'], {defaults: {'start': None, 'end': None}});
97 | Str.$map('encode');
98 | Str.$map('endswith', ['suffix', 'start', 'end'], {defaults: {'start': None, 'end': None}});
99 | Str.$map('expandtabs', ['tabsize'], {defaults: {'tabsize': new Int(8)}});
100 | Str.$map('find', ['sub', 'start', 'end'], {defaults: {'start': None, 'end': None}});
101 | Str.$map('index', ['sub', 'start', 'end'], {defaults: {'start': None, 'end': None}});
102 | Str.$map('isalnum');
103 | Str.$map('isalpha');
104 | Str.$map('isdecimal');
105 | Str.$map('isdigit');
106 | Str.$map('isidentifier');
107 | Str.$map('islower');
108 | Str.$map('isnumeric');
109 | Str.$map('isprintable');
110 | Str.$map('isspace');
111 | Str.$map('istitle');
112 | Str.$map('isupper');
113 | Str.$map('ljust', ['width', 'fillchar'], {defaults: {'fillchar': None}});
114 | Str.$map('lower');
115 | Str.$map('lstrip', ['chars'], {defaults: {'chars': None}});
116 | Str.$map('partition', ['sep']);
117 | Str.$map('replace', ['old', 'new', 'count'], {defaults: {'count': new Int(-1)}});
118 | Str.$map('rfind', ['sub', 'start', 'end'], {defaults: {'start': None, 'end': None}});
119 | Str.$map('rindex', ['sub', 'start', 'end'], {defaults: {'start': None, 'end': None}});
120 | Str.$map('rjust', ['width', 'fillchar'], {defaults: {'fillchar': None}});
121 | Str.$map('rpartition', ['sep']);
122 | Str.$map('rsplit', ['sep', 'maxsplit'], {defaults: {'sep': None, 'maxsplit': new Int(-1)}});
123 | Str.$map('rstrip', ['chars'], {defaults: {'chars': None}});
124 | Str.$map('split', ['sep', 'maxsplit'], {defaults: {'sep': None, 'maxsplit': new Int(-1)}});
125 | Str.$map('splitlines', ['keepends'], {defaults: {'keepends': False}});
126 | Str.$map('startswith', ['prefix', 'start', 'end'], {defaults: {'start': None, 'end': None}});
127 | Str.$map('strip', ['chars'], {defaults: {'chars': None}});
128 | Str.$map('swapcase');
129 | Str.$map('title');
130 | Str.$map('translate', ['table']);
131 | Str.$map('upper');
132 | Str.$map('zfill');
133 |
--------------------------------------------------------------------------------
/src/runtime/python/tuple.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | Tuple.$def('__new__', function (cls, initializer, state, frame) {
17 | switch (state) {
18 | case 0:
19 | if (initializer === None) {
20 | return Tuple.EMPTY;
21 | }
22 | if (call(unpack_sequence, [initializer])) {
23 | return 1;
24 | }
25 | case 1:
26 | if (vm.return_value) {
27 | return vm.return_value;
28 | }
29 | }
30 | }, ['initializer'], {defaults: {initializer: None}});
31 |
32 | Tuple.$def('__repr__', function (self, state, frame) {
33 | while (true) {
34 | switch (state) {
35 | case 0:
36 | Tuple.check(self);
37 | frame.parts = new Array(self.array.length);
38 | frame.index = 0;
39 | case 1:
40 | if (frame.index < self.array.length) {
41 | if (self.array[frame.index].call('__repr__')) {
42 | return 2;
43 | }
44 | } else {
45 | state = 3;
46 | break;
47 | }
48 | case 2:
49 | if (!vm.return_value) {
50 | return;
51 | }
52 | frame.parts[frame.index] = vm.return_value.toString();
53 | frame.index++;
54 | state = 1;
55 | break;
56 | case 3:
57 | return Str.pack('(' + frame.parts.join(', ') + ')');
58 | }
59 | }
60 | });
61 |
62 | Tuple.$map('__iter__');
63 |
--------------------------------------------------------------------------------
/src/runtime/python/type.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | py_type.$def_classmethod('__prepare__', function (mcs, bases) {
17 | return new Dict();
18 | }, ['bases']);
19 |
20 | py_type.$def('__new__', function (mcs, name, bases, attributes) {
21 | if (!(mcs instanceof PyType)) {
22 | raise(TypeError, 'invalid type of \'mcs\' argument');
23 | }
24 | if (!(attributes instanceof Dict)) {
25 | raise(TypeError, 'invalid type of \'attributes\' argument');
26 | }
27 | return new PyType(Str.unpack(name), unpack_tuple(bases), attributes, mcs);
28 | }, ['name', 'bases', 'attributes']);
29 |
30 | py_type.$def('__call__', function (cls, args, kwargs, state, frame) {
31 | switch (state) {
32 | case 0:
33 | if (cls.call_classmethod('__new__', Tuple.unpack(args), kwargs)) {
34 | return 1;
35 | }
36 | case 1:
37 | if (!vm.return_value) {
38 | return null;
39 | }
40 | frame.instance = vm.return_value;
41 | if (vm.return_value.__class__.lookup('__init__')) {
42 | if (vm.return_value.call('__init__', args, kwargs)) {
43 | return 2;
44 | }
45 | }
46 | case 2:
47 | if (vm.return_value) {
48 | return frame.instance;
49 | }
50 | }
51 | }, ['*args', '**kwargs']);
52 |
53 | py_type.$def('__str__', function (cls) {
54 | var module = cls.getattr('__module__');
55 | if (!(cls instanceof PyType)) {
56 | raise(TypeError, 'invalid type of \'cls\' argument');
57 | }
58 | if (module instanceof Str) {
59 | return Str.pack('');
60 | } else {
61 | return Str.pack('');
62 | }
63 | });
64 |
65 | py_type.$def_property('__name__', function (cls) {
66 | py_type.check(cls);
67 | return Str.pack(cls.name);
68 | }, function (cls, value) {
69 | py_type.check(cls);
70 | cls.name = Str.unpack(value);
71 | });
72 |
73 | py_type.$def_property('__mro__', function (cls) {
74 | py_type.check(cls);
75 | return pack_tuple(cls.mro);
76 | });
--------------------------------------------------------------------------------
/src/runtime/python/wrapper.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | py_js_object.$def('__getattr__', function (self, name) {
18 | var value;
19 | py_js_object.check(self);
20 | name = Str.unpack(name);
21 | if (name in self.object) {
22 | value = self.object[name];
23 | if (typeof value == 'function') {
24 | value = value.bind(self.object);
25 | }
26 | return pack(value);
27 | }
28 | raise(AttributeError, '\'' + self.__class__.name + '\' object has no attribute \'' + name + '\'');
29 | }, ['name']);
30 |
31 | py_js_object.$def('__setattr__', function (self, name, value) {
32 | py_js_object.check(self);
33 | self.object[Str.unpack(name)] = unpack(value);
34 | }, ['name', 'value']);
35 |
36 |
37 | py_js_function.$def('__call__', function (self, args) {
38 | py_js_function.check(self);
39 | return pack(self.func.apply(null, args.map(unpack)));
40 | }, ['*args']);
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/src/runtime/sys.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 | jaspy.module('sys', function ($, module, builtins) {
17 | var VersionInfo = module.$class('_VersionInfo', [builtins.tuple]);
18 |
19 | VersionInfo.$def('__new__', function (cls, major, minor, micro, releaselevel, serial) {
20 | VersionInfo.check_subclass(cls);
21 | return new $.Tuple([major, minor, micro, releaselevel, serial], cls);
22 | }, ['major', 'minor', 'patch', 'releaselevel', 'serial']);
23 |
24 | VersionInfo.$def('__str__', function (self) {
25 | VersionInfo.check(self);
26 | return $.Str.pack('version_info(' +
27 | 'major=' + self.array[0] + ', ' +
28 | 'minor=' + self.array[1] + ', ' +
29 | 'micro=' + self.array[2] + ', ' +
30 | 'releaselevel=' + self.array[3].repr() + ', ' +
31 | 'serial=' + self.array[4] + ')');
32 | });
33 |
34 | VersionInfo.$def_property('major', function (self) {
35 | VersionInfo.check(self);
36 | return self.array[0];
37 | });
38 |
39 | module.$set('byteorder', $.Str.pack('big'));
40 |
41 | module.$set('copyright', $.Str.pack('Copyright (C) 2016, Maximilian Koehl'));
42 |
43 | module.$set('platform', $.Str.pack('web'));
44 |
45 | module.$set('implementation', $.Str.pack('jaspy'));
46 |
47 | module.$set('maxunicode', $.Int.pack(0xFFFF));
48 |
49 | module.$set('version', $.Str.pack('3.5.1'));
50 | module.$set('version_info', new $.Tuple([$.Int.pack(3), $.Int.pack(5), $.Int.pack(0), $.Str.pack('dev'), $.Str.pack(0)], VersionInfo));
51 |
52 | module.$set('jaspy_version', $.Str.pack('/* {{metadata.__version__}} */'));
53 | module.$set('jaspy_version_info', new $.Tuple([
54 | $.Int.pack(/* {{metadata.__version_info__[0]}} */),
55 | $.Int.pack(/* {{metadata.__version_info__[1]}} */),
56 | $.Int.pack(/* {{metadata.__version_info__[2]}} */),
57 | $.Str.pack('/* {{metadata.__version_info__[3]}} */'),
58 | $.Int.pack(/* {{metadata.__version_info__[4]}} */)], VersionInfo)
59 | );
60 |
61 | module.$set('modules', new $.Dict($.modules));
62 | }, ['builtins']);
--------------------------------------------------------------------------------
/src/runtime/type.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2016, Maximilian Koehl
3 | *
4 | * This program is free software: you can redistribute it and/or modify it under
5 | * the terms of the GNU Lesser General Public License version 3 as published by
6 | * the Free Software Foundation.
7 | *
8 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY
9 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 | * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
11 | *
12 | * You should have received a copy of the GNU Lesser General Public License along
13 | * with this program. If not, see .
14 | */
15 |
16 |
17 | function get_mro(cls) {
18 | return cls.mro;
19 | }
20 |
21 | function linearize(cls) {
22 | var pending = cls.bases.map(get_mro), result = [cls];
23 | var index, head, good;
24 | while (pending.length != 0) {
25 | for (index = 0; index < pending.length; index++) {
26 | head = pending[index][0];
27 | good = true;
28 | pending.forEach(function (base_mro) {
29 | base_mro.slice(1, base_mro.length).forEach(function (base_cls) {
30 | good &= base_cls != head;
31 | })
32 | });
33 | if (good) {
34 | result.push(head);
35 | break;
36 | }
37 | }
38 | if (!good) {
39 | raise(TypeError, 'unable to linearize class hierarchy');
40 | }
41 | for (index = 0; index < pending.length; index++) {
42 | pending[index] = pending[index].filter(function (base_cls) {
43 | return base_cls != head;
44 | })
45 | }
46 | pending = pending.filter(function (base_mro) {
47 | return base_mro.length > 0;
48 | });
49 | }
50 | return result;
51 | }
52 |
53 |
54 | var PyType = PyObject.extend({
55 | constructor: function (name, bases, attributes, mcs) {
56 | var index, native;
57 | PyObject.call(this, mcs || py_type, attributes || {});
58 | this.name = name;
59 | this.bases = bases || [py_object];
60 | this.mro = linearize(this);
61 | this.native = null;
62 | for (index = 0; index < this.mro.length; index++) {
63 | native = this.mro[index].native;
64 | if (native === py_object) {
65 | continue;
66 | }
67 | if (this.native && this.native !== native && native) {
68 | raise(TypeError, 'invalid native type hierarchy');
69 | }
70 | this.native = native;
71 | }
72 | this.native = this.native || py_object;
73 | },
74 |
75 | lookup: function (name) {
76 | var index, value;
77 | for (index = 0; index < this.mro.length; index++) {
78 | value = this.mro[index].getattr(name);
79 | if (value) {
80 | return value;
81 | }
82 | }
83 | },
84 |
85 | define: function (name, item) {
86 | return this.__dict__[name] = item;
87 | },
88 |
89 | $def: function (name, func, signature, options) {
90 | options = options || {};
91 | options.name = options.name || name;
92 | options.qualname = options.qualname || (this.name + '.' + options.name);
93 | return this.define(name, $def(func, ['self'].concat(signature || []), options));
94 | },
95 |
96 | $def_property: function (name, getter, setter) {
97 | var options = {name: name, qualname: this.name + '.' + name};
98 | if (getter) {
99 | getter = $def(getter, ['self'], options);
100 | }
101 | if (setter) {
102 | setter = $def(setter, ['self', 'value'], options);
103 | }
104 | return this.define(name, new_property(getter, setter));
105 | },
106 |
107 | $def_classmethod: function (name, func, signature, options) {
108 | options = options || {};
109 | options.name = options.name || name;
110 | options.qualname = options.qualname || (this.name + '.' + options.name);
111 | return this.define(name, $def(func, ['cls'].concat(signature || []), options));
112 | },
113 |
114 | $def_alias: function (name, alias) {
115 | return this.define(alias, this.lookup(name));
116 | },
117 |
118 | call_classmethod: function (name, args, kwargs) {
119 | var method = this.lookup(name);
120 | if (method) {
121 | return call(method, [this].concat(args || []), kwargs);
122 | } else {
123 | vm.return_value = null;
124 | vm.last_exception = METHOD_NOT_FOUND;
125 | return false;
126 | }
127 | },
128 |
129 | call_staticmethod: function (name, args, kwargs) {
130 | var method = this.lookup(name);
131 | if (method) {
132 | return call(method, args, kwargs);
133 | } else {
134 | vm.return_value = null;
135 | vm.last_exception = METHOD_NOT_FOUND;
136 | return false;
137 | }
138 | },
139 |
140 | check: function (object) {
141 | if (!isinstance(object, this)) {
142 | raise(TypeError, 'native type check failed');
143 | }
144 | },
145 |
146 | check_subclass: function (cls) {
147 | if (!issubclass(cls, this)) {
148 | raise(TypeError, 'native subclass check failed');
149 | }
150 | },
151 |
152 | make: function (dict) {
153 | return new PyObject(this, dict)
154 | }
155 | });
156 |
157 |
158 |
159 | PyType.native = function (name, bases, attributes, mcs) {
160 | var type = new PyType(name, bases, attributes, mcs);
161 | type.native = type;
162 | return type;
163 | };
164 |
165 | function $class(name, bases, attributes, mcs) {
166 | return new PyType.native(name, bases, attributes, mcs);
167 | }
168 |
169 |
170 | function issubclass(cls, superclass) {
171 | var index;
172 | if (!(cls instanceof PyType)) {
173 | raise(TypeError, 'first argument must be a class')
174 | }
175 | for (index = 0; index < cls.mro.length; index++) {
176 | if (cls.mro[index] === superclass) {
177 | return true;
178 | }
179 | }
180 | return false;
181 | }
182 |
183 |
184 | $.PyType = PyType;
185 |
186 | $.$class = $class;
187 |
188 | $.issubclass = issubclass;
189 |
--------------------------------------------------------------------------------