implement basic context

This commit is contained in:
Brian Picciano 2016-07-28 18:39:18 -06:00
parent 63fead5d8b
commit 6595d291c1
4 changed files with 59 additions and 29 deletions

24
expr/ctx.go Normal file
View File

@ -0,0 +1,24 @@
package expr
// Ctx contains all the Macros and Identifiers available. A Ctx is based on the
// parent it was created from. If the current Ctx doesn't have a particular key
// being looked up, the parent is called instead, and so on. A consequence of
// this is that keys in the children take precedence over the parent's
type Ctx struct {
Parent *Ctx
Macros map[Macro]func(Expr) (Expr, error)
}
// GetMacro returns the first instance of the given of the given Macro found. If
// not found nil is returned.
func (c *Ctx) GetMacro(m Macro) func(Expr) (Expr, error) {
if c.Macros != nil {
if fn, ok := c.Macros[m]; ok {
return fn
}
}
if c.Parent != nil {
return c.Parent.GetMacro(m)
}
return nil
}

View File

@ -19,7 +19,7 @@ import (
// information, like the token to which Actual was originally parsed from // information, like the token to which Actual was originally parsed from
type Actual interface { type Actual interface {
// Initializes an llvm.Value and returns it. // Initializes an llvm.Value and returns it.
LLVMVal(llvm.Builder) llvm.Value LLVMVal(*Ctx, llvm.Builder) llvm.Value
} }
// equaler is used to compare two expressions. The comparison should not take // equaler is used to compare two expressions. The comparison should not take
@ -43,9 +43,9 @@ type Expr struct {
// LLVMVal passes its arguments to the underlying Actual instance. It caches the // LLVMVal passes its arguments to the underlying Actual instance. It caches the
// result, so if this is called multiple times the underlying one is only called // result, so if this is called multiple times the underlying one is only called
// the first time. // the first time.
func (e Expr) LLVMVal(builder llvm.Builder) llvm.Value { func (e Expr) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
if e.val == nil { if e.val == nil {
v := e.Actual.LLVMVal(builder) v := e.Actual.LLVMVal(ctx, builder)
e.val = &v e.val = &v
} }
return *e.val return *e.val
@ -67,7 +67,7 @@ func (e Expr) equal(e2 Expr) bool {
type Bool bool type Bool bool
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (b Bool) LLVMVal(builder llvm.Builder) llvm.Value { func (b Bool) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
return llvm.Value{} return llvm.Value{}
} }
@ -85,7 +85,7 @@ func (b Bool) equal(e equaler) bool {
type Int int64 type Int int64
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (i Int) LLVMVal(builder llvm.Builder) llvm.Value { func (i Int) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
v := builder.CreateAlloca(llvm.Int64Type(), "") v := builder.CreateAlloca(llvm.Int64Type(), "")
builder.CreateStore(llvm.ConstInt(llvm.Int64Type(), uint64(i), false), v) builder.CreateStore(llvm.ConstInt(llvm.Int64Type(), uint64(i), false), v)
return v return v
@ -105,7 +105,7 @@ func (i Int) equal(e equaler) bool {
type String string type String string
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (s String) LLVMVal(builder llvm.Builder) llvm.Value { func (s String) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
return llvm.Value{} return llvm.Value{}
} }
@ -124,7 +124,7 @@ func (s String) equal(e equaler) bool {
type Identifier string type Identifier string
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (id Identifier) LLVMVal(builder llvm.Builder) llvm.Value { func (id Identifier) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
return llvm.Value{} return llvm.Value{}
} }
@ -149,7 +149,7 @@ func (m Macro) String() string {
} }
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (m Macro) LLVMVal(builder llvm.Builder) llvm.Value { func (m Macro) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
panic("Macros have no inherent LLVMVal") panic("Macros have no inherent LLVMVal")
} }
@ -176,7 +176,7 @@ func (tup Tuple) String() string {
} }
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (tup Tuple) LLVMVal(builder llvm.Builder) llvm.Value { func (tup Tuple) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
return llvm.Value{} return llvm.Value{}
} }
@ -208,14 +208,15 @@ func (s Statement) String() string {
} }
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (s Statement) LLVMVal(builder llvm.Builder) llvm.Value { func (s Statement) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
m, ok := s.To.Actual.(Macro) m, ok := s.To.Actual.(Macro)
if !ok { if !ok {
// TODO proper error // TODO proper error
panic("statement To is not a macro") panic("statement To is not a macro")
} }
fn, ok := macros[m]
if !ok { fn := ctx.GetMacro(m)
if fn == nil {
// TODO proper error // TODO proper error
panic(fmt.Sprintf("unknown macro %q", m)) panic(fmt.Sprintf("unknown macro %q", m))
} }
@ -224,7 +225,7 @@ func (s Statement) LLVMVal(builder llvm.Builder) llvm.Value {
// TODO proper error // TODO proper error
panic(err) panic(err)
} }
return newe.LLVMVal(builder) return newe.LLVMVal(ctx, builder)
} }
func (s Statement) equal(e equaler) bool { func (s Statement) equal(e equaler) bool {
@ -248,7 +249,7 @@ func (b Block) String() string {
} }
// LLVMVal implements the Actual interface method // LLVMVal implements the Actual interface method
func (b Block) LLVMVal(builder llvm.Builder) llvm.Value { func (b Block) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
return llvm.Value{} return llvm.Value{}
} }

View File

@ -8,25 +8,30 @@ import (
type addActual []Expr type addActual []Expr
func (aa addActual) LLVMVal(builder llvm.Builder) llvm.Value { func (aa addActual) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
a := builder.CreateLoad(aa[0].LLVMVal(builder), "") a := builder.CreateLoad(aa[0].LLVMVal(ctx, builder), "")
for i := range aa[1:] { for i := range aa[1:] {
b := builder.CreateLoad(aa[i+1].LLVMVal(builder), "") b := builder.CreateLoad(aa[i+1].LLVMVal(ctx, builder), "")
a = builder.CreateAdd(a, b, "") a = builder.CreateAdd(a, b, "")
} }
return a return a
} }
var macros = map[Macro]func(Expr) (Expr, error){ // RootCtx describes what's available to *all* contexts, and is what all
// contexts should have as the root parent in the tree
var RootCtx = &Ctx{
Macros: map[Macro]func(Expr) (Expr, error){
"add": func(e Expr) (Expr, error) { "add": func(e Expr) (Expr, error) {
tup, ok := e.Actual.(Tuple) tup, ok := e.Actual.(Tuple)
if !ok { if !ok {
// TODO proper error // TODO proper error
return Expr{}, errors.New("add only accepts a tuple") return Expr{}, errors.New("add only accepts a tuple")
} }
// TODO check that it's a tuple of integers too
return Expr{ return Expr{
Actual: addActual(tup), Actual: addActual(tup),
Token: e.Token, Token: e.Token,
}, nil }, nil
}, },
},
} }

View File

@ -38,7 +38,7 @@ func main() {
addMacro := expr.Expr{Actual: expr.Macro("add")} addMacro := expr.Expr{Actual: expr.Macro("add")}
stmt := expr.Expr{Actual: expr.Statement{In: tup, To: addMacro}} stmt := expr.Expr{Actual: expr.Statement{In: tup, To: addMacro}}
result := stmt.LLVMVal(builder) result := stmt.LLVMVal(expr.RootCtx, builder)
builder.CreateRet(result) builder.CreateRet(result)
// verify it's all good // verify it's all good