ginger/macros/pkgctx/pkgctx.go

114 lines
2.8 KiB
Go
Raw Normal View History

2014-10-21 02:51:05 +00:00
package pkgctx
2014-10-24 18:10:07 +00:00
import (
"strings"
"github.com/mediocregopher/ginger/seq"
"github.com/mediocregopher/ginger/types"
)
const (
coreAbs = "github.com/mediocregopher/ginger/core"
coreAlias = "gingercore"
)
2014-10-21 02:51:05 +00:00
// PkgCtx is given to all macros and represents the package that they are being
// evaluated within.
type PkgCtx struct {
// Packages describes the external packages imported by this one. Each key
// is the absolute package path, the value is the alias for it (or empty
// string for no alias)
Packages map[string]string
2014-10-21 04:06:49 +00:00
// CallMap is a map used by Eval for making actual calls dynamically. The
2014-10-21 02:51:05 +00:00
// key is the string representation of the call to be used (for example,
// "fmt.Println") and must agree with the aliases being used in Packages.
// The value need not be set during actual compilation, but it is useful to
// use it during testing
2014-10-21 04:06:49 +00:00
CallMap map[string]interface{}
2014-10-21 02:51:05 +00:00
}
2014-10-24 18:10:07 +00:00
// 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
}