2016-08-05 18:34:17 +00:00
|
|
|
package expr
|
|
|
|
|
|
|
|
import "llvm.org/llvm/bindings/go/llvm"
|
|
|
|
|
2016-08-06 18:20:53 +00:00
|
|
|
type BuildCtx struct {
|
|
|
|
C *Ctx
|
2016-08-05 18:34:17 +00:00
|
|
|
B llvm.Builder
|
|
|
|
M llvm.Module
|
|
|
|
}
|
|
|
|
|
2016-08-06 18:20:53 +00:00
|
|
|
func (bctx BuildCtx) Build(stmts ...Statement) llvm.Value {
|
|
|
|
var lastVal llvm.Value
|
2016-08-05 18:34:17 +00:00
|
|
|
for _, stmt := range stmts {
|
2016-08-06 18:20:53 +00:00
|
|
|
if e := bctx.BuildStmt(stmt); e != nil {
|
|
|
|
lastVal = bctx.buildVal(e)
|
|
|
|
}
|
2016-08-05 18:34:17 +00:00
|
|
|
}
|
2016-08-06 18:20:53 +00:00
|
|
|
if (lastVal == llvm.Value{}) {
|
|
|
|
lastVal = bctx.B.CreateRetVoid()
|
|
|
|
}
|
|
|
|
return lastVal
|
2016-08-05 18:34:17 +00:00
|
|
|
}
|
|
|
|
|
2016-08-06 18:20:53 +00:00
|
|
|
func (bctx BuildCtx) BuildStmt(s Statement) Expr {
|
|
|
|
m := s.Op.(Macro)
|
2016-08-07 15:06:46 +00:00
|
|
|
return bctx.C.Macro(m)(bctx, s.Arg)
|
2016-08-06 18:20:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// may return nil if e is a Statement which has no return
|
|
|
|
func (bctx BuildCtx) buildExpr(e Expr) Expr {
|
2016-08-07 00:10:31 +00:00
|
|
|
return bctx.buildExprTill(e, func(Expr) bool { return false })
|
|
|
|
}
|
|
|
|
|
|
|
|
// like buildExpr, but will stop short and stop recursing when the function
|
|
|
|
// returns true
|
|
|
|
func (bctx BuildCtx) buildExprTill(e Expr, fn func(e Expr) bool) Expr {
|
|
|
|
if fn(e) {
|
|
|
|
return e
|
|
|
|
}
|
|
|
|
|
2016-08-06 18:20:53 +00:00
|
|
|
switch ea := e.(type) {
|
|
|
|
case llvmVal:
|
|
|
|
return e
|
|
|
|
case Int:
|
|
|
|
return llvmVal(llvm.ConstInt(llvm.Int64Type(), uint64(ea), false))
|
|
|
|
case Identifier:
|
2016-08-07 15:06:46 +00:00
|
|
|
return bctx.C.Identifier(ea)
|
2016-08-06 18:20:53 +00:00
|
|
|
case Statement:
|
|
|
|
return bctx.BuildStmt(ea)
|
|
|
|
case Tuple:
|
|
|
|
for i := range ea {
|
2016-08-07 00:10:31 +00:00
|
|
|
ea[i] = bctx.buildExprTill(ea[i], fn)
|
2016-08-06 18:20:53 +00:00
|
|
|
}
|
|
|
|
return ea
|
|
|
|
default:
|
|
|
|
panicf("type %T can't express a value", ea)
|
2016-08-05 18:34:17 +00:00
|
|
|
}
|
2016-08-06 18:20:53 +00:00
|
|
|
panic("go is dumb")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (bctx BuildCtx) buildVal(e Expr) llvm.Value {
|
|
|
|
return llvm.Value(bctx.buildExpr(e).(llvmVal))
|
|
|
|
}
|
|
|
|
|
|
|
|
// globalCtx describes what's available to *all* contexts, and is what all
|
|
|
|
// contexts should have as the root parent in the tree
|
|
|
|
var globalCtx = &Ctx{
|
|
|
|
macros: map[Macro]MacroFn{
|
|
|
|
"add": func(bctx BuildCtx, e Expr) Expr {
|
2016-08-07 00:10:31 +00:00
|
|
|
tup := bctx.buildExpr(e).(Tuple)
|
2016-08-06 18:20:53 +00:00
|
|
|
a := bctx.buildVal(tup[0])
|
|
|
|
b := bctx.buildVal(tup[1])
|
|
|
|
return llvmVal(bctx.B.CreateAdd(a, b, ""))
|
|
|
|
},
|
|
|
|
|
|
|
|
"bind": func(bctx BuildCtx, e Expr) Expr {
|
2016-08-07 00:10:31 +00:00
|
|
|
tup := bctx.buildExprTill(e, isIdentifier).(Tuple)
|
|
|
|
id := bctx.buildExprTill(tup[0], isIdentifier).(Identifier)
|
2016-08-07 15:06:46 +00:00
|
|
|
*bctx.C = bctx.C.Bind(id, bctx.buildExpr(tup[1]))
|
2016-08-06 18:20:53 +00:00
|
|
|
return nil
|
|
|
|
},
|
|
|
|
},
|
2016-08-05 18:34:17 +00:00
|
|
|
}
|