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"
|
|
|
|
"strings"
|
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
|
|
|
"github.com/mediocregopher/ginger/lexer"
|
|
|
|
)
|
2016-07-06 02:03:04 +00:00
|
|
|
|
2016-07-28 23:14:33 +00:00
|
|
|
// TODO empty blocks?
|
2016-07-23 16:59:11 +00:00
|
|
|
// TODO empty parenthesis
|
2016-07-28 20:09:33 +00:00
|
|
|
// TODO need to figure out how to test LLVMVal stuff
|
2016-07-28 23:14:33 +00:00
|
|
|
// TODO once we're a bit more confident, make ActualFunc
|
2016-07-24 21:57:43 +00:00
|
|
|
|
2016-07-24 20:52:15 +00:00
|
|
|
// 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 {
|
2016-07-28 19:57:17 +00:00
|
|
|
// Initializes an llvm.Value and returns it.
|
2016-07-29 00:39:18 +00:00
|
|
|
LLVMVal(*Ctx, llvm.Builder) llvm.Value
|
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-07-24 20:52:15 +00:00
|
|
|
// Expr contains the actual expression as well as some contextual information
|
|
|
|
// wrapping it. Most interactions will be with this and not with the Actual
|
|
|
|
// directly.
|
|
|
|
type Expr struct {
|
|
|
|
Actual Actual
|
2016-07-22 20:38:20 +00:00
|
|
|
|
2016-07-24 20:52:15 +00:00
|
|
|
// Token is a nice-to-have, nothing will break if it's not there
|
|
|
|
Token lexer.Token
|
2016-07-24 21:57:43 +00:00
|
|
|
|
|
|
|
val *llvm.Value
|
|
|
|
}
|
|
|
|
|
2016-07-28 23:07:04 +00:00
|
|
|
// 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.
|
2016-07-29 00:39:18 +00:00
|
|
|
func (e Expr) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
|
2016-07-24 21:57:43 +00:00
|
|
|
if e.val == nil {
|
2016-07-29 00:39:18 +00:00
|
|
|
v := e.Actual.LLVMVal(ctx, builder)
|
2016-07-24 21:57:43 +00:00
|
|
|
e.val = &v
|
|
|
|
}
|
|
|
|
return *e.val
|
2016-07-22 20:38:20 +00:00
|
|
|
}
|
|
|
|
|
2016-07-28 23:07:04 +00:00
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
|
2016-07-22 20:38:20 +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
|
|
|
// LLVMVal implements the Actual interface method
|
2016-07-29 00:39:18 +00:00
|
|
|
func (b Bool) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
|
2016-07-28 23:07:04 +00:00
|
|
|
return llvm.Value{}
|
|
|
|
}
|
|
|
|
|
|
|
|
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-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
|
|
|
// LLVMVal implements the Actual interface method
|
2016-07-29 00:39:18 +00:00
|
|
|
func (i Int) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
|
2016-07-28 23:07:04 +00:00
|
|
|
v := builder.CreateAlloca(llvm.Int64Type(), "")
|
|
|
|
builder.CreateStore(llvm.ConstInt(llvm.Int64Type(), uint64(i), false), v)
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
|
|
|
func (i Int) equal(e equaler) bool {
|
2016-07-22 20:38:20 +00:00
|
|
|
ii, ok := e.(Int)
|
|
|
|
if !ok {
|
|
|
|
return false
|
|
|
|
}
|
2016-07-24 20:52:15 +00:00
|
|
|
return ii == i
|
2016-07-22 20:38:20 +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
|
|
|
// LLVMVal implements the Actual interface method
|
2016-07-29 00:39:18 +00:00
|
|
|
func (s String) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
|
2016-07-28 23:07:04 +00:00
|
|
|
return llvm.Value{}
|
|
|
|
}
|
|
|
|
|
|
|
|
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-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
|
|
|
// LLVMVal implements the Actual interface method
|
2016-07-29 00:39:18 +00:00
|
|
|
func (id Identifier) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
|
2016-07-28 23:07:04 +00:00
|
|
|
return llvm.Value{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (id Identifier) equal(e equaler) bool {
|
2016-07-22 20:38:20 +00:00
|
|
|
idid, ok := e.(Identifier)
|
|
|
|
if !ok {
|
|
|
|
return false
|
|
|
|
}
|
2016-07-24 20:52:15 +00:00
|
|
|
return idid == id
|
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
|
|
|
// LLVMVal implements the Actual interface method
|
2016-07-29 00:39:18 +00:00
|
|
|
func (m Macro) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
|
2016-07-28 23:07:04 +00:00
|
|
|
panic("Macros have no inherent LLVMVal")
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m Macro) equal(e equaler) bool {
|
2016-07-24 21:04:06 +00:00
|
|
|
mm, ok := e.(Macro)
|
|
|
|
if !ok {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return m == mm
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
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
|
|
|
|
|
|
|
func (tup Tuple) String() string {
|
2016-07-24 20:52:15 +00:00
|
|
|
strs := make([]string, len(tup))
|
|
|
|
for i := range tup {
|
|
|
|
strs[i] = fmt.Sprint(tup[i].Actual)
|
2016-07-22 20:38:20 +00:00
|
|
|
}
|
|
|
|
return "(" + strings.Join(strs, ", ") + ")"
|
|
|
|
}
|
|
|
|
|
2016-07-28 23:07:04 +00:00
|
|
|
// LLVMVal implements the Actual interface method
|
2016-07-29 00:39:18 +00:00
|
|
|
func (tup Tuple) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
|
2016-07-28 23:07:04 +00:00
|
|
|
return llvm.Value{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (tup Tuple) equal(e equaler) bool {
|
2016-07-22 20:38:20 +00:00
|
|
|
tuptup, ok := e.(Tuple)
|
2016-07-24 20:52:15 +00:00
|
|
|
if !ok || len(tuptup) != len(tup) {
|
2016-07-22 20:38:20 +00:00
|
|
|
return false
|
|
|
|
}
|
2016-07-24 20:52:15 +00:00
|
|
|
for i := range tup {
|
2016-07-28 23:07:04 +00:00
|
|
|
if !tup[i].equal(tuptup[i]) {
|
2016-07-22 20:38:20 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
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-07-28 19:57:17 +00:00
|
|
|
In Expr
|
|
|
|
To Expr
|
2016-07-22 21:53:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (s Statement) String() string {
|
2016-07-28 19:57:17 +00:00
|
|
|
return fmt.Sprintf("(%v > %s)", s.In.Actual, s.To.Actual)
|
2016-07-22 21:53:27 +00:00
|
|
|
}
|
|
|
|
|
2016-07-28 23:07:04 +00:00
|
|
|
// LLVMVal implements the Actual interface method
|
2016-07-29 00:39:18 +00:00
|
|
|
func (s Statement) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
|
2016-07-28 19:57:17 +00:00
|
|
|
m, ok := s.To.Actual.(Macro)
|
|
|
|
if !ok {
|
|
|
|
// TODO proper error
|
|
|
|
panic("statement To is not a macro")
|
|
|
|
}
|
2016-07-29 00:39:18 +00:00
|
|
|
|
|
|
|
fn := ctx.GetMacro(m)
|
|
|
|
if fn == nil {
|
2016-07-28 19:57:17 +00:00
|
|
|
// TODO proper error
|
|
|
|
panic(fmt.Sprintf("unknown macro %q", m))
|
|
|
|
}
|
|
|
|
newe, err := fn(s.In)
|
|
|
|
if err != nil {
|
|
|
|
// TODO proper error
|
|
|
|
panic(err)
|
|
|
|
}
|
2016-07-29 00:39:18 +00:00
|
|
|
return newe.LLVMVal(ctx, builder)
|
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)
|
|
|
|
return ok && s.In.equal(ss.In) && s.To.equal(ss.To)
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
// that variable, including sub-blocks within this one.
|
|
|
|
type Block []Statement
|
2016-07-22 21:53:27 +00:00
|
|
|
|
|
|
|
func (b Block) String() string {
|
2016-07-24 20:52:15 +00:00
|
|
|
strs := make([]string, len(b))
|
|
|
|
for i := range b {
|
|
|
|
strs[i] = b[i].String()
|
2016-07-22 21:53:27 +00:00
|
|
|
}
|
|
|
|
return fmt.Sprintf("{ %s }", strings.Join(strs, " "))
|
|
|
|
}
|
|
|
|
|
2016-07-28 23:07:04 +00:00
|
|
|
// LLVMVal implements the Actual interface method
|
2016-07-29 00:39:18 +00:00
|
|
|
func (b Block) LLVMVal(ctx *Ctx, builder llvm.Builder) llvm.Value {
|
2016-07-28 23:07:04 +00:00
|
|
|
return llvm.Value{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (b Block) equal(e equaler) bool {
|
2016-07-22 21:53:27 +00:00
|
|
|
bb, ok := e.(Block)
|
|
|
|
if !ok {
|
|
|
|
return false
|
|
|
|
}
|
2016-07-24 20:52:15 +00:00
|
|
|
for i := range b {
|
2016-07-28 23:07:04 +00:00
|
|
|
if !b[i].equal(bb[i]) {
|
2016-07-22 21:53:27 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|