2016-07-23 17:06:26 +00:00
|
|
|
package expr
|
2016-07-06 02:03:04 +00:00
|
|
|
|
2016-07-22 20:38:20 +00:00
|
|
|
import (
|
|
|
|
"fmt"
|
2016-07-06 02:03:04 +00:00
|
|
|
|
2016-07-24 21:57:43 +00:00
|
|
|
"llvm.org/llvm/bindings/go/llvm"
|
2016-07-22 20:38:20 +00:00
|
|
|
)
|
2016-07-06 02:03:04 +00:00
|
|
|
|
2016-08-06 18:20:53 +00:00
|
|
|
// Expr represents the actual expression in question.
|
|
|
|
type Expr interface{}
|
2016-07-22 20:38:20 +00:00
|
|
|
|
2016-07-28 23:07:04 +00:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2016-08-06 18:20:53 +00:00
|
|
|
// will panic if either Expr doesn't implement equaler
|
|
|
|
func exprEqual(e1, e2 Expr) bool {
|
|
|
|
eq1, ok1 := e1.(equaler)
|
|
|
|
eq2, ok2 := e2.(equaler)
|
2016-07-28 23:07:04 +00:00
|
|
|
if !ok1 || !ok2 {
|
2016-08-06 18:20:53 +00:00
|
|
|
panic(fmt.Sprintf("can't compare %T and %T", e1, e2))
|
2016-07-28 23:07:04 +00:00
|
|
|
}
|
|
|
|
return eq1.equal(eq2)
|
|
|
|
}
|
|
|
|
|
2016-07-22 20:38:20 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-08-06 18:20:53 +00:00
|
|
|
// an Expr which simply wraps an existing llvm.Value
|
|
|
|
type llvmVal llvm.Value
|
|
|
|
|
|
|
|
/*
|
|
|
|
func voidVal(lctx LLVMCtx) llvmVal {
|
|
|
|
return llvmVal{lctx.B.CreateRetVoid()}
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
/*
|
2016-08-05 17:44:08 +00:00
|
|
|
// Void represents no data (size = 0)
|
|
|
|
type Void struct{}
|
|
|
|
|
2016-08-05 18:34:17 +00:00
|
|
|
func (v Void) equal(e equaler) bool {
|
|
|
|
_, ok := e.(Void)
|
|
|
|
return ok
|
2016-08-05 17:44:08 +00:00
|
|
|
}
|
2016-08-06 18:20:53 +00:00
|
|
|
*/
|
2016-08-05 17:44:08 +00:00
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2016-08-05 17:48:42 +00:00
|
|
|
/*
|
2016-07-24 20:52:15 +00:00
|
|
|
// Bool represents a true or false value
|
|
|
|
type Bool bool
|
2016-07-22 20:38:20 +00:00
|
|
|
|
2016-07-28 23:07:04 +00:00
|
|
|
func (b Bool) equal(e equaler) bool {
|
2016-07-22 20:38:20 +00:00
|
|
|
bb, ok := e.(Bool)
|
|
|
|
if !ok {
|
|
|
|
return false
|
|
|
|
}
|
2016-07-24 20:52:15 +00:00
|
|
|
return bb == b
|
2016-07-22 20:38:20 +00:00
|
|
|
}
|
2016-08-05 17:48:42 +00:00
|
|
|
*/
|
2016-07-22 20:38:20 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-07-24 20:52:15 +00:00
|
|
|
// Int represents an integer value
|
|
|
|
type Int int64
|
2016-07-22 20:38:20 +00:00
|
|
|
|
2016-07-28 23:07:04 +00:00
|
|
|
func (i Int) equal(e equaler) bool {
|
2016-07-22 20:38:20 +00:00
|
|
|
ii, ok := e.(Int)
|
2016-08-05 18:34:17 +00:00
|
|
|
return ok && ii == i
|
2016-07-22 20:38:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
2016-08-05 17:48:42 +00:00
|
|
|
/*
|
2016-07-24 20:52:15 +00:00
|
|
|
// String represents a string value
|
|
|
|
type String string
|
2016-07-22 20:38:20 +00:00
|
|
|
|
2016-07-28 23:07:04 +00:00
|
|
|
func (s String) equal(e equaler) bool {
|
2016-07-22 20:38:20 +00:00
|
|
|
ss, ok := e.(String)
|
|
|
|
if !ok {
|
|
|
|
return false
|
|
|
|
}
|
2016-07-24 20:52:15 +00:00
|
|
|
return ss == s
|
2016-07-22 20:38:20 +00:00
|
|
|
}
|
2016-08-05 17:48:42 +00:00
|
|
|
*/
|
2016-07-22 20:38:20 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-07-24 20:52:15 +00:00
|
|
|
// Identifier represents a binding to some other value which has been given a
|
|
|
|
// name
|
|
|
|
type Identifier string
|
2016-07-22 20:38:20 +00:00
|
|
|
|
2016-07-28 23:07:04 +00:00
|
|
|
func (id Identifier) equal(e equaler) bool {
|
2016-07-22 20:38:20 +00:00
|
|
|
idid, ok := e.(Identifier)
|
2016-08-05 18:34:17 +00:00
|
|
|
return ok && idid == id
|
2016-07-22 20:38:20 +00:00
|
|
|
}
|
|
|
|
|
2016-08-07 00:10:31 +00:00
|
|
|
func isIdentifier(e Expr) bool {
|
|
|
|
_, ok := e.(Identifier)
|
|
|
|
return ok
|
|
|
|
}
|
|
|
|
|
2016-07-22 20:38:20 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-07-24 21:04:06 +00:00
|
|
|
// Macro is an identifier for a macro which can be used to transform
|
|
|
|
// expressions. The tokens for macros start with a '%', but the Macro identifier
|
|
|
|
// itself has that stripped off
|
|
|
|
type Macro string
|
|
|
|
|
|
|
|
// String returns the Macro with a '%' prepended to it
|
|
|
|
func (m Macro) String() string {
|
|
|
|
return "%" + string(m)
|
|
|
|
}
|
|
|
|
|
2016-07-28 23:07:04 +00:00
|
|
|
func (m Macro) equal(e equaler) bool {
|
2016-07-24 21:04:06 +00:00
|
|
|
mm, ok := e.(Macro)
|
2016-08-05 18:34:17 +00:00
|
|
|
return ok && m == mm
|
2016-07-24 21:04:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-07-24 20:52:15 +00:00
|
|
|
// Tuple represents a fixed set of expressions which are interacted with as if
|
|
|
|
// they were a single value
|
|
|
|
type Tuple []Expr
|
2016-07-22 20:38:20 +00:00
|
|
|
|
2016-08-06 18:20:53 +00:00
|
|
|
// NewTuple returns a Tuple around the given list of Exprs
|
|
|
|
func NewTuple(ee ...Expr) Tuple {
|
|
|
|
return Tuple(ee)
|
|
|
|
}
|
|
|
|
|
2016-07-22 20:38:20 +00:00
|
|
|
func (tup Tuple) String() string {
|
2016-08-05 18:34:17 +00:00
|
|
|
return "(" + exprsJoin(tup) + ")"
|
2016-07-28 23:07:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (tup Tuple) equal(e equaler) bool {
|
2016-07-22 20:38:20 +00:00
|
|
|
tuptup, ok := e.(Tuple)
|
2016-08-05 18:34:17 +00:00
|
|
|
return ok && exprsEqual(tup, tuptup)
|
2016-07-22 20:38:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-07-24 20:52:15 +00:00
|
|
|
// Statement represents an actual action which will be taken. The input value is
|
|
|
|
// used as the input to the pipe, and the output of the pipe is the output of
|
|
|
|
// the statement
|
2016-07-22 21:53:27 +00:00
|
|
|
type Statement struct {
|
2016-08-05 18:34:17 +00:00
|
|
|
Op, Arg Expr
|
2016-07-22 21:53:27 +00:00
|
|
|
}
|
|
|
|
|
2016-08-06 18:36:46 +00:00
|
|
|
// NewStatement returns a Statement whose Op is the first Expr. If the given
|
|
|
|
// list is empty Arg will be nil, if its length is one Arg will be that single
|
|
|
|
// Expr, otherwise Arg will be a Tuple of the list
|
|
|
|
func NewStatement(e Expr, ee ...Expr) Statement {
|
|
|
|
s := Statement{Op: e}
|
|
|
|
if len(ee) > 1 {
|
|
|
|
s.Arg = NewTuple(ee...)
|
|
|
|
} else if len(ee) == 1 {
|
|
|
|
s.Arg = ee[0]
|
|
|
|
}
|
|
|
|
return s
|
|
|
|
}
|
|
|
|
|
2016-07-22 21:53:27 +00:00
|
|
|
func (s Statement) String() string {
|
2016-08-06 18:20:53 +00:00
|
|
|
return fmt.Sprintf("(%v %s)", s.Op, s.Arg)
|
2016-07-24 21:57:43 +00:00
|
|
|
}
|
|
|
|
|
2016-07-28 23:07:04 +00:00
|
|
|
func (s Statement) equal(e equaler) bool {
|
|
|
|
ss, ok := e.(Statement)
|
2016-08-06 18:20:53 +00:00
|
|
|
return ok && exprEqual(s.Op, ss.Op) && exprEqual(s.Arg, ss.Arg)
|
2016-07-28 23:07:04 +00:00
|
|
|
}
|
|
|
|
|
2016-07-22 21:53:27 +00:00
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
2016-07-24 20:52:15 +00:00
|
|
|
// 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
|
2016-08-05 18:34:17 +00:00
|
|
|
// that variable
|
|
|
|
type Block struct {
|
|
|
|
In []Expr
|
|
|
|
Stmts []Expr
|
|
|
|
Out []Expr
|
2016-08-05 17:44:08 +00:00
|
|
|
}
|
|
|
|
|
2016-08-05 18:34:17 +00:00
|
|
|
func (b Block) String() string {
|
|
|
|
return fmt.Sprintf(
|
|
|
|
"{[%s][%s][%s]}",
|
|
|
|
exprsJoin(b.In),
|
|
|
|
exprsJoin(b.Stmts),
|
|
|
|
exprsJoin(b.Out),
|
|
|
|
)
|
2016-08-05 17:44:08 +00:00
|
|
|
}
|
|
|
|
|
2016-08-05 18:34:17 +00:00
|
|
|
/*
|
2016-08-02 00:08:51 +00:00
|
|
|
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
|
2016-07-28 23:07:04 +00:00
|
|
|
}
|
2016-08-05 18:34:17 +00:00
|
|
|
*/
|
2016-07-28 23:07:04 +00:00
|
|
|
|
|
|
|
func (b Block) equal(e equaler) bool {
|
2016-07-22 21:53:27 +00:00
|
|
|
bb, ok := e.(Block)
|
2016-08-05 18:34:17 +00:00
|
|
|
return ok &&
|
|
|
|
exprsEqual(b.In, bb.In) &&
|
|
|
|
exprsEqual(b.Stmts, bb.Stmts) &&
|
|
|
|
exprsEqual(b.Out, bb.Out)
|
2016-07-22 21:53:27 +00:00
|
|
|
}
|