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 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 load_file(filename): import pixie.vm.reader as reader import pixie.vm.compiler as compiler 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".lisp" 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 = filename._str affirm(path.isfile(str(filename_str)), u"File does not exist on path") f = open(str(filename_str)) data = f.read() f.close() rdr = reader.StringReader(unicode(data)) with compiler.with_ns(u"user"): while True: form = reader.read(rdr, False) if form is reader.eof: return nil result = compiler.compile(form).invoke([])
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 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 c_cast(frm, to): if not isinstance(to, CStructType): runtime_error(u"Expected a CStruct type to cast to, got " + rt.name(rt.str(to))) if not isinstance(frm, CStruct) and not isinstance(frm, VoidP): runtime_error(u"From must be a CVoidP or a CStruct, got " + rt.name(rt.str(frm))) return to.cast_to(frm)
def index_of4(a, sep, start, end): affirm(isinstance(start, Integer) and isinstance(end, Integer), u"Third and fourth argument must be integers") start = start.int_val() end = end.int_val() if start >= 0 and end >= 0: return rt.wrap(rt.name(a).find(rt.name(sep), start, end)) else: runtime_error(u"Third and fourth argument must be non-negative integers")
def fqd(self, itm): ns_alias = rt.namespace(itm) current_nms = rt.ns.deref() if ns_alias is None: return keyword(rt.name(itm), rt.name(current_nms)) else: ns_fqd = current_nms.resolve_ns(ns_alias) return keyword(rt.name(itm), rt.name(ns_fqd))
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 c_cast(frm, to): """(cast from to) Converts a VoidP to a CStruct. From is either a VoidP or a CStruct, to is a CStruct type.""" if not isinstance(to, CStructType): runtime_error(u"Expected a CStruct type to cast to, got " + rt.name(rt.str(to))) if not isinstance(frm, CStruct) and not isinstance(frm, VoidP): runtime_error(u"From must be a CVoidP or a CStruct, got " + rt.name(rt.str(frm))) return to.cast_to(frm)
def load_reader(rdr): import pixie.vm.reader as reader import pixie.vm.compiler as compiler import sys if not we_are_translated(): print "Loading file while interpreted, this may take time" val = PXIC_WRITER.deref() if val is nil: pxic_writer = None else: pxic_writer = val.get_pxic_writer() with compiler.with_ns(u"user"): compiler.NS_VAR.deref().include_stdlib() while True: if not we_are_translated(): sys.stdout.write(".") sys.stdout.flush() form = reader.read(rdr, False) if form is reader.eof: return nil try: compiled = compiler.compile(form) except WrappedException as ex: meta = rt.meta(form) if meta is not nil: ci = rt.interpreter_code_info(meta) add_info(ex, ci.__repr__()) add_info(ex, u"Compiling: " + rt.name(rt.str(form))) raise ex try: if pxic_writer is not None: pxic_writer.write_object(compiled) compiled.invoke([]) except WrappedException as ex: meta = rt.meta(form) if meta is not nil: ci = rt.interpreter_code_info(meta) add_info(ex, ci.__repr__()) add_info(ex, u"Running: " + rt.name(rt.str(form))) raise ex if not we_are_translated(): print "done" return nil
def __repr__(self): import pixie.vm.rt as rt s = [] trace = self._trace[:] trace.reverse() for x in trace: s.append(x.__repr__()) s.append(u"\n") s.extend([u"RuntimeException: " + rt.name(rt.str(self._data)) + u" " + rt.name(rt.str(self._msg)) + u"\n"]) return u"".join(s)
def ffi_set_value(self, ptr, val): if isinstance(val, CCallback): casted = rffi.cast(rffi.VOIDPP, ptr) casted[0] = val.get_raw_closure() elif val is nil: casted = rffi.cast(rffi.VOIDPP, ptr) casted[0] = rffi.cast(rffi.VOIDP, 0) else: frm_name = rt.name(rt.str(val.type())) to_name = rt.name(rt.str(self)) affirm(False, u"Cannot encode " + frm_name + u" as " + to_name) return None
def add_args(name, args, ctx): required_args = -1 local_idx = 0 ctx.add_local(name, Self()) for x in range(rt.count(args)): arg = rt.nth(args, rt.wrap(x)) affirm(isinstance(arg, symbol.Symbol), u"Argument names must be symbols") if rt.name(arg) == u"&": required_args = intmask(x) continue ctx.add_local(rt.name(arg), Arg(local_idx)) local_idx += 1 return required_args
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 set_field(self, name, val): idx = self._custom_type.get_slot_idx(name) if idx == -1: runtime_error( u"Invalid field named " + rt.name(rt.str(name)) + u" on type " + rt.name(rt.str(self.type())), u"pixie.stdlib/InvalidFieldException", ) old_val = self.get_field_by_idx(idx) if isinstance(old_val, AbstractMutableCell): old_val.set_mutable_cell_value(self._custom_type, self, name, idx, val) else: self._custom_type.set_mutable(name) self.set_field_by_idx(idx, val) return self
def load_file(filename): import pixie.vm.reader as reader import pixie.vm.compiler as compiler 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".lisp" 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 = open(str(full_path)) break if f is None: affirm(False, u"File does not exist in any directory found in load-paths") else: data = f.read() f.close() if data.startswith("#!"): newline_pos = data.find("\n") if newline_pos > 0: data = data[newline_pos:] rdr = reader.StringReader(unicode(data)) with compiler.with_ns(u"user"): while True: form = reader.read(rdr, False) if form is reader.eof: return nil result = compiler.compile(form).invoke([]) return nil
def compile_fn_body(name, args, body, ctx): new_ctx = Context(rt.name(name), rt.count(args), ctx) required_args = add_args(rt.name(name), args, new_ctx) bc = 0 if name is not None: affirm(isinstance(name, symbol.Symbol), u"Function names must be symbols") #new_ctx.add_local(name._str, Self()) arg_syms = EMPTY for x in range(rt.count(args)): sym = rt.nth(args, rt.wrap(x)) if not rt.name(sym) == u"&": arg_syms = rt.conj(rt.conj(arg_syms, sym), sym) body = rt.list(rt.cons(LOOP, rt.cons(arg_syms, body))) #new_ctx.push_recur_point(FunctionRecurPoint()) new_ctx.disable_tail_call() if body is nil: compile_form(body, new_ctx) else: while body is not nil: if rt.next(body) is nil: new_ctx.enable_tail_call() compile_form(rt.first(body), new_ctx) body = rt.next(body) if body is not nil: new_ctx.pop() new_ctx.bytecode.append(code.RETURN) closed_overs = new_ctx.closed_overs if len(closed_overs) == 0: ctx.push_const(new_ctx.to_code(required_args)) else: ctx.push_const(new_ctx.to_code(required_args)) for x in closed_overs: x.emit(ctx) ctx.bytecode.append(code.MAKE_CLOSURE) ctx.bytecode.append(r_uint(len(closed_overs))) ctx.sub_sp(len(closed_overs)) if required_args >= 0: ctx.bytecode.append(code.MAKE_VARIADIC) ctx.bytecode.append(r_uint(required_args)) return required_args, intmask(rt.count(args))
def invoke(self, rdr, ch): nms = u"" ch = rdr.read() if ch == u":": itm = read_inner(rdr, True) nms = rt.name(rt.ns.deref()) else: rdr.unread() itm = read_inner(rdr, True) affirm(isinstance(itm, Symbol), u"Can't keyword quote a non-symbol") if nms: affirm(rt.namespace(itm) is None, u"Kewyword cannot have two namespaces") return keyword(rt.name(itm), nms) else: return keyword(rt.name(itm), rt.namespace(itm))
def in_ns(ns_name): from pixie.vm.compiler import NS_VAR NS_VAR.set_value(code._ns_registry.find_or_make(rt.name(ns_name))) NS_VAR.deref().include_stdlib() return nil
def run_load_stdlib(): global stdlib_loaded if stdlib_loaded.is_true(): return import pixie.vm.compiler as compiler import pixie.vm.reader as reader f = open(rpath.rjoin(str(rt.name(load_path.deref())), "pixie/stdlib.pxi")) data = f.read() f.close() rdr = reader.MetaDataReader(reader.StringReader(unicode(data)), u"pixie/stdlib.pxi") result = nil if not we_are_translated(): print "Loading stdlib while interpreted, this will take some time..." with compiler.with_ns(u"pixie.stdlib"): while True: if not we_are_translated(): sys.stdout.write(".") sys.stdout.flush() form = reader.read(rdr, False) if form is reader.eof: break result = compiler.compile(form).invoke([]) if not we_are_translated(): print "done" stdlib_loaded.set_true()
def resolve(self, s, use_refers=True): import pixie.vm.symbol as symbol affirm(isinstance(s, symbol.Symbol), u"Must resolve symbols") ns = rt.namespace(s) name = rt.name(s) if ns is not None: refer = self._refers.get(ns, None) resolved_ns = None if refer is not None: resolved_ns = refer._namespace if resolved_ns is None: resolved_ns = _ns_registry.get(ns, None) if resolved_ns is None: affirm(False, u"Unable to resolve namespace: " + ns + u" inside namespace " + self._name) else: resolved_ns = self assert isinstance(resolved_ns, Namespace) var = resolved_ns._registry.get(name, None) if var is None and use_refers: for refer_nm in self._refers: refer = self._refers[refer_nm] if name in refer._refer_syms or refer._refer_all: var = refer._namespace.resolve(symbol.Symbol(name), False) if var is not None: return var return None return var
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 prep_string(s): """Takes a Pixie string and returns a VoidP to that string. The string should be freed via dispose!, otherwise memory leaks could result.""" affirm(isinstance(s, String), u"Can only prep strings with prep-string") utf8 = unicode_to_utf8(rt.name(s)) raw = rffi.str2charp(utf8) return VoidP(rffi.cast(rffi.VOIDP, raw))
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 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 compiler_special(s): if isinstance(s, symbol.Symbol): ns = rt.namespace(s) if ns is None or ns == u"pixie.stdlib": return builtins.get(rt.name(s), None) return None
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 ffi_callback(args, ret_type): """(ffi-callback args ret-type) Creates a ffi callback type. Args is a vector of CType args. Ret-type is the CType return type of the callback. Returns a ffi callback type that can be used with ffi-prep-callback.""" args_w = [None] * rt.count(args) for x in range(rt.count(args)): arg = rt.nth(args, rt.wrap(x)) if not isinstance(arg, object.Type): runtime_error(u"Expected type, got " + rt.name(rt.str(arg))) args_w[x] = arg if not isinstance(ret_type, object.Type): runtime_error(u"Expected type, got " + rt.name(rt.str(ret_type))) return CFunctionType(args_w, ret_type)
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 create_type(type_name, fields): affirm(isinstance(type_name, Keyword), u"Type name must be a keyword") field_count = rt.count(fields) acc = {} for i in range(rt.count(fields)): val = rt.nth(fields, rt.wrap(i)) affirm(isinstance(val, Keyword), u"Field names must be keywords") acc[val] = i return CustomType(rt.name(type_name), acc)
def refer(ns, refer, alias): from pixie.vm.symbol import Symbol from pixie.vm.string import String if isinstance(ns, Symbol) or isinstance(ns, String): ns = _ns_registry.find_or_make(rt.name(ns)) if isinstance(refer, Symbol) or isinstance(refer, String): refer = _ns_registry.find_or_make(rt.name(refer)) affirm(isinstance(ns, code.Namespace), u"First argument must be a namespace") if not isinstance(refer, code.Namespace): runtime_error(u"Second argument must be a namespace not a " + refer.type().name()) affirm(isinstance(alias, Symbol), u"Third argument must be a symbol") ns.add_refer(refer, rt.name(alias)) return nil
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 ffi_set_value(self, ptr, val): pnt = rffi.cast(rffi.VOIDPP, ptr) if isinstance(val, String): pnt = rffi.cast(rffi.CCHARPP, ptr) utf8 = unicode_to_utf8(rt.name(val)) raw = rffi.str2charp(utf8) pnt[0] = raw return CCharPToken(raw) elif isinstance(val, Buffer): pnt[0] = val.buffer() elif isinstance(val, VoidP): pnt[0] = val.raw_data() elif val is nil: pnt[0] = rffi.cast(rffi.VOIDP, 0) elif isinstance(val, CStruct): pnt[0] = rffi.cast(rffi.VOIDP, val.raw_data()) else: frm_name = rt.name(rt.str(val.type())) to_name = rt.name(rt.str(self)) affirm(False, u"Cannot encode " + frm_name + u" as " + to_name)
def _ici(meta): import pixie.vm.reader as reader line = rt._val_at(meta, reader.LINE_KW, nil) line_number = rt._val_at(meta, reader.LINE_NUMBER_KW, nil) col_number = rt._val_at(meta, reader.COLUMN_NUMBER_KW, nil) file = rt._val_at(meta, reader.FILE_KW, nil) return InterpreterCodeInfo( line, line_number.int_val() if line_number is not nil else 0, col_number.int_val() if col_number is not nil else 0, rt.name(file) if file is not nil else u"<unknown>")
def substring3(a, start, end): affirm(isinstance(a, String), u"First argument must be a string") affirm( isinstance(start, Integer) and isinstance(end, Integer), u"Second and third argument must be integers") start = start.int_val() end = end.int_val() if start >= 0 and end >= 0: return rt.wrap(rt.name(a)[start:end]) else: runtime_error( u"Second and third argument must be non-negative integers")
def compile_ns(form, ctx): affirm(rt.count(form) == 2, u"ns only takes one argument, a symbol") nm = rt.first(rt.next(form)) affirm(isinstance(nm, symbol.Symbol), u"Namespace name must be a symbol") str_name = rt.name(nm) NS_VAR.set_value(code._ns_registry.find_or_make(str_name)) NS_VAR.deref().include_stdlib() ctx.push_const(nil)
def read(self): if self._string_reader is None: result = _readline(str(rt.name(rt.ns.deref())) + " => ") if result == u"": raise EOFError() self._string_reader = StringReader(result) try: return self._string_reader.read() except EOFError: self._string_reader = None return self.read()
def compile_var(form, ctx): form = rt.next(form) name = rt.first(form) affirm(isinstance(name, symbol.Symbol), u"var name must be a symbol") if rt.namespace(name) is not None: var = code._ns_registry.find_or_make(rt.namespace(name)) else: var = NS_VAR.deref().intern_or_make(rt.name(name)) ctx.push_const(var)
def __repr__(self): import pixie.vm.rt as rt s = [] trace = self._trace[:] trace.reverse() for x in trace: s.append(x.__repr__()) s.append(u"\n") s.extend([u"RuntimeException: " + rt.name(rt.str(self._data)) + u"\n"]) return u"".join(s)
def is_macro_call(form, ctx): if rt.seq_QMARK_(form) is true and isinstance(rt.first(form), symbol.Symbol): name = rt.name(rt.first(form)) if resolve_local(ctx, name): return None var = resolve_var(rt.first(form)) if var and var.is_defined(): val = var.deref() if isinstance(val, code.BaseCode) and val.is_macro(): return val return None
def read(self): if self._string_reader is None: result = rt.name(self._reader_fn.invoke([])) code._dynamic_vars.set_var_value(READING_FORM_VAR, rt.wrap(READING_FORM_VAR.deref().int_val() + 1)) if result == u"": raise EOFError() self._string_reader = StringReader(result) try: return self._string_reader.read() except EOFError: self._string_reader = None return self.read()
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) tp = CFunctionType(new_args, ret_type, is_variadic) nm = rt.name(nm) f = FFIFn(nm, lib.get_fn_ptr(nm), tp) return f
def set_field(self, name, val): idx = self._custom_type.get_slot_idx(name) if idx == -1: runtime_error(u"Invalid field named " + rt.name(rt.str(name)) + u" on type " + rt.name(rt.str(self.type())), u"pixie.stdlib/InvalidFieldException") old_val = self.get_field_by_idx(idx) if isinstance(old_val, AbstractMutableCell): old_val.set_mutable_cell_value(self._custom_type, self, name, idx, val) else: self._custom_type.set_mutable(name) self.set_field_by_idx(idx, val) return self
def c_struct(name, size, spec): """(c-struct name size spec) Creates a CStruct named name, of size size, with the given spec. Spec is a vector of vectors. Each row of the format [field-name type offset]""" 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()) tp = CStructType(rt.name(name), size.int_val(), d) proto._dispose_BANG_.extend(tp, _dispose_cstruct) return tp
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): return runtime_error(u"Unquote splicing not used inside list") elif rt.vector_QMARK_(form) is true: ret = rt.list(APPLY, CONCAT, SyntaxQuoteReader.expand_list(form)) elif form is not nil and 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 maybe_oop_invoke(form): head = rt.first(form) if isinstance(rt.first(form), symbol.Symbol) and rt.name(head).startswith(".-"): postfix = rt.next(form) affirm( rt.count(postfix) == 1, u" Attribute lookups must only have one argument") subject = rt.first(postfix) kw = keyword(rt.name(head)[2:]) fn = symbol.symbol(u"pixie.stdlib/-get-attr") return create_from_list([fn, subject, kw]) elif isinstance(rt.first(form), symbol.Symbol) and rt.name(head).startswith("."): subject = rt.first(rt.next(form)) postfix = rt.next(rt.next(form)) form = cons(keyword(rt.name(head)[1:]), postfix) form = cons(subject, form) form = cons(symbol.symbol(u"pixie.stdlib/-call-method"), form) return form else: return form
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 get_field(self, name): idx = self._custom_type.get_slot_idx(name) if idx == -1: runtime_error(u"Invalid field named " + rt.name(rt.str(name)) + u" on type " + rt.name(rt.str(self.type())), u"pixie.stdlib/InvalidFieldException") if self._custom_type.is_mutable(name): value = self.get_field_by_idx(idx) else: value = self.get_field_immutable(idx) if isinstance(value, AbstractMutableCell): return value.get_mutable_cell_value() else: return value
def _ffi_fn(lib, nm, args, ret_type): 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(args) new_args = [None] * cnt for x in range(cnt): t = rt.nth(args, rt.wrap(x)) affirm(isinstance(t, object.Type), u"Arg defs must be types") new_args[x] = t f = FFIFn(lib, rt.name(nm), new_args, ret_type) return f
def _load_file(filename, compile=False): from pixie.vm.string import String from pixie.vm.util import unicode_from_utf8 import pixie.vm.reader as reader import pixie.vm.libs.pxic.writer as pxic_writer affirm(isinstance(filename, String), u"filename must be a string") filename = str(rt.name(filename)) if filename.endswith(".pxic"): load_pxic_file(filename) return nil if path.isfile(filename + "c") and not compile: load_pxic_file(filename + "c") return nil affirm(path.isfile(filename), unicode(filename) + u" does not exist") f = open(filename) data = f.read() f.close() if data.startswith("#!"): newline_pos = data.find("\n") if newline_pos > 0: data = data[newline_pos:] if compile: pxic_f = open(filename + "c", "wb") wtr = pxic_writer.Writer(pxic_f, True) with code.bindings(PXIC_WRITER, pxic_writer.WriterBox(wtr)): rt.load_reader( reader.MetaDataReader( reader.StringReader(unicode_from_utf8(data)), unicode(filename))) wtr.finish() pxic_f.close() else: with code.bindings(PXIC_WRITER, nil): rt.load_reader( reader.MetaDataReader( reader.StringReader(unicode_from_utf8(data)), unicode(filename))) return nil
def compile_def(form, ctx): form = rt.next(form) name = rt.first(form) form = rt.next(form) val = rt.first(form) affirm(isinstance(name, symbol.Symbol), u"Def'd name must be a symbol") var = NS_VAR.deref().intern_or_make(rt.name(name)) if rt._val_at(rt.meta(name), DYNAMIC_KW, nil) is true: assert isinstance(var, code.Var) var.set_dynamic() ctx.push_const(var) compile_form(val, ctx) ctx.bytecode.append(code.SET_VAR) ctx.sub_sp(1)
def compile_local_macro(form, ctx): form = rt.next(form) binding = rt.first(form) body = rt.next(form) sym = rt.nth(binding, rt.wrap(0)) bind_form = rt.nth(binding, rt.wrap(1)) ctx.add_local(rt.name(sym), LocalMacro(bind_form)) while True: compile_form(rt.first(body), ctx) body = rt.next(body) if body is nil: break else: ctx.pop() ctx.pop_locals()
def compile_loop(form, ctx): form = rt.next(form) bindings = rt.first(form) affirm(isinstance(bindings, PersistentVector), u"Loop bindings must be a vector") body = rt.next(form) ctx.enable_tail_call() ctc = ctx.can_tail_call ctx.disable_tail_call() binding_count = 0 for i in range(0, rt.count(bindings), 2): binding_count += 1 name = rt.nth(bindings, rt.wrap(i)) affirm(isinstance(name, symbol.Symbol), u"Loop bindings must be symbols") bind = rt.nth(bindings, rt.wrap(i + 1)) compile_form(bind, ctx) ctx.add_local(rt.name(name), LetBinding(ctx.sp())) if ctc: ctx.enable_tail_call() ctx.push_recur_point(LoopRecurPoint(binding_count, ctx)) while True: compile_form(rt.first(body), ctx) body = rt.next(body) if body is nil: break else: ctx.pop() ctx.pop_recur_point() ctx.bytecode.append(code.POP_UP_N) ctx.sub_sp(binding_count) ctx.bytecode.append(binding_count) ctx.pop_locals(binding_count)
def ffi_set_value(self, ptr, val): if isinstance(val, String): pnt = rffi.cast(rffi.CCHARPP, ptr) utf8 = unicode_to_utf8(rt.name(val)) raw = rffi.str2charp(utf8) pnt[0] = raw return CCharPToken(raw) elif isinstance(val, Buffer): vpnt = rffi.cast(rffi.VOIDPP, ptr) vpnt[0] = val.buffer() elif isinstance(val, VoidP): vpnt = rffi.cast(rffi.VOIDPP, ptr) vpnt[0] = val.raw_data() elif val is nil: vpnt = rffi.cast(rffi.VOIDPP, ptr) vpnt[0] = rffi.cast(rffi.VOIDP, 0) elif isinstance(val, CStruct): vpnt = rffi.cast(rffi.VOIDPP, ptr) vpnt[0] = rffi.cast(rffi.VOIDP, val.raw_data()) else: print val affirm(False, u"Cannot encode this type")
def resolve(self, s, use_refers=True): import pixie.vm.symbol as symbol affirm(isinstance(s, symbol.Symbol), u"Must resolve symbols") ns = rt.namespace(s) name = rt.name(s) if ns is not None: resolved_ns = self.resolve_ns(ns) else: resolved_ns = self assert isinstance(resolved_ns, Namespace) var = resolved_ns._registry.get(name, None) if var is None and use_refers: for refer_nm in self._refers: refer = self._refers[refer_nm] if name in refer._refer_syms or refer._refer_all: var = refer._namespace.resolve(symbol.Symbol(name), False) if var is not None: return var return None return var
def load_file(filename): from pixie.vm.string import String from pixie.vm.util import unicode_from_utf8 import pixie.vm.reader as reader import os.path as path affirm(isinstance(filename, String), u"filename must be a string") filename = str(rt.name(filename)) affirm(path.isfile(filename), unicode(filename) + u" does not exist") f = open(filename) data = f.read() f.close() if data.startswith("#!"): newline_pos = data.find("\n") if newline_pos > 0: data = data[newline_pos:] rt.load_reader( reader.MetaDataReader(reader.StringReader(unicode_from_utf8(data)), unicode(filename))) return nil
def compile_in_ns(form, ctx): affirm(rt.count(form) == 2, u"in-ns requires an argument") arg = rt.first(rt.next(form)) NS_VAR.set_value(code._ns_registry.find_or_make(rt.name(arg))) NS_VAR.deref().include_stdlib() compile_fn_call(form, ctx)
def _ffi_library(ns): nm = rt.name(ns) return ExternalLib(nm)
def _ffi_voidp(lib, nm): affirm(isinstance(lib, ExternalLib), u"First argument to ffi-voidp should be an external library") name = rt.name(nm) return VoidP(lib.get_fn_ptr(name))