diff --git a/macros/pkgctx/pkgctx.go b/macros/pkgctx/pkgctx.go index 65c828e..6c87329 100644 --- a/macros/pkgctx/pkgctx.go +++ b/macros/pkgctx/pkgctx.go @@ -1,5 +1,17 @@ package pkgctx +import ( + "strings" + + "github.com/mediocregopher/ginger/seq" + "github.com/mediocregopher/ginger/types" +) + +const ( + coreAbs = "github.com/mediocregopher/ginger/core" + coreAlias = "gingercore" +) + // PkgCtx is given to all macros and represents the package that they are being // evaluated within. type PkgCtx struct { @@ -16,3 +28,86 @@ type PkgCtx struct { // use it during testing CallMap map[string]interface{} } + +// Returns an empty PkgCtx +func New() *PkgCtx { + return &PkgCtx{ + Packages: map[string]string{}, + CallMap: map[string]interface{}{}, + } +} + +// A returns a new PkgCtx, which is a copy of a merge between p and p2. p2's +// keys overwrite any conflicting keys in p. p and p2 are unaffected by this +// operation +func (p *PkgCtx) MergeLeft(p2 *PkgCtx) *PkgCtx { + p3 := New() + for pkg := range p.Packages { + p3.Packages[pkg] = p.Packages[pkg] + } + for pkg := range p2.Packages { + p3.Packages[pkg] = p2.Packages[pkg] + } + for fn := range p.CallMap { + p3.CallMap[fn] = p.CallMap[fn] + } + for fn := range p2.CallMap { + p3.CallMap[fn] = p2.CallMap[fn] + } + return p3 +} + +// Returns a copy of p +func (p *PkgCtx) Copy() *PkgCtx { + return p.MergeLeft(New()) +} + +func (p *PkgCtx) PopulateFromCode(el types.Elem) bool { + if s, ok := el.(seq.Seq); ok { + return seq.Traverse(p.PopulateFromCode, s) + } + + gt, ok := el.(types.GoType) + if !ok { + return true + } + + str, ok := gt.V.(string) + if !ok { + return true + } + + if len(str) < 2 { + return true + } + + if str[0] != ':' { + return true + } + str = str[1:] + + // At this point str is a reference to something. We check if it's already + // pointing somewhere first + if _, ok = p.CallMap[str]; ok { + return true + } + + // If there isn't a '.' in the string, it's not directly referencing another + // package. Since it isn't in this context either, it must be referencing + // something in core + var i int + if i = strings.IndexRune(str, '.'); i < 1 { + p.Packages[coreAbs] = coreAlias + p.CallMap[str] = nil + + // TODO there needs to be a CodeGen interface or something. The + // CallMap's value type needs to be that, because in all likelyhood the + // CallMap will be directly translated to a map variable in the + // generated package, with the values being different depending on what + // they're being used for (external functions will be references to + // those functions, local variables may just end up being just GoType's + // of the actual value. + } + + return true +}