def generate_server_es_defs(self, pkg_symbol_table, es, qname): """ Write the package-wide definitions (enums, structs). """ pkg_chpl = ChapelFile(qname) pkg_h = CFile(qname) pkg_h.genh(ir.Import('sidlType')) for es in self.pkg_enums_and_structs: es_ior = babel.lower_ir(pkg_symbol_table, es, header=pkg_h, qualify_names=True) es_chpl = es_ior if es[0] == sidlir.struct: es_ior = conv.ir_type_to_chpl(es_ior) es_chpl = conv.ir_type_to_chpl(es) pkg_h.gen(ir.Type_decl(es_ior)) pkg_chpl.gen(ir.Type_decl(es_chpl)) pkg_h.write() pkg_chpl.write()
def end_impl(self, qname): """ Chapel Impl (server-side Chapel implementation template) Finish generating the module_Impl.chpl file in Chapel. """ # write the Chapel skeleton to disk self.pkg_chpl_skel.write() # deal with the impl file if self.pkg_enums_and_structs: self.pkg_impl._header.append(chpl_gen(ir.Import(qname))) impl = qname + '_Impl.chpl' # Preserve code written by the user if os.path.isfile(impl): # FIXME: this is a possible race condition, we should # use a single file handle instead splicers = splicer.record(impl) lines = str(self.pkg_impl).split('\n') write_to(impl, splicer.apply_all(impl, lines, splicers)) else: write_to(impl, str(self.pkg_impl))
def lower_ir(symbol_table, sidl_term, header=None, struct_suffix='__data', enum_suffix='__enum', lower_scoped_ids=True, qualify_names=True, qualify_enums=True, raw_ior_arrays=False, wrap_rarrays=False): """ FIXME!! can we merge this with convert_arg?? lower SIDL types into IR The idea is that no Chapel-specific code is in this function. It should provide a generic translation from SIDL -> IR. @param lower_scoped_ids This is a broken design, but right now the Chapel code generator accepts some sidl node types such as array, rarray, and class. If False, then these types will not be lowered. @param qualify_names If \c True, enum values will get prefixed with the full qualified name of the enum. """ def low(sidl_term): return lower_ir(symbol_table, sidl_term, header, struct_suffix, enum_suffix, lower_scoped_ids, qualify_names, qualify_enums, raw_ior_arrays, wrap_rarrays) # print 'low(',sidl_term, ')' array_prefix = '/* IOR */ ' if raw_ior_arrays else '' with match(sidl_term): if (sidlir.arg, Attrs, Mode, (sidlir.scoped_id, _, _, _), Name): lowtype = low(sidl_term[3]) if lowtype[0] == ir.struct and Mode == ir.in_: # struct arguments are passed as pointer, regardless of mode # unless they are a return value lowtype = ir.Pointer_type(lowtype) return (ir.arg, Attrs, Mode, lowtype, Name) elif (sidlir.arg, Attrs, Mode, Typ, Name): return (ir.arg, Attrs, Mode, low(Typ), Name) elif (sidlir.scoped_id, Prefix, Name, Ext): return low(symbol_table[sidl_term][1]) elif (sidlir.void): return ir.pt_void elif (ir.void_ptr): return ir.void_ptr elif (sidlir.primitive_type, sidlir.opaque): return ir.Pointer_type(ir.pt_void) elif (sidlir.primitive_type, sidlir.string): return sidl_term #ir.const_str elif (sidlir.primitive_type, Type): return ir.Primitive_type(Type) elif (sidlir.enum, Name, Enumerators, DocComment): # in the IOR enums are represented as int64 if qualify_enums: es = lower_ir( SymbolTable(symbol_table, symbol_table.prefix + [Name]), Enumerators, header, struct_suffix, enum_suffix, lower_scoped_ids, qualify_names, qualify_enums, raw_ior_arrays, wrap_rarrays) return ir.Enum( qual_name(symbol_table, sidl_term[1]) + enum_suffix, es, DocComment) else: return ir.Enum(sidl_term[1], low(Enumerators), DocComment) elif (sidlir.enumerator, Name): if qualify_enums: return ir.Enumerator(qual_name(symbol_table, Name)) else: return sidl_term elif (sidlir.enumerator_value, Name, Val): if qualify_enums: return ir.Enumerator_value(qual_name(symbol_table, Name), Val) else: return sidl_term elif (sidlir.struct, (sidlir.scoped_id, Prefix, Name, Ext), Items, DocComment): # a nested Struct return ir.Struct( qual_id(sidl_term[1]) + struct_suffix, low(Items), '') elif (sidlir.struct, Name, Items, DocComment): return ir.Struct( qual_name(symbol_table, Name) + struct_suffix, low(Items), '') elif (sidlir.struct_item, Type, Name): if Type[0] == sidlir.scoped_id: t = symbol_table[Type][1] if t[0] == sidlir.class_ or t[0] == sidlir.interface: if header: header.genh(ir.Import(qual_id(t[1]) + '_IOR')) t = ir_object_type(t[1][1], t[1][2]) elif t[0] == sidlir.struct or t[0] == sidlir.enum: return (ir.struct_item, low(t), Name) return (ir.struct_item, t, Name) return (ir.struct_item, low(Type), Name) # elif (sidlir.rarray, Scalar_type, Dimension, Extents): # # Future optimization: # # Direct-call version (r-array IOR) # # return ir.Pointer_type(lower_type_ir(symbol_table, Scalar_type)) # FIXME # # SIDL IOR version # return ir.Typedef_type('sidl_%s__array'%Scalar_type[1]) elif (sidlir.rarray, Scalar_type, Dimension, Extents): if wrap_rarrays: return ir.Pointer_type( ir.Struct( '%ssidl_%s__array' % (array_prefix, Scalar_type[1]), [], '')) else: return ir.Rarray(low(Scalar_type), Dimension, Extents) elif (sidlir.array, [], [], []): #if not lower_scoped_ids: return sidl_term #return ir.Pointer_type(ir.pt_void) return ir.Pointer_type(ir.Struct('sidl__array', [], '')) elif (sidlir.array, Scalar_type, Dimension, Orientation): #if not lower_scoped_ids: return sidl_term if Scalar_type[0] == ir.scoped_id: # All object arrays are called sidl_interface__array t = 'interface' if header: header.genh(ir.Import('sidl_BaseInterface_IOR')) else: t = Scalar_type[1] if header: header.genh(ir.Import('sidl_' + t + '_IOR')) return ir.Pointer_type( ir.Struct('%ssidl_%s__array' % (array_prefix, t), [], '')) elif (sidlir.class_, ScopedId, _, _, _, _, _): if not lower_scoped_ids: return ScopedId else: return ir_object_type(ScopedId[1], ScopedId[2]) elif (sidlir.interface, ScopedId, _, _, _, _): if not lower_scoped_ids: return ScopedId return ir_object_type(ScopedId[1], ScopedId[2]) elif (Terms): if (isinstance(Terms, list)): return map(low, Terms) else: raise Exception("lower_ir: Not implemented: " + str(sidl_term)) else: raise Exception("match error")
def generate_ext_stub(cls): """ shared code for class/interface """ # Qualified name (C Version) qname = '_'.join(symbol_table.prefix + [cls.name]) self.exts.append(qname) if self.config.verbose: import sys mod_name = '.'.join(symbol_table.prefix[1:] + [cls.name]) sys.stdout.write('\r' + ' ' * 80) sys.stdout.write('\rgenerating glue code for %s' % mod_name) sys.stdout.flush() # Consolidate all methods, defined and inherited cls.scan_methods() # chpl_defs = ChapelScope(chpl_stub) ci = self.ClassInfo(cls) # if self.server: # ci.impl = self.pkg_impl ci.stub.new_def(babel.externals(cls.get_scoped_id())) ci.stub.new_def(babel.builtin_stub_functions(cls.get_scoped_id())) has_contracts = ior_template.generateContractChecks(cls) self.gen_default_methods(cls, has_contracts, ci) #print qname, map(lambda x: x[2][1]+x[2][2], cls.all_methods) for method in cls.all_methods: (Method, Type, Name, Attrs, Args, Except, From, Requires, Ensures, DocComment) = method ci.epv.add_method((method, Type, Name, Attrs, babel.drop_rarray_ext_args(Args), Except, From, Requires, Ensures, DocComment)) # all the methods for which we would generate a server impl impl_methods = babel.builtins + cls.get_methods() impl_methods_names = [ sidlir.method_method_name(m) for m in impl_methods ] # client for method in cls.all_methods: has_impl = sidlir.method_method_name( method) in impl_methods_names self.generate_client_method(symbol_table, method, ci, has_impl) if self.server: class_methods = filter(sidlir.is_not_static, impl_methods) static_methods = filter(sidlir.is_static, impl_methods) # # Class # ci.impl.new_def(gen_doc_comment(cls.doc_comment, chpl_stub)+ # 'class %s_Impl {'%qname) # splicer = '.'.join(cls.qualified_name+['Impl']) # ci.impl.new_def('// DO-NOT-DELETE splicer.begin(%s)'%splicer) # ci.impl.new_def('// DO-NOT-DELETE splicer.end(%s)'%splicer) # for method in class_methods: # self.generate_server_method(symbol_table, method, ci) # ci.impl.new_def('} // class %s_Impl'%qname) # ci.impl.new_def('') # ci.impl.new_def('') # # Static # if static_methods: # ci.impl.new_def('// all static member functions of '+qname) # ci.impl.new_def(gen_doc_comment(cls.doc_comment, chpl_stub)+ # '// FIXME: chpl allows only one module per library //'+ # ' module %s_static_Impl {'%qname) # for method in static_methods: # self.generate_server_method(symbol_table, method, ci) # ci.impl.new_def('//} // module %s_static_Impl'%qname) # ci.impl.new_def('') # ci.impl.new_def('') # # Chapel Stub (client-side Chapel bindings) # self.generate_chpl_stub(chpl_stub, qname, ci) # # Because of Chapel's implicit (filename-based) modules it # # is important for the Chapel stub to be one file, but we # # generate separate files for the cstubs # self.pkg_chpl_stub.new_def(chpl_stub) # Stub (in C), the order of these definitions is somewhat sensitive ci.stub.genh_top(ir.Import(qname + '_IOR')) ci.stub.gen(ir.Import(ci.stub._name)) pkg_name = '_'.join(symbol_table.prefix) ci.stub.gen(ir.Import(pkg_name)) ci.stub.write() # IOR ior_template.generate_ior(ci, with_ior_c=self.server, _braid_config=self.config) ci.ior.write() # Skeleton if self.server: self.generate_skeleton(ci, qname) # Convenience header ext_h = CFile(qname) ext_h.genh(ir.Import(qname + '_IOR')) ext_h.genh(ir.Import(qname + '_Stub')) ext_h.write() # Makefile self.classes.append(qname)
def generate_glue_code(self, node, data, symbol_table): """ Generate glue code for \c node . """ def gen(node): return self.generate_glue_code(node, data, symbol_table) def generate_ext_stub(cls): """ shared code for class/interface """ # Qualified name (C Version) qname = '_'.join(symbol_table.prefix + [cls.name]) self.exts.append(qname) if self.config.verbose: import sys mod_name = '.'.join(symbol_table.prefix[1:] + [cls.name]) sys.stdout.write('\r' + ' ' * 80) sys.stdout.write('\rgenerating glue code for %s' % mod_name) sys.stdout.flush() # Consolidate all methods, defined and inherited cls.scan_methods() # chpl_defs = ChapelScope(chpl_stub) ci = self.ClassInfo(cls) # if self.server: # ci.impl = self.pkg_impl ci.stub.new_def(babel.externals(cls.get_scoped_id())) ci.stub.new_def(babel.builtin_stub_functions(cls.get_scoped_id())) has_contracts = ior_template.generateContractChecks(cls) self.gen_default_methods(cls, has_contracts, ci) #print qname, map(lambda x: x[2][1]+x[2][2], cls.all_methods) for method in cls.all_methods: (Method, Type, Name, Attrs, Args, Except, From, Requires, Ensures, DocComment) = method ci.epv.add_method((method, Type, Name, Attrs, babel.drop_rarray_ext_args(Args), Except, From, Requires, Ensures, DocComment)) # all the methods for which we would generate a server impl impl_methods = babel.builtins + cls.get_methods() impl_methods_names = [ sidlir.method_method_name(m) for m in impl_methods ] # client for method in cls.all_methods: has_impl = sidlir.method_method_name( method) in impl_methods_names self.generate_client_method(symbol_table, method, ci, has_impl) if self.server: class_methods = filter(sidlir.is_not_static, impl_methods) static_methods = filter(sidlir.is_static, impl_methods) # # Class # ci.impl.new_def(gen_doc_comment(cls.doc_comment, chpl_stub)+ # 'class %s_Impl {'%qname) # splicer = '.'.join(cls.qualified_name+['Impl']) # ci.impl.new_def('// DO-NOT-DELETE splicer.begin(%s)'%splicer) # ci.impl.new_def('// DO-NOT-DELETE splicer.end(%s)'%splicer) # for method in class_methods: # self.generate_server_method(symbol_table, method, ci) # ci.impl.new_def('} // class %s_Impl'%qname) # ci.impl.new_def('') # ci.impl.new_def('') # # Static # if static_methods: # ci.impl.new_def('// all static member functions of '+qname) # ci.impl.new_def(gen_doc_comment(cls.doc_comment, chpl_stub)+ # '// FIXME: chpl allows only one module per library //'+ # ' module %s_static_Impl {'%qname) # for method in static_methods: # self.generate_server_method(symbol_table, method, ci) # ci.impl.new_def('//} // module %s_static_Impl'%qname) # ci.impl.new_def('') # ci.impl.new_def('') # # Chapel Stub (client-side Chapel bindings) # self.generate_chpl_stub(chpl_stub, qname, ci) # # Because of Chapel's implicit (filename-based) modules it # # is important for the Chapel stub to be one file, but we # # generate separate files for the cstubs # self.pkg_chpl_stub.new_def(chpl_stub) # Stub (in C), the order of these definitions is somewhat sensitive ci.stub.genh_top(ir.Import(qname + '_IOR')) ci.stub.gen(ir.Import(ci.stub._name)) pkg_name = '_'.join(symbol_table.prefix) ci.stub.gen(ir.Import(pkg_name)) ci.stub.write() # IOR ior_template.generate_ior(ci, with_ior_c=self.server, _braid_config=self.config) ci.ior.write() # Skeleton if self.server: self.generate_skeleton(ci, qname) # Convenience header ext_h = CFile(qname) ext_h.genh(ir.Import(qname + '_IOR')) ext_h.genh(ir.Import(qname + '_Stub')) ext_h.write() # Makefile self.classes.append(qname) if not symbol_table: raise Exception() with match(node): if (sidlir.class_, (Name), Extends, Implements, Invariants, Methods, DocComment): expect(data, None) generate_ext_stub( sidlobjects.Class(symbol_table, node, self.class_attrs)) elif (sidlir.struct, (Name), Items, DocComment): # Generate Chapel stub # self.pkg_chpl_stub.gen(ir.Type_decl(lower_ir(symbol_table, node, struct_suffix=''))) # record it for later, when the package is being finished self.pkg_enums_and_structs.append(struct_ior_names(node)) elif (sidlir.interface, (Name), Extends, Invariants, Methods, DocComment): # Interfaces also have an IOR to be generated expect(data, None) generate_ext_stub( sidlobjects.Interface(symbol_table, node, self.class_attrs)) elif (sidlir.enum, Name, Items, DocComment): # Generate Chapel stub # self.pkg_chpl_stub.gen(ir.Type_decl(node)) # record it for later, when the package is being finished self.pkg_enums_and_structs.append(node) elif (sidlir.package, Name, Version, UserTypes, DocComment): # Generate the chapel stub qname = '_'.join(symbol_table.prefix + [Name]) _, pkg_symbol_table = symbol_table[sidlir.Scoped_id([], Name, '')] if self.in_package: # nested modules are generated in-line # self.pkg_chpl_stub.new_def('module %s {'%Name) self.generate_glue_code(UserTypes, data, pkg_symbol_table) # self.pkg_chpl_stub.new_def('}') else: # server-side Chapel implementation template if self.server: self.begin_impl(qname) # new file for the toplevel package # self.pkg_chpl_stub = ChapelFile(relative_indent=0) self.pkg_enums_and_structs = [] self.in_package = True # recursion! self.generate_glue_code(UserTypes, data, pkg_symbol_table) # write_to(qname+'.chpl', str(self.pkg_chpl_stub)) # server-side Chapel implementation template if self.server: self.end_impl(qname) # Makefile self.pkgs.append(qname) pkg_h = CFile(qname) pkg_h = pkg_h pkg_h.genh(ir.Import('sidl_header')) for es in self.pkg_enums_and_structs: es_ior = babel.lower_ir(pkg_symbol_table, es, header=pkg_h, qualify_names=True) pkg_h.gen(ir.Type_decl(es_ior)) for ext in self.exts: pkg_h.genh(ir.Import(ext)) pkg_h.write() elif (sidlir.user_type, Attrs, Cipse): self.class_attrs = Attrs gen(Cipse) elif (sidlir.file, Requires, Imports, UserTypes): self.in_package = False gen(UserTypes) elif A: if (isinstance(A, list)): for defn in A: gen(defn) else: raise Exception("NOT HANDLED:" + repr(A)) else: raise Exception("match error") return data
def generate_skeleton(self, ci, qname): """ Chapel Skeleton (client-side Chapel bindings) Generate a Skeleton in Chapel. """ symbol_table = ci.epv.symbol_table cls = ci.co # Skeleton (in Chapel) self.pkg_chpl_skel.gen(ir.Import('.'.join(symbol_table.prefix))) self.pkg_chpl_skel.new_def('use sidl;') objname = '.'.join(ci.epv.symbol_table.prefix + [ci.epv.name]) + '_Impl' self.pkg_chpl_skel.new_def( 'extern record %s__object { var d_data: opaque; };' % qname) #,objname)) self.pkg_chpl_skel.new_def('extern proc %s__createObject(' % qname + 'd_data: int, ' + 'out ex: sidl_BaseInterface__object)' + ': %s__object;' % qname) self.pkg_chpl_skel.new_def(ci.chpl_skel) # Skeleton (in C) cskel = ci.chpl_skel.cstub cskel._name = qname + '_Skel' cskel.gen(ir.Import('stdint')) cskel.gen(ir.Import('stdio')) cskel.gen(ir.Import(cskel._name)) cskel.gen(ir.Import(qname + '_IOR')) cskel.gen( ir.Fn_defn([], ir.pt_void, qname + '__call_load', [], [ir.Comment("FIXME: [ir.Stmt(ir.Call('_load', []))")], '')) # set_epv ... Setup the entry-point vectors (EPV)s # # there are 2*3 types of EPVs: # epv: regular methods # sepv: static methods # pre_(s)epv: pre-hooks # post_(s)epv: post-hooks epv_t = ci.epv.get_ir() sepv_t = ci.epv.get_sepv_ir() pre_epv_t = ci.epv.get_pre_epv_ir() pre_sepv_t = ci.epv.get_pre_sepv_ir() post_epv_t = ci.epv.get_post_epv_ir() post_sepv_t = ci.epv.get_post_sepv_ir() cskel.gen(ir.Fn_decl([], ir.pt_void, 'ctor', [], '')) cskel.gen(ir.Fn_decl([], ir.pt_void, 'dtor', [], '')) epv_init = [] sepv_init = [] for m in builtins + cls.get_methods(): fname = m[2][1] + m[2][2] attrs = sidlir.method_method_attrs(m) static = member_chk(sidlir.static, attrs) def entry(stmts, epv_t, table, field, pointer): stmts.append( ir.Set_struct_item_stmt(epv_t, ir.Deref(table), field, pointer)) if static: entry(sepv_init, sepv_t, 'sepv', 'f_' + fname, '%s_%s_skel' % (qname, fname)) else: entry(epv_init, epv_t, 'epv', 'f_' + fname, '%s_%s_skel' % (qname, fname)) builtin_names = ['_ctor', '_ctor2', '_dtor'] with_hooks = member_chk(ir.hooks, attrs) if fname not in builtin_names and with_hooks: if static: entry(sepv_init, pre_sepv_t, 'pre_sepv', 'f_%s_pre' % fname, 'NULL') else: entry(epv_init, pre_epv_t, 'pre_epv', 'f_%s_pre' % fname, 'NULL') if static: entry(sepv_init, post_sepv_t, 'post_sepv', 'f_%s_post' % fname, 'NULL') else: entry(epv_init, post_epv_t, 'post_epv', 'f_%s_post' % fname, 'NULL') pkgname = '_'.join(ci.epv.symbol_table.prefix) dummyargv = ''' char* argv[] = { babel_program_name, "-nl", /* number of locales */ "", "-v", /* verbose chapel runtime */ NULL }; argv[2] = getenv("SLURM_NTASKS"); if (argv[2] == NULL) { fprintf(stdout, "**ERROR: please set the SLURM_NTASKS environment variable\\n" " to the desired number of Chapel locales."); argv[2] = "0"; } int ignored = setenv("GASNET_BACKTRACE", "1", 1); ''' cskel.genh(ir.Import('stdlib')) cskel.pre_def('extern int chpl_init_library(int argc, char* argv[]);') cskel.pre_def( '// You can set this to argv[0] in main() to get better debugging output' ) cskel.pre_def( 'char* __attribute__((weak)) babel_program_name = "BRAID_LIBRARY";' ) # These are now called by chpl_init_library -> chpl_gen_init #cskel.pre_def('extern void chpl__init_chpl__Program(int, const char*);') #cskel.pre_def('extern void chpl__init_%s_Impl(int, const char*);'%pkgname) init_code = [ dummyargv, 'int locale_id = chpl_init_library(4, argv)', # 'chpl__init_chpl__Program(__LINE__, __FILE__)', # 'chpl__init_%s_Impl(__LINE__, __FILE__)'%pkgname ] init_code = map(lambda x: (ir.stmt, x), init_code) epv_init.extend(init_code) sepv_init.extend(init_code) cskel.gen( ir.Fn_defn([], ir.pt_void, qname + '__set_epv', [ ir.Arg([], ir.out, epv_t, 'epv'), ir.Arg([], ir.out, pre_epv_t, 'pre_epv'), ir.Arg([], ir.out, post_epv_t, 'post_epv') ], epv_init, '')) if sepv_t: cskel.gen( ir.Fn_defn([], ir.pt_void, qname + '__set_sepv', [ ir.Arg([], ir.out, sepv_t, 'sepv'), ir.Arg([], ir.out, pre_sepv_t, 'pre_sepv'), ir.Arg([], ir.out, post_sepv_t, 'post_sepv') ], sepv_init, '')) # C Skel for code in cskel.optional: cskel.new_global_def(code) cskel.write()