refactor variable stuff to use fewer op types and be more consistent
This commit is contained in:
parent
ea869e7306
commit
97f972f287
88
vm/cmds.go
88
vm/cmds.go
@ -129,44 +129,38 @@ 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 {
|
type varOp struct {
|
||||||
op
|
op
|
||||||
name string
|
v llvm.Value
|
||||||
|
built bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vo varOp) build(mod *Module) (llvm.Value, error) {
|
func (vo *varOp) build(mod *Module) (llvm.Value, error) {
|
||||||
o, err := mod.ctx.get(vo.name)
|
if !vo.built {
|
||||||
if err != nil {
|
var err error
|
||||||
|
if vo.v, err = vo.op.build(mod); err != nil {
|
||||||
return llvm.Value{}, err
|
return llvm.Value{}, err
|
||||||
}
|
}
|
||||||
return o.build(mod)
|
vo.built = true
|
||||||
|
}
|
||||||
|
return vo.v, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type varCtx map[string]*varOp
|
||||||
|
|
||||||
|
func (c varCtx) assign(name string, vo *varOp) error {
|
||||||
|
if _, ok := c[name]; ok {
|
||||||
|
return fmt.Errorf("var %q already assigned", name)
|
||||||
|
}
|
||||||
|
c[name] = vo
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c varCtx) get(name string) (*varOp, error) {
|
||||||
|
if o, ok := c[name]; ok {
|
||||||
|
return o, nil
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("var %q referenced before assignment", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -244,29 +238,29 @@ func termToOp(ctx varCtx, t lang.Term) (op, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
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:
|
case Var:
|
||||||
if !lang.Match(aPat(lang.AUnder), v) {
|
if !lang.Match(aPat(lang.AUnder), v) {
|
||||||
return nil, errors.New("var requires atom arg")
|
return nil, errors.New("var requires atom arg")
|
||||||
}
|
}
|
||||||
name := v.(lang.Atom).String()
|
name := v.(lang.Atom).String()
|
||||||
o, err := ctx.get(name)
|
return ctx.get(name)
|
||||||
|
|
||||||
|
case Assign:
|
||||||
|
if !lang.Match(tPat(tPat(aPat(Var), aPat(lang.AUnder)), lang.TDblUnder), v) {
|
||||||
|
return nil, errors.New("assign requires 2-tuple arg, the first being a var")
|
||||||
|
}
|
||||||
|
tup := v.(lang.Tuple)
|
||||||
|
name := tup[0].(lang.Tuple)[1].String()
|
||||||
|
o, err := termToOp(ctx, tup[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return varOp{op: o, name: name}, nil
|
|
||||||
|
vo := &varOp{op: o}
|
||||||
|
if err := ctx.assign(name, vo); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return vo, nil
|
||||||
|
|
||||||
// Add is special in some way, I think it's a function not a compiler op,
|
// Add is special in some way, I think it's a function not a compiler op,
|
||||||
// not sure yet though
|
// not sure yet though
|
||||||
|
9
vm/vm.go
9
vm/vm.go
@ -24,14 +24,7 @@ var (
|
|||||||
Var = lang.Atom("var")
|
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
|
||||||
|
@ -8,6 +8,7 @@ import (
|
|||||||
|
|
||||||
func TestCompiler(t *T) {
|
func TestCompiler(t *T) {
|
||||||
mkcmd := func(a lang.Atom, args ...lang.Term) lang.Tuple {
|
mkcmd := func(a lang.Atom, args ...lang.Term) lang.Tuple {
|
||||||
|
// TODO a 1-tuple should be the same as its element?
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
return lang.Tuple{a, args[0]}
|
return lang.Tuple{a, args[0]}
|
||||||
}
|
}
|
||||||
@ -24,9 +25,9 @@ func TestCompiler(t *T) {
|
|||||||
|
|
||||||
one := mkint("1")
|
one := mkint("1")
|
||||||
two := mkint("2")
|
two := mkint("2")
|
||||||
foo := lang.Atom("foo")
|
foo := mkcmd(Var, lang.Atom("foo"))
|
||||||
bar := lang.Atom("bar")
|
bar := mkcmd(Var, lang.Atom("bar"))
|
||||||
baz := lang.Atom("baz")
|
baz := mkcmd(Var, lang.Atom("baz"))
|
||||||
|
|
||||||
tests := []test{
|
tests := []test{
|
||||||
{
|
{
|
||||||
@ -42,23 +43,23 @@ func TestCompiler(t *T) {
|
|||||||
{
|
{
|
||||||
in: []lang.Term{
|
in: []lang.Term{
|
||||||
mkcmd(Assign, foo, one),
|
mkcmd(Assign, foo, one),
|
||||||
mkcmd(Add, mkcmd(Tuple, mkcmd(Var, foo), two)),
|
mkcmd(Add, mkcmd(Tuple, foo, two)),
|
||||||
},
|
},
|
||||||
exp: 3,
|
exp: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: []lang.Term{
|
in: []lang.Term{
|
||||||
mkcmd(Assign, foo, mkcmd(Tuple, one, two)),
|
mkcmd(Assign, foo, mkcmd(Tuple, one, two)),
|
||||||
mkcmd(Add, mkcmd(Var, foo)),
|
mkcmd(Add, foo),
|
||||||
},
|
},
|
||||||
exp: 3,
|
exp: 3,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
in: []lang.Term{
|
in: []lang.Term{
|
||||||
mkcmd(Assign, foo, mkcmd(Tuple, one, two)),
|
mkcmd(Assign, foo, mkcmd(Tuple, one, two)),
|
||||||
mkcmd(Assign, bar, mkcmd(Add, mkcmd(Var, foo))),
|
mkcmd(Assign, bar, mkcmd(Add, foo)),
|
||||||
mkcmd(Assign, baz, mkcmd(Add, mkcmd(Var, foo))),
|
mkcmd(Assign, baz, mkcmd(Add, foo)),
|
||||||
mkcmd(Add, mkcmd(Tuple, mkcmd(Var, bar), mkcmd(Var, baz))),
|
mkcmd(Add, mkcmd(Tuple, bar, baz)),
|
||||||
},
|
},
|
||||||
exp: 6,
|
exp: 6,
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user