diff --git a/expr/build.go b/expr/build.go index 517f64b..a8b49c5 100644 --- a/expr/build.go +++ b/expr/build.go @@ -2,6 +2,7 @@ package expr import ( "fmt" + "log" "llvm.org/llvm/bindings/go/llvm" ) @@ -14,10 +15,11 @@ type BuildCtx struct { func (bctx BuildCtx) Build(ctx Ctx, stmts ...Statement) llvm.Value { var lastVal llvm.Value for _, stmt := range stmts { - fmt.Println(stmt) if e := bctx.BuildStmt(ctx, stmt); e != nil { if lv, ok := e.(llvmVal); ok { lastVal = llvm.Value(lv) + } else { + log.Printf("BuildStmt returned non llvmVal from %v: %v (%T)", stmt, e, e) } } } @@ -28,8 +30,18 @@ func (bctx BuildCtx) Build(ctx Ctx, stmts ...Statement) llvm.Value { } func (bctx BuildCtx) BuildStmt(ctx Ctx, s Statement) Expr { - m := s.Op.(Macro) - return ctx.Macro(m)(bctx, ctx, s.Arg) + log.Printf("building: %v", s) + switch o := s.Op.(type) { + case Macro: + return ctx.Macro(o)(bctx, ctx, s.Arg) + case Identifier: + fn := ctx.Identifier(o).(llvmVal) + arg := bctx.buildExpr(ctx, s.Arg).(llvmVal) + out := bctx.B.CreateCall(llvm.Value(fn), []llvm.Value{llvm.Value(arg)}, "") + return llvmVal(out) + default: + panic(fmt.Sprintf("non op type %v (%T)", s.Op, s.Op)) + } } // may return nil if e is a Statement which has no return @@ -94,7 +106,8 @@ var _ = func() bool { "bind": func(bctx BuildCtx, ctx Ctx, e Expr) Expr { tup := bctx.buildExprTill(ctx, e, isIdentifier).(Tuple) id := bctx.buildExprTill(ctx, tup[0], isIdentifier).(Identifier) - ctx.Bind(id, bctx.buildExpr(ctx, tup[1])) + val := bctx.buildExpr(ctx, tup[1]) + ctx.Bind(id, val) return NewTuple() }, @@ -129,6 +142,30 @@ var _ = func() bool { } return NewTuple() }, + + "op": func(bctx BuildCtx, ctx Ctx, e Expr) Expr { + l := bctx.buildExprTill(ctx, e, isList).(List) + stmts := make([]Statement, len(l)) + for i := range l { + stmts[i] = l[i].(Statement) + } + + // TODO obviously this needs to be fixed + fn := llvm.AddFunction(bctx.M, "", llvm.FunctionType(llvm.Int64Type(), []llvm.Type{llvm.Int64Type()}, false)) + fnbl := llvm.AddBasicBlock(fn, "entry") + + prevbl := bctx.B.GetInsertBlock() + bctx.B.SetInsertPoint(fnbl, fnbl.FirstInstruction()) + out := bctx.Build(NewCtx(), stmts...) + bctx.B.CreateRet(out) + bctx.B.SetInsertPointAtEnd(prevbl) + return llvmVal(fn) + }, + + "in": func(bctx BuildCtx, ctx Ctx, e Expr) Expr { + fn := bctx.B.GetInsertBlock().Parent() + return llvmVal(fn.Param(0)) + }, }, } return false diff --git a/expr/expr.go b/expr/expr.go index baea022..06d7020 100644 --- a/expr/expr.go +++ b/expr/expr.go @@ -71,6 +71,10 @@ func (i Int) equal(e equaler) bool { return ok && ii == i } +func (i Int) String() string { + return fmt.Sprint(int64(i)) +} + //////////////////////////////////////////////////////////////////////////////// /* // String represents a string value @@ -157,6 +161,11 @@ func (l List) equal(e equaler) bool { return ok && exprsEqual(l, ll) } +func isList(e Expr) bool { + _, ok := e.(List) + return ok +} + //////////////////////////////////////////////////////////////////////////////// // Statement represents an actual action which will be taken. The input value is diff --git a/main.go b/main.go index 998093b..f3a939f 100644 --- a/main.go +++ b/main.go @@ -2,6 +2,7 @@ package main import ( "fmt" + "log" "github.com/mediocregopher/ginger/expr" @@ -17,93 +18,68 @@ func main() { // fmt.Println(e) //} + log.Printf("initializing llvm") llvm.LinkInMCJIT() llvm.InitializeNativeTarget() llvm.InitializeNativeAsmPrinter() - // setup our context, builder, and module + log.Printf("initializing build context") ctx := expr.NewCtx() bctx := expr.BuildCtx{ B: llvm.NewBuilder(), M: llvm.NewModule("my_module"), } - // do the work in the function + log.Printf("making program") add := expr.Macro("add") 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") - idB := expr.Identifier("B") - - //myAdd := expr.Identifier("myAdd") - 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)), - //) - + op := expr.Macro("op") + in := expr.Macro("in") + incr := expr.Identifier("incr") 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(bind, incr, + expr.NewStatement(op, + expr.NewList( + expr.NewStatement(add, expr.NewTuple( + expr.Int(1), + expr.NewStatement(in, expr.NewTuple()), + )), + ), + ), + ), expr.NewStatement( - add, - expr.NewStatement(ctxget, ctx1, out), - expr.NewStatement(ctxget, ctx2, out), + incr, + expr.Int(5), ), } - // create main and call our function + log.Printf("creating main function") mainFn := llvm.AddFunction(bctx.M, "main", llvm.FunctionType(llvm.Int64Type(), []llvm.Type{}, false)) mainBlock := llvm.AddBasicBlock(mainFn, "entry") bctx.B.SetInsertPoint(mainBlock, mainBlock.FirstInstruction()) - v := bctx.Build(ctx, stmts...) - bctx.B.CreateRet(v) + log.Printf("actually processing program") + out := bctx.Build(ctx, stmts...) + bctx.B.CreateRet(out) + //bctx.Build(ctx, stmts...) + //bctx.B.CreateRet(llvm.ConstInt(llvm.Int64Type(), uint64(5), false)) - // verify it's all good + fmt.Println("######## dumping IR") + bctx.M.Dump() + fmt.Println("######## done dumping IR") + + log.Printf("verifying") if err := llvm.VerifyModule(bctx.M, llvm.ReturnStatusAction); err != nil { panic(err) } - fmt.Println("# verified") - // Dump the IR - fmt.Println("# dumping IR") - bctx.M.Dump() - fmt.Println("# done dumping IR") - - // create our exe engine - fmt.Println("# creating new execution engine") + log.Printf("creating execution enging") engine, err := llvm.NewExecutionEngine(bctx.M) if err != nil { panic(err) } - // run the function! - fmt.Println("# running the function main") + log.Printf("running main function") funcResult := engine.RunFunction(bctx.M.NamedFunction("main"), []llvm.GenericValue{}) - fmt.Printf("%d\n", funcResult.Int(false)) + fmt.Printf("\nOUTPUT:\n%d\n", funcResult.Int(false)) }