diff --git a/expr/expr.go b/expr/expr.go index 93a7eed..9ab9feb 100644 --- a/expr/expr.go +++ b/expr/expr.go @@ -24,6 +24,12 @@ type LLVMCtx struct { // 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 { + // 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 } @@ -46,6 +52,16 @@ type Expr struct { 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. @@ -69,9 +85,41 @@ func (e Expr) equal(e2 Expr) bool { //////////////////////////////////////////////////////////////////////////////// +// Void represents no data (size = 0) +type Void struct{} + +// LLVMInType implements the Actual interface method +func (v Void) LLVMInType(ctx *Ctx) llvm.Type { + panic("Void has no InType") +} + +// 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() +} + +//////////////////////////////////////////////////////////////////////////////// + // Bool represents a true or false value 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{} @@ -90,6 +138,16 @@ func (b Bool) equal(e equaler) bool { // Int represents an integer value type Int int64 +// LLVMInType implements the Actual interface method +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(), "") @@ -110,9 +168,19 @@ func (i Int) equal(e equaler) bool { // String represents a string value 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 { - return llvm.Value{} + panic("TODO") } func (s String) equal(e equaler) bool { @@ -129,9 +197,19 @@ func (s String) equal(e equaler) bool { // name 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 { - return llvm.Value{} + panic("TODO") } func (id Identifier) equal(e equaler) bool { @@ -154,9 +232,19 @@ func (m Macro) String() string { 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("Macros have no inherent LLVMVal") + panic("Macro has no Val") } func (m Macro) equal(e equaler) bool { @@ -181,9 +269,19 @@ func (tup Tuple) String() string { 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 { - return llvm.Value{} + panic("TODO") } func (tup Tuple) equal(e equaler) bool { @@ -213,25 +311,47 @@ func (s Statement) String() string { return fmt.Sprintf("(%v > %s)", s.In.Actual, s.To.Actual) } -// LLVMVal implements the Actual interface method -func (s Statement) LLVMVal(ctx *Ctx, lctx LLVMCtx) llvm.Value { +func (s Statement) maybeMacro(ctx *Ctx) (Expr, bool) { m, ok := s.To.Actual.(Macro) if !ok { - // TODO proper error - panic("statement To is not a macro") + return Expr{}, false } fn := ctx.GetMacro(m) if fn == nil { - // TODO proper error - panic(fmt.Sprintf("unknown macro %q", m)) + return Expr{}, false } newe, err := fn(s.In) if err != nil { // TODO proper error panic(err) } - return newe.LLVMVal(ctx, lctx) + 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 { @@ -254,6 +374,16 @@ func (b Block) String() string { return fmt.Sprintf("{ %s }", strings.Join(strs, " ")) } +// 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 { name := randStr() // TODO make this based on token diff --git a/expr/macros.go b/expr/macros.go index 9d83cc8..0e21dd1 100644 --- a/expr/macros.go +++ b/expr/macros.go @@ -8,6 +8,14 @@ import ( 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:] {