make Block implement LLVMVal
This commit is contained in:
parent
b9a40be6d8
commit
09573cf98b
55
expr/expr.go
55
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 {
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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)}
|
||||
}
|
||||
|
||||
|
14
expr/util.go
Normal file
14
expr/util.go
Normal file
@ -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)
|
||||
}
|
34
main.go
34
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))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user