implement basic context
This commit is contained in:
parent
63fead5d8b
commit
6595d291c1
24
expr/ctx.go
Normal file
24
expr/ctx.go
Normal 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
|
||||||
|
}
|
29
expr/expr.go
29
expr/expr.go
@ -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{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
2
main.go
2
main.go
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user