got variable assignment working
This commit is contained in:
parent
463d693b17
commit
685cde7afb
24
main.go
24
main.go
@ -9,16 +9,32 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
mkcmd := func(a lang.Atom, args ...lang.Term) lang.Tuple {
|
mkcmd := func(a lang.Atom, args ...lang.Term) lang.Tuple {
|
||||||
return lang.Tuple{a, lang.Tuple{vm.Tuple, lang.Tuple(args)}}
|
if len(args) == 1 {
|
||||||
|
return lang.Tuple{a, args[0]}
|
||||||
|
}
|
||||||
|
return lang.Tuple{a, lang.Tuple(args)}
|
||||||
}
|
}
|
||||||
mkint := func(i string) lang.Tuple {
|
mkint := func(i string) lang.Tuple {
|
||||||
return lang.Tuple{vm.Int, lang.Const(i)}
|
return lang.Tuple{vm.Int, lang.Const(i)}
|
||||||
}
|
}
|
||||||
|
|
||||||
t := mkcmd(vm.Add, mkint("1"),
|
//foo := lang.Atom("foo")
|
||||||
mkcmd(vm.Add, mkint("2"), mkint("3")))
|
//tt := []lang.Term{
|
||||||
|
// mkcmd(vm.Assign, foo, mkint("1")),
|
||||||
|
// mkcmd(vm.Add, mkcmd(vm.Tuple, mkcmd(vm.Var, foo), mkint("2"))),
|
||||||
|
//}
|
||||||
|
|
||||||
mod, err := vm.Build(t)
|
foo := lang.Atom("foo")
|
||||||
|
bar := lang.Atom("bar")
|
||||||
|
baz := lang.Atom("baz")
|
||||||
|
tt := []lang.Term{
|
||||||
|
mkcmd(vm.Assign, foo, mkcmd(vm.Tuple, mkint("1"), mkint("2"))),
|
||||||
|
mkcmd(vm.Assign, bar, mkcmd(vm.Add, mkcmd(vm.Var, foo))),
|
||||||
|
mkcmd(vm.Assign, baz, mkcmd(vm.Add, mkcmd(vm.Var, foo))),
|
||||||
|
mkcmd(vm.Add, mkcmd(vm.Tuple, mkcmd(vm.Var, bar), mkcmd(vm.Var, baz))),
|
||||||
|
}
|
||||||
|
|
||||||
|
mod, err := vm.Build(tt...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
83
vm/cmds.go
83
vm/cmds.go
@ -30,6 +30,7 @@ func (vt valType) eq(vt2 valType) bool {
|
|||||||
|
|
||||||
// primitive valTypes
|
// primitive valTypes
|
||||||
var (
|
var (
|
||||||
|
valTypeVoid = valType{term: lang.Tuple{}, llvm: llvm.VoidType()}
|
||||||
valTypeInt = valType{term: Int, llvm: llvm.Int64Type()}
|
valTypeInt = valType{term: Int, llvm: llvm.Int64Type()}
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -39,10 +40,7 @@ var (
|
|||||||
type voidIn struct{}
|
type voidIn struct{}
|
||||||
|
|
||||||
func (voidIn) inType() valType {
|
func (voidIn) inType() valType {
|
||||||
return valType{
|
return valTypeVoid
|
||||||
term: lang.Tuple{},
|
|
||||||
llvm: llvm.VoidType(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -94,8 +92,9 @@ func (to tupOp) build(mod *Module) (llvm.Value, error) {
|
|||||||
var err error
|
var err error
|
||||||
for i := range to.els {
|
for i := range to.els {
|
||||||
if val, err = to.els[i].build(mod); err != nil {
|
if val, err = to.els[i].build(mod); err != nil {
|
||||||
str = mod.b.CreateInsertValue(str, val, i, "")
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
|
str = mod.b.CreateInsertValue(str, val, i, "")
|
||||||
}
|
}
|
||||||
return str, err
|
return str, err
|
||||||
}
|
}
|
||||||
@ -130,6 +129,48 @@ func (teo tupElOp) build(mod *Module) (llvm.Value, error) {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
type assignOp struct {
|
||||||
|
name string
|
||||||
|
op
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ao assignOp) build(mod *Module) (llvm.Value, error) {
|
||||||
|
v, err := ao.op.build(mod)
|
||||||
|
if err != nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
|
mod.ctx[ao.name] = builtOp{op: ao.op, v: v}
|
||||||
|
return v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
type builtOp struct {
|
||||||
|
op
|
||||||
|
v llvm.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
func (bo builtOp) build(*Module) (llvm.Value, error) {
|
||||||
|
return bo.v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
type varOp struct {
|
||||||
|
op
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vo varOp) build(mod *Module) (llvm.Value, error) {
|
||||||
|
o, err := mod.ctx.get(vo.name)
|
||||||
|
if err != nil {
|
||||||
|
return llvm.Value{}, err
|
||||||
|
}
|
||||||
|
return o.build(mod)
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
type addOp struct {
|
type addOp struct {
|
||||||
voidIn
|
voidIn
|
||||||
a, b op
|
a, b op
|
||||||
@ -153,7 +194,7 @@ func (ao addOp) build(mod *Module) (llvm.Value, error) {
|
|||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
func termToOp(t lang.Term) (op, error) {
|
func termToOp(ctx varCtx, t lang.Term) (op, 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}
|
||||||
}
|
}
|
||||||
@ -172,7 +213,7 @@ func termToOp(t lang.Term) (op, error) {
|
|||||||
|
|
||||||
// for when v is a Tuple argument, convenience function for casting
|
// for when v is a Tuple argument, convenience function for casting
|
||||||
vAsTup := func(n int) ([]op, error) {
|
vAsTup := func(n int) ([]op, error) {
|
||||||
vop, err := termToOp(v)
|
vop, err := termToOp(ctx, v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -198,11 +239,37 @@ func termToOp(t lang.Term) (op, error) {
|
|||||||
tc := tupOp{els: make([]op, len(tup))}
|
tc := tupOp{els: make([]op, len(tup))}
|
||||||
var err error
|
var err error
|
||||||
for i := range tup {
|
for i := range tup {
|
||||||
if tc.els[i], err = termToOp(tup[i]); err != nil {
|
if tc.els[i], err = termToOp(ctx, tup[i]); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return tc, nil
|
return tc, nil
|
||||||
|
case Assign:
|
||||||
|
if !lang.Match(tPat(aPat(lang.AUnder), lang.TDblUnder), v) {
|
||||||
|
return nil, errors.New("assign requires 2-tuple arg")
|
||||||
|
}
|
||||||
|
tup := v.(lang.Tuple)
|
||||||
|
name := tup[0].String()
|
||||||
|
o, err := termToOp(ctx, tup[1])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ao := assignOp{op: o, name: name}
|
||||||
|
ctx[name] = o
|
||||||
|
return ao, nil
|
||||||
|
case Var:
|
||||||
|
if !lang.Match(aPat(lang.AUnder), v) {
|
||||||
|
return nil, errors.New("var requires atom arg")
|
||||||
|
}
|
||||||
|
name := v.(lang.Atom).String()
|
||||||
|
o, err := ctx.get(name)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return varOp{op: o, name: name}, nil
|
||||||
|
|
||||||
|
// Add is special in some way, I think it's a function not a compiler op,
|
||||||
|
// not sure yet though
|
||||||
case Add:
|
case Add:
|
||||||
els, err := vAsTup(2)
|
els, err := vAsTup(2)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
26
vm/vm.go
26
vm/vm.go
@ -17,24 +17,37 @@ var (
|
|||||||
Int = lang.Atom("int")
|
Int = lang.Atom("int")
|
||||||
)
|
)
|
||||||
|
|
||||||
// Commands supported by the vm. Each of the types are also commands
|
// Ops supported by the vm
|
||||||
var (
|
var (
|
||||||
Add = lang.Atom("add")
|
Add = lang.Atom("add")
|
||||||
|
Assign = lang.Atom("assign")
|
||||||
|
Var = lang.Atom("var")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type varCtx map[string]op
|
||||||
|
|
||||||
|
func (c varCtx) get(v string) (op, error) {
|
||||||
|
if o, ok := c[v]; ok {
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unknown assigned %q in this context", v)
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
// used.
|
// used.
|
||||||
type Module struct {
|
type Module struct {
|
||||||
b llvm.Builder
|
b llvm.Builder
|
||||||
m llvm.Module
|
m llvm.Module
|
||||||
|
ctx varCtx
|
||||||
mainFn llvm.Value
|
mainFn llvm.Value
|
||||||
}
|
}
|
||||||
|
|
||||||
var initOnce sync.Once
|
var initOnce sync.Once
|
||||||
|
|
||||||
// Build creates a new Module by compiling the given Term as code
|
// Build creates a new Module by compiling the given Terms as code
|
||||||
func Build(t lang.Term) (*Module, error) {
|
// TODO only take in a single Term, implement List and use that with a do op
|
||||||
|
func Build(tt ...lang.Term) (*Module, error) {
|
||||||
initOnce.Do(func() {
|
initOnce.Do(func() {
|
||||||
llvm.LinkInMCJIT()
|
llvm.LinkInMCJIT()
|
||||||
llvm.InitializeNativeTarget()
|
llvm.InitializeNativeTarget()
|
||||||
@ -43,10 +56,11 @@ func Build(t lang.Term) (*Module, error) {
|
|||||||
mod := &Module{
|
mod := &Module{
|
||||||
b: llvm.NewBuilder(),
|
b: llvm.NewBuilder(),
|
||||||
m: llvm.NewModule(""),
|
m: llvm.NewModule(""),
|
||||||
|
ctx: varCtx{},
|
||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if mod.mainFn, err = mod.buildFn(t); err != nil {
|
if mod.mainFn, err = mod.buildFn(tt...); err != nil {
|
||||||
mod.Dispose()
|
mod.Dispose()
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -75,7 +89,7 @@ func (mod *Module) buildFn(tt ...lang.Term) (llvm.Value, error) {
|
|||||||
ops := make([]op, len(tt))
|
ops := make([]op, len(tt))
|
||||||
var err error
|
var err error
|
||||||
for i := range tt {
|
for i := range tt {
|
||||||
if ops[i], err = termToOp(tt[i]); err != nil {
|
if ops[i], err = termToOp(mod.ctx, tt[i]); err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -95,7 +109,7 @@ func (mod *Module) buildFn(tt ...lang.Term) (llvm.Value, error) {
|
|||||||
var out llvm.Value
|
var out llvm.Value
|
||||||
for i := range ops {
|
for i := range ops {
|
||||||
if out, err = ops[i].build(mod); err != nil {
|
if out, err = ops[i].build(mod); err != nil {
|
||||||
return llvm.Value{}, nil
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mod.b.CreateRet(out)
|
mod.b.CreateRet(out)
|
||||||
|
Loading…
Reference in New Issue
Block a user