def main(argv): try: action = argv[1] except IndexError: raise RuntimeError('Action required') if 0: for spec_name in sorted(flag_spec.FLAG_SPEC_AND_MORE): log('%s', spec_name) # Both kinds of specs have 'fields' attributes specs = {} specs.update(flag_spec.FLAG_SPEC) specs.update(flag_spec.FLAG_SPEC_AND_MORE) for spec_name in sorted(specs): spec = specs[spec_name] #spec.spec.PrettyPrint(f=sys.stderr) #log('spec.arity1 %s', spec.spec.arity1) #log('%s', spec_name) #print(dir(spec)) #print(spec.arity0) #print(spec.arity1) #print(spec.options) # Every flag has a default #log('%s', spec.fields) if action == 'cpp': prefix = argv[2] with open(prefix + '.h', 'w') as header_f: with open(prefix + '.cc', 'w') as cc_f: Cpp(specs, header_f, cc_f) elif action == 'mypy': print(""" from frontend.args import _Attributes from _devbuild.gen.runtime_asdl import ( value, value_e, value_t, value__Bool, value__Int, value__Float, value__Str, ) from typing import cast, Dict, Optional """) for spec_name in sorted(specs): spec = specs[spec_name] #log('%s spec.fields %s', spec_name, spec.fields) if not spec.fields: continue # skip empty specs, e.g. eval print(""" class %s(object): def __init__(self, attrs): # type: (Dict[str, value_t]) -> None """ % spec_name) i = 0 for field_name in sorted(spec.fields): typ = spec.fields[field_name] field_name = field_name.replace('-', '_') with switch(typ) as case: if case(flag_type_e.Bool): print(' self.%s = cast(value__Bool, attrs[%r]).b # type: bool' % ( field_name, field_name)) elif case(flag_type_e.Str): tmp = 'val%d' % i print(' %s = attrs[%r]' % (tmp, field_name)) print(' self.%s = None if %s.tag_() == value_e.Undef else cast(value__Str, %s).s # type: Optional[str]' % (field_name, tmp, tmp)) elif case(flag_type_e.Int): tmp = 'val%d' % i print(' %s = attrs[%r]' % (tmp, field_name)) print(' self.%s = -1 if %s.tag_() == value_e.Undef else cast(value__Int, %s).i # type: int' % (field_name, tmp, tmp)) elif case(flag_type_e.Float): tmp = 'val%d' % i print(' %s = attrs[%r]' % (tmp, field_name)) print(' self.%s = -1.0 if %s.tag_() == value_e.Undef else cast(value__Float, %s).f # type: float' % (field_name, tmp, tmp)) else: raise AssertionError(typ) i += 1 print() else: raise RuntimeError('Invalid action %r' % action)
def EvalB(self, node): # type: (bool_expr_t) -> bool UP_node = node with tagswitch(node) as case: if case(bool_expr_e.WordTest): node = cast(bool_expr__WordTest, UP_node) s = self._EvalCompoundWord(node.w) return bool(s) elif case(bool_expr_e.LogicalNot): node = cast(bool_expr__LogicalNot, UP_node) b = self.EvalB(node.child) return not b elif case(bool_expr_e.LogicalAnd): node = cast(bool_expr__LogicalAnd, UP_node) # Short-circuit evaluation if self.EvalB(node.left): return self.EvalB(node.right) else: return False elif case(bool_expr_e.LogicalOr): node = cast(bool_expr__LogicalOr, UP_node) if self.EvalB(node.left): return True else: return self.EvalB(node.right) elif case(bool_expr_e.Unary): node = cast(bool_expr__Unary, UP_node) op_id = node.op_id s = self._EvalCompoundWord(node.child) # Now dispatch on arg type arg_type = consts.BoolArgType( op_id) # could be static in the LST? if arg_type == bool_arg_type_e.Path: return bool_stat.DoUnaryOp(op_id, s) if arg_type == bool_arg_type_e.Str: if op_id == Id.BoolUnary_z: return not bool(s) if op_id == Id.BoolUnary_n: return bool(s) raise AssertionError(op_id) # should never happen if arg_type == bool_arg_type_e.Other: if op_id == Id.BoolUnary_t: return bool_stat.isatty(s, node.child) # See whether 'set -o' options have been set if op_id == Id.BoolUnary_o: index = match.MatchOption(s) if index == 0: return False else: return self.exec_opts.opt0_array[index] if op_id == Id.BoolUnary_v: val = self.mem.GetVar(s) return val.tag_() != value_e.Undef e_die("%s isn't implemented", ui.PrettyId(op_id)) # implicit location raise AssertionError(arg_type) elif case(bool_expr_e.Binary): node = cast(bool_expr__Binary, UP_node) op_id = node.op_id # Whether to glob escape with switch(op_id) as case2: if case2(Id.BoolBinary_GlobEqual, Id.BoolBinary_GlobDEqual, Id.BoolBinary_GlobNEqual): quote_kind = quote_e.FnMatch elif case2(Id.BoolBinary_EqualTilde): quote_kind = quote_e.ERE else: quote_kind = quote_e.Default s1 = self._EvalCompoundWord(node.left) s2 = self._EvalCompoundWord(node.right, quote_kind=quote_kind) # Now dispatch on arg type arg_type = consts.BoolArgType(op_id) if arg_type == bool_arg_type_e.Path: return bool_stat.DoBinaryOp(op_id, s1, s2) if arg_type == bool_arg_type_e.Int: # NOTE: We assume they are constants like [[ 3 -eq 3 ]]. # Bash also allows [[ 1+2 -eq 3 ]]. i1 = self._StringToIntegerOrError(s1, blame_word=node.left) i2 = self._StringToIntegerOrError(s2, blame_word=node.right) if op_id == Id.BoolBinary_eq: return i1 == i2 if op_id == Id.BoolBinary_ne: return i1 != i2 if op_id == Id.BoolBinary_gt: return i1 > i2 if op_id == Id.BoolBinary_ge: return i1 >= i2 if op_id == Id.BoolBinary_lt: return i1 < i2 if op_id == Id.BoolBinary_le: return i1 <= i2 raise AssertionError(op_id) # should never happen if arg_type == bool_arg_type_e.Str: if op_id in (Id.BoolBinary_GlobEqual, Id.BoolBinary_GlobDEqual): #log('Matching %s against pattern %s', s1, s2) return libc.fnmatch(s2, s1, self.exec_opts.extglob()) if op_id == Id.BoolBinary_GlobNEqual: return not libc.fnmatch(s2, s1, self.exec_opts.extglob()) if op_id in (Id.BoolBinary_Equal, Id.BoolBinary_DEqual): return s1 == s2 if op_id == Id.BoolBinary_NEqual: return s1 != s2 if op_id == Id.BoolBinary_EqualTilde: # TODO: This should go to --debug-file #log('Matching %r against regex %r', s1, s2) try: matches = libc.regex_match(s2, s1) except RuntimeError as e: # Status 2 indicates a regex parse error. This is fatal in OSH but # not in bash, which treats [[ like a command with an exit code. msg = e.message # type: str e_die("Invalid regex %r: %s", s2, msg, word=node.right, status=2) if matches is None: return False self._SetRegexMatches(matches) return True if op_id == Id.Op_Less: return str_cmp(s1, s2) < 0 if op_id == Id.Op_Great: return str_cmp(s1, s2) > 0 raise AssertionError(op_id) # should never happen raise AssertionError(node.tag_())
def Cpp(specs, header_f, cc_f): counter = itertools.count() header_f.write("""\ // arg_types.h is generated by frontend/flag_gen.py #ifndef ARG_TYPES_H #define ARG_TYPES_H #include "frontend_flag_spec.h" // for FlagSpec_c #include "mylib.h" namespace value_e = runtime_asdl::value_e; using runtime_asdl::value__Bool; using runtime_asdl::value__Int; using runtime_asdl::value__Float; using runtime_asdl::value__Str; namespace arg_types { """) for spec_name in sorted(specs): spec = specs[spec_name] if not spec.fields: continue # skip empty 'eval' spec header_f.write(""" class %s { public: %s(Dict<Str*, runtime_asdl::value_t*>* attrs) : """ % (spec_name, spec_name)) init_vals = [] field_decls = [] for field_name in sorted(spec.fields): typ = spec.fields[field_name] field_name = field_name.replace('-', '_') with switch(typ) as case: if case(flag_type_e.Bool): init_vals.append('static_cast<value__Bool*>(attrs->index(new Str("%s")))->b' % field_name) field_decls.append('bool %s;' % field_name) elif case(flag_type_e.Str): # TODO: This code is ugly and inefficient! Generate something # better. At least get rid of 'new' everywhere? init_vals.append('''\ attrs->index(new Str("%s"))->tag_() == value_e::Undef ? nullptr : static_cast<value__Str*>(attrs->index(new Str("%s")))->s''' % ( field_name, field_name)) field_decls.append('Str* %s;' % field_name) elif case(flag_type_e.Int): init_vals.append('''\ attrs->index(new Str("%s"))->tag_() == value_e::Undef ? -1 : static_cast<value__Int*>(attrs->index(new Str("%s")))->i''' % (field_name, field_name)) field_decls.append('int %s;' % field_name) elif case(flag_type_e.Float): init_vals.append('''\ attrs->index(new Str("%s"))->tag_() == value_e::Undef ? -1 : static_cast<value__Float*>(attrs->index(new Str("%s")))->f''' % (field_name, field_name)) field_decls.append('float %s;' % field_name) else: raise AssertionError(typ) for i, field_name in enumerate(sorted(spec.fields)): field_name = field_name.replace('-', '_') if i != 0: header_f.write(',\n') header_f.write(' %s(%s)' % (field_name, init_vals[i])) header_f.write(' {\n') header_f.write(' }\n') for decl in field_decls: header_f.write(' %s\n' % decl) header_f.write("""\ }; """) header_f.write(""" extern FlagSpec_c kFlagSpecs[]; extern FlagSpecAndMore_c kFlagSpecsAndMore[]; } // namespace arg_types #endif // ARG_TYPES_H """) cc_f.write("""\ // arg_types.cc is generated by frontend/flag_gen.py #include "arg_types.h" using runtime_asdl::flag_type_e; namespace arg_types { """) var_names = [] for i, spec_name in enumerate(sorted(flag_spec.FLAG_SPEC)): spec = specs[spec_name] arity0_name = None arity1_name = None actions_long_name = None plus_name = None defaults_name = None if spec.arity0: arity0_name = 'arity0_%d' % i _WriteStrArray(cc_f, arity0_name, spec.arity0) if spec.arity1: arity1_name = 'arity1_%d' % i _WriteActions(cc_f, arity1_name, spec.arity1, counter) if spec.actions_long: actions_long_name = 'actions_long_%d' % i _WriteActions(cc_f, actions_long_name, spec.actions_long, counter) if spec.plus_flags: plus_name = 'plus_%d' % i _WriteStrArray(cc_f, plus_name, spec.plus_flags) if spec.defaults: defaults_name = 'defaults_%d' % i _WriteDefaults(cc_f, defaults_name, spec.defaults) var_names.append( (arity0_name, arity1_name, actions_long_name, plus_name, defaults_name) ) cc_f.write('\n') cc_f.write('FlagSpec_c kFlagSpecs[] = {\n') # Now print a table for i, spec_name in enumerate(sorted(flag_spec.FLAG_SPEC)): spec = specs[spec_name] names = var_names[i] cc_f.write(' { "%s", %s, %s, %s, %s, %s },\n' % ( spec_name, names[0] or 'nullptr', names[1] or 'nullptr', names[2] or 'nullptr', names[3] or 'nullptr', names[4] or 'nullptr', )) cc_f.write("""\ {}, }; """) var_names = [] for i, spec_name in enumerate(sorted(flag_spec.FLAG_SPEC_AND_MORE)): spec = specs[spec_name] actions_short_name = None actions_long_name = None plus_name = None defaults_name = None if spec.actions_short: actions_short_name = 'short_%d' % i _WriteActions(cc_f, actions_short_name, spec.actions_short, counter) #if spec.actions_long: if spec.actions_long: actions_long_name = 'long_%d' % i _WriteActions(cc_f, actions_long_name, spec.actions_long, counter) if spec.plus_flags: plus_name = 'plus_%d' % i _WriteStrArray(cc_f, plus_name, spec.plus_flags) if spec.defaults: defaults_name = 'defaults_%d' % i _WriteDefaults(cc_f, defaults_name, spec.defaults) var_names.append((actions_short_name, actions_long_name, plus_name, defaults_name)) cc_f.write('FlagSpecAndMore_c kFlagSpecsAndMore[] = {\n') for i, spec_name in enumerate(sorted(flag_spec.FLAG_SPEC_AND_MORE)): names = var_names[i] cc_f.write(' { "%s", %s, %s, %s, %s },\n' % ( spec_name, names[0] or 'nullptr', names[1] or 'nullptr', names[2] or 'nullptr', names[3] or 'nullptr', )) cc_f.write("""\ {}, }; """) cc_f.write("""\ } // namespace arg_types """)