refactor the Equal method out of the Actual interface

This commit is contained in:
Brian Picciano 2016-07-28 17:07:04 -06:00
parent 9c9c8afb7d
commit d48bcf34b8
3 changed files with 72 additions and 67 deletions

View File

@ -14,27 +14,22 @@ import (
// TODO empty blocks // TODO empty blocks
// TODO empty parenthesis // TODO empty parenthesis
// TODO having Equal as part of the Actual interface is going to be annoying.
// The built in macros which return their own expressions don't really care
// about it, and it's really only needed for tests I think.
//
// Alternatively, don't have token be embedded in the expression. I'm not sure
// if that's actually possible.
// TODO need to figure out how to test LLVMVal stuff // TODO need to figure out how to test LLVMVal stuff
// Actual represents the actual expression in question, and has certain // Actual represents the actual expression in question, and has certain
// properties. It is wrapped by Expr which also holds onto contextual // properties. It is wrapped by Expr which also holds onto contextual
// information, like the token to which Actual was originally parsed from // information, like the token to which Actual was originally parsed from
type Actual interface { type Actual interface {
// Equal should return true if the type and value of the other expression
// are equal.
Equal(Actual) bool
// Initializes an llvm.Value and returns it. // Initializes an llvm.Value and returns it.
LLVMVal(llvm.Builder) llvm.Value LLVMVal(llvm.Builder) llvm.Value
} }
// equaler is used to compare two expressions. The comparison should not take
// into account Token values, only the actual value being represented
type equaler interface {
equal(equaler) bool
}
// Expr contains the actual expression as well as some contextual information // Expr contains the actual expression as well as some contextual information
// wrapping it. Most interactions will be with this and not with the Actual // wrapping it. Most interactions will be with this and not with the Actual
// directly. // directly.
@ -47,6 +42,9 @@ type Expr struct {
val *llvm.Value val *llvm.Value
} }
// 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(builder llvm.Builder) llvm.Value { func (e Expr) LLVMVal(builder llvm.Builder) llvm.Value {
if e.val == nil { if e.val == nil {
v := e.Actual.LLVMVal(builder) v := e.Actual.LLVMVal(builder)
@ -55,13 +53,27 @@ func (e Expr) LLVMVal(builder llvm.Builder) llvm.Value {
return *e.val return *e.val
} }
// will panic if either Expr's Actual doesn't implement equaler
func (e Expr) equal(e2 Expr) bool {
eq1, ok1 := e.Actual.(equaler)
eq2, ok2 := e2.Actual.(equaler)
if !ok1 || !ok2 {
panic(fmt.Sprintf("can't compare %T and %T", e.Actual, e2.Actual))
}
return eq1.equal(eq2)
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Bool represents a true or false value // Bool represents a true or false value
type Bool bool type Bool bool
// Equal implements the Actual method // LLVMVal implements the Actual interface method
func (b Bool) Equal(e Actual) bool { func (b Bool) LLVMVal(builder llvm.Builder) llvm.Value {
return llvm.Value{}
}
func (b Bool) equal(e equaler) bool {
bb, ok := e.(Bool) bb, ok := e.(Bool)
if !ok { if !ok {
return false return false
@ -69,17 +81,19 @@ func (b Bool) Equal(e Actual) bool {
return bb == b return bb == b
} }
func (b Bool) LLVMVal(builder llvm.Builder) llvm.Value {
return llvm.Value{}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Int represents an integer value // Int represents an integer value
type Int int64 type Int int64
// Equal implements the Actual method // LLVMVal implements the Actual interface method
func (i Int) Equal(e Actual) bool { func (i Int) LLVMVal(builder llvm.Builder) llvm.Value {
v := builder.CreateAlloca(llvm.Int64Type(), "")
builder.CreateStore(llvm.ConstInt(llvm.Int64Type(), uint64(i), false), v)
return v
}
func (i Int) equal(e equaler) bool {
ii, ok := e.(Int) ii, ok := e.(Int)
if !ok { if !ok {
return false return false
@ -87,20 +101,17 @@ func (i Int) Equal(e Actual) bool {
return ii == i return ii == i
} }
// LLVMVal creates a new llvm value using the builder and returns it
func (i Int) LLVMVal(builder llvm.Builder) llvm.Value {
v := builder.CreateAlloca(llvm.Int64Type(), "")
builder.CreateStore(llvm.ConstInt(llvm.Int64Type(), uint64(i), false), v)
return v
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// String represents a string value // String represents a string value
type String string type String string
// Equal implements the Actual method // LLVMVal implements the Actual interface method
func (s String) Equal(e Actual) bool { func (s String) LLVMVal(builder llvm.Builder) llvm.Value {
return llvm.Value{}
}
func (s String) equal(e equaler) bool {
ss, ok := e.(String) ss, ok := e.(String)
if !ok { if !ok {
return false return false
@ -108,18 +119,18 @@ func (s String) Equal(e Actual) bool {
return ss == s return ss == s
} }
func (s String) LLVMVal(builder llvm.Builder) llvm.Value {
return llvm.Value{}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Identifier represents a binding to some other value which has been given a // Identifier represents a binding to some other value which has been given a
// name // name
type Identifier string type Identifier string
// Equal implements the Actual method // LLVMVal implements the Actual interface method
func (id Identifier) Equal(e Actual) bool { func (id Identifier) LLVMVal(builder llvm.Builder) llvm.Value {
return llvm.Value{}
}
func (id Identifier) equal(e equaler) bool {
idid, ok := e.(Identifier) idid, ok := e.(Identifier)
if !ok { if !ok {
return false return false
@ -127,10 +138,6 @@ func (id Identifier) Equal(e Actual) bool {
return idid == id return idid == id
} }
func (id Identifier) LLVMVal(builder llvm.Builder) llvm.Value {
return llvm.Value{}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Macro is an identifier for a macro which can be used to transform // Macro is an identifier for a macro which can be used to transform
@ -143,8 +150,12 @@ func (m Macro) String() string {
return "%" + string(m) return "%" + string(m)
} }
// Equal implements the Actual method // LLVMVal implements the Actual interface method
func (m Macro) Equal(e Actual) bool { func (m Macro) LLVMVal(builder llvm.Builder) llvm.Value {
panic("Macros have no inherent LLVMVal")
}
func (m Macro) equal(e equaler) bool {
mm, ok := e.(Macro) mm, ok := e.(Macro)
if !ok { if !ok {
return false return false
@ -152,10 +163,6 @@ func (m Macro) Equal(e Actual) bool {
return m == mm return m == mm
} }
func (m Macro) LLVMVal(builder llvm.Builder) llvm.Value {
panic("Macros have no inherent LLVMVal")
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Tuple represents a fixed set of expressions which are interacted with as if // Tuple represents a fixed set of expressions which are interacted with as if
@ -170,24 +177,24 @@ func (tup Tuple) String() string {
return "(" + strings.Join(strs, ", ") + ")" return "(" + strings.Join(strs, ", ") + ")"
} }
// Equal implements the Actual method // LLVMVal implements the Actual interface method
func (tup Tuple) Equal(e Actual) bool { func (tup Tuple) LLVMVal(builder llvm.Builder) llvm.Value {
return llvm.Value{}
}
func (tup Tuple) equal(e equaler) bool {
tuptup, ok := e.(Tuple) tuptup, ok := e.(Tuple)
if !ok || len(tuptup) != len(tup) { if !ok || len(tuptup) != len(tup) {
return false return false
} }
for i := range tup { for i := range tup {
if !tup[i].Actual.Equal(tuptup[i].Actual) { if !tup[i].equal(tuptup[i]) {
return false return false
} }
} }
return true return true
} }
func (tup Tuple) LLVMVal(builder llvm.Builder) llvm.Value {
return llvm.Value{}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// Statement represents an actual action which will be taken. The input value is // Statement represents an actual action which will be taken. The input value is
@ -202,12 +209,7 @@ func (s Statement) String() string {
return fmt.Sprintf("(%v > %s)", s.In.Actual, s.To.Actual) return fmt.Sprintf("(%v > %s)", s.In.Actual, s.To.Actual)
} }
// Equal implements the Actual method // LLVMVal implements the Actual interface method
func (s Statement) Equal(e Actual) bool {
ss, ok := e.(Statement)
return ok && s.In.Actual.Equal(ss.In.Actual) && s.To.Actual.Equal(ss.To.Actual)
}
func (s Statement) LLVMVal(builder llvm.Builder) llvm.Value { func (s Statement) LLVMVal(builder llvm.Builder) llvm.Value {
m, ok := s.To.Actual.(Macro) m, ok := s.To.Actual.(Macro)
if !ok { if !ok {
@ -227,6 +229,11 @@ func (s Statement) LLVMVal(builder llvm.Builder) llvm.Value {
return newe.LLVMVal(builder) return newe.LLVMVal(builder)
} }
func (s Statement) equal(e equaler) bool {
ss, ok := e.(Statement)
return ok && s.In.equal(ss.In) && s.To.equal(ss.To)
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// 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
@ -242,24 +249,24 @@ func (b Block) String() string {
return fmt.Sprintf("{ %s }", strings.Join(strs, " ")) return fmt.Sprintf("{ %s }", strings.Join(strs, " "))
} }
// Equal implements the Actual method // LLVMVal implements the Actual interface method
func (b Block) Equal(e Actual) bool { func (b Block) LLVMVal(builder llvm.Builder) llvm.Value {
return llvm.Value{}
}
func (b Block) equal(e equaler) bool {
bb, ok := e.(Block) bb, ok := e.(Block)
if !ok { if !ok {
return false return false
} }
for i := range b { for i := range b {
if !b[i].Equal(bb[i]) { if !b[i].equal(bb[i]) {
return false return false
} }
} }
return true return true
} }
func (b Block) LLVMVal(builder llvm.Builder) llvm.Value {
return llvm.Value{}
}
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
type exprErr struct { type exprErr struct {

View File

@ -37,7 +37,7 @@ func TestSliceEnclosedToks(t *T) {
func assertParse(t *T, in []lexer.Token, expExpr Expr, expOut []lexer.Token) { func assertParse(t *T, in []lexer.Token, expExpr Expr, expOut []lexer.Token) {
expr, out, err := parse(in) expr, out, err := parse(in)
require.Nil(t, err) require.Nil(t, err)
assert.True(t, expExpr.Actual.Equal(expr.Actual), "expr:%v expExpr:%v", expr, expExpr) assert.True(t, expExpr.equal(expr), "expr:%+v expExpr:%+v", expr, expExpr)
assert.Equal(t, expOut, out, "out:%v expOut:%v", out, expOut) assert.Equal(t, expOut, out, "out:%v expOut:%v", out, expOut)
} }

View File

@ -8,8 +8,6 @@ import (
type addActual []Expr type addActual []Expr
func (aa addActual) Equal(Actual) bool { return false }
func (aa addActual) LLVMVal(builder llvm.Builder) llvm.Value { func (aa addActual) LLVMVal(builder llvm.Builder) llvm.Value {
a := builder.CreateLoad(aa[0].LLVMVal(builder), "") a := builder.CreateLoad(aa[0].LLVMVal(builder), "")
for i := range aa[1:] { for i := range aa[1:] {