Skip to content

Commit

Permalink
v4.3.6 better dot-calls
Browse files Browse the repository at this point in the history
  • Loading branch information
glycerine committed Mar 20, 2016
1 parent 9689ebf commit 80817c1
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 35 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ for the whole project when speaking aloud. In writing, the full
$ go get github.com/glycerine/zygomys/cmd/zygo
~~~

### not your average parentheses... features in zygomys 4.3.5 include
### not your average parentheses... features in zygomys 4.3.6 include

* [x] struct defintion and type checking. [See `tests/declare.zy` for examples.](https://github.com/glycerine/zygomys/blob/master/tests/declare.zy)
* [x] dot-symbols such as `.plane` or `.plane.wing` give OO-flavor and compact, expressive notation. [See the wiki](https://github.com/glycerine/zygomys/wiki#differences-from-traditional-lisp-syntax) for discussion
Expand Down
4 changes: 2 additions & 2 deletions emacs/zygo.el
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@

(setq *inferior-zygo-regex-prompt* "[^\(zygo>\)\|\(\.\.\.\)]*[> ]")

(defvar *zygo-keypress-to-sendline* (kbd "C-u")
(defvar *zygo-keypress-to-sendline* (kbd "C-n")
"keypress that, when in a pure mode script, sends a line to the interpreter
and then steps to the next line.")

(defvar *zygo-keypress-to-send-sexp-jdev* (kbd "C-n")
(defvar *zygo-keypress-to-send-sexp-jdev* (kbd "C-u")
"keypress that sends the next sexp to the repl, and advances past it.")

(defvar *zygo-keypress-to-send-sexp-jdev-prev* (kbd "C-p")
Expand Down
2 changes: 1 addition & 1 deletion repl/gitcommit.go
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
package zygo
func init() { GITLASTTAG = "v4.3.5"; GITLASTCOMMIT = "9f55b209465717cf85b78961dde47a020994d896" }
func init() { GITLASTTAG = "v4.3.6"; GITLASTCOMMIT = "9689ebf1fd897697d560058bdd185fda5b57e02e" }
4 changes: 2 additions & 2 deletions repl/hashutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ func (hash *SexpHash) HashGet(env *Glisp, key Sexp) (Sexp, error) {
}

if val == SexpEnd {
msg := fmt.Sprintf("HashGet: key %s not found", key.SexpString(0))
return SexpNull, errors.New(msg)
return SexpNull, fmt.Errorf("%s has no field '%s'", hash.TypeName, key.SexpString(0))
//return SexpNull, fmt.Errorf("%s has no field '%s'", hash.UserStructDefn.Name, key.SexpString(0))
}
return val, nil
}
Expand Down
86 changes: 57 additions & 29 deletions repl/vm.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,18 +227,21 @@ func (c CallInstr) Execute(env *Glisp) error {
if err != nil {
return err
}
//Q("\n in CallInstr, after looking up c.sym='%s', got funcobj='%v'. datastack is:\n", c.sym.name, funcobj.SexpString(0))
Q("\n in CallInstr, after looking up c.sym='%s', got funcobj='%v'. datastack is:\n", c.sym.name, funcobj.SexpString(0))
//env.datastack.PrintStack()
switch f := funcobj.(type) {
case *SexpSymbol:
// is it a dot-symbol call?
//Q("\n in CallInstr, found symbol\n")
Q("\n in CallInstr, found symbol\n")
if c.sym.isDot {
Q("\n in CallInstr, found symbol, c.sym.isDot is true\n")

dotSymRef, dotLookupErr := dotGetSetHelper(env, c.sym.name, nil)
// cannot error out yet, we might be assigning to a new field,
// not already set.

// are we a value request (no further args), or a fuction/method call?
//Q("\n in CallInstr, found dot-symbol\n")
Q("\n in CallInstr, found dot-symbol\n")
if c.nargs == 0 {
// value request
if dotLookupErr != nil {
Expand All @@ -256,43 +259,43 @@ func (c CallInstr) Execute(env *Glisp) error {
return err
}

top := expressions[0]
switch ftop := top.(type) {
// does our dot-symbol itself refer to a function?
Q("in CallInstr, found dot-symbol, dot-symbol itself is of type %T", dotSymRef)
switch fn := dotSymRef.(type) {
case *SexpFunction:
//Q("\n in CallInstr, fetched out function call from top of datastack.\n")
indirectFuncName = ftop
if ftop.user {
//Q("\n in CallInstr, with user func, passing dot-symbol in directly so assignment will work.\n")
env.datastack.PushExpr(c.sym)
} else {
//Q("\n in CallInstr, with sexp func, dereferencing dot-symbol '%s' -> '%s'\n", c.sym.name, dotSymRef.SexpString(0))
if dotLookupErr != nil {
return dotLookupErr
}
env.datastack.PushExpr(dotSymRef)
}
pushme := expressions[1:]
for j := range pushme {
env.datastack.PushExpr(pushme[j])
}
//Q("\n in CallInstr, after setting up stack for dot-symbol call, datastack:\n")
//env.datastack.PrintStack()

c.setupDotCallHelper(env, fn, &indirectFuncName, expressions, 0, dotSymRef)
default:
return fmt.Errorf("dot-symbol '%s' was followed by non-function '%s'.",
c.sym.name, ftop.SexpString(0))
top := expressions[0]
Q("in CallInstr, found dot-symbol, first arg to dot-symbol is of type %T", top)
switch ftop := top.(type) {
case *SexpFunction:
c.setupDotCallHelper(env, ftop, &indirectFuncName, expressions, 1, dotSymRef)
default:
return fmt.Errorf("dot-symbol '%s' was followed by non-function '%s'.",
c.sym.name, ftop.SexpString(0))
}
}
}
} else {
// not isDot

// allow symbols to refer to functions that we then call
indirectFuncName, err, _ = env.LexicalLookupSymbol(f, false)

// allow symbols to refer to dot-symbols, that then we call
indirectFuncName, err = dotGetSetHelper(env, f.name, nil)
if err != nil {
return fmt.Errorf("'%s' refers to symbol '%s', but '%s' could not be resolved: '%s'.",
c.sym.name, f.name, f.name, err)
}

// allow symbols to refer to functions that we then call
/*
indirectFuncName, err, _ = env.LexicalLookupSymbol(f, false)
if err != nil {
return fmt.Errorf("'%s' refers to symbol '%s', but '%s' could not be resolved: '%s'.",
c.sym.name, f.name, f.name, err)
}
*/
Q("\n in CallInstr, found symbol, c.sym.isDot is false. f of type %T/val = %v. indirectFuncName = '%v'\n", f, f.SexpString(0), indirectFuncName.SexpString(0))

}

switch g := indirectFuncName.(type) {
Expand Down Expand Up @@ -804,3 +807,28 @@ func (a AssignInstr) Execute(env *Glisp) error {
}
return fmt.Errorf("AssignInstr: don't know how to assign to %T", lhs)
}

func (c *CallInstr) setupDotCallHelper(
env *Glisp,
ftop *SexpFunction,
indirectFuncName *Sexp,
expressions []Sexp,
xprBegin int,
dotSymRef Sexp) {

Q("\n in CallInstr, fetched out function call from top of datastack.\n")
*indirectFuncName = ftop
if ftop.user {
Q("\n in CallInstr, with user func, passing dot-symbol in directly so assignment will work.\n")
env.datastack.PushExpr(c.sym)
} else {
Q("\n in CallInstr, with sexp func, dereferencing dot-symbol '%s' -> '%s'\n", c.sym.name, dotSymRef.SexpString(0))
env.datastack.PushExpr(dotSymRef)
}
pushme := expressions[xprBegin:]
for j := range pushme {
env.datastack.PushExpr(pushme[j])
}
Q("\n in CallInstr, after setting up stack for dot-symbol call, datastack:\n")
//env.datastack.PrintStack()
}
12 changes: 12 additions & 0 deletions tests/dotcall.zy
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,15 @@
(assert (== (g greet) expected))
(assert (== (.greet g) expected))
(assert (== (.greet) "hello"))

// automatic * dereference of a.f dot-symbol should
// happen for call-position
(def h2 (hash g:3 f:(fn [x] {x*x})))
(assert (== (h2.f 4) 16))

(def g h2.f)
(assert (== (g 3) 9))

// perhaps more properly, not depending on the auto-deference mechanism:
(def ff (* h2.f))
(assert (== (ff 3) 9))

0 comments on commit 80817c1

Please sign in to comment.