def _find_module_file(module_dir_list, module_name): #按目录查找 for module_dir in module_dir_list: module_file_path_name = os.path.join(module_dir, module_name) + ".lar" if os.path.exists(module_file_path_name): return module_file_path_name larc_common.exit("找不到模块:%s" % module_name)
def _output_util(): #拷贝runtime中固定的util代码 util_fix_file_path_name = runtime_dir + "/lar_util.go" if not os.path.exists(util_fix_file_path_name): larc_common.exit("runtime文件缺失,请检查编译器环境:[%s]" % util_fix_file_path_name) f = open("%s/%s.util_fix.go" % (_out_prog_dir, _prog_module_name), "w") print >> f, "package %s" % _prog_module_name print >> f f.write(larc_common.open_src_file(util_fix_file_path_name).read()) f.close() #生成util代码 with _Code("%s/%s.util.go" % (_out_prog_dir, _prog_module_name)) as code: #生成数组相关代码 for tp in larc_type.array_type_set: assert tp.is_array arr_type = larc_type.gen_arr_type(tp) dim_count = tp.array_dim_count while tp.is_array: tp = tp.to_elem_type() tp_name = _gen_non_array_type_name(tp) #数组结构体名和元素类型的code arr_tp_name = _gen_arr_tp_name(tp_name, dim_count) code += "type %s = %s" % (arr_tp_name, _gen_type_name_code_without_star(arr_type)) #traceback信息 with code.new_blk("var lar_util_tb_map = map[lar_util_go_tb]*lar_util_lar_tb"): for (go_file_name, go_line_no), tb_info in _tb_map.iteritems(): if tb_info is None: code += "lar_util_go_tb{file: %s, line: %d}: nil," % (_gen_str_literal(go_file_name), go_line_no) else: lar_file_name, lar_line_no, lar_fom_name = tb_info code += ("lar_util_go_tb{file: %s, line: %d}: &lar_util_lar_tb{file: %s, line: %d, fom_name: %s}," % (_gen_str_literal(go_file_name), go_line_no, _gen_str_literal(lar_file_name), lar_line_no, _gen_str_literal(lar_fom_name)))
def _get_encoding(src_file, line): encoding = "ascii" #默认用ascii编码 if line.startswith("\xEF\xBB\xBF"): #utf-8 bom line = line[3 :] encoding = "utf8" utf8_bom = True else: utf8_bom = False m = re.match(r"#.*coding[=:]\s*([-\w.]+)", line) if m is not None: #指定了编码 if utf8_bom: larc_common.warning( "警告:文件[%s]使用了utf8 bom,忽略指定的coding" % src_file) else: encoding = m.groups()[0] try: codecs.lookup(encoding) except LookupError: larc_common.exit("文件[%s]指定了不支持的编码[%s]" % (src_file, encoding)) return encoding, line
def parse_token_list(src_file): f = open(src_file) f.seek(0, os.SEEK_END) if f.tell() > 100 * 1024 ** 2: larc_common.exit("源代码文件[%s]过大" % src_file) f.seek(0, os.SEEK_SET) line_list = f.read().splitlines() token_list = TokenList(src_file) in_comment = False for line_no, line in enumerate(line_list): line_no += 1 if in_comment: #有未完的注释 pos = line.find("*/") if pos < 0: #整行都是注释,忽略 continue pos += 2 in_comment = False else: pos = 0 #解析当前行token while pos < len(line): #跳过空格 while pos < len(line) and line[pos] in "\t\x20": pos += 1 if pos >= len(line): #行结束 break if line[pos : pos + 2] == "//": #单行注释,略过本行 break if line[pos : pos + 2] == "/*": #块注释 pos += 2 comment_end_pos = line[pos :].find("*/") if comment_end_pos < 0: #注释跨行了,设置标记略过本行 in_comment = True break #注释在本行结束,跳过它 pos += comment_end_pos + 2 continue #解析token token, token_len = _parse_token(src_file, line_no, line, pos) token_list.append(token) pos += token_len if in_comment: _syntax_err(src_file, len(line_list), len(line_list[-1]), "存在未结束的块注释") token_list.join_str_literal() return token_list
def _find_module_file(module_dir_list, module_name): #按目录查找,每个目录下优先级:lar、lar_ext for module_dir in module_dir_list: for ext in (".lar", ".lar_ext"): module_file_path_name = os.path.join(module_dir, module_name) + ext if os.path.exists(module_file_path_name): return module_file_path_name larc_common.exit("找不到模块:%s" % module_name)
def _run_prog(args_for_run): if platform.system() in ("Darwin", "Linux"): pass else: raise Exception("Bug") if os.path.exists(_exe_file): os.execv(_exe_file, [_exe_file] + args_for_run) else: larc_common.exit("找不到可执行文件[%s]" % _exe_file)
def main(): #解析命令行参数 opt_list, args = getopt.getopt(sys.argv[1:], "", []) if len(args) != 1: _show_usage_and_exit() #已编译的模块,模块名映射模块Module对象 module_map = larc_common.OrderedDict() #先编译主模块 main_file_path_name = os.path.abspath(args[0]) if main_file_path_name.endswith(".lar"): main_module = larc_module.Module(main_file_path_name) elif main_file_path_name.endswith(".lar_ext"): main_module = larc_module.ExternModule(main_file_path_name) else: larc_common.exit("非法的主模块文件名[%s]" % main_file_path_name) module_map[main_module.name] = main_module #模块查找的目录列表 src_dir = os.path.dirname(main_file_path_name) compiler_dir = os.path.dirname(os.path.abspath(sys.argv[0])) lib_dir = os.path.join(os.path.dirname(compiler_dir), "lib") module_dir_list = [src_dir, lib_dir] #编译所有涉及到的模块 compiling_set = main_module.dep_module_set #需要编译的模块名集合 compiling_set |= set(["sys"]) #因为要接收argv,sys模块必须有 while compiling_set: new_compiling_set = set() for module_name in compiling_set: if module_name in module_map: #已编译过 continue module_file_path_name = (_find_module_file(module_dir_list, module_name)) if module_file_path_name.endswith(".lar"): module_map[module_name] = m = ( larc_module.Module(module_file_path_name)) elif module_file_path_name.endswith(".lar_ext"): module_map[module_name] = m = ( larc_module.ExternModule(module_file_path_name)) else: raise Exception("unreachable") new_compiling_set |= m.dep_module_set compiling_set = new_compiling_set prog = larc_prog.Prog(main_module.name, module_map) output_lib = larc_output.to_java out_dir = src_dir output_lib.output(out_dir, prog, lib_dir)
def main(): #解析命令行参数 opt_list, args = getopt.getopt(sys.argv[1 :], "", []) if len(args) != 1: _show_usage_and_exit() #已编译的模块,模块名映射模块Module对象 module_map = larc_common.OrderedDict() #先编译主模块 main_file_path_name = os.path.abspath(args[0]) if main_file_path_name.endswith(".lar"): main_module = larc_module.Module(main_file_path_name) elif main_file_path_name.endswith(".lar_ext"): main_module = larc_module.ExternModule(main_file_path_name) else: larc_common.exit("非法的主模块文件名[%s]" % main_file_path_name) module_map[main_module.name] = main_module #模块查找的目录列表 src_dir = os.path.dirname(main_file_path_name) compiler_dir = os.path.dirname(os.path.abspath(sys.argv[0])) lib_dir = os.path.join(os.path.dirname(compiler_dir), "lib") module_dir_list = [src_dir, lib_dir] #编译所有涉及到的模块 compiling_set = main_module.dep_module_set #需要编译的模块名集合 compiling_set |= set(["sys"]) #因为要接收argv,sys模块必须有 while compiling_set: new_compiling_set = set() for module_name in compiling_set: if module_name in module_map: #已编译过 continue module_file_path_name = ( _find_module_file(module_dir_list, module_name)) if module_file_path_name.endswith(".lar"): module_map[module_name] = m = ( larc_module.Module(module_file_path_name)) elif module_file_path_name.endswith(".lar_ext"): module_map[module_name] = m = ( larc_module.ExternModule(module_file_path_name)) else: raise Exception("unreachable") new_compiling_set |= m.dep_module_set compiling_set = new_compiling_set prog = larc_prog.Prog(main_module.name, module_map) output_lib = larc_output.to_java out_dir = src_dir output_lib.output(out_dir, prog, lib_dir)
def _output_booter(): booter_fix_file_path_name = runtime_dir + "/lar_booter.go" if not os.path.exists(booter_fix_file_path_name): larc_common.exit("runtime文件缺失,请检查编译器环境:[%s]" % booter_fix_file_path_name) f = open("%s/%s.booter_fix.go" % (_out_prog_dir, _prog_module_name), "w") print >> f, "package %s" % _prog_module_name print >> f f.write(larc_common.open_src_file(booter_fix_file_path_name).read()) f.close() with _Code("%s/%s.booter.go" % (_out_prog_dir, _prog_module_name)) as code: with code.new_blk("func %s()" % _BOOTER_START_PROC_FUNC_NAME): code += ("lar_booter_start_prog(%s, %s)" % (_gen_init_mod_func_name(larc_module.module_map[main_module_name]), _gen_func_name(larc_module.module_map[main_module_name].get_main_func())))
def _find_module_file(module_path_list, module_name): #按模块查找路径逐个目录找 assert module_path_list if module_name == "__builtins": mpl = [module_path_list[0]] #__builtins比较特殊,只从lib_dir找 else: mpl = module_path_list for module_dir in mpl: module_path = os.path.join(module_dir, *module_name.split("/")) if os.path.isdir(module_path): return module_path t = larc_module.dep_module_token_map.get(module_name) if t is None: larc_common.exit("找不到模块:%s" % module_name) else: t.syntax_err("找不到模块:%s" % module_name)
def _find_module_file(module_path_list, module_name): #按模块查找路径逐个目录找 assert module_path_list if module_name.split("/")[0] in ("__builtins", "__internal", "__array"): mpl = [module_path_list[0]] #这几个模块比较特殊,只从lib_dir找 else: mpl = module_path_list for i, module_dir in enumerate(mpl): module_path = os.path.join(module_dir, *module_name.split("/")) if os.path.isdir(module_path): return module_path, i == 0 t = larc_module.dep_module_token_map.get(module_name) if t is None: larc_common.exit("找不到模块:%s" % module_name) else: t.syntax_err("找不到模块:%s" % module_name)
def _output_booter(): booter_fix_file_path_name = runtime_dir + "/lar_booter.go" if not os.path.exists(booter_fix_file_path_name): larc_common.exit("runtime文件缺失,请检查编译器环境:[%s]" % booter_fix_file_path_name) f = open("%s/%s.booter_fix.go" % (_out_prog_dir, _prog_module_name), "w") print >> f, "package %s" % _prog_module_name print >> f f.write(larc_common.open_src_file(booter_fix_file_path_name).read()) f.close() with _Code("%s/%s.booter.go" % (_out_prog_dir, _prog_module_name)) as code: with code.new_blk("func %s()" % _BOOTER_START_PROC_FUNC_NAME): code += ("lar_booter_start_prog(%s, %s)" % ( _gen_init_mod_func_name( larc_module.module_map[main_module_name]), _gen_func_name( larc_module.module_map[main_module_name].get_main_func())))
def _output_util(): #拷贝runtime中固定的util代码 util_fix_file_path_name = runtime_dir + "/lar_util.go" if not os.path.exists(util_fix_file_path_name): larc_common.exit("runtime文件缺失,请检查编译器环境:[%s]" % util_fix_file_path_name) f = open("%s/%s.util_fix.go" % (_out_prog_dir, _prog_module_name), "w") print >> f, "package %s" % _prog_module_name print >> f f.write(larc_common.open_src_file(util_fix_file_path_name).read()) f.close() #生成util代码 with _Code("%s/%s.util.go" % (_out_prog_dir, _prog_module_name)) as code: #生成数组相关代码 for tp in larc_type.array_type_set: assert tp.is_array arr_type = larc_type.gen_arr_type(tp) dim_count = tp.array_dim_count while tp.is_array: tp = tp.to_elem_type() tp_name = _gen_non_array_type_name(tp) #数组结构体名和元素类型的code arr_tp_name = _gen_arr_tp_name(tp_name, dim_count) code += "type %s = %s" % ( arr_tp_name, _gen_type_name_code_without_star(arr_type)) #traceback信息 with code.new_blk( "var lar_util_tb_map = map[lar_util_go_tb]*lar_util_lar_tb"): for (go_file_name, go_line_no), tb_info in _tb_map.iteritems(): if tb_info is None: code += "lar_util_go_tb{file: %s, line: %d}: nil," % ( _gen_str_literal(go_file_name), go_line_no) else: lar_file_name, lar_line_no, lar_fom_name = tb_info code += ( "lar_util_go_tb{file: %s, line: %d}: &lar_util_lar_tb{file: %s, line: %d, fom_name: %s}," % (_gen_str_literal(go_file_name), go_line_no, _gen_str_literal(lar_file_name), lar_line_no, _gen_str_literal(lar_fom_name)))
def _make_prog(): if platform.system() in ("Darwin", "Linux"): try: p = subprocess.Popen(["go", "env", "GOPATH"], stdout = subprocess.PIPE) except OSError: larc_common.exit("无法执行go命令") rc = p.wait() if rc != 0: larc_common.exit("通过go env获取GOPATH失败") go_path = p.stdout.read().strip() os.environ["GOPATH"] = out_dir + ":" + go_path rc = os.system("go build -o %s %s" % (_exe_file, _main_pkg_file)) if rc != 0: larc_common.exit("go build失败") else: larc_common.exit("不支持在平台'%s'生成可执行程序" % platform.system())
def _get_encoding(src_file, line): encoding = "ascii" # 默认用ascii编码 if line.startswith("\xEF\xBB\xBF"): # utf-8 bom line = line[3:] encoding = "utf8" utf8_bom = True else: utf8_bom = False m = re.match(r"#.*coding[=:]\s*([-\w.]+)", line) if m is not None: # 指定了编码 if utf8_bom: larc_common.warning("警告:文件[%s]使用了utf8 bom,忽略指定的coding" % src_file) else: encoding = m.groups()[0] try: codecs.lookup(encoding) except LookupError: larc_common.exit("文件[%s]指定了不支持的编码[%s]" % (src_file, encoding)) return encoding, line
def _make_prog(): if platform.system() in ("Darwin", "Linux"): try: p = subprocess.Popen(["go", "env", "GOPATH"], stdout=subprocess.PIPE) except OSError: larc_common.exit("无法执行go命令") rc = p.wait() if rc != 0: larc_common.exit("通过go env获取GOPATH失败") go_path = p.stdout.read().strip() os.environ["GOPATH"] = out_dir + ":" + go_path rc = os.system("go build -o %s %s" % (_exe_file, _main_pkg_file)) if rc != 0: larc_common.exit("go build失败") else: larc_common.exit("不支持在平台'%s'生成可执行程序" % platform.system())
def _output_booter(): booter_fix_file_path_name = runtime_dir + "/lar_booter.go" if not os.path.exists(booter_fix_file_path_name): larc_common.exit("runtime文件缺失,请检查编译器环境:[%s]" % booter_fix_file_path_name) f = open("%s/%s.booter_fix.go" % (_out_prog_dir, _prog_module_name), "w") print >> f, "package %s" % _prog_module_name print >> f f.write(open(booter_fix_file_path_name).read()) f.close() with _Code("%s/%s.booter.go" % (_out_prog_dir, _prog_module_name)) as code: with code.new_blk("import"): code += '"os"' with code.new_blk("func %s() int" % _BOOTER_START_PROC_FUNC_NAME): code += "argv := %s(int64(len(os.Args)))" % ( _gen_new_arr_func_name(larc_type.STR_TYPE, 1, 1)) with code.new_blk("for i := 0; i < len(os.Args); i ++"): code += "argv.arr[i] = lar_str_from_go_str(os.Args[i])" code += ("return lar_booter_start_prog(%s, %s, argv)" % ( _gen_init_mod_func_name( larc_module.module_map[main_module_name]), _gen_func_name( larc_module.module_map[main_module_name].get_main_func())))
def syntax_err(self, msg=""): larc_common.exit("%s %s" % (self.pos_desc(), msg))
def _show_usage_and_exit(): larc_common.exit("使用方法:\n" "\t%s --module_path=MODULE_PATH_LIST MAIN_MODULE\n" "\t%s --module_path=MODULE_PATH_LIST --run MAIN_MODULE ARGS" % (sys.argv[0], sys.argv[0]))
def main(): #解析命令行参数 try: opt_list, args = getopt.getopt(sys.argv[1 :], "", ["module_path=", "run"]) except getopt.GetoptError: _show_usage_and_exit() opt_map = dict(opt_list) if "--module_path" not in opt_map: _show_usage_and_exit() module_path_list = [os.path.abspath(p) for p in opt_map["--module_path"].split(":") if p] need_run = "--run" in opt_map if len(args) < 1: _show_usage_and_exit() main_module_name = args[0] args_for_run = args[1 :] if not need_run and args_for_run: _show_usage_and_exit() #通用目录 compiler_dir = os.path.dirname(os.path.abspath(sys.argv[0])) lib_dir = os.path.join(os.path.dirname(compiler_dir), "lib") module_path_list = [lib_dir] + module_path_list larc_module.find_module_file = lambda mn: _find_module_file(module_path_list, mn) #larva对标准库第一级模块有一些命名要求,虽然内建模块不会被一般用户修改,但为了稳妥还是检查下,免得开发者不小心弄了个非法名字 for fn in os.listdir(lib_dir): #若为私有模块则忽略掉前缀 if fn[: 2] == "__": fn = fn[2 :] #第一级模块名不能有下划线 if os.path.isdir(os.path.join(lib_dir, fn)) and "_" in fn: larc_common.exit("环境检查失败:内建模块[%s]名字含有下划线" % fn) #预处理内建模块族 larc_module.builtins_module = larc_module.module_map["__builtins"] = larc_module.Module("__builtins") assert larc_module.builtins_module.get_dep_module_set() == set(["__internal"]) #内建模块只能而且必须导入__internal模块 internal_module = larc_module.module_map["__internal"] = larc_module.Module("__internal") assert not internal_module.get_dep_module_set() #__internal模块不能导入其他模块 larc_module.array_module = larc_module.module_map["__array"] = larc_module.Module("__array") #预处理主模块 if not (all([larc_token.is_valid_name(p) for p in main_module_name.split("/")]) and main_module_name != "__builtins"): larc_common.exit("非法的主模块名[%s]" % main_module_name) larc_module.module_map[main_module_name] = main_module = larc_module.Module(main_module_name) #预处理所有涉及到的模块 compiling_set = (larc_module.builtins_module.get_dep_module_set() | larc_module.array_module.get_dep_module_set() | main_module.get_dep_module_set()) #需要预处理的模块名集合 while compiling_set: new_compiling_set = set() for module_name in compiling_set: if module_name in larc_module.module_map: #已预处理过 continue larc_module.module_map[module_name] = m = larc_module.Module(module_name) new_compiling_set |= m.get_dep_module_set() compiling_set = new_compiling_set assert larc_module.module_map.value_at(0) is larc_module.builtins_module #检查循环import for m in larc_module.module_map.itervalues(): m.check_cycle_import() #模块元素级别的check_type,先对非泛型元素做check,然后对泛型实例采用类似深度优先的方式,直到没有ginst生成 for m in larc_module.module_map.itervalues(): m.check_type_for_non_ginst() larc_module.check_type_for_ginst() #扩展接口中通过usemethod继承的方法 for m in larc_module.module_map.itervalues(): m.expand_intf_usemethod() #扩展类中通过usemethod继承的方法 for m in larc_module.module_map.itervalues(): m.expand_cls_usemethod() #主模块main函数检查 main_module.check_main_func() #编译各模块代码,先编译非泛型元素,然后反复编译到没有ginst生成,类似上面的check type过程 for m in larc_module.module_map.itervalues(): m.compile_non_ginst() while True: for m in larc_module.module_map.itervalues(): if m.compile_ginst(): #有一个模块刚编译了新的ginst,有可能生成新ginst,重启编译流程 break else: #所有ginst都编译完毕 break #输出目标代码 larc_output.main_module_name = main_module.name larc_output.out_dir = main_module.dir + ".lar_out" larc_output.runtime_dir = os.path.join(os.path.dirname(lib_dir), "runtime") larc_output.output(need_run, args_for_run)
def _show_usage_and_exit(): larc_common.exit("使用方法:%s 主模块.lar" % sys.argv[0])
def main(): #解析命令行参数 try: opt_list, args = getopt.getopt(sys.argv[1:], "", ["module_path=", "run"]) except getopt.GetoptError: _show_usage_and_exit() opt_map = dict(opt_list) if "--module_path" not in opt_map: _show_usage_and_exit() module_path_list = [ os.path.abspath(p) for p in opt_map["--module_path"].split(":") if p ] need_run = "--run" in opt_map if len(args) < 1: _show_usage_and_exit() main_module_name = args[0] args_for_run = args[1:] if not need_run and args_for_run: _show_usage_and_exit() #通用目录 compiler_dir = os.path.dirname(os.path.abspath(sys.argv[0])) lib_dir = os.path.join(os.path.dirname(compiler_dir), "lib") module_path_list = [lib_dir] + module_path_list larc_module.find_module_file = lambda mn: _find_module_file( module_path_list, mn) #预处理builtins模块 larc_module.builtins_module = larc_module.module_map[ "__builtins"] = larc_module.Module("__builtins") #预处理主模块 if not (all( [larc_token.is_valid_name(p) for p in main_module_name.split("/")]) and main_module_name != "__builtins"): larc_common.exit("非法的主模块名[%s]" % main_module_name) larc_module.module_map[ main_module_name] = main_module = larc_module.Module(main_module_name) #预处理所有涉及到的模块 compiling_set = larc_module.builtins_module.get_dep_module_set( ) | main_module.get_dep_module_set() #需要预处理的模块名集合 while compiling_set: new_compiling_set = set() for module_name in compiling_set: if module_name in larc_module.module_map: #已预处理过 continue larc_module.module_map[module_name] = m = larc_module.Module( module_name) new_compiling_set |= m.get_dep_module_set() compiling_set = new_compiling_set assert larc_module.module_map.value_at(0) is larc_module.builtins_module #模块元素级别的check_type,先对非泛型元素做check,然后对泛型实例采用类似深度优先的方式,直到没有ginst生成 for m in larc_module.module_map.itervalues(): m.check_type_for_non_ginst() larc_module.check_type_for_ginst() #扩展通过usemethod继承的方法 for m in larc_module.module_map.itervalues(): m.expand_usemethod() #主模块main函数检查 main_module.check_main_func() #编译各模块代码,先编译非泛型元素,然后反复编译到没有ginst生成,类似上面的check type过程 for m in larc_module.module_map.itervalues(): m.compile_non_ginst() while True: for m in larc_module.module_map.itervalues(): if m.compile_ginst(): #有一个模块刚编译了新的ginst,有可能生成新ginst,重启编译流程 break else: #所有ginst都编译完毕 break #输出目标代码 larc_output.main_module_name = main_module.name larc_output.out_dir = main_module.dir + ".lar_out" larc_output.runtime_dir = os.path.join(os.path.dirname(lib_dir), "runtime") larc_output.output(need_run, args_for_run)
def peek(self): if not self: larc_common.exit("语法错误:文件[%s]代码意外结束" % self.src_file) return self.l[self.i]
def main(): #解析命令行参数 opt_list, args = getopt.getopt(sys.argv[1:], "", []) if len(args) != 1: _show_usage_and_exit() #通用目录 compiler_dir = os.path.dirname(os.path.abspath(sys.argv[0])) lib_dir = os.path.join(os.path.dirname(compiler_dir), "lib") #预处理builtins等模块 larc_module.module_map["__builtins"] = larc_module.Module( os.path.join(lib_dir, "__builtins.lar")) #先预处理主模块 main_file_path_name = os.path.abspath(args[0]) if not main_file_path_name.endswith(".lar"): larc_common.exit("非法的主模块文件名[%s]" % main_file_path_name) if not os.path.exists(main_file_path_name): larc_common.exit("找不到主模块文件[%s]" % main_file_path_name) main_module = larc_module.Module(main_file_path_name) larc_module.module_map[main_module.name] = main_module #模块查找的目录列表 src_dir = os.path.dirname(main_file_path_name) module_dir_list = [src_dir, lib_dir] #预处理所有涉及到的模块 compiling_set = main_module.dep_module_set #需要预处理的模块名集合 while compiling_set: new_compiling_set = set() for module_name in compiling_set: if module_name in larc_module.module_map: #已预处理过 continue module_file_path_name = _find_module_file(module_dir_list, module_name) larc_module.module_map[module_name] = m = larc_module.Module( module_file_path_name) new_compiling_set |= m.dep_module_set compiling_set = new_compiling_set #主模块main函数检查 if ("main", 1) not in main_module.func_map: larc_common.exit("主模块[%s]没有func main(argv)" % main_module.name) #检查子类的继承是否合法 ''' for m in larc_module.module_map.itervalues(): m.check_sub_class() ''' #正式编译各模块 for m in larc_module.module_map.itervalues(): m.compile() #暂时写死output流程 output_lib = larc_output.to_go output_lib.main_module_name = main_module.name output_lib.out_dir = os.path.join(src_dir, main_module.name) output_lib.runtime_dir = os.path.join(os.path.dirname(lib_dir), "runtime") output_lib.output()
def syntax_err(self, msg = ""): larc_common.exit("语法错误:文件[%s]行[%d]列[%d]%s" % (self.src_file, self.line_no, self.pos + 1, msg))
def peek(self, start_idx=0): try: return self.l[self.i + start_idx] except IndexError: larc_common.exit("文件[%s]代码意外结束" % self.src_file)
def syntax_err(self, msg = ""): larc_common.exit("%s %s" % (self.pos_desc(), msg))
def _syntax_err(src_file, line_no, pos, msg): larc_common.exit("文件[%s]行[%d]列[%d] %s" % (src_file, line_no, pos + 1, msg))
def peek(self, start_idx = 0): try: return self.l[self.i + start_idx] except IndexError: larc_common.exit("文件[%s]代码意外结束" % self.src_file)
def syntax_err(self, msg=""): larc_common.exit("语法错误:文件[%s]行[%d]列[%d]%s" % (self.src_file, self.line_no, self.pos + 1, msg))
def _check_main_func(self): main_module = self.module_map[self.main_module_name] if ("main", 0) not in main_module.export_func_set: larc_common.exit("链接错误:主模块'%s'缺少main函数" % self.main_module_name)
def main(): #定位目录 THIS_SCRIPT_NAME_SUFFIX = "/compiler/larc.py" this_script_name = os.path.realpath(sys.argv[0]) assert this_script_name.endswith(THIS_SCRIPT_NAME_SUFFIX) larva_dir = this_script_name[:-len(THIS_SCRIPT_NAME_SUFFIX)] def _show_usage_and_exit(): print >> sys.stderr, """ Larva编译器 使用方法 python larc.py OPTIONS MAIN_MODULE_SPEC [ARGS] 各参数说明 OPTIONS: [-v] [-u] [--recoverable_detecting] [-o OUT_BIN] [--run] {v} {u} {recoverable_detecting} {o} --run 编译后立即执行 -o和--run至少要指定一个,若都指定,则先输出为可执行程序然后执行 {MAIN_MODULE_SPEC} ARGS 运行模块时的命令行参数,指定--run选项的时候有效,如未指定--run,则不能指定ARGS """.format(**eval(open(larva_dir + "/compiler/help_dict").read())) sys.exit(1) #解析命令行参数 try: opt_list, args = getopt.getopt(sys.argv[1:], "vuo:m:", ["recoverable_detecting", "run"]) except getopt.GetoptError: _show_usage_and_exit() opt_map = dict(opt_list) if "-v" in opt_map: larc_common.enable_verbose_mode() larc_common.verbose_log("开始") larc_module.need_update_git = "-u" in opt_map if "--recoverable_detecting" in opt_map: larc_common.enable_recoverable_detecting() out_bin = opt_map.get("-o") if out_bin is not None: if os.path.exists(out_bin) and not os.path.isfile(out_bin): larc_common.exit("[%s]不是一个常规文件" % out_bin) need_run = "--run" in opt_map if out_bin is None and not need_run: #至少要指定一种行为 _show_usage_and_exit() main_module_name = opt_map.get("-m") if main_module_name is None: if len(args) < 1: _show_usage_and_exit() main_module_path = larc_common.abs_path(args[0]) if not os.path.isdir(main_module_path): larc_common.exit("无效的主模块路径[%s]:不存在或不是目录" % main_module_path) args_for_run = args[1:] else: main_module_path = None args_for_run = args[:] if not need_run and args_for_run: _show_usage_and_exit() #获取标准库、用户库和临时输出的目录,并做检查 compiler_dir = larva_dir + "/compiler" std_lib_dir = larva_dir + "/lib" assert os.path.isdir(std_lib_dir) usr_lib_dir_original = os.getenv("LARVA_USR_LIB_DIR", "~/larva") usr_lib_dir = os.path.realpath(larc_common.abs_path(usr_lib_dir_original)) if not os.path.isdir(usr_lib_dir): larc_common.exit("无效的用户库路径:[%s]不存在或不是一个目录" % usr_lib_dir_original) tmp_dir_original = os.getenv("LARVA_TMP_DIR", "~/tmp") tmp_dir = os.path.realpath(larc_common.abs_path(tmp_dir_original)) if not os.path.isdir(tmp_dir): larc_common.exit("无效的临时工作目录:[%s]不存在或不是一个目录" % tmp_dir_original) for (dn_1, d_1), (dn_2, d_2) in itertools.combinations({ "标准库目录": std_lib_dir, "用户库目录": usr_lib_dir, "临时工作目录": tmp_dir, }.iteritems(), 2): if d_1 == d_2: larc_common.exit("环境检查失败:%s[%s]和%s[%s]是相同目录" % (dn_1, d_1, dn_2, d_2)) if d_1.startswith(d_2 + "/") or d_2.startswith(d_1 + "/"): larc_common.exit("环境检查失败:%s[%s]和%s[%s]存在包含关系" % (dn_1, d_1, dn_2, d_2)) #建立临时输出目录 tmp_out_dir = tmp_dir + "/.larva_tmp_out" if not os.path.isdir(tmp_out_dir): try: os.makedirs(tmp_out_dir) except OSError: larc_common.exit("创建临时输出目录[%s]失败" % tmp_out_dir) if std_lib_dir.startswith(usr_lib_dir) or usr_lib_dir.startswith( std_lib_dir): larc_common.exit("环境检查失败:标准库和用户库路径存在包含关系:[%s] & [%s]" % (std_lib_dir, usr_lib_dir)) #larva对标准库第一级模块有一些命名要求,虽然内建模块不会被一般用户修改,但为了稳妥还是检查下,免得开发者不小心弄了个非法名字 first_level_std_module_set = set() for fn in os.listdir(std_lib_dir): if os.path.isdir(std_lib_dir + "/" + fn): if not larc_token.is_valid_name(fn): larc_common.exit("环境检查失败:标准库模块[%s]名字不是合法的标识符" % fn) #第一级模块名不能有除了私有模块前导之外的下划线 if fn.count("_") != (2 if fn.startswith("__") else 0): larc_common.exit("环境检查失败:标准库模块[%s]名字含有非法的下划线" % fn) first_level_std_module_set.add(fn) #检查一下几个特殊的标准库模块,必须有 for mn in larc_common.STD_LIB_INTERNAL_MODULES: if mn not in first_level_std_module_set: larc_common.exit("环境检查失败:标准库模块[%s]缺失" % mn) #对于用户库中的模块,如果不是git地址,则也要满足合法标识符条件,且不能和标准库的冲突 for fn in os.listdir(usr_lib_dir): if os.path.isdir(usr_lib_dir + "/" + fn): if "." not in fn: if not larc_token.is_valid_name(fn): larc_common.exit("环境检查失败:用户库模块[%s]名字不是合法的标识符" % fn) if fn in first_level_std_module_set: larc_common.exit("环境检查失败:用户库模块[%s]和标准库同名模块冲突" % fn) #校验通过,设置到module模块中 larc_module.std_lib_dir = std_lib_dir larc_module.usr_lib_dir = usr_lib_dir def fix_git_module_name(mn): parts = mn.split("/") if len(parts) > 3 and "." in parts[0]: git_repo = "/".join(parts[:3]) mn_of_repo = "/".join(parts[3:]) if larc_module.is_valid_git_repo(git_repo): mn = '"%s"/%s' % (git_repo, mn_of_repo) return mn if main_module_path is not None: #处理main_module_path,提取main_module_name if main_module_path.startswith(std_lib_dir + "/"): main_module_name = main_module_path[len(std_lib_dir) + 1:] if main_module_name in larc_common.STD_LIB_INTERNAL_MODULES: larc_common.exit("不能以'%s'作为主模块" % main_module_name) elif main_module_path.startswith(usr_lib_dir + "/"): main_module_name = fix_git_module_name( main_module_path[len(usr_lib_dir) + 1:]) else: larc_common.exit("主模块路径不存在于标准库或用户库[%s]" % main_module_path) else: #如果module_name是不带引号的git路径,则像上面一样修正一下 main_module_name = fix_git_module_name(main_module_name) #检查 if not larc_module.is_valid_module_name(main_module_name): larc_common.exit("非法的主模块全名'%s'" % main_module_name) git_repo, mnpl = larc_module.split_module_name(main_module_name) if any([mnp.startswith("__") for mnp in mnpl]): larc_common.exit("不能使用私有模块作为主模块'%s'" % main_module_name) larc_common.verbose_log("初始化完毕,主模块'%s'" % main_module_name) #预处理内建模块族 larc_module.builtins_module = larc_module.module_map[ "__builtins"] = larc_module.Module("__builtins") assert larc_module.builtins_module.get_dep_module_set() == set( ["__internal"]) #内建模块只能而且必须导入__internal模块 internal_module = larc_module.module_map[ "__internal"] = larc_module.Module("__internal") assert not internal_module.get_dep_module_set() #__internal模块不能导入其他模块 larc_module.array_module = larc_module.module_map[ "__array"] = larc_module.Module("__array") larc_module.module_map["__runtime"] = larc_module.Module("__runtime") larc_module.module_map["__default"] = larc_module.Module("__default") #预处理主模块 larc_module.module_map[ main_module_name] = main_module = larc_module.Module(main_module_name) module_tmp_out_dir = tmp_out_dir + "/" + main_module_name.replace('"', "") larc_common.verbose_log("内建模块和主模块预处理完毕") #预处理所有涉及到的模块 larc_common.inc_verbose_indent() compiling_set = set() #需要预处理的模块全名集合 for m in larc_module.module_map.itervalues(): compiling_set |= m.get_dep_module_set() while compiling_set: new_compiling_set = set() for module_name in compiling_set: if module_name in larc_module.module_map: #已预处理过 continue larc_module.module_map[module_name] = m = larc_module.Module( module_name) new_compiling_set |= m.get_dep_module_set() compiling_set = new_compiling_set assert larc_module.module_map.value_at(0) is larc_module.builtins_module larc_common.dec_verbose_indent() larc_common.verbose_log("所有模块预处理完毕") compile_start_time = time.time() #检查循环import for m in larc_module.module_map.itervalues(): m.check_cycle_import() #模块元素级别的check_type,先对非泛型元素做check,然后对泛型实例采用类似深度优先的方式,直到没有ginst生成 for m in larc_module.module_map.itervalues(): m.check_type_for_non_ginst() larc_module.check_type_for_ginst() #扩展接口中通过usemethod继承的方法 for m in larc_module.module_map.itervalues(): m.expand_intf_usemethod() #扩展类中通过usemethod继承的方法 for m in larc_module.module_map.itervalues(): m.expand_cls_usemethod() #初始化函数的合法性检查 for m in larc_module.module_map.itervalues(): m.check_init_func() #主模块main函数检查 main_module.check_main_func() #编译各模块代码,先编译非泛型元素,然后反复编译到没有ginst生成,类似上面的check type过程 for m in larc_module.module_map.itervalues(): m.compile_non_ginst() while True: for m in larc_module.module_map.itervalues(): if m.compile_ginst(): #有一个模块刚编译了新的ginst,有可能生成新ginst,重启编译流程 break else: #所有ginst都编译完毕 break larc_common.verbose_log("语法编译完毕,耗时%.2f秒" % (time.time() - compile_start_time)) #输出目标代码 larc_output.main_module_name = main_module.name larc_output.out_dir = module_tmp_out_dir larc_output.output(out_bin, need_run, args_for_run)
def _output_util(): #拷贝runtime中固定的util代码 util_fix_file_path_name = runtime_dir + "/lar_util.go" if not os.path.exists(util_fix_file_path_name): larc_common.exit("runtime文件缺失,请检查编译器环境:[%s]" % util_fix_file_path_name) f = open("%s/%s.util_fix.go" % (_out_prog_dir, _prog_module_name), "w") print >> f, "package %s" % _prog_module_name print >> f f.write(open(util_fix_file_path_name).read()) f.close() #生成util代码 with _Code("%s/%s.util.go" % (_out_prog_dir, _prog_module_name)) as code: with code.new_blk("import"): code += '"fmt"' code += '"strings"' #生成数组相关代码 for tp in larc_type.array_type_set: assert tp.is_array dim_count = tp.array_dim_count while tp.is_array: tp = tp.to_elem_type() tp_name = _gen_non_array_type_name(tp) #数组结构体名和元素类型的code arr_tp_name = _gen_arr_tp_name(tp_name, dim_count) if dim_count == 1: elem_tp_name_code = _gen_tp_name_code_from_tp_name(tp_name) else: elem_tp_name_code = _gen_arr_tp_name_code( tp_name, dim_count - 1) #数组结构体定义:元素的slice with code.new_blk("type %s struct" % arr_tp_name): code += "arr []%s" % elem_tp_name_code #数组的方法 with code.new_blk("func (la *%s) lar_method_size() int64" % arr_tp_name): code += "return int64(len(la.arr))" with code.new_blk("func (la *%s) lar_method_cap() int64" % arr_tp_name): code += "return int64(cap(la.arr))" with code.new_blk( "func (la *%s) lar_method_repr() %s" % (arr_tp_name, _gen_type_name_code(larc_type.STR_TYPE))): code += 'sl := []string{%s, "", ">"}' % _gen_str_literal( "<%s " % (str(tp) + "[]" * dim_count)) code += "sl[1] = la.sub_arr_repr()" code += 'return lar_str_from_go_str(strings.Join(sl, ""))' with code.new_blk("func (la *%s) sub_arr_repr() string" % arr_tp_name): if tp == larc_type.CHAR_TYPE and dim_count == 1: code += 'return fmt.Sprintf("%q", string(la.arr))' else: code += "sl := make([]string, 0, len(la.arr) + 2)" code += 'sl = append(sl, "[")' with code.new_blk("for i, elem := range la.arr"): if dim_count == 1: elem_repr_code = "lar_go_func_any_repr_to_go_str(elem)" else: assert dim_count > 1 elem_repr_code = "elem.sub_arr_repr()" with code.new_blk("if i == 0"): code += "sl = append(sl, %s)" % elem_repr_code with code.new_blk("else"): code += 'sl = append(sl, ", " + %s)' % elem_repr_code code += 'sl = append(sl, "]")' code += 'return strings.Join(sl, "")' with code.new_blk("func (la *%s) lar_method_get(idx int64) %s" % (arr_tp_name, elem_tp_name_code)): code += "return la.arr[idx]" with code.new_blk( "func (la *%s) lar_method_set(idx int64, elem %s)" % (arr_tp_name, elem_tp_name_code)): code += "la.arr[idx] = elem" with code.new_blk( "func (la *%s) lar_method_iter() *lar_gcls_inst_10___builtins_9_ArrayIter_1_%s" % (arr_tp_name, elem_tp_name_code.lstrip("*"))): code += "return lar_new_obj_lar_gcls_inst_10___builtins_9_ArrayIter_1_%s(la, 0)" % elem_tp_name_code.lstrip( "*") with code.new_blk( "func (la *%s) lar_method_copy_from(src *%s) int64" % (arr_tp_name, arr_tp_name)): code += "return int64(copy(la.arr, src.arr))" #输出数组的反射接口 code += "var lar_reflect_type_name_%s = lar_str_from_go_str(%s)" % ( arr_tp_name, _gen_str_literal(str(tp) + "[]" * dim_count)) with code.new_blk( "func (la *%s) lar_reflect_type_name() %s" % (arr_tp_name, _gen_type_name_code(larc_type.STR_TYPE))): code += "return lar_reflect_type_name_%s" % arr_tp_name #new数组的函数 for new_dim_count in xrange(1, dim_count + 1): new_arr_func_name = _gen_new_arr_func_name_by_tp_name( tp_name, dim_count, new_dim_count) arg_code = ", ".join( ["d%d_size" % i for i in xrange(new_dim_count)]) + " int64" if new_dim_count == 1: if elem_tp_name_code[ 0] == "*" or elem_tp_name_code.startswith( "lar_intf") or elem_tp_name_code.startswith( "lar_gintf"): elem_code = "nil" elif elem_tp_name_code == "bool": elem_code = "false" else: elem_code = "0" else: assert new_dim_count > 1 elem_code = "%s(%s)" % (_gen_new_arr_func_name_by_tp_name( tp_name, dim_count - 1, new_dim_count - 1), ", ".join( ["d%d_size" % i for i in xrange(1, new_dim_count)])) with code.new_blk("func %s(%s) *%s" % (new_arr_func_name, arg_code, arr_tp_name)): code += "la := &%s{arr: make([]%s, d0_size)}" % ( arr_tp_name, elem_tp_name_code) with code.new_blk("for i := int64(0); i < d0_size; i ++"): code += "la.arr[i] = %s" % elem_code code += "return la" #traceback信息 with code.new_blk( "var lar_util_tb_map = map[lar_util_go_tb]*lar_util_lar_tb"): for (go_file_name, go_line_no), tb_info in _tb_map.iteritems(): if tb_info is None: code += "lar_util_go_tb{file: %s, line: %d}: nil," % ( _gen_str_literal(go_file_name), go_line_no) else: lar_file_name, lar_line_no, lar_fom_name = tb_info code += ( "lar_util_go_tb{file: %s, line: %d}: &lar_util_lar_tb{file: %s, line: %d, fom_name: %s}," % (_gen_str_literal(go_file_name), go_line_no, _gen_str_literal(lar_file_name), lar_line_no, _gen_str_literal(lar_fom_name))) #native文件名映射信息 with code.new_blk( "var lar_util_native_file_name_map = map[string]string"): for out_nfn, in_nfn in _native_file_name_map.iteritems(): code += "%s: %s," % (_gen_str_literal(out_nfn), _gen_str_literal(in_nfn))
def _show_usage_and_exit(): larc_common.exit( "使用方法:\n" "\t%s --module_path=MODULE_PATH_LIST MAIN_MODULE\n" "\t%s --module_path=MODULE_PATH_LIST --run MAIN_MODULE ARGS" % (sys.argv[0], sys.argv[0]))