def product_path_for_source(source_path): 'Retern the product path for `sourc_path` (which may itself be a product).' path = path_stem(source_path) # strip off source ext. if is_product_path(path): # source might be a product. return path else: return path_join(build_dir, path)
def py_dep_import(src_path, module_name, dir_names): 'Calculate dependencies for a Python ast.Import or ast.ImportFrom node.' src_dir = path_dir(src_path) leading_dots_count = re.match('\.*', module_name).end() module_parts = ['..'] * leading_dots_count + module_name[leading_dots_count:].split('.') module_path = path_join(src_dir, *module_parts) + '.py' if is_file(module_path): yield module_path
def source_for_target(ctx, target_path): ''' Find the unique source path whose name matches `target_path`, or else error. ''' src_dir, prod_name = split_dir_name(target_path) src_name = source_candidate(ctx, target_path, src_dir, prod_name) src = path_join(src_dir, src_name) assert src != target_path return src
def fetch(url, expected_status_code=200, headers={}, timeout=4, delay=0, delay_range=0): "Fetch the data at `url` and save it to a path in the '_fetch' directory derived from the URL." path = path_join('_fetch', path_for_url(url)) if not path_exists(path): errFL('fetch: {}', url) r = _fetch(url, timeout, headers, expected_status_code) make_dirs(path_dir(path)) with open(path, 'wb') as f: f.write(r.content) sleep_min = delay - delay_range * 0.5 sleep_max = delay + delay_range * 0.5 sleep_time = random.uniform(sleep_min, sleep_max) if sleep_time > 0: time.sleep(sleep_time) return path
def output_swift(path:str, dfas:List[DFA], mode_transitions:ModeTransitions, pattern_descs:Dict[str,str], license:str, args:Namespace) -> None: # Create safe mode names. modes = { dfa.name : swift_safe_sym(dfa.name) for dfa in dfas } mode_case_defs = [f'case {modes[dfa.name]} = {dfa.start_node}' for dfa in dfas] # Create safe token kind names. kind_syms = { kind : swift_safe_sym(kind) for kind in pattern_descs } kind_syms['incomplete'] = 'incomplete' assert len(kind_syms) == len(set(kind_syms.values())) token_kind_case_defs = [f'case {sym}' for sym in sorted(kind_syms.values())] # Token kind descriptions. def pattern_desc(kind:str) -> str: return swift_repr(pattern_descs[kind]) token_kind_case_descs = [f'case .{sym}: return {pattern_desc(kind)}' for kind, sym in sorted(kind_syms.items())] # Mode transitions dictionary. def mode_trans_dict(d:Dict[str,Tuple[str,str]]) -> dict: return {SwiftEnum(parent_kind): (SwiftEnum(child_mode), SwiftEnum(child_kind)) for parent_kind, (child_mode, child_kind) in d.items()} mode_transitions_dict = {SwiftEnum(modes[name]):mode_trans_dict(d) for name, d in mode_transitions.items()} # State cases. def byte_case_patterns(chars:List[int]) -> List[str]: def fmt(l:int, h:int) -> str: if l == h: return hex(l) return hex(l) + (', ' if l + 1 == h else '...') + hex(h) return [fmt(*r) for r in closed_int_intervals(chars)] def byte_case(dfa:DFA, chars:List[int], dst:int) -> str: pattern_kind = dfa.match_kind(dst) sym = None if pattern_kind is None else kind_syms.get(pattern_kind) return 'case {chars}: state = {dst}{suffix}'.format( chars=', '.join(byte_case_patterns(chars)), dst=dst, suffix=f'; last = pos; kind = .{sym}' if sym else '') def byte_cases(dfa:DFA, node:int) -> List[str]: dst_chars:DefaultDict[int, List[int]] = DefaultDict(list) for char, dst in sorted(dfa.transitions[node].items()): dst_chars[dst].append(char) dst_chars_sorted = sorted(dst_chars.items(), key=lambda p: p[1]) return [byte_case(dfa, chars, dst) for dst, chars in dst_chars_sorted] def transition_code(dfa:DFA, node:int) -> str: d = dfa.transitions[node] if not d: return 'break loop' # no transitions. return render_template('''switch byte { ${byte_cases} default: break loop }''', byte_cases='\n '.join(byte_cases(dfa, node))) def state_case(dfa:DFA, node:int) -> str: mode = dfa.name kind = dfa.match_kind(node) if kind: desc = kind elif node in dfa.pre_match_nodes: desc = f'{mode} pre-match' else: desc = f'{mode} post-match' return 'case {node}: // {desc}.\n {transition_code}'.format( desc=desc, node=node, transition_code=transition_code(dfa, node)) state_cases = [state_case(dfa, node) for dfa in dfas for node in sorted(dfa.transitions.keys())] with open(path, 'w', encoding='utf8') as f: src = render_template(template, Name=args.type_prefix, license=license, mode_case_defs='\n '.join(mode_case_defs), mode_transitions_dict=swift_repr(mode_transitions_dict, indent=2), patterns_path=args.path, state_cases='\n '.join(state_cases), token_kind_case_defs='\n '.join(token_kind_case_defs), token_kind_case_descs='\n '.join(token_kind_case_descs), ) f.write(src) if args.test: # Append the base source because `swift` will only interpret a single file. spec = find_module_spec('legs') assert spec is not None pkg_dir_path = path_dir(cast(str, spec.origin)) legs_base_path = path_join(pkg_dir_path, 'legs_base.swift') legs_base_contents = open(legs_base_path).read() f.write(legs_base_contents) # Write the test main function. test_src = render_template(test_template, Name=args.type_prefix) f.write(test_src)
def product_path_for_target(target_path): if target_path == build_dir or is_product_path(target_path): raise ValueError('provided target path is prefixed with build dir: {}'.format(target_path)) return path_join(build_dir, target_path)
# gloss uses a single system installation directory for all files, to ease removal and upgrade. # a custom installation directory can be speficied as an argument to the installation scripts. # please note that custom directories are not well tested. install_prefix = '/usr/local' # parse arguments. if len(argv) > 2: exit('usage: optionally specify a custom installation prefix.') if len(argv) == 2: install_prefix = argv[1] check(' ' not in install_prefix, "installation prefix contains space.") # determine the gloss source directory. src_dir = abs_path(path_join(path_dir(argv[0]), '..')) check(is_dir(src_dir), 'bad source directory:', src_dir) dst_dir = path_join(install_prefix, 'gloss') uname = os_uname()[0].lower() if uname == 'darwin': platform = 'mac' elif uname == 'linux': with open('/etc/issue') as f: # get the first word from the issue string (e.g. 'Fedora') platform = f.readline().split()[0].lower() else: platform = uname.lower() errSL('src_dir:', src_dir)