implement ctx management macros, and do.... oooooh yeaaaaaah
This commit is contained in:
parent
f751924b26
commit
51367a253a
103
expr/build.go
103
expr/build.go
@ -1,18 +1,24 @@
|
|||||||
package expr
|
package expr
|
||||||
|
|
||||||
import "llvm.org/llvm/bindings/go/llvm"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"llvm.org/llvm/bindings/go/llvm"
|
||||||
|
)
|
||||||
|
|
||||||
type BuildCtx struct {
|
type BuildCtx struct {
|
||||||
C *Ctx
|
|
||||||
B llvm.Builder
|
B llvm.Builder
|
||||||
M llvm.Module
|
M llvm.Module
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bctx BuildCtx) Build(stmts ...Statement) llvm.Value {
|
func (bctx BuildCtx) Build(ctx Ctx, stmts ...Statement) llvm.Value {
|
||||||
var lastVal llvm.Value
|
var lastVal llvm.Value
|
||||||
for _, stmt := range stmts {
|
for _, stmt := range stmts {
|
||||||
if e := bctx.BuildStmt(stmt); e != nil {
|
fmt.Println(stmt)
|
||||||
lastVal = bctx.buildVal(e)
|
if e := bctx.BuildStmt(ctx, stmt); e != nil {
|
||||||
|
if lv, ok := e.(llvmVal); ok {
|
||||||
|
lastVal = llvm.Value(lv)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lastVal == llvm.Value{}) {
|
if (lastVal == llvm.Value{}) {
|
||||||
@ -21,19 +27,19 @@ func (bctx BuildCtx) Build(stmts ...Statement) llvm.Value {
|
|||||||
return lastVal
|
return lastVal
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bctx BuildCtx) BuildStmt(s Statement) Expr {
|
func (bctx BuildCtx) BuildStmt(ctx Ctx, s Statement) Expr {
|
||||||
m := s.Op.(Macro)
|
m := s.Op.(Macro)
|
||||||
return bctx.C.Macro(m)(bctx, s.Arg)
|
return ctx.Macro(m)(bctx, ctx, s.Arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// may return nil if e is a Statement which has no return
|
// may return nil if e is a Statement which has no return
|
||||||
func (bctx BuildCtx) buildExpr(e Expr) Expr {
|
func (bctx BuildCtx) buildExpr(ctx Ctx, e Expr) Expr {
|
||||||
return bctx.buildExprTill(e, func(Expr) bool { return false })
|
return bctx.buildExprTill(ctx, e, func(Expr) bool { return false })
|
||||||
}
|
}
|
||||||
|
|
||||||
// like buildExpr, but will stop short and stop recursing when the function
|
// like buildExpr, but will stop short and stop recursing when the function
|
||||||
// returns true
|
// returns true
|
||||||
func (bctx BuildCtx) buildExprTill(e Expr, fn func(e Expr) bool) Expr {
|
func (bctx BuildCtx) buildExprTill(ctx Ctx, e Expr, fn func(e Expr) bool) Expr {
|
||||||
if fn(e) {
|
if fn(e) {
|
||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
@ -44,45 +50,86 @@ func (bctx BuildCtx) buildExprTill(e Expr, fn func(e Expr) bool) Expr {
|
|||||||
case Int:
|
case Int:
|
||||||
return llvmVal(llvm.ConstInt(llvm.Int64Type(), uint64(ea), false))
|
return llvmVal(llvm.ConstInt(llvm.Int64Type(), uint64(ea), false))
|
||||||
case Identifier:
|
case Identifier:
|
||||||
return bctx.C.Identifier(ea)
|
return ctx.Identifier(ea)
|
||||||
case Statement:
|
case Statement:
|
||||||
return bctx.BuildStmt(ea)
|
return bctx.BuildStmt(ctx, ea)
|
||||||
case Tuple:
|
case Tuple:
|
||||||
for i := range ea {
|
for i := range ea {
|
||||||
ea[i] = bctx.buildExprTill(ea[i], fn)
|
ea[i] = bctx.buildExprTill(ctx, ea[i], fn)
|
||||||
}
|
}
|
||||||
return ea
|
return ea
|
||||||
case List:
|
case List:
|
||||||
for i := range ea {
|
for i := range ea {
|
||||||
ea[i] = bctx.buildExprTill(ea[i], fn)
|
ea[i] = bctx.buildExprTill(ctx, ea[i], fn)
|
||||||
}
|
}
|
||||||
return ea
|
return ea
|
||||||
|
case Ctx:
|
||||||
|
return ea
|
||||||
default:
|
default:
|
||||||
panicf("type %T can't express a value", ea)
|
panicf("%v (type %T) can't express a value", ea, ea)
|
||||||
}
|
}
|
||||||
panic("go is dumb")
|
panic("go is dumb")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bctx BuildCtx) buildVal(e Expr) llvm.Value {
|
func (bctx BuildCtx) buildVal(ctx Ctx, e Expr) llvm.Value {
|
||||||
return llvm.Value(bctx.buildExpr(e).(llvmVal))
|
return llvm.Value(bctx.buildExpr(ctx, e).(llvmVal))
|
||||||
}
|
}
|
||||||
|
|
||||||
// globalCtx describes what's available to *all* contexts, and is what all
|
// globalCtx describes what's available to *all* contexts, and is what all
|
||||||
// contexts should have as the root parent in the tree
|
// contexts should have as the root parent in the tree.
|
||||||
var globalCtx = &Ctx{
|
//
|
||||||
|
// We define in this weird way cause NewCtx actually references globalCtx
|
||||||
|
var globalCtx *Ctx
|
||||||
|
var _ = func() bool {
|
||||||
|
globalCtx = &Ctx{
|
||||||
macros: map[Macro]MacroFn{
|
macros: map[Macro]MacroFn{
|
||||||
"add": func(bctx BuildCtx, e Expr) Expr {
|
"add": func(bctx BuildCtx, ctx Ctx, e Expr) Expr {
|
||||||
tup := bctx.buildExpr(e).(Tuple)
|
tup := bctx.buildExpr(ctx, e).(Tuple)
|
||||||
a := bctx.buildVal(tup[0])
|
a := bctx.buildVal(ctx, tup[0])
|
||||||
b := bctx.buildVal(tup[1])
|
b := bctx.buildVal(ctx, tup[1])
|
||||||
return llvmVal(bctx.B.CreateAdd(a, b, ""))
|
return llvmVal(bctx.B.CreateAdd(a, b, ""))
|
||||||
},
|
},
|
||||||
|
|
||||||
"bind": func(bctx BuildCtx, e Expr) Expr {
|
// TODO this chould be a user macro!!!! WUT this language is baller
|
||||||
tup := bctx.buildExprTill(e, isIdentifier).(Tuple)
|
"bind": func(bctx BuildCtx, ctx Ctx, e Expr) Expr {
|
||||||
id := bctx.buildExprTill(tup[0], isIdentifier).(Identifier)
|
tup := bctx.buildExprTill(ctx, e, isIdentifier).(Tuple)
|
||||||
*bctx.C = bctx.C.Bind(id, bctx.buildExpr(tup[1]))
|
id := bctx.buildExprTill(ctx, tup[0], isIdentifier).(Identifier)
|
||||||
return nil
|
ctx.Bind(id, bctx.buildExpr(ctx, tup[1]))
|
||||||
|
return NewTuple()
|
||||||
|
},
|
||||||
|
|
||||||
|
"ctxnew": func(bctx BuildCtx, ctx Ctx, e Expr) Expr {
|
||||||
|
return NewCtx()
|
||||||
|
},
|
||||||
|
|
||||||
|
"ctxthis": func(bctx BuildCtx, ctx Ctx, e Expr) Expr {
|
||||||
|
return ctx
|
||||||
|
},
|
||||||
|
|
||||||
|
"ctxbind": func(bctx BuildCtx, ctx Ctx, e Expr) Expr {
|
||||||
|
tup := bctx.buildExprTill(ctx, e, isIdentifier).(Tuple)
|
||||||
|
thisCtx := bctx.buildExpr(ctx, tup[0]).(Ctx)
|
||||||
|
id := bctx.buildExprTill(ctx, tup[1], isIdentifier).(Identifier)
|
||||||
|
thisCtx.Bind(id, bctx.buildExpr(ctx, tup[2]))
|
||||||
|
return NewTuple()
|
||||||
|
},
|
||||||
|
|
||||||
|
"ctxget": func(bctx BuildCtx, ctx Ctx, e Expr) Expr {
|
||||||
|
tup := bctx.buildExprTill(ctx, e, isIdentifier).(Tuple)
|
||||||
|
thisCtx := bctx.buildExpr(ctx, tup[0]).(Ctx)
|
||||||
|
id := bctx.buildExprTill(ctx, tup[1], isIdentifier).(Identifier)
|
||||||
|
return thisCtx.Identifier(id)
|
||||||
|
},
|
||||||
|
|
||||||
|
"do": func(bctx BuildCtx, ctx Ctx, e Expr) Expr {
|
||||||
|
tup := bctx.buildExprTill(ctx, e, isStmt).(Tuple)
|
||||||
|
thisCtx := tup[0].(Ctx)
|
||||||
|
for _, stmtE := range tup[1].(List) {
|
||||||
|
bctx.BuildStmt(thisCtx, stmtE.(Statement))
|
||||||
|
}
|
||||||
|
return NewTuple()
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
return false
|
||||||
|
}()
|
||||||
|
@ -2,7 +2,7 @@ package expr
|
|||||||
|
|
||||||
// MacroFn is a compiler function which takes in an existing Expr and returns
|
// MacroFn is a compiler function which takes in an existing Expr and returns
|
||||||
// the llvm Value for it
|
// the llvm Value for it
|
||||||
type MacroFn func(BuildCtx, Expr) Expr
|
type MacroFn func(BuildCtx, Ctx, Expr) Expr
|
||||||
|
|
||||||
// Ctx contains all the Macros and Identifiers available. A Ctx also keeps a
|
// Ctx contains all the Macros and Identifiers available. A Ctx also keeps a
|
||||||
// reference to the global context, which has a number of macros available for
|
// reference to the global context, which has a number of macros available for
|
||||||
@ -45,7 +45,8 @@ func (c Ctx) Identifier(i Identifier) Expr {
|
|||||||
panic("go is dumb")
|
panic("go is dumb")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c Ctx) cp() Ctx {
|
// Copy returns a deep copy of the Ctx
|
||||||
|
func (c Ctx) Copy() Ctx {
|
||||||
cc := Ctx{
|
cc := Ctx{
|
||||||
global: c.global,
|
global: c.global,
|
||||||
macros: make(map[Macro]MacroFn, len(c.macros)),
|
macros: make(map[Macro]MacroFn, len(c.macros)),
|
||||||
@ -63,11 +64,9 @@ func (c Ctx) cp() Ctx {
|
|||||||
// Bind returns a new Ctx which is a copy of this one, but with the given
|
// 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
|
// Identifier bound to the given Expr. Will panic if the Identifier is already
|
||||||
// bound
|
// bound
|
||||||
func (c Ctx) Bind(i Identifier, e Expr) Ctx {
|
func (c Ctx) Bind(i Identifier, e Expr) {
|
||||||
if _, ok := c.idents[i]; ok {
|
if _, ok := c.idents[i]; ok {
|
||||||
panicf("identifier %q is already bound", i)
|
panicf("identifier %q is already bound", i)
|
||||||
}
|
}
|
||||||
c = c.cp()
|
|
||||||
c.idents[i] = e
|
c.idents[i] = e
|
||||||
return c
|
|
||||||
}
|
}
|
||||||
|
56
expr/expr.go
56
expr/expr.go
@ -167,14 +167,16 @@ type Statement struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewStatement returns a Statement whose Op is the first Expr. If the given
|
// NewStatement returns a Statement whose Op is the first Expr. If the given
|
||||||
// list is empty Arg will be nil, if its length is one Arg will be that single
|
// list is empty Arg will be 0-tuple, if its length is one Arg will be that
|
||||||
// Expr, otherwise Arg will be a Tuple of the list
|
// single Expr, otherwise Arg will be a Tuple of the list
|
||||||
func NewStatement(e Expr, ee ...Expr) Statement {
|
func NewStatement(e Expr, ee ...Expr) Statement {
|
||||||
s := Statement{Op: e}
|
s := Statement{Op: e}
|
||||||
if len(ee) > 1 {
|
if len(ee) > 1 {
|
||||||
s.Arg = NewTuple(ee...)
|
s.Arg = NewTuple(ee...)
|
||||||
} else if len(ee) == 1 {
|
} else if len(ee) == 1 {
|
||||||
s.Arg = ee[0]
|
s.Arg = ee[0]
|
||||||
|
} else if len(ee) == 0 {
|
||||||
|
s.Arg = NewTuple()
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
@ -188,51 +190,7 @@ func (s Statement) equal(e equaler) bool {
|
|||||||
return ok && exprEqual(s.Op, ss.Op) && exprEqual(s.Arg, ss.Arg)
|
return ok && exprEqual(s.Op, ss.Op) && exprEqual(s.Arg, ss.Arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
func isStmt(e Expr) bool {
|
||||||
|
_, ok := e.(Statement)
|
||||||
// Block represents a set of statements which share a scope, i.e. If one
|
return ok
|
||||||
// statement binds a variable the rest of the statements in the block can use
|
|
||||||
// that variable
|
|
||||||
type Block struct {
|
|
||||||
In []Expr
|
|
||||||
Stmts []Expr
|
|
||||||
Out []Expr
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b Block) String() string {
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"{[%s][%s][%s]}",
|
|
||||||
exprsJoin(b.In),
|
|
||||||
exprsJoin(b.Stmts),
|
|
||||||
exprsJoin(b.Out),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
func (b Block) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
|
||||||
name := randStr() // TODO make this based on token
|
|
||||||
// TODO make these based on actual statements
|
|
||||||
out := llvm.Int64Type()
|
|
||||||
in := []llvm.Type{}
|
|
||||||
fn := llvm.AddFunction(lctx.M, name, llvm.FunctionType(out, in, false))
|
|
||||||
block := llvm.AddBasicBlock(fn, "entry")
|
|
||||||
lctx.B.SetInsertPoint(block, block.FirstInstruction())
|
|
||||||
|
|
||||||
var v llvm.Value
|
|
||||||
for _, se := range b {
|
|
||||||
v = se.Actual.LLVMVal(ctx, lctx)
|
|
||||||
}
|
|
||||||
// last v is used as return
|
|
||||||
// TODO empty return
|
|
||||||
lctx.B.CreateRet(v)
|
|
||||||
return fn
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
func (b Block) equal(e equaler) bool {
|
|
||||||
bb, ok := e.(Block)
|
|
||||||
return ok &&
|
|
||||||
exprsEqual(b.In, bb.In) &&
|
|
||||||
exprsEqual(b.Stmts, bb.Stmts) &&
|
|
||||||
exprsEqual(b.Out, bb.Out)
|
|
||||||
}
|
}
|
||||||
|
57
main.go
57
main.go
@ -24,7 +24,6 @@ func main() {
|
|||||||
// setup our context, builder, and module
|
// setup our context, builder, and module
|
||||||
ctx := expr.NewCtx()
|
ctx := expr.NewCtx()
|
||||||
bctx := expr.BuildCtx{
|
bctx := expr.BuildCtx{
|
||||||
C: &ctx,
|
|
||||||
B: llvm.NewBuilder(),
|
B: llvm.NewBuilder(),
|
||||||
M: llvm.NewModule("my_module"),
|
M: llvm.NewModule("my_module"),
|
||||||
}
|
}
|
||||||
@ -32,29 +31,59 @@ func main() {
|
|||||||
// do the work in the function
|
// do the work in the function
|
||||||
add := expr.Macro("add")
|
add := expr.Macro("add")
|
||||||
bind := expr.Macro("bind")
|
bind := expr.Macro("bind")
|
||||||
|
do := expr.Macro("do")
|
||||||
|
ctxnew := expr.Macro("ctxnew")
|
||||||
|
ctxbind := expr.Macro("ctxbind")
|
||||||
|
ctxget := expr.Macro("ctxget")
|
||||||
|
|
||||||
|
ctx1 := expr.Identifier("ctx1")
|
||||||
|
ctx2 := expr.Identifier("ctx2")
|
||||||
idA := expr.Identifier("A")
|
idA := expr.Identifier("A")
|
||||||
idB := expr.Identifier("B")
|
idB := expr.Identifier("B")
|
||||||
idC := expr.Identifier("C")
|
|
||||||
stmts := []expr.Statement{
|
|
||||||
expr.NewStatement(bind, idA, expr.NewStatement(add, expr.Int(1), expr.Int(2))),
|
|
||||||
expr.NewStatement(bind, idB, expr.Int(3)),
|
|
||||||
expr.NewStatement(bind, idC, expr.NewTuple(idA, idB)),
|
|
||||||
expr.NewStatement(add, expr.NewStatement(add, idC), expr.NewStatement(add, idC)),
|
|
||||||
}
|
|
||||||
|
|
||||||
//block := expr.Block([]expr.Expr{stmt})
|
//myAdd := expr.Identifier("myAdd")
|
||||||
//fn := block.LLVMVal(expr.RootCtx, lctx)
|
out := expr.Identifier("out")
|
||||||
|
// TODO we couldn't actually use this either, because the builder was
|
||||||
|
// changing out the internal values of the List the first time it was hit,
|
||||||
|
// and then just using those the second time around
|
||||||
|
//myAddStmts := expr.NewList(
|
||||||
|
// expr.NewStatement(bind, out, expr.NewStatement(add, idA, idB)),
|
||||||
|
//)
|
||||||
|
|
||||||
|
stmts := []expr.Statement{
|
||||||
|
// TODO revisit how bind and related macros (maybe all macros?) deal
|
||||||
|
// with arguments and their evaluation (keeping an identifier vs
|
||||||
|
// eval-ing it)
|
||||||
|
//expr.NewStatement(bind, myAdd, myAddStmts),
|
||||||
|
|
||||||
|
expr.NewStatement(bind, ctx1, expr.NewStatement(ctxnew)),
|
||||||
|
expr.NewStatement(ctxbind, ctx1, idA, expr.Int(1)),
|
||||||
|
expr.NewStatement(ctxbind, ctx1, idB, expr.Int(2)),
|
||||||
|
expr.NewStatement(do, ctx1, expr.NewList(
|
||||||
|
expr.NewStatement(bind, out, expr.NewStatement(add, idA, idB)),
|
||||||
|
)),
|
||||||
|
|
||||||
|
expr.NewStatement(bind, ctx2, expr.NewStatement(ctxnew)),
|
||||||
|
expr.NewStatement(ctxbind, ctx2, idA, expr.Int(3)),
|
||||||
|
expr.NewStatement(ctxbind, ctx2, idB, expr.Int(4)),
|
||||||
|
expr.NewStatement(do, ctx2, expr.NewList(
|
||||||
|
expr.NewStatement(bind, out, expr.NewStatement(add, idA, idB)),
|
||||||
|
)),
|
||||||
|
|
||||||
|
expr.NewStatement(
|
||||||
|
add,
|
||||||
|
expr.NewStatement(ctxget, ctx1, out),
|
||||||
|
expr.NewStatement(ctxget, ctx2, out),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
// create main and call our function
|
// create main and call our function
|
||||||
mainFn := llvm.AddFunction(bctx.M, "main", llvm.FunctionType(llvm.Int64Type(), []llvm.Type{}, false))
|
mainFn := llvm.AddFunction(bctx.M, "main", llvm.FunctionType(llvm.Int64Type(), []llvm.Type{}, false))
|
||||||
mainBlock := llvm.AddBasicBlock(mainFn, "entry")
|
mainBlock := llvm.AddBasicBlock(mainFn, "entry")
|
||||||
bctx.B.SetInsertPoint(mainBlock, mainBlock.FirstInstruction())
|
bctx.B.SetInsertPoint(mainBlock, mainBlock.FirstInstruction())
|
||||||
v := bctx.Build(stmts...)
|
v := bctx.Build(ctx, stmts...)
|
||||||
bctx.B.CreateRet(v)
|
bctx.B.CreateRet(v)
|
||||||
|
|
||||||
//ret := lctx.B.CreateCall(fn, []llvm.Value{}, "")
|
|
||||||
//lctx.B.CreateRet(ret)
|
|
||||||
|
|
||||||
// verify it's all good
|
// verify it's all good
|
||||||
if err := llvm.VerifyModule(bctx.M, llvm.ReturnStatusAction); err != nil {
|
if err := llvm.VerifyModule(bctx.M, llvm.ReturnStatusAction); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
|
Loading…
Reference in New Issue
Block a user