make Ctx operations immutable

This commit is contained in:
Brian Picciano 2016-08-07 09:06:46 -06:00
parent ae11b55653
commit 2433e4a175
3 changed files with 42 additions and 39 deletions

View File

@ -23,13 +23,7 @@ func (bctx BuildCtx) Build(stmts ...Statement) llvm.Value {
func (bctx BuildCtx) BuildStmt(s Statement) Expr {
m := s.Op.(Macro)
fn := bctx.C.GetMacro(m)
if fn == nil {
panicf("unknown macro: %q", m)
}
return fn(bctx, s.Arg)
return bctx.C.Macro(m)(bctx, s.Arg)
}
// may return nil if e is a Statement which has no return
@ -50,10 +44,7 @@ func (bctx BuildCtx) buildExprTill(e Expr, fn func(e Expr) bool) Expr {
case Int:
return llvmVal(llvm.ConstInt(llvm.Int64Type(), uint64(ea), false))
case Identifier:
if ev := bctx.C.GetIdentifier(ea); ev != nil {
return ev
}
panicf("identifier %q not found", ea)
return bctx.C.Identifier(ea)
case Statement:
return bctx.BuildStmt(ea)
case Tuple:
@ -85,10 +76,7 @@ var globalCtx = &Ctx{
"bind": func(bctx BuildCtx, e Expr) Expr {
tup := bctx.buildExprTill(e, isIdentifier).(Tuple)
id := bctx.buildExprTill(tup[0], isIdentifier).(Identifier)
if bctx.C.idents[id] != nil {
panicf("identifier %q is already bound", id)
}
bctx.C.idents[id] = bctx.buildExpr(tup[1])
*bctx.C = bctx.C.Bind(id, bctx.buildExpr(tup[1]))
return nil
},
},

View File

@ -14,17 +14,17 @@ type Ctx struct {
}
// NewCtx returns a blank context instance
func NewCtx() *Ctx {
return &Ctx{
func NewCtx() Ctx {
return Ctx{
global: globalCtx,
macros: map[Macro]MacroFn{},
idents: map[Identifier]Expr{},
}
}
// GetMacro returns the MacroFn associated with the given identifier, or panics
// Macro returns the MacroFn associated with the given identifier, or panics
// if the macro isn't found
func (c *Ctx) GetMacro(m Macro) MacroFn {
func (c Ctx) Macro(m Macro) MacroFn {
if fn := c.macros[m]; fn != nil {
return fn
}
@ -35,25 +35,39 @@ func (c *Ctx) GetMacro(m Macro) MacroFn {
return nil
}
// GetIdentifier returns the llvm.Value for the Identifier, or panics
func (c *Ctx) GetIdentifier(i Identifier) Expr {
// Identifier returns the llvm.Value for the Identifier, or panics
func (c Ctx) Identifier(i Identifier) Expr {
if e := c.idents[i]; e != nil {
return e
}
// The global context doesn't have any identifiers, so don't bother checking
return c.idents[i]
panicf("identifier %q not found", i)
panic("go is dumb")
}
// NewWith returns a new Ctx instance which imports the given macros from the
// parent
//func (c *Ctx) NewWith(mm ...Macro) *Ctx {
// nc := &Ctx{
// global: c.global,
// macros: map[Macro]MacroFn{},
// }
// for _, m := range mm {
// fn := c.macros[m]
// if fn == nil {
// panicf("no macro %q found in context", m)
// }
// nc.macros[m] = fn
// }
// return nc
//}
func (c Ctx) cp() Ctx {
cc := Ctx{
global: c.global,
macros: make(map[Macro]MacroFn, len(c.macros)),
idents: make(map[Identifier]Expr, len(c.idents)),
}
for m, mfn := range c.macros {
cc.macros[m] = mfn
}
for i, e := range c.idents {
cc.idents[i] = e
}
return cc
}
// Bind returns a new Ctx which is a copy of this one, but with the given
// Identifier bound to the given Expr. Will panic if the Identifier is already
// bound
func (c Ctx) Bind(i Identifier, e Expr) Ctx {
if _, ok := c.idents[i]; ok {
panicf("identifier %q is already bound", i)
}
c = c.cp()
c.idents[i] = e
return c
}

View File

@ -22,8 +22,9 @@ func main() {
llvm.InitializeNativeAsmPrinter()
// setup our context, builder, and module
ctx := expr.NewCtx()
bctx := expr.BuildCtx{
C: expr.NewCtx(),
C: &ctx,
B: llvm.NewBuilder(),
M: llvm.NewModule("my_module"),
}