<reponame>bvberkum/oil<gh_stars>0
#!/usr/bin/env python2
"""
flag_gen.py
"""
from __future__ import print_function

import sys

from _devbuild.gen.runtime_asdl import flag_type_e, value_e
from core.pyerror import log
from frontend import args
from frontend import flag_def  # side effect: flags are defined!
from frontend import flag_spec
from mycpp.mylib import tagswitch
# This causes a circular build dependency!  That is annoying.
# builtin_comp -> core/completion -> pylib/{os_path,path_stat,...} -> posix_
#from osh import builtin_comp


def CString(s):
  # HACK for now
  assert '"' not in s, s
  assert '\\' not in s, s

  return '"%s"' % s


def Cpp(specs, header_f, cc_f):
  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__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]

      with tagswitch(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, flag_type_e.Enum):
          default_val = spec.defaults[field_name]
          with tagswitch(default_val) as case:
            if case(value_e.Undef):
              default_str = 'nullptr'
            elif case(value_e.Str):
              default_str = 'new Str("%s")' % default_val.s
            else:
              raise AssertionError()

          # 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
      ? %s
      : static_cast<value__Str*>(attrs->index(new Str("%s")))->s''' % (
              field_name, default_str, 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)

        else:
          raise AssertionError(typ)

    for i, field_name in enumerate(sorted(spec.fields)):
      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"

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
    plus_name = None
    defaults_name = None

    if spec.arity0:
      arity0_name = 'arity0_%d' % i
      c_strs = ', '.join(CString(s) for s in sorted(spec.arity0))
      cc_f.write('const char* %s[] = {%s, nullptr};\n' % (arity0_name, c_strs))

    if spec.arity1:
      arity1_name = 'arity1_%d' % i
      cc_f.write('SetToArg_c %s[] = {\n' % arity1_name)
      for name in sorted(spec.arity1):
        set_to_arg = spec.arity1[name]

        # Using an integer here
        # TODO: doesn't work for enum flag_type::Enum(...)
        f2 = set_to_arg.flag_type.tag_()

        cc_f.write('    {"%s", %s, %s},\n' % (name, f2, 'true' if set_to_arg.quit_parsing_flags else 'false'))
      #cc_f.write('SetToArg_c %s[] = {\n' % arity1_name)
      cc_f.write('''\
    {},
};
''')

    if spec.plus_flags:
      plus_name = 'plus_%d' % i
      c_strs = ', '.join(CString(s) for s in sorted(spec.plus_flags))
      cc_f.write('const char* %s[] = {%s, nullptr};\n' % (plus_name, c_strs))

    if spec.defaults:
      defaults_name = 'defaults_%d' % i
      cc_f.write('DefaultPair_c %s[] = {\n' % defaults_name)
      for name in sorted(spec.defaults):
        val = spec.defaults[name]
        if val.tag_() == value_e.Bool:
          d = 'True' if val.b else 'False'
        elif val.tag_() == value_e.Int:
          d = 'Undef'  # TODO: fix this.  Should be -1
        elif val.tag_() == value_e.Undef:
          d = 'Undef'

        # NOTE: 'osh' FlagSpecAndMore_ has default='nice' and default='abbrev-text'
        else:
          raise AssertionError(val)

        cc_f.write('    {%s, Default_c::%s},\n' % (CString(name), d))

      cc_f.write('''\
    {},
};
''')
    var_names.append((arity0_name, arity1_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 },\n' % (
      spec_name,
      names[0] or 'nullptr', 
      names[1] or 'nullptr', 
      names[2] or 'nullptr', 
      names[3] 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
    defaults_name = None

    if spec.actions_short:
      actions_short_name = 'short_%d' % i
      cc_f.write('Action_c %s[] = {\n' % actions_short_name)
      for name in sorted(spec.actions_short):
        action = spec.actions_short[name]
        log('%s %s', name, action)
        if isinstance(action, args.SetToArgAction):
          set_to_arg = action
          f2 = set_to_arg.flag_type.tag_()

          action_type = 'ActionType_c::SetToArg'
          cc_f.write('    {%s, "%s", %s, %s},\n' % (action_type, name, f2, 'true' if set_to_arg.quit_parsing_flags else 'false'))
        elif isinstance(action, args.SetToTrue):
          log('action %s', action.name)
      cc_f.write('''\
    {},
};

