mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Update RapydScript
This commit is contained in:
parent
27672b7832
commit
3c7c651e14
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
*_ui.py
|
*_ui.py
|
||||||
*.pyc
|
*.pyc
|
||||||
*.pyo
|
*.pyo
|
||||||
|
*.pyj-cached
|
||||||
.bzr
|
.bzr
|
||||||
.bzrignore
|
.bzrignore
|
||||||
.check-cache.pickle
|
.check-cache.pickle
|
||||||
|
File diff suppressed because one or more lines are too long
BIN
resources/rapydscript/compiler.js.bz2
Normal file
BIN
resources/rapydscript/compiler.js.bz2
Normal file
Binary file not shown.
192
resources/rapydscript/lib/math.pyj
Normal file
192
resources/rapydscript/lib/math.pyj
Normal file
@ -0,0 +1,192 @@
|
|||||||
|
###########################################################
|
||||||
|
# RapydScript Standard Library
|
||||||
|
# Author: Alexander Tsepkov
|
||||||
|
# Copyright 2013 Pyjeon Software LLC
|
||||||
|
# License: Apache License 2.0
|
||||||
|
# This library is covered under Apache license, so that
|
||||||
|
# you can distribute it with your RapydScript applications.
|
||||||
|
###########################################################
|
||||||
|
|
||||||
|
|
||||||
|
# basic implementation of Python's 'math' library
|
||||||
|
|
||||||
|
# NOTE: this is only meant to aid those porting lots of Python code into RapydScript,
|
||||||
|
# if you're writing a new RapydScript application, in most cases you probably want to
|
||||||
|
# use JavaScript's Math module directly instead
|
||||||
|
|
||||||
|
|
||||||
|
pi = Math.PI
|
||||||
|
e = Math.E
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Number-theoretic and representation functions
|
||||||
|
########################################
|
||||||
|
def ceil(x):
|
||||||
|
return Math.ceil(x)
|
||||||
|
def copysign(x, y):
|
||||||
|
x = Math.abs(x)
|
||||||
|
if y < 0:
|
||||||
|
return -x
|
||||||
|
else:
|
||||||
|
return x
|
||||||
|
def fabs(x):
|
||||||
|
return Math.abs(x)
|
||||||
|
def factorial(x):
|
||||||
|
if Math.abs(int(x)) != x:
|
||||||
|
raise ValueError("factorial() only accepts integral values")
|
||||||
|
factorial.cache = []
|
||||||
|
r = def(n):
|
||||||
|
if n == 0 or n == 1:
|
||||||
|
return 1
|
||||||
|
if not factorial.cache[n]:
|
||||||
|
factorial.cache[n] = r(n-1) * n
|
||||||
|
return factorial.cache[n]
|
||||||
|
return r(x)
|
||||||
|
def floor(x):
|
||||||
|
return Math.floor(x)
|
||||||
|
def fmod(x, y):
|
||||||
|
# javascript's % operator isn't consistent with C fmod implementation, this function is
|
||||||
|
while y <= x:
|
||||||
|
x -= y
|
||||||
|
return x
|
||||||
|
def fsum(iterable):
|
||||||
|
# like Python's fsum, this method is much more resilient to rounding errors than regular sum
|
||||||
|
partials = [] # sorted, non-overlapping partial sums
|
||||||
|
for x in iterable:
|
||||||
|
i = 0
|
||||||
|
for y in partials:
|
||||||
|
if Math.abs(x) < Math.abs(y):
|
||||||
|
x, y = y, x
|
||||||
|
hi = x + y
|
||||||
|
lo = y - (hi - x)
|
||||||
|
if lo:
|
||||||
|
partials[i] = lo
|
||||||
|
i += 1
|
||||||
|
x = hi
|
||||||
|
#partials[i:] = [x]
|
||||||
|
partials.splice(i, partials.length-i, x)
|
||||||
|
return sum(partials)
|
||||||
|
def isinf(x):
|
||||||
|
return not isFinite(x)
|
||||||
|
def isnan(x):
|
||||||
|
return isNaN(x)
|
||||||
|
def modf(x):
|
||||||
|
m = fmod(x, 1)
|
||||||
|
return m, x-m
|
||||||
|
def trunc(x):
|
||||||
|
return x | 0
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Power and logarithmic functions
|
||||||
|
########################################
|
||||||
|
def exp(x):
|
||||||
|
return Math.exp(x)
|
||||||
|
def expm1(x):
|
||||||
|
# NOTE: Math.expm1() is currently only implemented in Firefox, this provides alternative implementation
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/expm1
|
||||||
|
#return Math.expm1(x)
|
||||||
|
if Math.abs(x) < 1e-5:
|
||||||
|
return x + 0.5*x*x
|
||||||
|
else:
|
||||||
|
return Math.exp(x) - 1
|
||||||
|
def log(x, base=e):
|
||||||
|
return Math.log(x)/Math.log(base)
|
||||||
|
def log1p(x):
|
||||||
|
# NOTE: Math.log1p() is currently only implemented in Firefox, this provides alternative implementation
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log1p
|
||||||
|
# this version has been taken from http://phpjs.org/functions/log1p/
|
||||||
|
# admittedly it's not as accurate as MDN version, as you can see from math.log1p(1) result
|
||||||
|
ret = 0
|
||||||
|
n = 50
|
||||||
|
if x <= -1:
|
||||||
|
return Number.NEGATIVE_INFINITY
|
||||||
|
if x < 0 or x > 1:
|
||||||
|
return Math.log(1 + x)
|
||||||
|
for i in range(1, n):
|
||||||
|
if i % 2 == 0:
|
||||||
|
ret -= Math.pow(x, i) / i
|
||||||
|
else:
|
||||||
|
ret += Math.pow(x, i) / i
|
||||||
|
return ret
|
||||||
|
def log10(x):
|
||||||
|
# NOTE: Math.log10() is currently only implemented in Firefox, this provides alternative implementation
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/log10
|
||||||
|
# I didn't find a more accurate algorithm so I'm using the basic implementation
|
||||||
|
return Math.log(x)/Math.LN10
|
||||||
|
def pow(x, y):
|
||||||
|
if x < 0 and int(y) != y:
|
||||||
|
raise ValueError('math domain error')
|
||||||
|
if isnan(y) and x == 1:
|
||||||
|
return 1
|
||||||
|
return Math.pow(x, y)
|
||||||
|
def sqrt(x):
|
||||||
|
return Math.sqrt(x)
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Trigonometric functions
|
||||||
|
########################################
|
||||||
|
def acos(x): return Math.acos(x)
|
||||||
|
def asin(x): return Math.asin(x)
|
||||||
|
def atan(x): return Math.atan(x)
|
||||||
|
def atan2(y, x): return Math.atan2(y, x)
|
||||||
|
def cos(x): return Math.cos(x)
|
||||||
|
def sin(x): return Math.sin(x)
|
||||||
|
def hypot(x, y): return Math.sqrt(x*x + y*y)
|
||||||
|
def tan(x): return Math.tan(x)
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Angular conversion
|
||||||
|
########################################
|
||||||
|
def degrees(x): return x*180/pi
|
||||||
|
def radians(x): return x*pi/180
|
||||||
|
|
||||||
|
########################################
|
||||||
|
# Hyperbolic functions
|
||||||
|
########################################
|
||||||
|
def acosh(x):
|
||||||
|
# NOTE: will be replaced with official, when it becomes mainstream
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/acosh
|
||||||
|
return Math.log(x + Math.sqrt(x*x - 1))
|
||||||
|
def asinh(x):
|
||||||
|
# NOTE: will be replaced with official, when it becomes mainstream
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/asinh
|
||||||
|
return Math.log(x + Math.sqrt(x*x + 1))
|
||||||
|
def atanh(x):
|
||||||
|
# NOTE: will be replaced with official, when it becomes mainstream
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/atanh
|
||||||
|
return 0.5 * Math.log((1 + x) / (1 - x))
|
||||||
|
def cosh(x):
|
||||||
|
# NOTE: will be replaced with official, when it becomes mainstream
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/cosh
|
||||||
|
return (Math.exp(x) + Math.exp(-x)) / 2
|
||||||
|
def sinh(x):
|
||||||
|
# NOTE: will be replaced with official, when it becomes mainstream
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/sinh
|
||||||
|
return (Math.exp(x) - Math.exp(-x)) / 2
|
||||||
|
def tanh(x):
|
||||||
|
# NOTE: will be replaced with official, when it becomes mainstream
|
||||||
|
# https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/tanh
|
||||||
|
return (Math.exp(x) - Math.exp(-x)) / (Math.exp(x) + Math.exp(-x))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#import stdlib
|
||||||
|
#print(math.ceil(4.2))
|
||||||
|
#print(math.floor(4.2))
|
||||||
|
#print(math.fabs(-6))
|
||||||
|
#print(math.copysign(-5, 7))
|
||||||
|
#print(math.factorial(4))
|
||||||
|
#print(math.fmod(-1e100, 1e100))
|
||||||
|
#
|
||||||
|
#d = [0.9999999, 1, 2, 3]
|
||||||
|
#print(sum(d), math.fsum(d))
|
||||||
|
#print(math.isinf(5), math.isinf(Infinity))
|
||||||
|
#print(math.modf(5.5))
|
||||||
|
#print(math.trunc(2.6), math.trunc(-2.6))
|
||||||
|
#print(math.exp(1e-5), math.expm1(1e-5))
|
||||||
|
#print(math.log(10), math.log(10, 1000))
|
||||||
|
#print(math.log1p(1e-15), math.log1p(1))
|
||||||
|
#print(math.log10(1000), math.log(1000, 10))
|
||||||
|
#print(math.pow(1, 0), math.pow(1, NaN), math.pow(0, 0), math.pow(NaN, 0), math.pow(4,3), math.pow(100, -2))
|
||||||
|
#print(math.hypot(3,4))
|
||||||
|
#print(math.acosh(2), math.asinh(1), math.atanh(0.5), math.cosh(1), math.cosh(-1), math.sinh(1), math.tanh(1))
|
11
resources/rapydscript/lib/operator.pyj
Normal file
11
resources/rapydscript/lib/operator.pyj
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
add = __add__ = def(x, y): return x + y
|
||||||
|
sub = __sub__ = def(x, y): return x - y
|
||||||
|
mul = __mul__ = def(x, y): return x * y
|
||||||
|
div = __div__ = def(x, y): return x / y
|
||||||
|
|
||||||
|
lt = __lt__ = def(x, y): return x < y
|
||||||
|
le = __le__ = def(x, y): return x <= y
|
||||||
|
eq = __eq__ = def(x, y): return x == y
|
||||||
|
ne = __ne__ = def(x, y): return x != y
|
||||||
|
ge = __ge__ = def(x, y): return x >= y
|
||||||
|
gt = __gt__ = def(x, y): return x > y
|
93
resources/rapydscript/lib/random.pyj
Normal file
93
resources/rapydscript/lib/random.pyj
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
###########################################################
|
||||||
|
# RapydScript Standard Library
|
||||||
|
# Author: Alexander Tsepkov
|
||||||
|
# Copyright 2013 Pyjeon Software LLC
|
||||||
|
# License: Apache License 2.0
|
||||||
|
# This library is covered under Apache license, so that
|
||||||
|
# you can distribute it with your RapydScript applications.
|
||||||
|
###########################################################
|
||||||
|
|
||||||
|
|
||||||
|
# basic implementation of Python's 'random' library
|
||||||
|
|
||||||
|
# JavaScript's Math.random() does not allow seeding its random generator, to bypass that, this module implements its own
|
||||||
|
# version that can be seeded. I decided on RC4 algorithm for this.
|
||||||
|
|
||||||
|
# please don't mess with this from the outside
|
||||||
|
|
||||||
|
_$rapyd$_seed_state = {
|
||||||
|
'key': [],
|
||||||
|
'key_i': 0,
|
||||||
|
'key_j': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
_$rapyd$_get_random_byte = def():
|
||||||
|
_$rapyd$_seed_state.key_i = (_$rapyd$_seed_state.key_i + 1) % 256
|
||||||
|
_$rapyd$_seed_state.key_j = (_$rapyd$_seed_state.key_j + _$rapyd$_seed_state.key[_$rapyd$_seed_state.key_i]) % 256
|
||||||
|
_$rapyd$_seed_state.key[_$rapyd$_seed_state.key_i], _$rapyd$_seed_state.key[_$rapyd$_seed_state.key_j] = \
|
||||||
|
_$rapyd$_seed_state.key[_$rapyd$_seed_state.key_j], _$rapyd$_seed_state.key[_$rapyd$_seed_state.key_i]
|
||||||
|
return _$rapyd$_seed_state.key[(_$rapyd$_seed_state.key[_$rapyd$_seed_state.key_i] + \
|
||||||
|
_$rapyd$_seed_state.key[_$rapyd$_seed_state.key_j]) % 256]
|
||||||
|
|
||||||
|
def seed(x=Date().getTime()):
|
||||||
|
if type(x) is 'number':
|
||||||
|
x = x.toString()
|
||||||
|
elif type(x) is not 'string':
|
||||||
|
raise TypeError("unhashable type: '" + type(x) + "'")
|
||||||
|
for i in range(256):
|
||||||
|
_$rapyd$_seed_state.key[i] = i
|
||||||
|
j = 0
|
||||||
|
for i in range(256):
|
||||||
|
j = (j + _$rapyd$_seed_state.key[i] + x.charCodeAt(i % x.length)) % 256
|
||||||
|
_$rapyd$_seed_state.key[i], _$rapyd$_seed_state.key[j] = _$rapyd$_seed_state.key[j], _$rapyd$_seed_state.key[i]
|
||||||
|
seed()
|
||||||
|
|
||||||
|
def random():
|
||||||
|
n = 0
|
||||||
|
m = 1
|
||||||
|
for i in range(8):
|
||||||
|
n += _$rapyd$_get_random_byte() * m
|
||||||
|
m *= 256
|
||||||
|
return n / 18446744073709551616
|
||||||
|
|
||||||
|
# unlike the python version, this DOES build a range object, feel free to reimplement
|
||||||
|
def randrange():
|
||||||
|
return choice(range.apply(this, arguments))
|
||||||
|
|
||||||
|
def randint(a, b):
|
||||||
|
return int(random()*(b-a+1) + a)
|
||||||
|
|
||||||
|
def uniform(a, b):
|
||||||
|
return random()*(b-a) + a
|
||||||
|
|
||||||
|
def choice(seq):
|
||||||
|
if seq.length > 0:
|
||||||
|
return seq[Math.floor(random()*seq.length)]
|
||||||
|
else:
|
||||||
|
raise IndexError()
|
||||||
|
|
||||||
|
# uses Fisher-Yates algorithm to shuffle an array
|
||||||
|
def shuffle(x, random_f=random):
|
||||||
|
for i in range(x.length):
|
||||||
|
j = Math.floor(random_f() * (i+1))
|
||||||
|
x[i], x[j] = x[j], x[i]
|
||||||
|
return x
|
||||||
|
|
||||||
|
# similar to shuffle, but only shuffles a subset and creates a copy
|
||||||
|
def sample(population, k):
|
||||||
|
x = population.slice()
|
||||||
|
for i in range(population.length-1, population.length-k-1, -1):
|
||||||
|
j = Math.floor(random() * (i+1))
|
||||||
|
x[i], x[j] = x[j], x[i]
|
||||||
|
return x.slice(population.length-k)
|
||||||
|
|
||||||
|
|
||||||
|
#import stdlib
|
||||||
|
#a = range(50)
|
||||||
|
#random.seed(5)
|
||||||
|
#print(random.choice(a))
|
||||||
|
#print(random.shuffle(a))
|
||||||
|
#print(random.randrange(10))
|
||||||
|
#print(random.randint(1,5))
|
||||||
|
#print(random.uniform(1,5))
|
||||||
|
#print(random.sample(range(20),5))
|
468
resources/rapydscript/lib/re.pyj
Normal file
468
resources/rapydscript/lib/re.pyj
Normal file
File diff suppressed because one or more lines are too long
@ -6,7 +6,7 @@ from __future__ import (unicode_literals, division, absolute_import,
|
|||||||
__license__ = 'GPL v3'
|
__license__ = 'GPL v3'
|
||||||
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2015, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
|
|
||||||
import os, json, sys, re, atexit, errno
|
import os, sys, atexit, errno, subprocess, bz2, glob, shutil, json
|
||||||
from threading import local
|
from threading import local
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from threading import Thread
|
from threading import Thread
|
||||||
@ -16,105 +16,30 @@ from duktape import Context, JSError, to_python
|
|||||||
from calibre.constants import cache_dir
|
from calibre.constants import cache_dir
|
||||||
from calibre.utils.terminal import ANSIStream
|
from calibre.utils.terminal import ANSIStream
|
||||||
|
|
||||||
COMPILER_PATH = 'rapydscript/compiler.js'
|
COMPILER_PATH = 'rapydscript/compiler.js.bz2'
|
||||||
|
|
||||||
def abspath(x):
|
def abspath(x):
|
||||||
return os.path.realpath(os.path.abspath(x))
|
return os.path.realpath(os.path.abspath(x))
|
||||||
|
|
||||||
# Update RapydScript {{{
|
# Update RapydScript {{{
|
||||||
def parse_baselib(src):
|
|
||||||
# duktape does not store function source code, so we have to do it manually
|
|
||||||
start = re.compile(r'''['"]([a-zA-Z0-9()]+)['"]\s*:''')
|
|
||||||
in_func = None
|
|
||||||
funcs = {}
|
|
||||||
for line in src.splitlines():
|
|
||||||
line = line.rstrip()
|
|
||||||
if in_func is None:
|
|
||||||
m = start.match(line)
|
|
||||||
if m is not None:
|
|
||||||
funcs[m.group(1)] = in_func = [line.partition(':')[-1].lstrip()]
|
|
||||||
else:
|
|
||||||
if line in (',', '}'):
|
|
||||||
in_func = None
|
|
||||||
else:
|
|
||||||
in_func.append(line)
|
|
||||||
funcs = {k:'\n'.join(v) for k, v in funcs.iteritems()}
|
|
||||||
return funcs
|
|
||||||
|
|
||||||
def compile_baselib(ctx, baselib, beautify=True):
|
|
||||||
ctx.g.current_output_options = {'beautify':beautify, 'private_scope':False, 'write_name':False}
|
|
||||||
ctx.g.filename = 'baselib.pyj'
|
|
||||||
ctx.g.basedir = ''
|
|
||||||
ctx.g.libdir = ''
|
|
||||||
|
|
||||||
def doit(src):
|
|
||||||
src += '\n'
|
|
||||||
ctx.g.code = src
|
|
||||||
try:
|
|
||||||
return ctx.eval(COMPILER_JS)
|
|
||||||
except Exception as e:
|
|
||||||
print ('Failed to compile source:')
|
|
||||||
print (src)
|
|
||||||
raise SystemExit(str(e))
|
|
||||||
|
|
||||||
return {k:doit(v) for k, v in sorted(baselib.iteritems())}
|
|
||||||
|
|
||||||
def update_rapydscript():
|
def update_rapydscript():
|
||||||
vm_js = '''
|
|
||||||
exports.createContext = function(x) { x.AST_Node = {}; return x; }
|
|
||||||
exports.runInContext = function() { return null; }
|
|
||||||
'''
|
|
||||||
fs_js = '''
|
|
||||||
exports.realpathSync = function(x) { return x; }
|
|
||||||
exports.readFileSync = function() { return ""; }
|
|
||||||
'''
|
|
||||||
path_js = '''
|
|
||||||
exports.join = function(x, y) { return x + '/' + y; }
|
|
||||||
exports.dirname = function(x) { return x; }
|
|
||||||
exports.resolve = function(x) { return x; }
|
|
||||||
'''
|
|
||||||
|
|
||||||
d = os.path.dirname
|
d = os.path.dirname
|
||||||
base = d(d(d(d(d(abspath(__file__))))))
|
base = d(d(d(d(d(abspath(__file__))))))
|
||||||
base = os.path.join(base, 'rapydscript')
|
base = os.path.join(base, 'rapydscript')
|
||||||
ctx = Context(base_dirs=(base,), builtin_modules={'path':path_js, 'fs':fs_js, 'vm':vm_js})
|
raw = subprocess.check_output(['node', '--harmony', os.path.join(base, 'bin', 'export')])
|
||||||
ctx.g.require.id = 'rapydscript/bin'
|
path = P(COMPILER_PATH, allow_user_override=False)
|
||||||
try:
|
with open(path, 'wb') as f:
|
||||||
ctx.eval('RapydScript = require("../tools/compiler")', fname='bin/rapydscript')
|
f.write(bz2.compress(raw, 9))
|
||||||
except JSError as e:
|
base = os.path.join(base, 'src', 'lib')
|
||||||
raise SystemExit('%s:%s:%s' % (e.fileName, e.lineNumber, e.message))
|
dest = os.path.join(P('rapydscript', allow_user_override=False), 'lib')
|
||||||
data = b'\n\n'.join(open(os.path.join(base, 'lib', x + '.js'), 'rb').read() for x in ctx.g.RapydScript.FILENAMES)
|
if not os.path.exists(dest):
|
||||||
|
os.mkdir(dest)
|
||||||
package = json.load(open(os.path.join(base, 'package.json')))
|
for x in glob.glob(os.path.join(base, '*.pyj')):
|
||||||
baselib = parse_baselib(open(os.path.join(base, 'src', 'baselib.pyj'), 'rb').read().decode('utf-8'))
|
shutil.copy2(x, dest)
|
||||||
ctx = Context()
|
|
||||||
ctx.eval(data.decode('utf-8'))
|
|
||||||
baselib = {'beautifed': compile_baselib(ctx, baselib), 'minified': compile_baselib(ctx, baselib, False)}
|
|
||||||
repl = open(os.path.join(base, 'tools', 'repl.js'), 'rb').read()
|
|
||||||
|
|
||||||
with open(P(COMPILER_PATH, allow_user_override=False), 'wb') as f:
|
|
||||||
f.write(data)
|
|
||||||
f.write(b'\n\nrs_baselib_pyj = ' + json.dumps(baselib) + b';')
|
|
||||||
f.write(b'\n\nrs_repl_js = ' + json.dumps(repl) + b';')
|
|
||||||
f.write(b'\n\nrs_package_version = ' + json.dumps(package['version']) + b';\n')
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# Compiler {{{
|
# Compiler {{{
|
||||||
tls = local()
|
tls = local()
|
||||||
COMPILER_JS = '''
|
|
||||||
(function() {
|
|
||||||
var output = OutputStream(current_output_options);
|
|
||||||
var ast = parse(code, {
|
|
||||||
filename: filename,
|
|
||||||
readfile: Duktape.readfile,
|
|
||||||
basedir: basedir,
|
|
||||||
auto_bind: false,
|
|
||||||
libdir: libdir
|
|
||||||
});
|
|
||||||
ast.print(output);
|
|
||||||
return output.get();
|
|
||||||
})();
|
|
||||||
'''
|
|
||||||
|
|
||||||
def to_dict(obj):
|
def to_dict(obj):
|
||||||
return dict(zip(obj.keys(), obj.values()))
|
return dict(zip(obj.keys(), obj.values()))
|
||||||
@ -122,9 +47,9 @@ def to_dict(obj):
|
|||||||
def compiler():
|
def compiler():
|
||||||
c = getattr(tls, 'compiler', None)
|
c = getattr(tls, 'compiler', None)
|
||||||
if c is None:
|
if c is None:
|
||||||
c = tls.compiler = Context(base_dirs=(P('rapydscript', allow_user_override=False),))
|
c = tls.compiler = Context()
|
||||||
c.eval(P(COMPILER_PATH, data=True, allow_user_override=False).decode('utf-8'), fname='rapydscript-compiler.js')
|
c.eval('exports = {}; sha1sum = Duktape.sha1sum;', noreturn=True)
|
||||||
c.g.current_output_options = {}
|
c.eval(bz2.decompress(P(COMPILER_PATH, data=True, allow_user_override=False)), fname=COMPILER_PATH, noreturn=True)
|
||||||
return c
|
return c
|
||||||
|
|
||||||
class PYJError(Exception):
|
class PYJError(Exception):
|
||||||
@ -133,31 +58,20 @@ class PYJError(Exception):
|
|||||||
Exception.__init__(self, '')
|
Exception.__init__(self, '')
|
||||||
self.errors = errors
|
self.errors = errors
|
||||||
|
|
||||||
def compile_pyj(data, filename='<stdin>', beautify=True, private_scope=True, libdir=None, omit_baselib=False, write_name=True):
|
def compile_pyj(data, filename='<stdin>', beautify=True, private_scope=True, libdir=None, omit_baselib=False):
|
||||||
import duktape
|
|
||||||
if isinstance(data, bytes):
|
if isinstance(data, bytes):
|
||||||
data = data.decode('utf-8')
|
data = data.decode('utf-8')
|
||||||
c = compiler()
|
c = compiler()
|
||||||
c.g.current_output_options = {
|
c.g.current_options = {
|
||||||
'beautify':beautify,
|
'beautify':beautify,
|
||||||
'private_scope':private_scope,
|
'private_scope':private_scope,
|
||||||
'omit_baselib': omit_baselib,
|
'omit_baselib': omit_baselib,
|
||||||
'write_name': write_name,
|
'libdir': libdir or P('rapydscript/lib', allow_user_override=False),
|
||||||
'baselib':dict(dict(c.g.rs_baselib_pyj)['beautifed' if beautify else 'minified']),
|
'basedir': os.getcwdu() if not filename or filename == '<stdin>' else os.path.dirname(filename),
|
||||||
|
'filename': filename,
|
||||||
}
|
}
|
||||||
d = os.path.dirname
|
c.g.rs_source_code = data
|
||||||
c.g.libdir = libdir or os.path.join(d(d(d(abspath(__file__)))), 'pyj')
|
return c.eval('exports["compile"](rs_source_code, %s, current_options)' % json.dumps(filename))
|
||||||
c.g.code = data
|
|
||||||
c.g.filename = filename
|
|
||||||
c.g.basedir = os.getcwdu() if not filename or filename == '<stdin>' else d(filename)
|
|
||||||
errors = []
|
|
||||||
c.g.AST_Node.warn = lambda templ, data:errors.append(to_dict(data))
|
|
||||||
try:
|
|
||||||
return c.eval(COMPILER_JS)
|
|
||||||
except duktape.JSError:
|
|
||||||
if errors:
|
|
||||||
raise PYJError(errors)
|
|
||||||
raise
|
|
||||||
# }}}
|
# }}}
|
||||||
|
|
||||||
# REPL {{{
|
# REPL {{{
|
||||||
@ -192,30 +106,14 @@ class Repl(Thread):
|
|||||||
self.start()
|
self.start()
|
||||||
|
|
||||||
def init_ctx(self):
|
def init_ctx(self):
|
||||||
cc = '''
|
|
||||||
exports.AST_Node = AST_Node;
|
|
||||||
exports.ALL_KEYWORDS = ALL_KEYWORDS;
|
|
||||||
exports.tokenizer = tokenizer;
|
|
||||||
exports.parse = parse;
|
|
||||||
exports.OutputStream = OutputStream;
|
|
||||||
exports.IDENTIFIER_PAT = IDENTIFIER_PAT;
|
|
||||||
'''
|
|
||||||
self.prompt = self.ps1
|
self.prompt = self.ps1
|
||||||
readline = '''
|
|
||||||
exports.createInterface = function(options) { rl.completer = options.completer; return rl; }
|
self.ctx = compiler()
|
||||||
'''
|
|
||||||
self.ctx = Context(builtin_modules={'readline':readline, 'compiler':cc})
|
|
||||||
self.ctx.g.Duktape.write = self.output.write
|
self.ctx.g.Duktape.write = self.output.write
|
||||||
self.ctx.eval(r'''console = { log: function() { Duktape.write(Array.prototype.slice.call(arguments).join(' ') + '\n');}};
|
self.ctx.eval(r'''console = { log: function() { Duktape.write(Array.prototype.slice.call(arguments).join(' ') + '\n');}};
|
||||||
console['error'] = console['log'];''')
|
console['error'] = console['log'];''')
|
||||||
cc = P(COMPILER_PATH, data=True, allow_user_override=False)
|
|
||||||
self.ctx.eval(cc)
|
|
||||||
baselib = dict(dict(self.ctx.g.rs_baselib_pyj)['beautifed'])
|
|
||||||
baselib = '\n\n'.join(baselib.itervalues())
|
|
||||||
self.ctx.eval('module = {}')
|
|
||||||
self.ctx.eval(self.ctx.g.rs_repl_js, fname='repl.js')
|
|
||||||
self.ctx.g.repl_options = {
|
self.ctx.g.repl_options = {
|
||||||
'baselib': baselib, 'show_js': self.show_js,
|
'show_js': self.show_js,
|
||||||
'histfile':False,
|
'histfile':False,
|
||||||
'input':True, 'output':True, 'ps1':self.ps1, 'ps2':self.ps2,
|
'input':True, 'output':True, 'ps1':self.ps1, 'ps2':self.ps2,
|
||||||
'terminal':self.output.isatty,
|
'terminal':self.output.isatty,
|
||||||
@ -257,9 +155,10 @@ class Repl(Thread):
|
|||||||
send_interrupt: function() { listeners['SIGINT'](); },
|
send_interrupt: function() { listeners['SIGINT'](); },
|
||||||
close: function() {listeners['close'](); },
|
close: function() {listeners['close'](); },
|
||||||
};
|
};
|
||||||
''')
|
repl_options.readline = { createInterface: function(options) { rl.completer = options.completer; return rl; }};
|
||||||
|
exports.init_repl(repl_options)
|
||||||
|
''', fname='<init repl>')
|
||||||
rl = self.ctx.g.rl
|
rl = self.ctx.g.rl
|
||||||
self.ctx.eval('module.exports(repl_options)')
|
|
||||||
completer = to_python(rl.completer)
|
completer = to_python(rl.completer)
|
||||||
send_interrupt = to_python(rl.send_interrupt)
|
send_interrupt = to_python(rl.send_interrupt)
|
||||||
send_line = to_python(rl.send_line)
|
send_line = to_python(rl.send_line)
|
||||||
@ -333,7 +232,7 @@ class Repl(Thread):
|
|||||||
|
|
||||||
def main(args=sys.argv):
|
def main(args=sys.argv):
|
||||||
import argparse
|
import argparse
|
||||||
ver = compiler().g.rs_package_version
|
ver = compiler().g.exports.rs_version
|
||||||
parser = argparse.ArgumentParser(prog='pyj',
|
parser = argparse.ArgumentParser(prog='pyj',
|
||||||
description='RapydScript compiler and REPL. If passed input on stdin, it is compiled and written to stdout. Otherwise a REPL is started.')
|
description='RapydScript compiler and REPL. If passed input on stdin, it is compiled and written to stdout. Otherwise a REPL is started.')
|
||||||
parser.add_argument('--version', action='version',
|
parser.add_argument('--version', action='version',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user