refactor to use Build and BuildStmt, remove a buttload of code
This commit is contained in:
parent
bdd5711773
commit
813117c0f4
28
expr/build.go
Normal file
28
expr/build.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package expr
|
||||||
|
|
||||||
|
import "llvm.org/llvm/bindings/go/llvm"
|
||||||
|
|
||||||
|
type LLVMCtx struct {
|
||||||
|
B llvm.Builder
|
||||||
|
M llvm.Module
|
||||||
|
}
|
||||||
|
|
||||||
|
func Build(ctx *Ctx, lctx LLVMCtx, stmts []Expr) {
|
||||||
|
for _, stmt := range stmts {
|
||||||
|
BuildStmt(ctx, lctx, stmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BuildStmt(ctx *Ctx, lctx LLVMCtx, stmtE Expr) {
|
||||||
|
s := stmtE.Actual.(Statement)
|
||||||
|
m := s.Op.Actual.(Macro)
|
||||||
|
|
||||||
|
fn := ctx.GetMacro(m)
|
||||||
|
if fn == nil {
|
||||||
|
panicf("unknown macro: %q", m)
|
||||||
|
}
|
||||||
|
lv, ok := fn(ctx, lctx, s.Arg)
|
||||||
|
if ok {
|
||||||
|
ctx.LastVal = lv
|
||||||
|
}
|
||||||
|
}
|
10
expr/ctx.go
10
expr/ctx.go
@ -1,17 +1,23 @@
|
|||||||
package expr
|
package expr
|
||||||
|
|
||||||
|
import "llvm.org/llvm/bindings/go/llvm"
|
||||||
|
|
||||||
|
type MacroFn func(*Ctx, LLVMCtx, Expr) (llvm.Value, bool)
|
||||||
|
|
||||||
// Ctx contains all the Macros and Identifiers available. A Ctx is based on the
|
// Ctx contains all the Macros and Identifiers available. A Ctx is based on the
|
||||||
// parent it was created from. If the current Ctx doesn't have a particular key
|
// parent it was created from. If the current Ctx doesn't have a particular key
|
||||||
// being looked up, the parent is called instead, and so on. A consequence of
|
// being looked up, the parent is called instead, and so on. A consequence of
|
||||||
// this is that keys in the children take precedence over the parent's
|
// this is that keys in the children take precedence over the parent's
|
||||||
type Ctx struct {
|
type Ctx struct {
|
||||||
Parent *Ctx
|
Parent *Ctx
|
||||||
Macros map[Macro]func(Expr) (Expr, error)
|
Macros map[Macro]MacroFn
|
||||||
|
|
||||||
|
LastVal llvm.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMacro returns the first instance of the given of the given Macro found. If
|
// GetMacro returns the first instance of the given of the given Macro found. If
|
||||||
// not found nil is returned.
|
// not found nil is returned.
|
||||||
func (c *Ctx) GetMacro(m Macro) func(Expr) (Expr, error) {
|
func (c *Ctx) GetMacro(m Macro) MacroFn {
|
||||||
if c.Macros != nil {
|
if c.Macros != nil {
|
||||||
if fn, ok := c.Macros[m]; ok {
|
if fn, ok := c.Macros[m]; ok {
|
||||||
return fn
|
return fn
|
||||||
|
275
expr/expr.go
275
expr/expr.go
@ -2,7 +2,6 @@ package expr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"llvm.org/llvm/bindings/go/llvm"
|
"llvm.org/llvm/bindings/go/llvm"
|
||||||
|
|
||||||
@ -13,25 +12,11 @@ import (
|
|||||||
// TODO empty parenthesis
|
// TODO empty parenthesis
|
||||||
// TODO need to figure out how to test LLVMVal stuff
|
// TODO need to figure out how to test LLVMVal stuff
|
||||||
// TODO once we're a bit more confident, make ActualFunc
|
// TODO once we're a bit more confident, make ActualFunc
|
||||||
// TODO LLVMVal -> LLVMBuild?
|
|
||||||
|
|
||||||
type LLVMCtx struct {
|
// Actual represents the actual expression in question. It is wrapped by Expr
|
||||||
B llvm.Builder
|
// which also holds onto contextual information, like the token to which Actual
|
||||||
M llvm.Module
|
// was originally parsed from
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
type Actual interface {
|
||||||
// Returns the llvm.Type which the expression accepts as an input, if any
|
|
||||||
LLVMInType(ctx *Ctx) llvm.Type
|
|
||||||
|
|
||||||
// Returns the llvm.Type which the expressions outputs
|
|
||||||
LLVMOutType(ctx *Ctx) llvm.Type
|
|
||||||
|
|
||||||
// Initializes an llvm.Value and returns it.
|
|
||||||
LLVMVal(*Ctx, LLVMCtx) llvm.Value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// equaler is used to compare two expressions. The comparison should not take
|
// equaler is used to compare two expressions. The comparison should not take
|
||||||
@ -52,27 +37,6 @@ type Expr struct {
|
|||||||
val *llvm.Value
|
val *llvm.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLVMInType passes through to the method on the underlying Actual
|
|
||||||
func (e Expr) LLVMInType(ctx *Ctx) llvm.Type {
|
|
||||||
return e.Actual.LLVMInType(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMOutType passes through to the method on the underlying Actual
|
|
||||||
func (e Expr) LLVMOutType(ctx *Ctx) llvm.Type {
|
|
||||||
return e.Actual.LLVMOutType(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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, lctx LLVMCtx) llvm.Value {
|
|
||||||
if e.val == nil {
|
|
||||||
v := e.Actual.LLVMVal(ctx, lctx)
|
|
||||||
e.val = &v
|
|
||||||
}
|
|
||||||
return *e.val
|
|
||||||
}
|
|
||||||
|
|
||||||
// will panic if either Expr's Actual doesn't implement equaler
|
// will panic if either Expr's Actual doesn't implement equaler
|
||||||
func (e Expr) equal(e2 Expr) bool {
|
func (e Expr) equal(e2 Expr) bool {
|
||||||
eq1, ok1 := e.Actual.(equaler)
|
eq1, ok1 := e.Actual.(equaler)
|
||||||
@ -88,21 +52,9 @@ func (e Expr) equal(e2 Expr) bool {
|
|||||||
// Void represents no data (size = 0)
|
// Void represents no data (size = 0)
|
||||||
type Void struct{}
|
type Void struct{}
|
||||||
|
|
||||||
// LLVMInType implements the Actual interface method
|
func (v Void) equal(e equaler) bool {
|
||||||
func (v Void) LLVMInType(ctx *Ctx) llvm.Type {
|
_, ok := e.(Void)
|
||||||
panic("Void has no InType")
|
return ok
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMOutType implements the Actual interface method
|
|
||||||
func (v Void) LLVMOutType(ctx *Ctx) llvm.Type {
|
|
||||||
return llvm.VoidType()
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMVal implements the Actual interface method
|
|
||||||
func (v Void) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
|
||||||
// Kind of weird that this only works for return type, but I guess makes
|
|
||||||
// sense
|
|
||||||
return lctx.B.CreateRetVoid()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -110,21 +62,6 @@ func (v Void) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
|||||||
// Bool represents a true or false value
|
// Bool represents a true or false value
|
||||||
type Bool bool
|
type Bool bool
|
||||||
|
|
||||||
// LLVMInType implements the Actual interface method
|
|
||||||
func (b Bool) LLVMInType(ctx *Ctx) llvm.Type {
|
|
||||||
panic("Bool has no InType")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMOutType implements the Actual interface method
|
|
||||||
func (b Bool) LLVMOutType(ctx *Ctx) llvm.Type {
|
|
||||||
return llvm.IntType(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMVal implements the Actual interface method
|
|
||||||
func (b Bool) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
|
||||||
return llvm.Value{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b Bool) equal(e equaler) bool {
|
func (b Bool) equal(e equaler) bool {
|
||||||
bb, ok := e.(Bool)
|
bb, ok := e.(Bool)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -138,18 +75,7 @@ func (b Bool) equal(e equaler) bool {
|
|||||||
// Int represents an integer value
|
// Int represents an integer value
|
||||||
type Int int64
|
type Int int64
|
||||||
|
|
||||||
// LLVMInType implements the Actual interface method
|
func (i Int) build(lctx LLVMCtx) llvm.Value {
|
||||||
func (i Int) LLVMInType(ctx *Ctx) llvm.Type {
|
|
||||||
panic("Int has no InType")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMOutType implements the Actual interface method
|
|
||||||
func (i Int) LLVMOutType(ctx *Ctx) llvm.Type {
|
|
||||||
return llvm.Int64Type()
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMVal implements the Actual interface method
|
|
||||||
func (i Int) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
|
||||||
v := lctx.B.CreateAlloca(llvm.Int64Type(), "")
|
v := lctx.B.CreateAlloca(llvm.Int64Type(), "")
|
||||||
lctx.B.CreateStore(llvm.ConstInt(llvm.Int64Type(), uint64(i), false), v)
|
lctx.B.CreateStore(llvm.ConstInt(llvm.Int64Type(), uint64(i), false), v)
|
||||||
return v
|
return v
|
||||||
@ -157,10 +83,7 @@ func (i Int) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
|||||||
|
|
||||||
func (i Int) equal(e equaler) bool {
|
func (i Int) equal(e equaler) bool {
|
||||||
ii, ok := e.(Int)
|
ii, ok := e.(Int)
|
||||||
if !ok {
|
return ok && ii == i
|
||||||
return false
|
|
||||||
}
|
|
||||||
return ii == i
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -168,21 +91,6 @@ func (i Int) equal(e equaler) bool {
|
|||||||
// String represents a string value
|
// String represents a string value
|
||||||
type String string
|
type String string
|
||||||
|
|
||||||
// LLVMInType implements the Actual interface method
|
|
||||||
func (s String) LLVMInType(ctx *Ctx) llvm.Type {
|
|
||||||
panic("String has no InType")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMOutType implements the Actual interface method
|
|
||||||
func (s String) LLVMOutType(ctx *Ctx) llvm.Type {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMVal implements the Actual interface method
|
|
||||||
func (s String) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s String) equal(e equaler) bool {
|
func (s String) equal(e equaler) bool {
|
||||||
ss, ok := e.(String)
|
ss, ok := e.(String)
|
||||||
if !ok {
|
if !ok {
|
||||||
@ -197,27 +105,9 @@ func (s String) equal(e equaler) bool {
|
|||||||
// name
|
// name
|
||||||
type Identifier string
|
type Identifier string
|
||||||
|
|
||||||
// LLVMInType implements the Actual interface method
|
|
||||||
func (id Identifier) LLVMInType(ctx *Ctx) llvm.Type {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMOutType implements the Actual interface method
|
|
||||||
func (id Identifier) LLVMOutType(ctx *Ctx) llvm.Type {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMVal implements the Actual interface method
|
|
||||||
func (id Identifier) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (id Identifier) equal(e equaler) bool {
|
func (id Identifier) equal(e equaler) bool {
|
||||||
idid, ok := e.(Identifier)
|
idid, ok := e.(Identifier)
|
||||||
if !ok {
|
return ok && idid == id
|
||||||
return false
|
|
||||||
}
|
|
||||||
return idid == id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -232,27 +122,9 @@ func (m Macro) String() string {
|
|||||||
return "%" + string(m)
|
return "%" + string(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLVMInType implements the Actual interface method
|
|
||||||
func (m Macro) LLVMInType(ctx *Ctx) llvm.Type {
|
|
||||||
panic("Macro has no InType")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMOutType implements the Actual interface method
|
|
||||||
func (m Macro) LLVMOutType(ctx *Ctx) llvm.Type {
|
|
||||||
panic("Macro has no OutType")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMVal implements the Actual interface method
|
|
||||||
func (m Macro) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
|
||||||
panic("Macro has no Val")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m Macro) equal(e equaler) bool {
|
func (m Macro) equal(e equaler) bool {
|
||||||
mm, ok := e.(Macro)
|
mm, ok := e.(Macro)
|
||||||
if !ok {
|
return ok && m == mm
|
||||||
return false
|
|
||||||
}
|
|
||||||
return m == mm
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -262,39 +134,12 @@ func (m Macro) equal(e equaler) bool {
|
|||||||
type Tuple []Expr
|
type Tuple []Expr
|
||||||
|
|
||||||
func (tup Tuple) String() string {
|
func (tup Tuple) String() string {
|
||||||
strs := make([]string, len(tup))
|
return "(" + exprsJoin(tup) + ")"
|
||||||
for i := range tup {
|
|
||||||
strs[i] = fmt.Sprint(tup[i].Actual)
|
|
||||||
}
|
|
||||||
return "(" + strings.Join(strs, ", ") + ")"
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMInType implements the Actual interface method
|
|
||||||
func (tup Tuple) LLVMInType(ctx *Ctx) llvm.Type {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMOutType implements the Actual interface method
|
|
||||||
func (tup Tuple) LLVMOutType(ctx *Ctx) llvm.Type {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMVal implements the Actual interface method
|
|
||||||
func (tup Tuple) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tup Tuple) equal(e equaler) bool {
|
func (tup Tuple) equal(e equaler) bool {
|
||||||
tuptup, ok := e.(Tuple)
|
tuptup, ok := e.(Tuple)
|
||||||
if !ok || len(tuptup) != len(tup) {
|
return ok && exprsEqual(tup, tuptup)
|
||||||
return false
|
|
||||||
}
|
|
||||||
for i := range tup {
|
|
||||||
if !tup[i].equal(tuptup[i]) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -303,89 +148,39 @@ func (tup Tuple) equal(e equaler) bool {
|
|||||||
// used as the input to the pipe, and the output of the pipe is the output of
|
// used as the input to the pipe, and the output of the pipe is the output of
|
||||||
// the statement
|
// the statement
|
||||||
type Statement struct {
|
type Statement struct {
|
||||||
// TODO change to Op and Arg
|
Op, Arg Expr
|
||||||
In Expr
|
|
||||||
To Expr
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Statement) String() string {
|
func (s Statement) String() string {
|
||||||
return fmt.Sprintf("(%v > %s)", s.In.Actual, s.To.Actual)
|
return fmt.Sprintf("(%v %s)", s.Op.Actual, s.Arg.Actual)
|
||||||
}
|
|
||||||
|
|
||||||
func (s Statement) maybeMacro(ctx *Ctx) (Expr, bool) {
|
|
||||||
m, ok := s.To.Actual.(Macro)
|
|
||||||
if !ok {
|
|
||||||
return Expr{}, false
|
|
||||||
}
|
|
||||||
|
|
||||||
fn := ctx.GetMacro(m)
|
|
||||||
if fn == nil {
|
|
||||||
return Expr{}, false
|
|
||||||
}
|
|
||||||
newe, err := fn(s.In)
|
|
||||||
if err != nil {
|
|
||||||
// TODO proper error
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return newe, true
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMInType implements the Actual interface method
|
|
||||||
func (s Statement) LLVMInType(ctx *Ctx) llvm.Type {
|
|
||||||
if newe, ok := s.maybeMacro(ctx); ok {
|
|
||||||
return newe.LLVMInType(ctx)
|
|
||||||
}
|
|
||||||
// TODO futures
|
|
||||||
panic("unknown Statement.To")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMOutType implements the Actual interface method
|
|
||||||
func (s Statement) LLVMOutType(ctx *Ctx) llvm.Type {
|
|
||||||
if newe, ok := s.maybeMacro(ctx); ok {
|
|
||||||
return newe.LLVMOutType(ctx)
|
|
||||||
}
|
|
||||||
panic("unknown Statement.To")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMVal implements the Actual interface method
|
|
||||||
func (s Statement) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
|
||||||
if newe, ok := s.maybeMacro(ctx); ok {
|
|
||||||
return newe.LLVMVal(ctx, lctx)
|
|
||||||
}
|
|
||||||
panic("unknown Statement.To")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Statement) equal(e equaler) bool {
|
func (s Statement) equal(e equaler) bool {
|
||||||
ss, ok := e.(Statement)
|
ss, ok := e.(Statement)
|
||||||
return ok && s.In.equal(ss.In) && s.To.equal(ss.To)
|
return ok && s.Op.equal(ss.Op) && s.Arg.equal(ss.Arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// Block represents a set of statements which share a scope, i.e. If one
|
// 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
|
// statement binds a variable the rest of the statements in the block can use
|
||||||
// that variable, including sub-blocks within this one.
|
// that variable
|
||||||
type Block []Expr
|
type Block struct {
|
||||||
|
In []Expr
|
||||||
|
Stmts []Expr
|
||||||
|
Out []Expr
|
||||||
|
}
|
||||||
|
|
||||||
func (b Block) String() string {
|
func (b Block) String() string {
|
||||||
strs := make([]string, len(b))
|
return fmt.Sprintf(
|
||||||
for i := range b {
|
"{[%s][%s][%s]}",
|
||||||
strs[i] = b[i].Actual.(Statement).String()
|
exprsJoin(b.In),
|
||||||
}
|
exprsJoin(b.Stmts),
|
||||||
return fmt.Sprintf("{ %s }", strings.Join(strs, " "))
|
exprsJoin(b.Out),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// LLVMInType implements the Actual interface method
|
/*
|
||||||
func (b Block) LLVMInType(ctx *Ctx) llvm.Type {
|
|
||||||
panic("TODO")
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMOutType implements the Actual interface method
|
|
||||||
func (b Block) LLVMOutType(ctx *Ctx) llvm.Type {
|
|
||||||
return b[len(b)-1].LLVMOutType(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
// LLVMVal implements the Actual interface method
|
|
||||||
func (b Block) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
func (b Block) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
||||||
name := randStr() // TODO make this based on token
|
name := randStr() // TODO make this based on token
|
||||||
// TODO make these based on actual statements
|
// TODO make these based on actual statements
|
||||||
@ -404,16 +199,12 @@ func (b Block) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value {
|
|||||||
lctx.B.CreateRet(v)
|
lctx.B.CreateRet(v)
|
||||||
return fn
|
return fn
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
func (b Block) equal(e equaler) bool {
|
func (b Block) equal(e equaler) bool {
|
||||||
bb, ok := e.(Block)
|
bb, ok := e.(Block)
|
||||||
if !ok {
|
return ok &&
|
||||||
return false
|
exprsEqual(b.In, bb.In) &&
|
||||||
}
|
exprsEqual(b.Stmts, bb.Stmts) &&
|
||||||
for i := range b {
|
exprsEqual(b.Out, bb.Out)
|
||||||
if !b[i].equal(bb[i]) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
@ -1,45 +1,23 @@
|
|||||||
package expr
|
package expr
|
||||||
|
|
||||||
import (
|
import "llvm.org/llvm/bindings/go/llvm"
|
||||||
"errors"
|
|
||||||
|
|
||||||
"llvm.org/llvm/bindings/go/llvm"
|
|
||||||
)
|
|
||||||
|
|
||||||
type addActual []Expr
|
|
||||||
|
|
||||||
func (aa addActual) LLVMInType(ctx *Ctx) llvm.Type {
|
|
||||||
panic("addActual has no InType")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (aa addActual) LLVMOutType(ctx *Ctx) llvm.Type {
|
|
||||||
return aa[0].LLVMOutType(ctx)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 := lctx.B.CreateLoad(aa[i+1].LLVMVal(ctx, lctx), "")
|
|
||||||
a = lctx.B.CreateAdd(a, b, "")
|
|
||||||
}
|
|
||||||
return a
|
|
||||||
}
|
|
||||||
|
|
||||||
// RootCtx describes what's available to *all* contexts, and is what all
|
// RootCtx 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 RootCtx = &Ctx{
|
var RootCtx = &Ctx{
|
||||||
Macros: map[Macro]func(Expr) (Expr, error){
|
Macros: map[Macro]MacroFn{
|
||||||
"add": func(e Expr) (Expr, error) {
|
"add": func(ctx *Ctx, lctx LLVMCtx, e Expr) (llvm.Value, bool) {
|
||||||
tup, ok := e.Actual.(Tuple)
|
tup := e.Actual.(Tuple)
|
||||||
if !ok {
|
buildInt := func(e Expr) llvm.Value {
|
||||||
// TODO proper error
|
return lctx.B.CreateLoad(e.Actual.(Int).build(lctx), "")
|
||||||
return Expr{}, errors.New("add only accepts a tuple")
|
|
||||||
}
|
}
|
||||||
// TODO check that it's a tuple of integers too
|
|
||||||
return Expr{
|
a := buildInt(tup[0])
|
||||||
Actual: addActual(tup),
|
for i := range tup[1:] {
|
||||||
Token: e.Token,
|
b := buildInt(tup[i+1])
|
||||||
}, nil
|
a = lctx.B.CreateAdd(a, b, "")
|
||||||
|
}
|
||||||
|
return a, true
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
26
expr/util.go
26
expr/util.go
@ -2,7 +2,9 @@ package expr
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func randStr() string {
|
func randStr() string {
|
||||||
@ -12,3 +14,27 @@ func randStr() string {
|
|||||||
}
|
}
|
||||||
return hex.EncodeToString(b)
|
return hex.EncodeToString(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func exprsJoin(ee []Expr) string {
|
||||||
|
strs := make([]string, len(ee))
|
||||||
|
for i := range ee {
|
||||||
|
strs[i] = fmt.Sprint(ee[i].Actual)
|
||||||
|
}
|
||||||
|
return strings.Join(strs, ", ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func exprsEqual(ee1, ee2 []Expr) bool {
|
||||||
|
if len(ee1) != len(ee2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for i := range ee1 {
|
||||||
|
if !ee1[i].equal(ee2[i]) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func panicf(msg string, args ...interface{}) {
|
||||||
|
panic(fmt.Sprintf(msg, args...))
|
||||||
|
}
|
||||||
|
13
main.go
13
main.go
@ -33,17 +33,20 @@ func main() {
|
|||||||
c := expr.Expr{Actual: expr.Int(3)}
|
c := expr.Expr{Actual: expr.Int(3)}
|
||||||
tup := expr.Expr{Actual: expr.Tuple([]expr.Expr{a, b, c})}
|
tup := expr.Expr{Actual: expr.Tuple([]expr.Expr{a, b, c})}
|
||||||
addMacro := expr.Expr{Actual: expr.Macro("add")}
|
addMacro := expr.Expr{Actual: expr.Macro("add")}
|
||||||
stmt := expr.Expr{Actual: expr.Statement{In: tup, To: addMacro}}
|
stmt := expr.Expr{Actual: expr.Statement{Op: addMacro, Arg: tup}}
|
||||||
block := expr.Block([]expr.Expr{stmt})
|
|
||||||
fn := block.LLVMVal(expr.RootCtx, lctx)
|
//block := expr.Block([]expr.Expr{stmt})
|
||||||
|
//fn := block.LLVMVal(expr.RootCtx, lctx)
|
||||||
|
|
||||||
// create main and call our function
|
// create main and call our function
|
||||||
mainFn := llvm.AddFunction(lctx.M, "main", llvm.FunctionType(llvm.Int64Type(), []llvm.Type{}, false))
|
mainFn := llvm.AddFunction(lctx.M, "main", llvm.FunctionType(llvm.Int64Type(), []llvm.Type{}, false))
|
||||||
mainBlock := llvm.AddBasicBlock(mainFn, "entry")
|
mainBlock := llvm.AddBasicBlock(mainFn, "entry")
|
||||||
lctx.B.SetInsertPoint(mainBlock, mainBlock.FirstInstruction())
|
lctx.B.SetInsertPoint(mainBlock, mainBlock.FirstInstruction())
|
||||||
|
expr.BuildStmt(expr.RootCtx, lctx, stmt)
|
||||||
|
lctx.B.CreateRet(expr.RootCtx.LastVal)
|
||||||
|
|
||||||
ret := lctx.B.CreateCall(fn, []llvm.Value{}, "")
|
//ret := lctx.B.CreateCall(fn, []llvm.Value{}, "")
|
||||||
lctx.B.CreateRet(ret)
|
//lctx.B.CreateRet(ret)
|
||||||
|
|
||||||
// verify it's all good
|
// verify it's all good
|
||||||
if err := llvm.VerifyModule(lctx.M, llvm.ReturnStatusAction); err != nil {
|
if err := llvm.VerifyModule(lctx.M, llvm.ReturnStatusAction); err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user