''')

    #if spec.actions_long:
    if 0:
      actions_long_name = 'long_%d' % i
      cc_f.write('Action_c %s[] = {\n' % actions_long_name)
      for name in sorted(spec.actions_long):
        action = spec.actions_long[name]
        if isinstance(action, args.SetToArgAction):
          a = action.action
          log('action %s %s', name, a.name)
        elif isinstance(action, args.SetToTrue):
          log('action %s %s', name, action.name)

    if spec.defaults:
      defaults_name = 'defaults_%d' % i
      cc_f.write('DefaultPair_c %s[] = {\n' % defaults_name)
      for name in sorted(spec.defaults):
        val = spec.defaults[name]
        if val.tag_() == value_e.Bool:
          d = 'True' if val.b else 'False'
        elif val.tag_() == value_e.Int:
          d = 'Undef'  # TODO: fix this.  Should be -1
        elif val.tag_() == value_e.Undef:
          d = 'Undef'

        # NOTE: 'osh' FlagSpecAndMore_ has default='nice' and default='abbrev-text'
        else:
          d = 'Undef'
          #raise AssertionError(val)

        cc_f.write('    {%s, Default_c::%s},\n' % (CString(name), d))

      cc_f.write('''\
    {},
};
''')

    var_names.append((actions_short_name, actions_long_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 },\n' % (
      spec_name,
      names[0] or 'nullptr', 
      names[1] or 'nullptr', 
      names[2] or 'nullptr', 
    ))

  cc_f.write("""\
    {},
};
""")

  cc_f.write("""\
}  // namespace arg_types
""")


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)

  log('--')
  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]

        with tagswitch(typ) as case:
          if case(flag_type_e.Bool):
            print('    self.%s = cast(value__Bool, attrs[%r]).b  # type: bool' % (
              field_name, field_name))

          # enums are strings for now
          elif case(flag_type_e.Str, flag_type_e.Enum):
            tmp = 'val%d' % i
            default_val = spec.defaults[field_name]
            with tagswitch(default_val) as case:
              if case(value_e.Undef):
                default_str = 'None'
              elif case(value_e.Str):
                default_str = '%r' % default_val.s
              else:
                raise AssertionError()
            print('    %s = attrs[%r]' % (tmp, field_name))
            print('    self.%s = %s if %s.tag_() == value_e.Undef else cast(value__Str, %s).s  # type: Optional[str]' % (field_name, default_str, 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))

          else:
            raise AssertionError(typ)

        i += 1

      print()

  else:
    raise RuntimeError('Invalid action %r' % action)


if __name__ == '__main__':
  try:
    main(sys.argv)
  except RuntimeError as e:
    print('FATAL: %s' % e, file=sys.stderr)
    sys.exit(1)

#!/usr/bin/env python2
"""
flag_gen.py
"""
from __future__ import print_function

import sys

from _devbuild.gen.runtime_asdl import flag_type_e, value_e
from core.pyerror import log
from frontend import args
from frontend import flag_def  # side effect: flags are defined!
from frontend import flag_spec
from mycpp.mylib import tagswitch
# This causes a circular build dependency!  That is annoying.
# builtin_comp -> core/completion -> pylib/{os_path,path_stat,...} -> posix_
#from osh import builtin_comp


def CString(s):
  # HACK for now
  assert '"' not in s, s
  assert '\\' not in s, s

  return '"%s"' % s


def Cpp(specs, header_f, cc_f):
  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__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]

      with tagswitch(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, flag_type_e.Enum):
          default_val = spec.defaults[field_name]
          with tagswitch(default_val) as case:
            if case(value_e.Undef):
              default_str = 'nullptr'
            elif case(value_e.Str):
              default_str = 'new Str("%s")' % default_val.s
            else:
              raise AssertionError()

          # 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
      ? %s
      : static_cast<value__Str*>(attrs->index(new Str("%s")))->s''' % (
              field_name, default_str, 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)

        else:
          raise AssertionError(typ)

    for i, field_name in enumerate(sorted(spec.fields)):
      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"

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
    plus_name = None
    defaults_name = None

    if spec.arity0:
      arity0_name = 'arity0_%d' % i
      c_strs = ', '.join(CString(s) for s in sorted(spec.arity0))
      cc_f.write('const char* %s[] = {%s, nullptr};\n' % (arity0_name, c_strs))

    if spec.arity1:
      arity1_name = 'arity1_%d' % i
      cc_f.write('SetToArg_c %s[] = {\n' % arity1_name)
      for name in sorted(spec.arity1):
        set_to_arg = spec.arity1[name]

        # Using an integer here
        # TODO: doesn't work for enum flag_type::Enum(...)
        f2 = set_to_arg.flag_type.tag_()

        cc_f.write('    {"%s", %s, %s},\n' % (name, f2, 'true' if set_to_arg.quit_parsing_flags else 'false'))
      #cc_f.write('SetToArg_c %s[] = {\n' % arity1_name)
      cc_f.write('''\
    {},
};
''')

    if spec.plus_flags:
      plus_name = 'plus_%d' % i
      c_strs = ', '.join(CString(s) for s in sorted(spec.plus_flags))
      cc_f.write('const char* %s[] = {%s, nullptr};\n' % (plus_name, c_strs))

    if spec.defaults:
      defaults_name = 'defaults_%d' % i
      cc_f.write('DefaultPair_c %s[] = {\n' % defaults_name)
      for name in sorted(spec.defaults):
        val = spec.defaults[name]
        if val.tag_() == value_e.Bool:
          d = 'True' if val.b else 'False'
        elif val.tag_() == value_e.Int:
          d = 'Undef'  # TODO: fix this.  Should be -1
        elif val.tag_() == value_e.Undef:
          d = 'Undef'

        # NOTE: 'osh' FlagSpecAndMore_ has default='nice' and default='abbrev-text'
        else:
          raise AssertionError(val)

        cc_f.write('    {%s, Default_c::%s},\n' % (CString(name), d))

      cc_f.write('''\
    {},
};
''')
    var_names.append((arity0_name, arity1_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 },\n' % (
      spec_name,
      names[0] or 'nullptr', 
      names[1] or 'nullptr', 
      names[2] or 'nullptr', 
      names[3] 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
    defaults_name = None

    if spec.actions_short:
      actions_short_name = 'short_%d' % i
      cc_f.write('Action_c %s[] = {\n' % actions_short_name)
      for name in sorted(spec.actions_short):
        action = spec.actions_short[name]
        log('%s %s', name, action)
        if isinstance(action, args.SetToArgAction):
          set_to_arg = action
          f2 = set_to_arg.flag_type.tag_()

          action_type = 'ActionType_c::SetToArg'
          cc_f.write('    {%s, "%s", %s, %s},\n' % (action_type, name, f2, 'true' if set_to_arg.quit_parsing_flags else 'false'))
        elif isinstance(action, args.SetToTrue):
          log('action %s', action.name)
      cc_f.write('''\
    {},
};

''')

    #if spec.actions_long:
    if 0:
      actions_long_name = 'long_%d' % i
      cc_f.write('Action_c %s[] = {\n' % actions_long_name)
      for name in sorted(spec.actions_long):
        action = spec.actions_long[name]
        if isinstance(action, args.SetToArgAction):
          a = action.action
          log('action %s %s', name, a.name)
        elif isinstance(action, args.SetToTrue):
          log('action %s %s', name, action.name)

    if spec.defaults:
      defaults_name = 'defaults_%d' % i
      cc_f.write('DefaultPair_c %s[] = {\n' % defaults_name)
      for name in sorted(spec.defaults):
        val = spec.defaults[name]
        if val.tag_() == value_e.Bool:
          d = 'True' if val.b else 'False'
        elif val.tag_() == value_e.Int:
          d = 'Undef'  # TODO: fix this.  Should be -1
        elif val.tag_() == value_e.Undef:
          d = 'Undef'

        # NOTE: 'osh' FlagSpecAndMore_ has default='nice' and default='abbrev-text'
        else:
          d = 'Undef'
          #raise AssertionError(val)

        cc_f.write('    {%s, Default_c::%s},\n' % (CString(name), d))

      cc_f.write('''\
    {},
};
''')

    var_names.append((actions_short_name, actions_long_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 },\n' % (
      spec_name,
      names[0] or 'nullptr', 
      names[1] or 'nullptr', 
      names[2] or 'nullptr', 
    ))

  cc_f.write("""\
    {},
};
""")

  cc_f.write("""\
}  // namespace arg_types
""")


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)

  log('--')
  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]

        with tagswitch(typ) as case:
          if case(flag_type_e.Bool):
            print('    self.%s = cast(value__Bool, attrs[%r]).b  # type: bool' % (
              field_name, field_name))

          # enums are strings for now
          elif case(flag_type_e.Str, flag_type_e.Enum):
            tmp = 'val%d' % i
            default_val = spec.defaults[field_name]
            with tagswitch(default_val) as case:
              if case(value_e.Undef):
                default_str = 'None'
              elif case(value_e.Str):
                default_str = '%r' % default_val.s
              else:
                raise AssertionError()
            print('    %s = attrs[%r]' % (tmp, field_name))
            print('    self.%s = %s if %s.tag_() == value_e.Undef else cast(value__Str, %s).s  # type: Optional[str]' % (field_name, default_str, 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))

          else:
            raise AssertionError(typ)

        i += 1

      print()

  else:
    raise RuntimeError('Invalid action %r' % action)


