def _repr(self): assert isinstance(self, Character) cv = self.char_val() if cv < 128: return rt.wrap(u"\\"+unicode(chr(cv))) hexv = rt.name(rt.bit_str(rt.wrap(self.char_val()), rt.wrap(4))) return rt.wrap(u"\\u" + u"0" * (4 - len(hexv)) + hexv)
def test_hashmap_create(): acc = rt.hashmap(rt.wrap(1), rt.wrap(2)) val = rt._val_at(acc, rt.wrap(1), nil) assert val.int_val() == 2
def compile_let(form, ctx): form = next(form) bindings = rt.first(form) affirm(isinstance(bindings, PersistentVector), u"Bindings must be a vector") body = next(form) ctc = ctx.can_tail_call ctx.disable_tail_call() binding_count = 0 for i in range(0, rt.count(bindings).int_val(), 2): binding_count += 1 name = rt.nth(bindings, rt.wrap(i)) affirm(isinstance(name, symbol.Symbol), u"Let locals must be symbols") bind = rt.nth(bindings, rt.wrap(i + 1)) compile_form(bind, ctx) ctx.add_local(name._str, LetBinding(ctx.sp())) if ctc: ctx.enable_tail_call() while True: compile_form(rt.first(body), ctx) body = rt.next(body) if body is nil: break else: ctx.pop() ctx.bytecode.append(code.POP_UP_N) ctx.sub_sp(binding_count) ctx.bytecode.append(binding_count)
def parse_int(m): sign = 1 if m.group(1) == u'-': sign = -1 radix = 10 if m.group(7): num = m.group(7) elif m.group(2): radix = 16 num = m.group(3) elif m.group(4): radix = 8 num = m.group(4) elif m.group(5): radix = int(m.group(5)) num = m.group(6) else: return None if m.group(8): return rt.wrap(rbigint.fromstr(str(m.group(1) + num), radix)) else: return rt.wrap(sign * int(str(num), radix))
def invoke(self, rdr, ch): if ARG_ENV.deref() is not nil: throw_syntax_error_with_data(rdr, u"Nested #()s are not allowed") try: ARG_ENV.set_value(rt.assoc(EMPTY_MAP, ARG_MAX, rt.wrap(-1))) rdr.unread() form = read_inner(rdr, True) args = EMPTY_VECTOR percent_args = ARG_ENV.deref() max_arg = rt.get(percent_args, ARG_MAX) for i in range(1, max_arg.int_val() + 1): arg = rt.get(percent_args, rt.wrap(i)) if arg is nil: arg = ArgReader.gen_arg(i) args = rt.conj(args, arg) rest_arg = rt.get(percent_args, rt.wrap(-1)) if rest_arg is not nil: args = rt.conj(args, ARG_AMP) args = rt.conj(args, rest_arg) return rt.cons(symbol(u"fn*"), rt.cons(args, rt.cons(form, nil))) finally: ARG_ENV.set_value(nil)
def syntax_quote(form): if isinstance(form, Symbol) and compiler.is_compiler_special(form): ret = rt.list(QUOTE, form) elif isinstance(form, Symbol): if rt.namespace(form) is None and rt.name(form).endswith("#"): gmap = rt.deref(GEN_SYM_ENV) affirm(gmap is not nil, u"Gensym literal used outside a syntax quote") gs = rt.get(gmap, form) if gs is nil: gs = rt.symbol(rt.str(form, rt.wrap(u"__"), rt.gensym())) GEN_SYM_ENV.set_value(rt.assoc(gmap, form, gs)) form = gs else: var = rt.resolve_in(compiler.NS_VAR.deref(), form) if var is nil: form = rt.symbol(rt.str(rt.wrap(rt.name(rt.deref(compiler.NS_VAR))), rt.wrap(u"/"), form)) else: form = rt.symbol(rt.str(rt.wrap(rt.namespace(var)), rt.wrap(u"/"), rt.str(rt.wrap(rt.name(var))))) ret = rt.list(QUOTE, form) elif is_unquote(form): ret = rt.first(rt.next(form)) elif is_unquote_splicing(form): raise Exception("Unquote splicing not used inside list") elif rt.vector_QMARK_(form) is true: ret = rt.list(APPLY, CONCAT, SyntaxQuoteReader.expand_list(form)) elif rt.seq_QMARK_(form) is true: ret = rt.list(APPLY, LIST, rt.cons(CONCAT, SyntaxQuoteReader.expand_list(rt.seq(form)))) else: ret = rt.list(QUOTE, form) return ret
def load_ns(filename): import pixie.vm.string as string import pixie.vm.symbol as symbol import os.path as path if isinstance(filename, symbol.Symbol): affirm(rt.namespace(filename) is None, u"load-file takes a un-namespaced symbol") filename_str = rt.name(filename).replace(u".", u"/") + u".pxi" loaded_ns = code._ns_registry.get(rt.name(filename), None) if loaded_ns is not None: return loaded_ns else: affirm(isinstance(filename, string.String), u"Filename must be string") filename_str = rt.name(filename) paths = rt.deref(rt.deref(rt.load_paths)) f = None for x in range(rt.count(paths)): path_x = rt.nth(paths, rt.wrap(x)) affirm(isinstance(path_x, string.String), u"Contents of load-paths must be strings") full_path = path.join(str(rt.name(path_x)), str(filename_str)) if path.isfile(full_path): f = full_path break if f is None: affirm(False, u"File '" + rt.name(filename) + u"' does not exist in any directory found in load-paths") else: rt.load_file(rt.wrap(f)) return nil
def _compare(self, frm, to): if isinstance(to, tuple): assert isinstance(frm, Cons) for x in to: self._compare(frm.first(), x) frm = frm.next() assert frm == nil elif isinstance(to, int): assert isinstance(frm, Integer) assert frm._int_val == to elif isinstance(to, Symbol): assert isinstance(frm, Symbol) assert frm._str == to._str elif isinstance(to, list): assert isinstance(frm, PersistentVector) for x in range(max(len(to), rt._count(frm)._int_val)): self._compare(rt.nth(frm, rt.wrap(x)), to[x]) elif isinstance(to, dict): assert isinstance(frm, PersistentHashMap) for key in dict.keys(to): self._compare(frm.val_at(rt.wrap(key), ""), to[key]) assert rt._count(frm)._int_val == len(dict.keys(to)) elif isinstance(to, Character): assert isinstance(frm, Character) assert to._char_val == frm._char_val else: raise Exception("Don't know how to handle " + str(type(to)))
def to_float(x): if isinstance(x, Float): return x if isinstance(x, Ratio): return rt.wrap(x.numerator() / float(x.denominator())) if isinstance(x, BigInteger): return rt.wrap(x.bigint_val().tofloat()) assert False
def trimr(a): a = rt.name(a) j = len(a) while j > 0 and unicodedb.isspace(ord(a[j - 1])): j -= 1 if j <= 0: return rt.wrap(u"") return rt.wrap(a[0:j])
def run_load_stdlib(): global stdlib_loaded if stdlib_loaded.is_true(): return rt.load_ns(rt.wrap(u"pixie/stdlib.pxi")) rt.load_ns(rt.wrap(u"pixie/stacklets.pxi")) stdlib_loaded.set_true()
def to_float(x): if isinstance(x, Float): return x if isinstance(x, Ratio): return rt.wrap(x.numerator() / float(x.denominator())) if isinstance(x, Integer): return rt.wrap(float(x.int_val())) if isinstance(x, BigInteger): return rt.wrap(x.bigint_val().tofloat()) object.runtime_error(u"Cannot convert %s to float" %x.type().name())
def add_refer_symbol(self, sym, var): assert isinstance(self, Namespace) name = rt.name(sym) prev_binding = self._registry.get(name, None) if prev_binding is not None: print rt.name(rt.str(rt.wrap(u"Warning: "), sym, rt.wrap(u" already refers to "), prev_binding)) self._registry[name] = var return var
def trim(a): a = rt.name(a) i = 0 while i < len(a) and unicodedb.isspace(ord(a[i])): i += 1 j = len(a) while j > 0 and unicodedb.isspace(ord(a[j - 1])): j -= 1 if j <= i: return rt.wrap(u"") return rt.wrap(a[i:j])
def init_load_path(self_path): if not path.isfile(self_path): self_path = find_in_path(self_path) assert self_path is not None if path.islink(self_path): self_path = os.readlink(self_path) self_path = dirname(rpath.rabspath(self_path)) # runtime is not loaded yet, so we have to do it manually LOAD_PATHS.set_root(Atom(EMPTY_VECTOR.conj(rt.wrap(self_path)))) # just for run_load_stdlib (global variables can't be assigned to) load_path.set_root(rt.wrap(self_path))
def register_next_arg(n): arg_env = ARG_ENV.deref() max_arg = rt.get(arg_env, ARG_MAX) if n > max_arg.int_val(): arg_env = rt.assoc(arg_env, ARG_MAX, rt.wrap(n)) arg = rt.get(arg_env, rt.wrap(n), nil) if arg is nil: arg = ArgReader.gen_arg(n) arg_env = rt.assoc(arg_env, rt.wrap(n), arg) ARG_ENV.set_value(arg_env) return arg
def init_names(self): if self._w_name is None: s = self._str.split(u"/") if len(s) == 2: self._w_ns = rt.wrap(s[0]) self._w_name = rt.wrap(s[1]) elif len(s) == 1: self._w_name = rt.wrap(s[0]) self._w_ns = nil else: self._w_ns = rt.wrap(s[0]) self._w_name = rt.wrap(u"/".join(s[1:]))
def _reduce(self, f, init): assert isinstance(self, Path) for dirpath, dirnames, filenames in os.walk(str(self._path)): for dirname in dirnames: init = f.invoke([init, Path(rt.wrap(dirpath + "/" + dirname))]) if rt.reduced_QMARK_(init): return rt.deref(init) for filename in filenames: init = f.invoke([init, Path(rt.wrap(dirpath + "/" + filename))]) if rt.reduced_QMARK_(init): return rt.deref(init) return init
def _throw(ex): from pixie.vm.keyword import keyword if isinstance(ex, RuntimeException): raise WrappedException(ex) if rt._satisfies_QMARK_(IVector, ex): data = rt.nth(ex, rt.wrap(0)) msg = rt.nth(ex, rt.wrap(1)) elif rt._satisfies_QMARK_(ILookup, ex): data = rt._val_at(ex, keyword(u"data"), nil) msg = rt._val_at(ex, keyword(u"msg"), nil) else: affirm(False, u"Can only throw vectors, maps and exceptions") return nil raise WrappedException(RuntimeException(msg, data))
def c_struct(name, size, spec): d = {} for x in range(rt.count(spec)): row = rt.nth(spec, rt.wrap(x)) nm = rt.nth(row, rt.wrap(0)) tp = rt.nth(row, rt.wrap(1)) offset = rt.nth(row, rt.wrap(2)) affirm(isinstance(nm, Keyword), u"c-struct field names must be keywords") if not isinstance(tp, CType): runtime_error(u"c-struct field types must be c types, got: " + rt.name(rt.str(tp))) d[nm] = (tp, offset.int_val()) return CStructType(rt.name(name), size.int_val(), d)
def affirm(val, msg): """Works a lot like assert except it throws RuntimeExceptions""" assert isinstance(msg, unicode) if not val: import pixie.vm.rt as rt from pixie.vm.keyword import keyword raise WrappedException(RuntimeException(rt.wrap(msg), keyword(u"pixie.stdlib/AssertionException")))
def load_lib(self): if not self._is_inited: load_paths = rt.deref(rt.deref(rt.load_paths)) for x in range(rt.count(load_paths)): s = rffi.str2charp(str(rt.name(rt.nth(load_paths, rt.wrap(x)))) + "/" + str(self._name)) try: self._dyn_lib = dynload.dlopen(s) self._is_inited = True except dynload.DLOpenError as ex: continue finally: rffi.free_charp(s) break if not self._is_inited: s = rffi.str2charp(str(self._name)) try: self._dyn_lib = dynload.dlopen(s) self._is_inited = True except dynload.DLOpenError as ex: raise object.runtime_error(u"Couldn't Load Library: " + self._name, u"pixie.stdlib/LibraryNotFoundException") finally: rffi.free_charp(s)
def add_env_to_load_path(): pp = os.environ.get("PIXIE_PATH") if pp is not None: LP = rt.deref(LOAD_PATHS.deref()) for path in pp.split(":"): LP = rt.conj(LP, rt.wrap(path)) LOAD_PATHS.set_root(Atom(LP))
def _ffi_fn__args(args): affirm(len(args) >= 4, u"ffi-fn requires at least 4 arguments") lib, nm, arg_types, ret_type = args[:4] affirm(isinstance(lib, ExternalLib), u"First argument must be an ExternalLib") affirm(isinstance(ret_type, object.Type), u"Ret type must be a type") affirm(rt.namespace(nm) is None, u"Name must not be namespaced") cnt = rt.count(arg_types) new_args = [None] * cnt for x in range(cnt): t = rt.nth(arg_types, rt.wrap(x)) affirm(isinstance(t, object.Type), u"Arg defs must be types") new_args[x] = t kwargs = args[4:] affirm(len(kwargs) & 0x1 == 0, u"ffi-fn requires even number of options") is_variadic = False for i in range(0, len(kwargs)/2, 2): key = kwargs[i] val = kwargs[i+1] affirm(isinstance(key, Keyword), u"ffi-fn options should be keyword/bool pairs") affirm(val is true or val is false, u"ffi-fn options should be keyword/bool pairs") k = rt.name(key) if k == u"variadic?": is_variadic = True if val is true else False else: affirm(False, u"unknown ffi-fn option: :" + k) f = FFIFn(lib, rt.name(nm), new_args, ret_type, is_variadic) return f
def struct_size(tp): """(struct-size tp) Gives the size of the given CStruct type tp, in bytes.""" if not isinstance(tp, CStructType): runtime_error(u"Expected a CStruct type to get the size of, got " + rt.name(rt.str(tp))) return rt.wrap(tp.get_size())
def invoke(self, rdr, ch): acc = [] # TODO: implement escape characters while True: try: v = rdr.read() except EOFError: return throw_syntax_error_with_data(rdr, u"Unmatched string quote '\"'") if v == "\"": return rt.wrap(u"".join(acc)) elif v == "\\": #inside escape... TODO handle everything. try: v = rdr.read() if v == "\"": acc.append("\"") elif v == "\\": acc.append("\\") elif v == "n": acc.append("\n") elif v == "r": acc.append("\r") elif v == "t": acc.append("\t") else: throw_syntax_error_with_data(rdr, u"unhandled escape character: " + v) except EOFError: throw_syntax_error_with_data(rdr, u"eof after escape character") else: acc.append(v)
def macroexpand(form): sym = rt.first(form) if isinstance(sym, symbol.Symbol): s = rt.name(sym) if s.startswith(".") and s != u".": if rt.count(form) < 2: raise Exception("malformed dot expression, expecting (.member obj ...)") method = rt.keyword(rt.wrap(rt.name(sym)[1:])) obj = rt.first(rt.next(form)) dot = rt.symbol(rt.wrap(u".")) call = rt.cons(dot, rt.cons(obj, rt.cons(method, rt.next(rt.next(form))))) return call return form
def index_of3(a, sep, start): affirm(isinstance(start, Integer), u"Third argument must be an integer") start = start.int_val() if start >= 0: return rt.wrap(rt.name(a).find(rt.name(sep), start)) else: runtime_error(u"Third argument must be a non-negative integer")
def inner_invoke(self, args): import pixie.vm.rt as rt import pixie.vm.persistent_vector as vector with with_ns(u"user"): NS_VAR.deref().include_stdlib() acc = vector.EMPTY for x in self._argv: acc = rt.conj(acc, rt.wrap(x)) PROGRAM_ARGUMENTS.set_root(acc) with with_ns(u"user"): try: f = None if self._file == '-': f, _, _ = create_stdio() else: if not path.isfile(self._file): print "Error: Cannot open '" + self._file + "'" os._exit(1) f = open(self._file) data = f.read() f.close() if data.startswith("#!"): newline_pos = data.find("\n") if newline_pos > 0: data = data[newline_pos:] rt.load_reader(StringReader(unicode_from_utf8(data))) except WrappedException as ex: print "Error: ", ex._ex.__repr__() os._exit(1)
def inner_invoke(self, args): import pixie.vm.rt as rt try: rt.compile_file(rt.wrap(self._filename)) except WrappedException as ex: print "Error: ", ex._ex.__repr__() os._exit(1)
def runtime_error(msg, data=None): import pixie.vm.rt as rt from pixie.vm.keyword import keyword if data is None: data = u"pixie.stdlib/AssertionException" raise WrappedException(RuntimeException(rt.wrap(msg), keyword(data)))
def _acquire_lock(self, ms): assert isinstance(self, Lock) return rt.wrap(self._ll_lock.acquire(ms.int_val()))
def _release_lock(self): assert isinstance(self, Lock) return rt.wrap(self._ll_lock.release())
def _count(self): assert isinstance(self, PersistentHashMap) return rt.wrap(intmask(self._cnt))
def _count(self): assert isinstance(self, TransientVector) return rt.wrap(intmask(self._cnt))
def denominator(r): affirm(isinstance(r, Ratio), u"First argument must be a Ratio") return rt.wrap(r.denominator())
def _doc(self): assert isinstance(self, code.NativeFn) return rt.wrap(self._doc)
def ratio_write(obj): assert isinstance(obj, Ratio) return rt.vector(rt.wrap(obj.numerator()), rt.wrap(obj.denominator()))
def _acquire_lock(self, no_wait): assert isinstance(self, Lock) return rt.wrap(self._ll_lock.acquire(no_wait == true))
def reduce_large(self, f, init): for x in range(self._cnt): if rt.reduced_QMARK_(init): return rt.deref(init) init = f.invoke([init, rt.wrap(ord(self._buffer[x]))]) return init
def alength(self): assert isinstance(self, Array) return rt.wrap(len(self._list))
def _repr(f): return rt.wrap(unicode(str(f.float_val())))
def _str(r): return rt.wrap( unicode(str(r.numerator()) + "/" + str(r.denominator())))
def _repr(b): return rt.wrap(unicode(b.bigint_val().format('0123456789', suffix='N')))
def _nth_not_found(self, idx, not_found): return rt.wrap(ord(self.nth_char(idx.int_val())))
def hash(self): import pixie.vm.rt as rt return rt.wrap(compute_identity_hash(self))
def _quot(a, b): assert isinstance(a, Ratio) and isinstance(b, Ratio) return rt.wrap( (a.numerator() * b.denominator()) / (a.denominator() * b.numerator()))
def _str(self): assert isinstance(self, RuntimeException) return rt.wrap(self.__repr__())
def _nth(self, idx): return rt.wrap(ord(self.nth_char(idx.int_val())))
def is_undefined(var): return rt.wrap(not var.is_defined())
def _str(self): return rt.wrap(self.to_string())
def buffer_capacity(buffer): return rt.wrap(intmask(buffer.capacity()))
def _repr(i): return rt.wrap(unicode(str(i.int_val())))
def get_mutable_cell_value(self): return rt.wrap(self._mutable_integer_val)
def _rem(a, b): assert isinstance(a, Ratio) and isinstance(b, Ratio) q = rt.wrap( (a.numerator() * b.denominator()) / (a.denominator() * b.numerator())) return rt._sub(a, rt._mul(q, b))
def _count(self): return rt.wrap(intmask(self.count()))
def ratio_read(obj): return Ratio( rt.nth(obj, rt.wrap(0)).int_val(), rt.nth(obj, rt.wrap(1)).int_val())
def get_mutable_cell_value(self): return rt.wrap(self._mutable_float_val)
def add_to_load_paths(path): rt.reset_BANG_(LOAD_PATHS.deref(), rt.conj(rt.deref(LOAD_PATHS.deref()), rt.wrap(path)))
def _div(a, b): assert isinstance(a, Ratio) and isinstance(b, Ratio) return rt._div(rt.wrap(b.denominator() * a.numerator()), rt.wrap(b.numerator() * a.denominator()))