-
Notifications
You must be signed in to change notification settings - Fork 67
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
same exact codebase now runs in the browser as in node
- Loading branch information
Showing
9 changed files
with
487 additions
and
104 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,305 @@ | ||
BASELIB = '''""" | ||
********************************************************************** | ||
|
||
A RapydScript to JavaScript compiler. | ||
https://github.com/atsepkov/RapydScript | ||
|
||
-------------------------------- (C) --------------------------------- | ||
|
||
Author: Alexander Tsepkov | ||
<atsepkov@pyjeon.com> | ||
http://www.pyjeon.com | ||
|
||
Distributed under BSD license: | ||
Copyright 2013 (c) Alexander Tsepkov <atsepkov@pyjeon.com> | ||
|
||
********************************************************************** | ||
""" | ||
|
||
|
||
# for convenience we'll use a convention here that will work as follows: | ||
# | ||
# if function is named, assume we'll be outputting the function itself | ||
# if the given baselib chunk is triggered | ||
# | ||
# if function is unnamed, assume the function is a container for the logic | ||
# to be output. We're basically ignoring the wrapper and dumping what's inside | ||
|
||
{ | ||
"abs": def abs(n): | ||
return Math.abs(n) | ||
, | ||
"all": def all(a): | ||
for e in a: | ||
if not e: return False | ||
return True | ||
, | ||
"any": def any(a): | ||
for e in a: | ||
if e: return True | ||
return False | ||
, | ||
"bin": def bin(a): return '0b' + (a >>> 0).toString(2) | ||
, | ||
"bind": def ՐՏ_bind(fn, thisArg): | ||
if fn.orig: fn = fn.orig | ||
if thisArg is False: return fn | ||
ret = def(): | ||
return fn.apply(thisArg, arguments) | ||
ret.orig = fn | ||
return ret | ||
, | ||
"rebind_all": def ՐՏ_rebindAll(thisArg, rebind): | ||
if rebind is undefined: rebind = True | ||
for JS('var p in thisArg'): | ||
if thisArg[p] and thisArg[p].orig: | ||
if rebind: thisArg[p] = bind(thisArg[p], thisArg) | ||
else: thisArg[p] = thisArg[p].orig | ||
, | ||
"cmp": def cmp(a, b): return a < b ? -1 : a > b ? 1 : 0 | ||
, | ||
"chr": def(): chr = String.fromCharCode | ||
, | ||
"dir": def dir(item): | ||
# TODO: this isn't really representative of real Python's dir(), nor is it | ||
# an intuitive replacement for "for ... in" loop, need to update this logic | ||
# and introduce a different way of achieving "for ... in" | ||
arr = [] | ||
for JS('var i in item'): arr.push(i) | ||
return arr | ||
, | ||
"enumerate": def enumerate(item): | ||
arr = [] | ||
iter = ՐՏ_Iterable(item) | ||
for i in range(iter.length): | ||
arr[arr.length] = [i, item[i]] | ||
return arr | ||
, | ||
"eslice": def ՐՏ_eslice(arr, step, start, end): | ||
arr = arr[:] | ||
if JS('typeof arr') is 'string' or isinstance(arr, String): | ||
isString = True | ||
arr = arr.split('') | ||
|
||
if step < 0: | ||
step = -step | ||
arr.reverse() | ||
if JS('typeof start') is not "undefined": start = arr.length - start - 1 | ||
if JS('typeof end') is not "undefined": end = arr.length - end - 1 | ||
if JS('typeof start') is "undefined": start = 0 | ||
if JS('typeof end') is "undefined": end = arr.length | ||
|
||
arr = arr.slice(start, end).filter(def(e, i): return i % step is 0;) | ||
return isString ? arr.join('') : arr | ||
, | ||
"extends": def ՐՏ_extends(child, parent): | ||
child.prototype = Object.create(parent.prototype) | ||
child.prototype.__base__ = parent # since we don't support multiple inheritance, __base__ seemed more appropriate than __bases__ array of 1 | ||
child.prototype.constructor = child | ||
, | ||
"filter": def filter(oper, arr): | ||
return arr.filter(oper) | ||
, | ||
"hex": def hex(a): return '0x' + (a >>> 0).toString(16) | ||
, | ||
"in": def ՐՏ_in(val, arr): | ||
if JS('typeof arr.indexOf') is 'function': return arr.indexOf(val) is not -1 | ||
return arr.hasOwnProperty(val) | ||
, | ||
"iterable": def ՐՏ_Iterable(iterable): | ||
# can't use Symbol.iterator yet since it's not supported on all platforms until ES6 (i.e. mobile browsers don't have it) | ||
if iterable.constructor is [].constructor | ||
or iterable.constructor is ''.constructor | ||
or (tmp = Array.prototype.slice.call(iterable)).length: | ||
return tmp or iterable | ||
return Object.keys(iterable) # so we can use 'for ... in' syntax with hashes | ||
, | ||
"len": def len(obj): | ||
# can't use Symbol.iterator yet since it's not supported on all platforms until ES6 (i.e. mobile browsers don't have it) | ||
if obj.constructor is [].constructor | ||
or obj.constructor is ''.constructor | ||
or (tmp = Array.prototype.slice.call(obj)).length: | ||
return (tmp or obj).length | ||
return Object.keys(obj).length | ||
, | ||
"map": def map(oper, arr): | ||
return arr.map(oper) | ||
, | ||
"max": def max(a): | ||
if Array.isArray(a): | ||
return Math.max.apply(null, a) | ||
else: | ||
return Math.max.apply(null, arguments) | ||
, | ||
"min": def min(a): | ||
if Array.isArray(a): | ||
return Math.min.apply(null, a) | ||
else: | ||
return Math.min.apply(null, arguments) | ||
, | ||
"merge": def ՐՏ_merge(target, source, overwrite): | ||
for JS('var i in source'): | ||
# instance variables | ||
if source.hasOwnProperty(i) and (overwrite or JS('typeof target[i]') is 'undefined'): target[i] = source[i] | ||
for prop in Object.getOwnPropertyNames(source.prototype): | ||
# methods | ||
if overwrite or JS('typeof target.prototype[prop]') is 'undefined': target.prototype[prop] = source.prototype[prop] | ||
, | ||
"mixin": def ՐՏ_mixin(*classes): | ||
return def(baseClass): | ||
for cls in classes: | ||
for key in Object.getOwnPropertyNames(cls.prototype): | ||
if key not in baseClass.prototype: | ||
baseClass.prototype[key] = cls.prototype[key] | ||
return baseClass | ||
|
||
, | ||
"print": def ՐՏ_print(): | ||
if JS('typeof console') is 'object': console.log.apply(console, arguments) | ||
, | ||
"range": def range(start, stop, step): | ||
if arguments.length <= 1: | ||
stop = start or 0 | ||
start = 0 | ||
step = arguments[2] or 1 | ||
|
||
length = Math.max(Math.ceil((stop - start) / step), 0) | ||
idx = 0 | ||
range = Array(length) | ||
|
||
while idx < length: | ||
range[JS('idx++')] = start | ||
start += step | ||
return range | ||
, | ||
"reduce": def reduce(f, a): return Array.reduce(a, f) | ||
, | ||
"reversed": def reversed(arr): | ||
tmp = arr[:] | ||
return tmp.reverse() | ||
, | ||
"sorted": def sorted(arr): | ||
tmp = arr[:] | ||
return tmp.sort() | ||
, | ||
"sum": def sum(arr, start=0): | ||
return arr.reduce( | ||
def(prev, cur): return prev+cur | ||
, | ||
start | ||
) | ||
, | ||
"type": def ՐՏ_type(obj): | ||
return obj.constructor and obj.constructor.name ? obj.constructor.name : Object.prototype.toString.call(obj).slice(8, -1) | ||
, | ||
"zip": def zip(a, b): | ||
return [[a[i], b[i]] for i in range(Math.min(a.length, b.length))] | ||
, | ||
"getattr": def getattr(obj, name): | ||
return obj[name] | ||
, | ||
"setattr": def setattr(obj, name, value): | ||
obj[name] = value | ||
, | ||
"hasattr": def hasattr(obj, name): | ||
return JS('name in obj') | ||
, | ||
"eq": def ՐՏ_eq(a, b): | ||
""" | ||
Equality comparison that works with all data types, returns true if structure and | ||
contents of first object equal to those of second object | ||
|
||
Arguments: | ||
a: first object | ||
b: second object | ||
""" | ||
if a is b: | ||
# simple object | ||
return True | ||
|
||
if (Array.isArray(a) and Array.isArray(b)) or (isinstance(a, Object) and isinstance(b, Object)): | ||
# if length ot type doesn't match, they can't be equal | ||
if a.constructor is not b.constructor or a.length is not b.length: | ||
return False | ||
|
||
if Array.isArray(a): | ||
# arrays | ||
for i in range(len(a)): | ||
if not ՐՏ_eq(a[i], b[i]): | ||
return False | ||
else: | ||
# hashes | ||
# compare individual properties (order doesn't matter if it's a hash) | ||
if Object.keys(a).length is not Object.keys(b).length: return False | ||
for i in a: | ||
# recursively test equality of object children | ||
if not ՐՏ_eq(a[i], b[i]): | ||
return False | ||
return True | ||
return False | ||
, | ||
"kwargs": def(): | ||
# WARNING: when using this function decorator, you will not be able to use obfuscators that rename local variables | ||
def kwargs(f): | ||
argNames = f.toString().match(/\\(([^\\)]+)/)[1] | ||
if not kwargs.memo[argNames]: | ||
kwargs.memo[argNames] = argNames ? argNames.split(',').map(def(s): return s.trim();) : [] | ||
argNames = kwargs.memo[argNames] | ||
return def(): | ||
args = [].slice.call(arguments) | ||
if args.length: | ||
kw = args[-1] | ||
if JS('typeof kw') is 'object': | ||
for i in range(argNames.length): | ||
if argNames[i] in dir(kw): | ||
args[i] = kw[argNames[i]] | ||
else: | ||
args.push(kw) | ||
|
||
# This logic is very fragile and very subtle, it needs to work both in ES6 and ES5, don't try to optimize the | ||
# apply away into *args because having it in this format ensures correct 'this' context, otherwise the function | ||
# ends up unbound. Similarly, the fallthrough to except handles class creation in ES6. | ||
try: | ||
return f.apply(this, args) | ||
except as e: | ||
if /Class constructor \\w+ cannot be invoked without 'new'/.test(e): | ||
return new f(*args) | ||
raise | ||
kwargs.memo = {} | ||
, | ||
|
||
# Errors | ||
# temporarily implemented via a wrapper pattern since there is no mechanism for assigning | ||
# classes to dictionary keys yet | ||
"AssertionError": def(): | ||
class AssertionError(Error): | ||
def __init__(self, message): | ||
self.name = "AssertionError" | ||
self.message = message | ||
, | ||
"IndexError": def(): | ||
class IndexError(Error): | ||
def __init__(self, message): | ||
self.name = "IndexError" | ||
self.message = message | ||
, | ||
"KeyError": def(): | ||
class KeyError(Error): | ||
def __init__(self, message): | ||
self.name = "KeyError" | ||
self.message = message | ||
, | ||
"TypeError": def(): | ||
class TypeError(Error): | ||
def __init__(self, message): | ||
self.name = "TypeError" | ||
self.message = message | ||
, | ||
"ValueError": def(): | ||
class ValueError(Error): | ||
def __init__(self, message): | ||
self.name = "ValueError" | ||
self.message = message | ||
, | ||
} | ||
''' |
Oops, something went wrong.