if __name__ == '__main__':
  try:
    main(sys.argv)
  except RuntimeError as e:
    print('FATAL: %s' % e, file=sys.stderr)
    sys.exit(1)
#!/usr/bin/env python2 flag_gen.py # side effect: flags are defined! # This causes a circular build dependency!  That is annoying. # builtin_comp -> core/completion -> pylib/{os_path,path_stat,...} -> posix_ #from osh import builtin_comp # HACK for now \ // 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__Str;  namespace arg_types { # skip empty 'eval' spec class %s {  public:   %s(Dict<Str*, runtime_asdl::value_t*>* attrs) : # TODO: This code is ugly and inefficient!  Generate something # better.  At least get rid of 'new' everywhere? \ attrs->index(new Str("%s"))->tag_() == value_e::Undef       ? %s       : static_cast<value__Str*>(attrs->index(new Str("%s")))->s \ attrs->index(new Str("%s"))->tag_() == value_e::Undef       ? -1       : static_cast<value__Int*>(attrs->index(new Str("%s")))->i \ }; extern FlagSpec_c kFlagSpecs[]; extern FlagSpecAndMore_c kFlagSpecsAndMore[];  }  // namespace arg_types  #endif  // ARG_TYPES_H \ // arg_types.cc is generated by frontend/flag_gen.py  #include "arg_types.h"  namespace arg_types { # Using an integer here # TODO: doesn't work for enum flag_type::Enum(...) #cc_f.write('SetToArg_c %s[] = {\n' % arity1_name) \     {}, }; # TODO: fix this.  Should be -1 # NOTE: 'osh' FlagSpecAndMore_ has default='nice' and default='abbrev-text' \     {}, }; # Now print a table \     {}, }; \     {}, }; #if spec.actions_long: # TODO: fix this.  Should be -1 # NOTE: 'osh' FlagSpecAndMore_ has default='nice' and default='abbrev-text' #raise AssertionError(val) \     {}, }; \     {}, }; \ }  // namespace arg_types # Both kinds of specs have 'fields' attributes #spec.spec.PrettyPrint(f=sys.stderr) #log('spec.arity1 %s', spec.spec.arity1) #print(dir(spec)) #print(spec.arity0) #print(spec.arity1) #print(spec.options) # Every flag has a default #log('%s', spec.fields) 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 #log('%s spec.fields %s', spec_name, spec.fields) # skip empty specs, e.g. eval class %s(object):   def __init__(self, attrs):     # type: (Dict[str, value_t]) -> None # type: bool' % ( # enums are strings for now # type: Optional[str]' % (field_name, default_str, tmp, tmp)) # type: int' % (field_name, tmp, tmp))