refactor to use an interface instead of buildCmd
This commit is contained in:
parent
4180e6b072
commit
73d81dcbcc
@ -1,17 +0,0 @@
|
|||||||
package lang
|
|
||||||
|
|
||||||
// Commonly used Terms
|
|
||||||
var (
|
|
||||||
// Language structure types
|
|
||||||
AAtom = Atom("atom")
|
|
||||||
AConst = Atom("const")
|
|
||||||
ATuple = Atom("tup")
|
|
||||||
AList = Atom("list")
|
|
||||||
|
|
||||||
// Match shortcuts
|
|
||||||
AUnder = Atom("_")
|
|
||||||
TDblUnder = Tuple{AUnder, AUnder}
|
|
||||||
|
|
||||||
// VM commands
|
|
||||||
AAdd = Atom("add")
|
|
||||||
)
|
|
21
lang/lang.go
21
lang/lang.go
@ -6,6 +6,19 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Commonly used Terms
|
||||||
|
var (
|
||||||
|
// Language structure types
|
||||||
|
AAtom = Atom("atom")
|
||||||
|
AConst = Atom("const")
|
||||||
|
ATuple = Atom("tup")
|
||||||
|
AList = Atom("list")
|
||||||
|
|
||||||
|
// Match shortcuts
|
||||||
|
AUnder = Atom("_")
|
||||||
|
TDblUnder = Tuple{AUnder, AUnder}
|
||||||
|
)
|
||||||
|
|
||||||
// Term is a unit of language which carries some meaning. Some Terms are
|
// Term is a unit of language which carries some meaning. Some Terms are
|
||||||
// actually comprised of multiple sub-Terms.
|
// actually comprised of multiple sub-Terms.
|
||||||
type Term interface {
|
type Term interface {
|
||||||
@ -33,7 +46,7 @@ func (a Atom) String() string {
|
|||||||
|
|
||||||
// Type implements the method for Term
|
// Type implements the method for Term
|
||||||
func (a Atom) Type() Term {
|
func (a Atom) Type() Term {
|
||||||
return Atom("atom")
|
return AAtom
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -47,7 +60,7 @@ func (a Const) String() string {
|
|||||||
|
|
||||||
// Type implements the method for Term
|
// Type implements the method for Term
|
||||||
func (a Const) Type() Term {
|
func (a Const) Type() Term {
|
||||||
return Const("const")
|
return AConst
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -71,7 +84,7 @@ func (t Tuple) Type() Term {
|
|||||||
for i := range t {
|
for i := range t {
|
||||||
tt[i] = t[i].Type()
|
tt[i] = t[i].Type()
|
||||||
}
|
}
|
||||||
return Tuple{Atom("tup"), tt}
|
return Tuple{ATuple, tt}
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -101,5 +114,5 @@ func (l list) String() string {
|
|||||||
|
|
||||||
// Type implements the method for Term
|
// Type implements the method for Term
|
||||||
func (l list) Type() Term {
|
func (l list) Type() Term {
|
||||||
return Tuple{Atom("list"), l.typ}
|
return Tuple{AList, l.typ}
|
||||||
}
|
}
|
||||||
|
4
main.go
4
main.go
@ -8,10 +8,10 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
t := lang.Tuple{lang.AAdd, lang.Tuple{
|
t := lang.Tuple{vm.Add, lang.Tuple{vm.Tuple, lang.Tuple{
|
||||||
lang.Tuple{vm.Int, lang.Const("1")},
|
lang.Tuple{vm.Int, lang.Const("1")},
|
||||||
lang.Tuple{vm.Int, lang.Const("2")},
|
lang.Tuple{vm.Int, lang.Const("2")},
|
||||||
}}
|
}}}
|
||||||
|
|
||||||
mod, err := vm.Build(t)
|
mod, err := vm.Build(t)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
243
vm/cmds.go
243
vm/cmds.go
@ -1,42 +1,119 @@
|
|||||||
package vm
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
"github.com/mediocregopher/ginger/lang"
|
"github.com/mediocregopher/ginger/lang"
|
||||||
"llvm.org/llvm/bindings/go/llvm"
|
"llvm.org/llvm/bindings/go/llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type buildCmd struct {
|
type cmd interface {
|
||||||
pattern lang.Tuple
|
inType() valType
|
||||||
inTypeFn func(lang.Term) (llvm.Type, error)
|
outType() valType
|
||||||
outTypeFn func(lang.Term) (llvm.Type, error)
|
build(*Module) (llvm.Value, error)
|
||||||
buildFn func(lang.Term) (val, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd buildCmd) matches(t lang.Term) bool {
|
type valType struct {
|
||||||
return lang.Match(cmd.pattern, t)
|
term lang.Term
|
||||||
|
llvm llvm.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd buildCmd) inType(t lang.Term) (llvm.Type, error) {
|
// most types don't have an input, so we use this as a shortcut
|
||||||
if cmd.inTypeFn == nil {
|
type voidIn struct{}
|
||||||
return llvm.VoidType(), nil
|
|
||||||
|
func (voidIn) inType() valType {
|
||||||
|
return valType{
|
||||||
|
term: lang.Tuple{},
|
||||||
|
llvm: llvm.VoidType(),
|
||||||
}
|
}
|
||||||
return cmd.inTypeFn(t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd buildCmd) outType(t lang.Term) (llvm.Type, error) {
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
if cmd.outTypeFn == nil {
|
|
||||||
return llvm.VoidType(), nil
|
type intCmd struct {
|
||||||
|
voidIn
|
||||||
|
c lang.Const
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ic intCmd) outType() valType {
|
||||||
|
return valType{
|
||||||
|
term: Int,
|
||||||
|
llvm: llvm.Int64Type(),
|
||||||
}
|
}
|
||||||
return cmd.outTypeFn(t)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cmd buildCmd) build(t lang.Term) (val, error) {
|
func (ic intCmd) build(mod *Module) (llvm.Value, error) {
|
||||||
return cmd.buildFn(t)
|
ci, err := strconv.ParseInt(string(ic.c), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
|
return llvm.ConstInt(llvm.Int64Type(), uint64(ci), false), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildCmds(mod *Module) []buildCmd {
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
type tupCmd struct {
|
||||||
|
voidIn
|
||||||
|
els []cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc tupCmd) outType() valType {
|
||||||
|
termTypes := make(lang.Tuple, len(tc.els))
|
||||||
|
llvmTypes := make([]llvm.Type, len(tc.els))
|
||||||
|
for i := range tc.els {
|
||||||
|
elValType := tc.els[i].outType()
|
||||||
|
termTypes[i] = elValType.term
|
||||||
|
llvmTypes[i] = elValType.llvm
|
||||||
|
}
|
||||||
|
vt := valType{term: lang.Tuple{Tuple, termTypes}}
|
||||||
|
if len(llvmTypes) == 0 {
|
||||||
|
vt.llvm = llvm.VoidType()
|
||||||
|
} else {
|
||||||
|
vt.llvm = llvm.StructType(llvmTypes, false)
|
||||||
|
}
|
||||||
|
return vt
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tc tupCmd) build(mod *Module) (llvm.Value, error) {
|
||||||
|
str := llvm.Undef(tc.outType().llvm)
|
||||||
|
var val llvm.Value
|
||||||
|
var err error
|
||||||
|
for i := range tc.els {
|
||||||
|
if val, err = tc.els[i].build(mod); err != nil {
|
||||||
|
str = mod.b.CreateInsertValue(str, val, i, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return str, err
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
type addCmd struct {
|
||||||
|
voidIn
|
||||||
|
a, b intCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac addCmd) outType() valType {
|
||||||
|
return ac.a.outType()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac addCmd) build(mod *Module) (llvm.Value, error) {
|
||||||
|
av, err := ac.a.build(mod)
|
||||||
|
if err != nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
|
bv, err := ac.b.build(mod)
|
||||||
|
if err != nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
|
return mod.b.CreateAdd(av, bv, ""), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
func matchCmd(t lang.Term) (cmd, error) {
|
||||||
aPat := func(a lang.Atom) lang.Tuple {
|
aPat := func(a lang.Atom) lang.Tuple {
|
||||||
return lang.Tuple{lang.AAtom, a}
|
return lang.Tuple{lang.AAtom, a}
|
||||||
}
|
}
|
||||||
@ -46,98 +123,58 @@ func buildCmds(mod *Module) []buildCmd {
|
|||||||
tPat := func(el ...lang.Term) lang.Tuple {
|
tPat := func(el ...lang.Term) lang.Tuple {
|
||||||
return lang.Tuple{Tuple, lang.Tuple(el)}
|
return lang.Tuple{Tuple, lang.Tuple(el)}
|
||||||
}
|
}
|
||||||
buildPat := func(a lang.Atom, b lang.Tuple) lang.Tuple {
|
|
||||||
return tPat(aPat(a), b)
|
|
||||||
}
|
|
||||||
return []buildCmd{
|
|
||||||
{ // (int 42)
|
|
||||||
pattern: buildPat(Int, cPat(lang.AUnder)),
|
|
||||||
outTypeFn: func(t lang.Term) (llvm.Type, error) {
|
|
||||||
return llvm.Int64Type(), nil
|
|
||||||
},
|
|
||||||
buildFn: func(t lang.Term) (val, error) {
|
|
||||||
con := t.(lang.Const)
|
|
||||||
coni, err := strconv.ParseInt(string(con), 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return val{}, err
|
|
||||||
}
|
|
||||||
return val{
|
|
||||||
// TODO why does this have to be cast?
|
|
||||||
v: llvm.ConstInt(llvm.Int64Type(), uint64(coni), false),
|
|
||||||
typ: Int,
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{ // (tup ((atom foo) (const 10)))
|
if !lang.Match(tPat(aPat(lang.AUnder), lang.TDblUnder), t) {
|
||||||
pattern: buildPat(Tuple, lang.Tuple{Tuple, lang.AUnder}),
|
return nil, fmt.Errorf("term %v does not look like a vm command", t)
|
||||||
outTypeFn: func(t lang.Term) (llvm.Type, error) {
|
|
||||||
tup := t.(lang.Tuple)
|
|
||||||
if len(tup) == 0 {
|
|
||||||
return llvm.VoidType(), nil
|
|
||||||
}
|
}
|
||||||
|
k := t.(lang.Tuple)[0].(lang.Atom)
|
||||||
|
v := t.(lang.Tuple)[1]
|
||||||
|
|
||||||
|
// for when v is a Tuple argument, convenience function for casting
|
||||||
|
vAsTup := func(n int) ([]cmd, error) {
|
||||||
|
vcmd, err := matchCmd(v)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
vtup, ok := vcmd.(tupCmd)
|
||||||
|
if !ok || len(vtup.els) != n {
|
||||||
|
return nil, fmt.Errorf("cmd %v expects a %d-tuple argument", k, n)
|
||||||
|
}
|
||||||
|
return vtup.els, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
switch k {
|
||||||
|
case Int:
|
||||||
|
if !lang.Match(cPat(lang.AUnder), v) {
|
||||||
|
return nil, errors.New("int requires constant arg")
|
||||||
|
}
|
||||||
|
return intCmd{c: v.(lang.Const)}, nil
|
||||||
|
case Tuple:
|
||||||
|
if !lang.Match(lang.Tuple{Tuple, lang.AUnder}, v) {
|
||||||
|
return nil, errors.New("tup requires tuple arg")
|
||||||
|
}
|
||||||
|
tup := v.(lang.Tuple)
|
||||||
|
tc := tupCmd{els: make([]cmd, len(tup))}
|
||||||
var err error
|
var err error
|
||||||
typs := make([]llvm.Type, len(tup))
|
|
||||||
for i := range tup {
|
for i := range tup {
|
||||||
if typs[i], err = mod.outType(tup[i]); err != nil {
|
if tc.els[i], err = matchCmd(tup[i]); err != nil {
|
||||||
return llvm.Type{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return llvm.StructType(typs, false), nil
|
return tc, nil
|
||||||
},
|
case Add:
|
||||||
buildFn: func(t lang.Term) (val, error) {
|
els, err := vAsTup(2)
|
||||||
tup := t.(lang.Tuple)
|
|
||||||
// if the tuple is empty then it is a void
|
|
||||||
if len(tup) == 0 {
|
|
||||||
return val{
|
|
||||||
v: llvm.Undef(llvm.VoidType()),
|
|
||||||
typ: lang.Tuple{Tuple, lang.Tuple{}},
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var err error
|
|
||||||
vals := make([]val, len(tup))
|
|
||||||
typs := make([]llvm.Type, len(tup))
|
|
||||||
ttyps := make([]lang.Term, len(tup))
|
|
||||||
for i := range tup {
|
|
||||||
if vals[i], err = mod.build(tup[i]); err != nil {
|
|
||||||
return val{}, err
|
|
||||||
}
|
|
||||||
typs[i] = vals[i].v.Type()
|
|
||||||
ttyps[i] = vals[i].typ
|
|
||||||
}
|
|
||||||
|
|
||||||
str := llvm.Undef(llvm.StructType(typs, false))
|
|
||||||
for i := range vals {
|
|
||||||
str = mod.b.CreateInsertValue(str, vals[i].v, i, "")
|
|
||||||
}
|
|
||||||
return val{
|
|
||||||
v: str,
|
|
||||||
typ: lang.Tuple{Tuple, lang.Tuple(ttyps)},
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
{ // (add ((const 5) (var foo)))
|
|
||||||
pattern: buildPat(lang.AAdd, tPat(lang.TDblUnder, lang.TDblUnder)),
|
|
||||||
outTypeFn: func(t lang.Term) (llvm.Type, error) {
|
|
||||||
return llvm.Int64Type(), nil
|
|
||||||
},
|
|
||||||
buildFn: func(t lang.Term) (val, error) {
|
|
||||||
tup := t.(lang.Tuple)
|
|
||||||
v1, err := mod.build(tup[0])
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return val{}, err
|
return nil, err
|
||||||
|
} else if _, ok := els[0].(intCmd); !ok {
|
||||||
|
return nil, errors.New("add args must be numbers")
|
||||||
|
} else if _, ok := els[1].(intCmd); !ok {
|
||||||
|
return nil, errors.New("add args must be numbers")
|
||||||
|
} else if !lang.Equal(els[0].outType().term, els[1].outType().term) {
|
||||||
|
return nil, errors.New("add args must be the same type")
|
||||||
}
|
}
|
||||||
v2, err := mod.build(tup[1])
|
return addCmd{a: els[0].(intCmd), b: els[1].(intCmd)}, nil
|
||||||
if err != nil {
|
default:
|
||||||
return val{}, err
|
return nil, fmt.Errorf("cmd %v unknown, or its args are malformed", t)
|
||||||
}
|
|
||||||
return val{
|
|
||||||
v: mod.b.CreateAdd(v1.v, v2.v, ""),
|
|
||||||
typ: v1.typ,
|
|
||||||
}, nil
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
44
vm/types.go
44
vm/types.go
@ -1,44 +0,0 @@
|
|||||||
package vm
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/mediocregopher/ginger/lang"
|
|
||||||
"llvm.org/llvm/bindings/go/llvm"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Types supported by the vm in addition to those which are part of lang
|
|
||||||
var (
|
|
||||||
Atom = lang.AAtom
|
|
||||||
Tuple = lang.ATuple
|
|
||||||
Int = lang.Atom("int")
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
tupPat = lang.Tuple{lang.ATuple, lang.Tuple{
|
|
||||||
lang.Tuple{lang.AAtom, Tuple},
|
|
||||||
lang.Tuple{lang.ATuple, lang.AUnder},
|
|
||||||
}}
|
|
||||||
)
|
|
||||||
|
|
||||||
func termToType(t lang.Term) (llvm.Type, error) {
|
|
||||||
switch {
|
|
||||||
case lang.Equal(t, Int):
|
|
||||||
return llvm.Int64Type(), nil
|
|
||||||
case lang.Match(tupPat, t):
|
|
||||||
tup := t.(lang.Tuple)[1].(lang.Tuple)
|
|
||||||
if len(tup) == 0 {
|
|
||||||
return llvm.VoidType(), nil
|
|
||||||
}
|
|
||||||
var err error
|
|
||||||
typs := make([]llvm.Type, len(tup))
|
|
||||||
for i := range tup {
|
|
||||||
if typs[i], err = termToType(tup[i]); err != nil {
|
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return llvm.StructType(typs, false), nil
|
|
||||||
default:
|
|
||||||
return llvm.Type{}, fmt.Errorf("type %v not supported", t)
|
|
||||||
}
|
|
||||||
}
|
|
85
vm/vm.go
85
vm/vm.go
@ -10,10 +10,17 @@ import (
|
|||||||
"llvm.org/llvm/bindings/go/llvm"
|
"llvm.org/llvm/bindings/go/llvm"
|
||||||
)
|
)
|
||||||
|
|
||||||
type val struct {
|
// Types supported by the vm in addition to those which are part of lang
|
||||||
typ lang.Term
|
var (
|
||||||
v llvm.Value
|
Atom = lang.AAtom
|
||||||
}
|
Tuple = lang.ATuple
|
||||||
|
Int = lang.Atom("int")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Commands supported by the vm. Each of the types are also commands
|
||||||
|
var (
|
||||||
|
Add = lang.Atom("add")
|
||||||
|
)
|
||||||
|
|
||||||
// Module contains a compiled set of code which can be run, dumped in IR form,
|
// Module contains a compiled set of code which can be run, dumped in IR form,
|
||||||
// or compiled. A Module should be Dispose()'d of once it's no longer being
|
// or compiled. A Module should be Dispose()'d of once it's no longer being
|
||||||
@ -22,7 +29,6 @@ type Module struct {
|
|||||||
b llvm.Builder
|
b llvm.Builder
|
||||||
m llvm.Module
|
m llvm.Module
|
||||||
mainFn llvm.Value
|
mainFn llvm.Value
|
||||||
buildCmds []buildCmd
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var initOnce sync.Once
|
var initOnce sync.Once
|
||||||
@ -38,7 +44,6 @@ func Build(t lang.Term) (*Module, error) {
|
|||||||
b: llvm.NewBuilder(),
|
b: llvm.NewBuilder(),
|
||||||
m: llvm.NewModule(""),
|
m: llvm.NewModule(""),
|
||||||
}
|
}
|
||||||
mod.buildCmds = buildCmds(mod)
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if mod.mainFn, err = mod.buildFn(t); err != nil {
|
if mod.mainFn, err = mod.buildFn(t); err != nil {
|
||||||
@ -61,73 +66,39 @@ func (mod *Module) Dispose() {
|
|||||||
//mod.b.Dispose()
|
//mod.b.Dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (mod *Module) matchingBuildCmd(t lang.Term) (buildCmd, error) {
|
|
||||||
for _, cmd := range mod.buildCmds {
|
|
||||||
if !cmd.matches(t) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return cmd, nil
|
|
||||||
}
|
|
||||||
return buildCmd{}, fmt.Errorf("unknown compiler command %v", t)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mod *Module) inType(t lang.Term) (llvm.Type, error) {
|
|
||||||
cmd, err := mod.matchingBuildCmd(t)
|
|
||||||
if err != nil {
|
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
return cmd.inType(t.(lang.Tuple)[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mod *Module) outType(t lang.Term) (llvm.Type, error) {
|
|
||||||
cmd, err := mod.matchingBuildCmd(t)
|
|
||||||
if err != nil {
|
|
||||||
return llvm.Type{}, err
|
|
||||||
}
|
|
||||||
return cmd.outType(t.(lang.Tuple)[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (mod *Module) build(t lang.Term) (val, error) {
|
|
||||||
cmd, err := mod.matchingBuildCmd(t)
|
|
||||||
if err != nil {
|
|
||||||
return val{}, err
|
|
||||||
}
|
|
||||||
return cmd.build(t.(lang.Tuple)[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO make this return a val once we get function types
|
// TODO make this return a val once we get function types
|
||||||
func (mod *Module) buildFn(tt ...lang.Term) (llvm.Value, error) {
|
func (mod *Module) buildFn(tt ...lang.Term) (llvm.Value, error) {
|
||||||
if len(tt) == 0 {
|
if len(tt) == 0 {
|
||||||
return llvm.Value{}, errors.New("function cannot be empty")
|
return llvm.Value{}, errors.New("function cannot be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
inType, err := mod.inType(tt[0])
|
cmds := make([]cmd, len(tt))
|
||||||
if err != nil {
|
var err error
|
||||||
|
for i := range tt {
|
||||||
|
if cmds[i], err = matchCmd(tt[i]); err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
var inTypes []llvm.Type
|
}
|
||||||
if inType.TypeKind() == llvm.VoidTypeKind {
|
|
||||||
inTypes = []llvm.Type{}
|
var llvmIns []llvm.Type
|
||||||
|
if in := cmds[0].inType(); in.llvm.TypeKind() == llvm.VoidTypeKind {
|
||||||
|
llvmIns = []llvm.Type{}
|
||||||
} else {
|
} else {
|
||||||
inTypes = []llvm.Type{inType}
|
llvmIns = []llvm.Type{in.llvm}
|
||||||
}
|
}
|
||||||
|
llvmOut := cmds[len(cmds)-1].outType().llvm
|
||||||
|
|
||||||
outType, err := mod.outType(tt[len(tt)-1])
|
fn := llvm.AddFunction(mod.m, "", llvm.FunctionType(llvmOut, llvmIns, false))
|
||||||
if err != nil {
|
|
||||||
return llvm.Value{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
fn := llvm.AddFunction(mod.m, "", llvm.FunctionType(outType, inTypes, false))
|
|
||||||
block := llvm.AddBasicBlock(fn, "")
|
block := llvm.AddBasicBlock(fn, "")
|
||||||
mod.b.SetInsertPoint(block, block.FirstInstruction())
|
mod.b.SetInsertPoint(block, block.FirstInstruction())
|
||||||
|
|
||||||
var out val
|
var out llvm.Value
|
||||||
for _, t := range tt {
|
for i := range cmds {
|
||||||
if out, err = mod.build(t); err != nil {
|
if out, err = cmds[i].build(mod); err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mod.b.CreateRet(out.v)
|
mod.b.CreateRet(out)
|
||||||
return fn, nil
|
return fn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user