diff --git a/expr/expr.go b/expr/expr.go index fa49081..93a7eed 100644 --- a/expr/expr.go +++ b/expr/expr.go @@ -13,13 +13,19 @@ import ( // TODO empty parenthesis // TODO need to figure out how to test LLVMVal stuff // TODO once we're a bit more confident, make ActualFunc +// TODO LLVMVal -> LLVMBuild? + +type LLVMCtx struct { + B llvm.Builder + M llvm.Module +} // Actual represents the actual expression in question, and has certain // properties. It is wrapped by Expr which also holds onto contextual // information, like the token to which Actual was originally parsed from type Actual interface { // Initializes an llvm.Value and returns it. - LLVMVal(*Ctx, llvm.Builder) llvm.Value + LLVMVal(*Ctx, LLVMCtx) llvm.Value } // equaler is used to compare two expressions. The comparison should not take @@ -43,9 +49,9 @@ type Expr struct { // 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 // the first time. -func (e Expr) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { +func (e Expr) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value { if e.val == nil { - v := e.Actual.LLVMVal(ctx, builder) + v := e.Actual.LLVMVal(ctx, lctx) e.val = &v } return *e.val @@ -67,7 +73,7 @@ func (e Expr) equal(e2 Expr) bool { type Bool bool // LLVMVal implements the Actual interface method -func (b Bool) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { +func (b Bool) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value { return llvm.Value{} } @@ -85,9 +91,9 @@ func (b Bool) equal(e equaler) bool { type Int int64 // LLVMVal implements the Actual interface method -func (i Int) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { - v := builder.CreateAlloca(llvm.Int64Type(), "") - builder.CreateStore(llvm.ConstInt(llvm.Int64Type(), uint64(i), false), v) +func (i Int) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value { + v := lctx.B.CreateAlloca(llvm.Int64Type(), "") + lctx.B.CreateStore(llvm.ConstInt(llvm.Int64Type(), uint64(i), false), v) return v } @@ -105,7 +111,7 @@ func (i Int) equal(e equaler) bool { type String string // LLVMVal implements the Actual interface method -func (s String) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { +func (s String) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value { return llvm.Value{} } @@ -124,7 +130,7 @@ func (s String) equal(e equaler) bool { type Identifier string // LLVMVal implements the Actual interface method -func (id Identifier) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { +func (id Identifier) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value { return llvm.Value{} } @@ -149,7 +155,7 @@ func (m Macro) String() string { } // LLVMVal implements the Actual interface method -func (m Macro) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { +func (m Macro) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value { panic("Macros have no inherent LLVMVal") } @@ -176,7 +182,7 @@ func (tup Tuple) String() string { } // LLVMVal implements the Actual interface method -func (tup Tuple) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { +func (tup Tuple) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value { return llvm.Value{} } @@ -208,7 +214,7 @@ func (s Statement) String() string { } // LLVMVal implements the Actual interface method -func (s Statement) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { +func (s Statement) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value { m, ok := s.To.Actual.(Macro) if !ok { // TODO proper error @@ -225,7 +231,7 @@ func (s Statement) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { // TODO proper error panic(err) } - return newe.LLVMVal(ctx, builder) + return newe.LLVMVal(ctx, lctx) } func (s Statement) equal(e equaler) bool { @@ -238,19 +244,34 @@ func (s Statement) equal(e equaler) bool { // Block represents a set of statements which share a scope, i.e. If one // statement binds a variable the rest of the statements in the block can use // that variable, including sub-blocks within this one. -type Block []Statement +type Block []Expr func (b Block) String() string { strs := make([]string, len(b)) for i := range b { - strs[i] = b[i].String() + strs[i] = b[i].Actual.(Statement).String() } return fmt.Sprintf("{ %s }", strings.Join(strs, " ")) } // LLVMVal implements the Actual interface method -func (b Block) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { - return llvm.Value{} +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 { diff --git a/expr/macros.go b/expr/macros.go index 6ca2563..9d83cc8 100644 --- a/expr/macros.go +++ b/expr/macros.go @@ -8,11 +8,11 @@ import ( type addActual []Expr -func (aa addActual) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value { - a := builder.CreateLoad(aa[0].LLVMVal(ctx, builder), "") +func (aa addActual) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value { + a := lctx.B.CreateLoad(aa[0].LLVMVal(ctx, lctx), "") for i := range aa[1:] { - b := builder.CreateLoad(aa[i+1].LLVMVal(ctx, builder), "") - a = builder.CreateAdd(a, b, "") + b := lctx.B.CreateLoad(aa[i+1].LLVMVal(ctx, lctx), "") + a = lctx.B.CreateAdd(a, b, "") } return a } diff --git a/expr/parse.go b/expr/parse.go index a44de26..81f99a9 100644 --- a/expr/parse.go +++ b/expr/parse.go @@ -291,14 +291,13 @@ func parseBlock(toks []lexer.Token) (Expr, error) { if expr, toks, err = parse(toks); err != nil { return Expr{}, err } - stmt, ok := expr.Actual.(Statement) - if !ok { + if _, ok := expr.Actual.(Statement); !ok { return Expr{}, exprErr{ reason: "blocks may only contain full statements", tok: expr.Token, tokCtx: "non-statement here", } } - b = append(b, stmt) + b = append(b, expr) } } diff --git a/expr/parse_test.go b/expr/parse_test.go index e0aaf6b..db4601e 100644 --- a/expr/parse_test.go +++ b/expr/parse_test.go @@ -131,10 +131,10 @@ func TestParseStatement(t *T) { } func TestParseBlock(t *T) { - stmt := func(in, to Expr) Statement { - return Statement{In: in, To: to} + stmt := func(in, to Expr) Expr { + return Expr{Actual: Statement{In: in, To: to}} } - block := func(stmts ...Statement) Expr { + block := func(stmts ...Expr) Expr { return Expr{Actual: Block(stmts)} } diff --git a/expr/util.go b/expr/util.go new file mode 100644 index 0000000..7648094 --- /dev/null +++ b/expr/util.go @@ -0,0 +1,14 @@ +package expr + +import ( + "encoding/hex" + "math/rand" +) + +func randStr() string { + b := make([]byte, 16) + if _, err := rand.Read(b); err != nil { + panic(err) + } + return hex.EncodeToString(b) +} diff --git a/main.go b/main.go index 980b069..ef3c819 100644 --- a/main.go +++ b/main.go @@ -22,45 +22,49 @@ func main() { llvm.InitializeNativeAsmPrinter() // setup our builder and module - builder := llvm.NewBuilder() - mod := llvm.NewModule("my_module") - - // create our function prologue - main := llvm.FunctionType(llvm.Int64Type(), []llvm.Type{}, false) - llvm.AddFunction(mod, "main", main) - block := llvm.AddBasicBlock(mod.NamedFunction("main"), "entry") - builder.SetInsertPoint(block, block.FirstInstruction()) + lctx := expr.LLVMCtx{ + B: llvm.NewBuilder(), + M: llvm.NewModule("my_module"), + } + // do the work in the function a := expr.Expr{Actual: expr.Int(1)} b := expr.Expr{Actual: expr.Int(2)} c := expr.Expr{Actual: expr.Int(3)} - tup := expr.Expr{Actual: expr.Tuple{a, b, c}} + tup := expr.Expr{Actual: expr.Tuple([]expr.Expr{a, b, c})} addMacro := expr.Expr{Actual: expr.Macro("add")} stmt := expr.Expr{Actual: expr.Statement{In: tup, To: addMacro}} + block := expr.Block([]expr.Expr{stmt}) + fn := block.LLVMVal(expr.RootCtx, lctx) - result := stmt.LLVMVal(expr.RootCtx, builder) - builder.CreateRet(result) + // create main and call our function + mainFn := llvm.AddFunction(lctx.M, "main", llvm.FunctionType(llvm.Int64Type(), []llvm.Type{}, false)) + mainBlock := llvm.AddBasicBlock(mainFn, "entry") + lctx.B.SetInsertPoint(mainBlock, mainBlock.FirstInstruction()) + + ret := lctx.B.CreateCall(fn, []llvm.Value{}, "") + lctx.B.CreateRet(ret) // verify it's all good - if err := llvm.VerifyModule(mod, llvm.ReturnStatusAction); err != nil { + if err := llvm.VerifyModule(lctx.M, llvm.ReturnStatusAction); err != nil { panic(err) } fmt.Println("# verified") // Dump the IR fmt.Println("# dumping IR") - mod.Dump() + lctx.M.Dump() fmt.Println("# done dumping IR") // create our exe engine fmt.Println("# creating new execution engine") - engine, err := llvm.NewExecutionEngine(mod) + engine, err := llvm.NewExecutionEngine(lctx.M) if err != nil { panic(err) } // run the function! fmt.Println("# running the function main") - funcResult := engine.RunFunction(mod.NamedFunction("main"), []llvm.GenericValue{}) + funcResult := engine.RunFunction(lctx.M.NamedFunction("main"), []llvm.GenericValue{}) fmt.Printf("%d\n", funcResult.Int(false)) }