def run() -> Module: r = get_resolver() m = Module(indent="\t") classes = [Person, Person2] for item in walk(classes): m.stmt(f"type {goname(item.cls.__name__)} struct {{") with m.scope(): for name, typeinfo, _metadata in item.fields: metadata = t.cast(Metadata, _metadata) if metadata.get("default") == MISSING: metadata.pop("default") try: gotype = r.resolve_gotype( typeinfo.normalized) # todo: pointer except KeyError: gotype = goname(typeinfo.normalized.__name__) if metadata.get("pointer", False): gotype = f"*{gotype}" if metadata.get("inline", False): m.append(gotype) else: m.append(f"{goname(name)} {gotype}") if metadata: m.stmt(f" // {metadata}") else: m.stmt("") m.stmt("}") m.sep() return m
def __init__( self, classes: t.List[t.Type[t.Any]], *, m: Module, metadata_handler: metadata_.MetadataHandlerFunction, ) -> None: from egoist.go.resolver import get_resolver self.m = m self.resolver = get_resolver(m) self.ctx = Context( m=m, resolver=self.resolver, _metadata_handler=metadata_handler, ) self._walker = self.ctx.get_metashape_walker(classes)
def emit(classes: t.List[t.Type[t.Any]], *, name: str = "main") -> Module: m = gofile(name) r = get_resolver(m) for item in walk(classes): if item.is_union: emit_union(m, item, resolver=r) m.sep() else: emit_struct(m, item, resolver=r) m.sep() if item.fields: emit_unmarshalJSON(m, item, resolver=r) m.sep() with m.func("main"): pass return m
def run() -> Module: r = get_resolver() m = gofile("main") classes = [Person, Person2] for item in walk(classes): gopackage = get_gopackage(item.cls) if gopackage is not None: continue m.stmt(f"type {goname(item.cls.__name__)} struct {{") with m.scope(): for name, typeinfo, _metadata in item.fields: metadata = t.cast(Metadata, _metadata) if metadata.get("default") == MISSING: metadata.pop("default") typ = typeinfo.raw if metadata.get("pointer", False): typ = t.Optional[typ] gotype: str = r.resolve_gotype(typ) gopackage = get_gopackage( typeinfo.normalized) # todo: support composite if gopackage is not None: gotype = f"{m.import_(gopackage)}.{gotype}" if metadata.get("inline", False): m.append(gotype) else: m.append(f"{goname(name)} {gotype}") if metadata: m.stmt(f" // {metadata}") else: m.stmt("") m.stmt("}") m.sep() return m
def clikit( env: Env, dry_run: bool, *, resolver: t.Optional[Resolver] = None, option_prefix: str = _PREFIX_DEFAULT, ) -> t.Iterator[Module]: if dry_run: logger.debug("dry run, %s skipped", __name__) yield env.m return from egoist.runtime import _REST_ARGS_NAME # xxx from egoist.internal.prestringutil import goname from egoist.go.resolver import get_resolver m = env.m fn = env.fn spec = env.fnspec if len(spec.arguments) > 0: logger.info("%s(), positional arguments are ignored", fn.__name__) resolver = resolver or get_resolver(m) opt = m.symbol(option_prefix) description = None doc = inspect.getdoc(fn) if doc is not None: description = f"{env.fnspec.shortname} - {doc}" # TODO: support normal arguments m.package("main") m.import_("") m.stmt(f"// this file is generated by {__name__}") m.sep() m.stmt("// Option ...") with m.struct("Option"): for name, typ, kind in spec.keyword_arguments: m.stmt(f"{goname(name)} {resolver.resolve_gotype(typ)} // for `-{name}`") # NOTE: accessable via runtime.get_cli_rest_args() m.stmt(f"{goname(_REST_ARGS_NAME)} []string // cmd.Args") m.sep() with m.func("main"): m.stmt(f"{opt} := &Option{{}}") m.import_("flag") # import: m.stmt( 'cmd := flag.NewFlagSet("{}", flag.ContinueOnError)', env.fnspec.shortname, ) if description is not None: m.stmt("cmd.Usage = func() {") with m.scope(): m.import_("fmt") # import: m.stmt(f"fmt.Fprintln(cmd.Output(), `{description}`)") m.stmt('fmt.Fprintln(cmd.Output(), "")') m.stmt('fmt.Fprintln(cmd.Output(), "Usage:")') m.stmt("cmd.PrintDefaults()") m.append("}") m.sep() for name, typ, kind in spec.keyword_arguments: arg = getattr(env.args, name) parse_method = resolver.resolve_parse_method(typ) help_usage = resolver.resolve_default(str, arg.help or "-") default = resolver.resolve_default(typ, arg.default) m.stmt( f'cmd.{parse_method}(&{opt}.{goname(name)}, "{name}", {default}, {help_usage})' ) m.sep() m.import_("os") # import: m.stmt("if err := cmd.Parse(os.Args[1:]); err != nil {") with m.scope(): m.stmt("if err != flag.ErrHelp {") with m.scope(): m.stmt("cmd.Usage()") m.stmt("}") m.stmt("os.Exit(1)") m.stmt("}") m.stmt(f"{opt}.Args = cmd.Args()") m.stmt(f"if err := run({opt}); err != nil {{") with m.scope(): m.import_("log") # import: m.stmt('log.Fatalf("!!%+v", err)') m.stmt("}") with m.func("run", f"{opt} *Option", returns="error"): m.stmt("// generated by `with runtime.generate(clikit): ...`") yield m if spec.return_type == type(None): # noqa: E721 m.return_("nil")
def emit(classes: t.List[t.Type[t.Any]]) -> Module: m = gofile("main") r = get_resolver(m) for item in walk(classes): this = m.symbol(f"{item.type_.__name__[0].lower()}") this_type = f"{r.resolve_gotype(item.type_)}" this_type_pointer = f"*{this_type}" # func (ob *Ob) UnmarshalJSON(b []byte) error { b = m.symbol("b") m.stmt( f"func ({this} {this_type_pointer}) UnmarshalJSON({b} []byte) error {{" ) with m.scope(): # var err *maperr.Error err = m.symbol("err") maperr_pkg = m.import_("github.com/podhmo/maperr") m.stmt(f"var {err} *{maperr_pkg}.Error") m.sep() # var inner struct { # ... # } m.stmt("// loading internal data") inner = m.symbol("inner") m.stmt(f"var {inner} struct {{") with m.scope(): for name, typeinfo, metadata in item.fields: if name.startswith("_"): continue # xxx: gotype: str = r.resolve_gotype(typeinfo.raw) m.append(f'{goname(name)} *{gotype} `json:"{name}"`') m.stmt("// required" if metadata["required"] else "") m.stmt("}") # if rawErr := json.Unmarshal(b, &inner); rawErr != nil { # ... # } json_pkg = m.import_("encoding/json") raw_err = m.symbol("rawErr") with m.if_( f"{raw_err} := {json_pkg}.Unmarshal(b, &{inner}); {raw_err} != nil" ): m.return_(err.addSummary(raw_err.Error())) m.sep() # if <field> != nil { # ob.<field> = *<field> # } else { # m.add(<field>, "required") # } m.stmt("// binding field value and required check") for name, typeinfo, metadata in item.fields: field = m.symbol(goname(name)) with m.if_(f"{inner}.{field} != nil"): m.stmt(f"{this}.{field} = *{inner}.{field}") if metadata["required"]: with m.else_(): m.stmt(f'{err} = err.Add("{name}", "required")') m.sep() # return err.Untyped() m.return_(err.Untyped()) m.stmt("}") return m
import typing as t from prestring.go.codeobject import gofile from egoist.go.resolver import get_resolver from emit import emit_enums Op = t.Literal["add", "sub", "mul"] Op.__name__ = "Op" m = gofile("main") resolver = get_resolver(m) emit_enums(m, Op, resolver=resolver, name="op") print(m)
from __future__ import annotations from prestring.text import Module from prestring.go import goname from egoist.go.resolver import get_resolver from walker import walk class Person: name: str age: int info: Info class Info: memo: str r = get_resolver() m = Module(indent="\t") for item in walk([Person]): m.stmt(f"type {goname(item.cls.__name__)} struct {{") with m.scope(): for name, typeinfo, metadata in item.fields: gotype = r.resolve_gotype(typeinfo.normalized) # todo: pointer m.stmt(f"{goname(name)} {gotype}") m.stmt("}") print(m)