]> hydra-www.ietfng.org Git - dyna2/commitdiff
small improvements to handling booleans
authorTim Vieira <tim.f.vieira@gmail.com>
Tue, 9 Jul 2013 19:55:22 +0000 (15:55 -0400)
committerTim Vieira <tim.f.vieira@gmail.com>
Tue, 9 Jul 2013 19:55:22 +0000 (15:55 -0400)
clean up aggregators

crash handler hook (write repl lines)

hide ugly file names in error messages

more test cases added coverage target to makefile

added a few more test cases.

16 files changed:
Makefile
src/Dyna/Backend/Python/Backend.hs
src/Dyna/Backend/Python/aggregator.py
src/Dyna/Backend/Python/chart.py
src/Dyna/Backend/Python/errors.py
src/Dyna/Backend/Python/interpreter.py
src/Dyna/Backend/Python/load/sexpr.py
src/Dyna/Backend/Python/repl.py
src/Dyna/Backend/Python/stdlib.py
src/Dyna/Backend/Python/term.py
src/Dyna/Backend/Python/utils.py
test/app/ptb.dynadoc
test/repl/boolean-aggregators.dynadoc
test/repl/equals-errors.dynadoc
test/repl/list.dynadoc [new file with mode: 0644]
test/repl/trace.dynadoc

index 0b1cd38c90ce8de9bfef352e584e0e6ccd97a6d1..4048471bcb65c4f9bc30590a73166e93178a299d 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -31,12 +31,12 @@ fcomp:
 .PHONY: clean veryclean
 clean:
        rm -rf examples/*.dyna.*.plan  \
-           examples/*.dyna.*.planc \
-           examples/*.dyna.plan.py \
-           examples/*.dyna.plan.pyc \
-           examples/*.dyna.*.out \
-           examples/*.dyna.d \
-           examples/*.hist
+          examples/*.dyna.*.planc \
+          examples/*.dyna.plan.py \
+          examples/*.dyna.plan.pyc \
+          examples/*.dyna.*.out \
+          examples/*.dyna.d \
+          examples/*.hist
        rm -rf test/*/*.out
        rm -f tags TAGS
 veryclean: clean
@@ -80,7 +80,6 @@ ghcbuild:
                -o         dist/build/dyna/dyna     \
                -outputdir dist/build/dyna/dyna-tmp \
                -main-is Dyna.Main.Driver Dyna.Main.Driver
-       
        mkdir -p dist/build/dyna-selftests
        mkdir -p dist/build/dyna-selftests/dyna-selftests-tmp
        ghc --make -isrc                          \
@@ -105,3 +104,8 @@ profbuild:
 .PHONY: tags TAGS
 tags TAGS:
        hasktags -b src
+
+coverage:
+       (coverage run run-doctests.py \
+        ; coverage html --include 'src/*' -d coverage-report \
+        ; gnome-open coverage-report/index.html)
index d6423eb446e1a7e0a7da6bcf20f6b8bcf7a3067c..9bef41833a3e1e1721d6060b9ccca32c572d997c 100644 (file)
@@ -51,7 +51,7 @@ aggrs :: S.Set String
 aggrs = S.fromList
   [ "max=" , "min="
   , "+=" , "*="
-  , "and=" , "or=" , "&=" , "|="
+  , "&=" , "|="
   , ":-"
   , "="
   , "majority=" , "mean="
@@ -182,8 +182,8 @@ constants = go
 
   go ("<=",2)    = Just $ PDBS $ infixOp "<="
   go ("<",2)     = Just $ PDBS $ infixOp "<"
-  go ("=",2)     = Just $ PDBS $ infixOp "=="
-  go ("==",2)    = Just $ PDBS $ infixOp "=="
+  go ("=",2)     = Just $ PDBS $ call "equals" []
+  go ("==",2)    = Just $ PDBS $ call "equals" []
   go (">=",2)    = Just $ PDBS $ infixOp ">="
   go (">",2)     = Just $ PDBS $ infixOp ">"
   go ("!=",2)    = Just $ PDBS $ infixOp "!="
@@ -252,10 +252,8 @@ piterate vs = if length vs == 0 then "_"
 pdope_ :: S.Set DFunctAr -> DOpAMine PyDopeBS -> State Int (Doc e)
 pdope_ _ (OPIndr _ _)   = dynacSorry "indirect evaluation not implemented"
 pdope_ _ (OPAsgn v val) = return $ pretty v <+> equals <+> pretty val
-pdope_ _ (OPCheq v val) = return $ "if" <+> pretty v <+> "!="
-                                      <+> pretty val <> ": continue"
-pdope_ _ (OPCkne v val) = return $ "if" <+> pretty v <+> "=="
-                                      <+> pretty val <> ": continue"
+pdope_ _ (OPCheq v val) = return $ "if not equals(" <> pretty v <> ", " <> pretty val <> "): continue"
+pdope_ _ (OPCkne v val) = return $ "if equals(" <> pretty v <> ", " <> pretty val <> "): continue"
 pdope_ _ (OPPeel vs i f _) = return $
     "try:" `above` (indent 4 $
            tupledOrUnderscore vs
index 3a5ca30957cba8ca3a3ead5e6fbdcd7a9e3a75ee..fd3f76bde4f2d13f93dd6604988a0e52b762bc50 100644 (file)
@@ -148,25 +148,25 @@ class min_equals(BAggregator):
         if len(s):
             return min(s)
 
-class maxwithkey_equals(max_equals):
-    def fold(self):
-        m = max_equals.fold(self)
-        self.key = None
-        if m is not None:
-            if not hasattr(m, 'aslist') or len(m.aslist) != 2:
-                raise AggregatorError("argmax expects a pair of values")
-            self.key = m.aslist[1]
-            return m.aslist[0]
-
-class minwithkey_equals(min_equals):
-    def fold(self):
-        m = min_equals.fold(self)
-        self.key = None
-        if m is not None:
-            if not hasattr(m, 'aslist') or len(m.aslist) != 2:
-                raise AggregatorError("argmin expects a pair of values")
-            self.key = m.aslist[1]
-            return m.aslist[0]
+#class maxwithkey_equals(max_equals):
+#    def fold(self):
+#        m = max_equals.fold(self)
+#        self.key = None
+#        if m is not None:
+#            if not hasattr(m, 'aslist') or len(m.aslist) != 2:
+#                raise AggregatorError("argmax expects a pair of values")
+#            self.key = m.aslist[1]
+#            return m.aslist[0]
+
+#class minwithkey_equals(min_equals):
+#    def fold(self):
+#        m = min_equals.fold(self)
+#        self.key = None
+#        if m is not None:
+#            if not hasattr(m, 'aslist') or len(m.aslist) != 2:
+#                raise AggregatorError("argmin expects a pair of values")
+#            self.key = m.aslist[1]
+#            return m.aslist[0]
 
 
 class plus_equals(BAggregator):
@@ -181,18 +181,17 @@ class times_equals(BAggregator):
         if len(s):
             return reduce(operator.mul, s)
 
-class and_equals(BAggregator):
-    def fold(self):
-        s = [k for k, m in self.iteritems() if m > 0]
-        if len(s):
-            return reduce(lambda x,y: x and y, s)
-
-class or_equals(BAggregator):
-    def fold(self):
-        s = [k for k, m in self.iteritems() if m > 0]
-        if len(s):
-            return reduce(lambda x,y: x or y, s)
+#class and_equals(BAggregator):
+#    def fold(self):
+#        s = [k for k, m in self.iteritems() if m > 0]
+#        if len(s):
+#            return reduce(lambda x,y: x and y, s)
 
+#class or_equals(BAggregator):
+#    def fold(self):
+#        s = [k for k, m in self.iteritems() if m > 0]
+#        if len(s):
+#            return reduce(lambda x,y: x or y, s)
 
 class boolean_or_equals(BAggregator):
     def fold(self):
@@ -232,8 +231,6 @@ defs = {
     'min=': min_equals,
     '+=': plus_equals,
     '*=': times_equals,
-    'and=': and_equals,
-    'or=': or_equals,
     '&=': boolean_and_equals,
     '|=': boolean_or_equals,
     ':-': boolean_or_equals,
index a2b9c2b59572e9d9711694da5edb06c65a086707..8e8df05b7e6973a191b3473afec6b09be899c599 100644 (file)
@@ -2,7 +2,7 @@ from collections import defaultdict
 from aggregator import aggregator
 from term import Term
 from utils import _repr
-
+from stdlib import equals
 
 class Chart(object):
 
@@ -80,7 +80,7 @@ class Chart(object):
                     yield term, term.args, term.value
         else:
             for term in candidates:
-                if term.value == val:
+                if equals(term.value, val):
                     yield term, term.args, term.value
 
     def insert(self, args):        # TODO: rename
index 7d31fb46266e66a856d495763349e3f574f26bcd..b775d1b832f64a6a8ebc10218366ebf62a5ae8c7 100644 (file)
@@ -5,7 +5,9 @@ from config import dotdynadir
 
 
 class DynaCompilerError(Exception):
-    pass
+    def __init__(self, msg, filename):
+        self.filename = filename
+        super(DynaCompilerError, self).__init__(msg)
 
 
 class AggregatorError(Exception):
@@ -45,8 +47,8 @@ def exception_handler(etype, evalue, tb):
     # chart -- because it might be too big to email); input to repl.
     # This should all go into a tarball.
 
-    if crash_handler.interp is not None:
-        crash_handler.interp()
+    for hook in crash_handler.hooks:
+        hook()
 
     print 'FATAL ERROR (%s): %s' % (etype.__name__, evalue)
     print 'Crash log available %s' % crashreport.name
@@ -58,8 +60,8 @@ def crash_handler():
     """
     sys.excepthook = exception_handler
 
-# XXX: global state...
-crash_handler.interp = None
+
+crash_handler.hooks = []
 
 
 def show_traceback(einfo=None):
index e14fe4d5e60c92c4ff7220d25399e85e644b3894..7f65a2c06b5d180cc3bebbfbefeea797484de9a0 100644 (file)
@@ -116,7 +116,7 @@ import load, post
 from term import Term, Cons, Nil
 from chart import Chart
 from utils import ip, red, green, blue, magenta, yellow, parse_attrs, \
-    ddict, dynac, read_anf, strip_comments, _repr
+    ddict, dynac, read_anf, strip_comments, _repr, hide_ugly_filename
 
 from prioritydict import prioritydict
 from config import dotdynadir
@@ -132,7 +132,8 @@ class Rule(object):
         self.query = None
     @property
     def span(self):
-        return parse_attrs(self.init or self.query)['Span']
+        span = parse_attrs(self.init or self.query)['Span']
+        return hide_ugly_filename(span)
     @property
     def src(self):
         return strip_comments(parse_attrs(self.init or self.query)['rule'])
@@ -254,7 +255,7 @@ class Interpreter(object):
                     E[h.rule][type(e)].append((e, item, val))
 
         # aggregation errors
-        for r in I:
+        for r in sorted(I, key=lambda r: r.index):
             print >> out, 'Error(s) aggregating %s:' % r
             for etype in I[r]:
                 print >> out, '  %s:' % etype.__name__
@@ -266,7 +267,7 @@ class Interpreter(object):
                 print >> out
 
         # errors pertaining to rules
-        for r in E:
+        for r in sorted(E, key=lambda r: r.index):
             print >> out, 'Error(s) in rule:', r.span
             print >> out
             for line in r.src.split('\n'):
@@ -505,10 +506,6 @@ class Interpreter(object):
             item.aggregator.inc(val, ruleix, variables)
         self.agenda[item] = time()  # FIFO
 
-    def repl(self):
-        import repl
-        repl.REPL(self).cmdloop()
-
     def do(self, filename, initialize=True):
         """
         Compile, load, and execute new dyna rules.
@@ -595,12 +592,10 @@ class Interpreter(object):
     def dynac(self, filename):
         filename = path(filename)
         self.files.append(filename)
-
         out = self.tmp / filename.read_hexhash('sha1') + '.plan.py'
 #        out = filename + '.plan.py'
-
-        dynac(filename, out)
         self.files.append(out)
+        dynac(filename, out)
         return out
 
     def dynac_code(self, code):
@@ -675,9 +670,6 @@ def main():
             args.source.copy(plan)
 
         else:
-            #plan = args.source + '.plan.py'
-            #interp.dynac(args.source, plan)
-
             try:
                 plan = interp.dynac(args.source)
             except DynaCompilerError as e:
@@ -718,7 +710,18 @@ def main():
         interp.dump_charts(args.output)      # should be a post-processor
 
     if args.interactive or not args.source:
-        interp.repl()
+        from repl import REPL
+        repl = REPL(interp)
+
+        def repl_crash():
+            # all files the interpreter generated
+            with file(dotdynadir / 'crash-repl.log', 'wb') as f:
+                for line in repl.lines:
+                    print >> f, line
+
+        crash_handler.hooks.append(repl_crash)
+
+        repl.cmdloop()
 
 
 if __name__ == '__main__':
index 358e9b8a19fbd22bd79471e64d43c248477580fa..c02222b3957ee8329593df4eb224255342f19e72 100644 (file)
@@ -45,31 +45,3 @@ class sexpr(object):
                         variables=None,
                         delete=False)
 
-
-# TODO: maybe really big terms should have a pretty printer
-def pretty(t, initialindent=0):
-    "Pretty print tree as a tabbified s-expression."
-    f = StringIO()
-    out = f.write
-    def pp(t, indent=initialindent, indentme=True):
-        if indentme:
-            out(' '*indent)
-        if isinstance(t, basestring):                    # base case
-            return out('"%s"' % t)
-        if len(t) == 1:
-            if t[0]:
-                pp('"%s"' % t[0], indent, indentme)
-            return
-        label, children = t[0], t[1:]
-        label = '"%s"' % label
-        assert isinstance(label, basestring)
-        out('&t(%s, ' % label)
-        n = len(children)
-        for i, child in enumerate(children):
-            pp(child, indent + len(label) + 5, i != 0)   # first child already indented
-            if i != n-1:                                 # no newline after last child
-                out(',\n')
-        out(')')
-    pp(t)
-    out('\n')
-    return f.getvalue()
index 6133c4552bfae5096e127d296ac8dc53c50fe341..c3c19dfaebaefe27877a0e3523fe27a94a153944 100644 (file)
@@ -8,7 +8,7 @@ to help.
 """
 
 import os, cmd, readline
-from utils import dynac, ip, lexer, subst, drepr, _repr, get_module
+from utils import ip, lexer, subst, drepr, _repr, get_module
 from stdlib import topython, todyna
 from errors import DynaCompilerError, DynaInitializerException
 from config import dotdynadir
@@ -29,6 +29,7 @@ class REPL(cmd.Cmd, object):
                 f.write('')
         readline.read_history_file(hist)
         self.lineno = 0
+        self.lines = []
 
         # create help routines based on doc string.
         for x, v in REPL.__dict__.iteritems():
@@ -111,6 +112,7 @@ class REPL(cmd.Cmd, object):
         been interpreted. If you want to modify the input line before execution
         (for example, variable substitution) do it here.
         """
+        self.lines.append(line)
         return line
 
     def postcmd(self, stop, line):
@@ -127,11 +129,11 @@ class REPL(cmd.Cmd, object):
         """Do nothing on empty input line"""
         pass
 
-#    def do_ip(self, _):
-#        """
-#        Development tool. Jump into an interactive python shell.
-#        """
-#        ip()
+    def do_ip(self, _):
+        """
+        Development tool. Jump into an interactive python shell.
+        """
+        ip()
 
     def do_debug(self, line):
         """
@@ -142,19 +144,15 @@ class REPL(cmd.Cmd, object):
             f.write(line)
         debug.main(f.name)
 
-#    def do_run(self, filename):
-#        """
-#        Load dyna rules from `filename`.
-#
-#        > run examples/papa.dyna
-#
-#        """
-#        try:
-#            changed = self.interp.do(self.interp.dynac(filename))
-#        except DynaCompilerError as e:
-#            print e
-#        else:
-#            self._changed(changed)
+    def do_dynac(self, line):
+        try:
+            src = self.interp.dynac_code(line)   # might raise DynaCompilerError
+        except DynaCompilerError as e:
+            src = e.filename
+            print e
+        finally:
+            print 'opening file %s' % src
+            os.system('emacs -nw %s' % src)
 
     def _query(self, q):
 
@@ -261,7 +259,7 @@ class REPL(cmd.Cmd, object):
             print "ERROR: Line doesn't end with period."
             return
         try:
-            src = self.interp.dynac_code(line)   # might raise DynaCompilerError
+            src = self.interp.dynac_code(line + '   %% repl line %s' % self.lineno)
             changed = self.interp.do(src)
 
         except (DynaInitializerException, DynaCompilerError) as e:
@@ -289,22 +287,6 @@ class REPL(cmd.Cmd, object):
             print '%s = %s.' % (x, _repr(x.value))
         print
 
-#    def _changed_subscriptions(self, changed):
-#
-#        # TODO: this doesn't show changes - it redumps everything.
-#
-#        if not changed:
-#            return
-#        for x, _ in sorted(changed.items()):
-#            if x.fn == '$subscribed/2':
-#                [i, q] = x.args
-#                if x.value:
-#                    print '%s: %s' % (i, q)
-#                    for result in x.value:
-#                        print ' ', _repr(result.value), 'where', drepr(dict(result.variables))
-#        print
-#        self.interp.dump_errors()
-
     def cmdloop(self, _=None):
         try:
             super(REPL, self).cmdloop()
@@ -353,6 +335,22 @@ class REPL(cmd.Cmd, object):
 #                    print ' ', _repr(result.value), 'where', drepr(dict(result.variables))
 #        print
 
+#    def _changed_subscriptions(self, changed):
+#
+#        # TODO: this doesn't show changes - it redumps everything.
+#
+#        if not changed:
+#            return
+#        for x, _ in sorted(changed.items()):
+#            if x.fn == '$subscribed/2':
+#                [i, q] = x.args
+#                if x.value:
+#                    print '%s: %s' % (i, q)
+#                    for result in x.value:
+#                        print ' ', _repr(result.value), 'where', drepr(dict(result.variables))
+#        print
+#        self.interp.dump_errors()
+
     def do_help(self, line):
         mod = line.split()
         if len(mod) <= 1:
index 5e8e922d80f27b51954c4dc30b31aac73d46d1d9..921d043de2d0c5e420ac0881a5867972c737aed0 100644 (file)
@@ -1,6 +1,7 @@
 import re
 from term import Term, Cons, Nil
 from collections import Counter
+from utils import pretty, pretty_print
 
 try:
     from numpy import log, exp, sqrt
@@ -12,6 +13,22 @@ except ImportError:                       # XXX: should probably issue a warning
         return _random() * (b - a) + a
 
 
+def equals(x,y):
+    """
+    My work around for discrepency in bool equality True==1 and False==0.
+
+    >>> equals(True, 1)
+    False
+
+    >>> equals(1, 1.0)
+    True
+    """
+    if isinstance(x, bool) or isinstance(y, bool):
+        return type(x) == type(y) and x == y
+    else:
+        return x == y
+
+
 _range = range
 def range(*x):
     return todyna(_range(*x))
@@ -20,8 +37,7 @@ def split(s, delim='\s+'):
     return todynalist(re.split(delim, s))
 
 def crash():
-    class Crasher(Exception):
-        pass
+    class Crasher(Exception): pass
     raise Crasher('Hey, you asked for it!')
 
 def pycall(name, *args):
index 0b9598286d57e10b53a9ef33fd5e9a485e01cacf..47c0df20073efb74062fa8a0b00805286d3a6870 100644 (file)
@@ -35,23 +35,23 @@ class Term(object):
             return fn
         return '%s(%s)' % (fn, ','.join(map(_repr, self.args)))
 
-    def __getstate__(self):
-        return (self.fn, self.args, self.value, self.aggregator)
+#    def __getstate__(self):
+#        return (self.fn, self.args, self.value, self.aggregator)
 
-    def __setstate__(self, state):
-        (self.fn, self.args, self.value, self.aggregator) = state
+#    def __setstate__(self, state):
+#        (self.fn, self.args, self.value, self.aggregator) = state
 
-    def __add__(self, _):
-        raise TypeError("Can't subtract terms.")
+#    def __add__(self, _):
+#        raise TypeError("Can't subtract terms.")
 
-    def __sub__(self, _):
-        raise TypeError("Can't add terms.")
+#    def __sub__(self, _):
+#        raise TypeError("Can't add terms.")
 
-    def __mul__(self, _):
-        raise TypeError("Can't multiply terms.")
+#    def __mul__(self, _):
+#        raise TypeError("Can't multiply terms.")
 
-    def __div__(self, _):
-        raise TypeError("Can't divide terms.")
+#    def __div__(self, _):
+#        raise TypeError("Can't divide terms.")
 
 
 class Cons(Term):
@@ -90,11 +90,11 @@ class Cons(Term):
     def __hash__(self):
         return hash(tuple(self.aslist))
 
-    def __cmp__(self, other):
-        try:
-            return cmp(self.aslist, other.aslist)
-        except AttributeError:
-            return 1
+#    def __cmp__(self, other):
+#        try:
+#            return cmp(self.aslist, other.aslist)
+#        except AttributeError:
+#            return 
 
 
 class _Nil(Term):
@@ -121,6 +121,12 @@ class _Nil(Term):
         except AttributeError:
             return False
 
+#    def __cmp__(self, other):
+#        try:
+#            return cmp(self.aslist, other.aslist)
+#        except AttributeError:
+#            return 1
+
 
 Nil = _Nil()
 
index 1cef4f7d8858a8f94cd3efd9156aab8b349ff03d..affd0bce80445b90da4d58680f663bc30cd221e7 100644 (file)
@@ -4,6 +4,7 @@ from path import path
 from subprocess import Popen, PIPE
 from config import dynahome, dotdynadir
 from collections import namedtuple
+from cStringIO import StringIO
 
 
 def _repr(x):
@@ -80,10 +81,13 @@ def dynac(f, out, anf=None, compiler_args=()):
     stdout, stderr = p.communicate()
     if p.returncode:
         assert not stdout.strip(), [stdout, stderr]
-        # hide our temporary file's ugly sha1 file names from users.
-        ugly_file_name = dotdynadir + '[a-z0-9/.]+\.dyna\S*'
-        stderr = re.sub(ugly_file_name, '<repl>', stderr)
-        raise DynaCompilerError(stderr)
+        stderr = hide_ugly_filename(stderr)
+        raise DynaCompilerError(stderr, f)
+
+
+def hide_ugly_filename(x, replacement='<repl>'):
+    p = dotdynadir + '[a-z0-9/.]+\.dyna\S*'
+    return re.sub(p, replacement, x)
 
 
 def lexer(term):
@@ -175,6 +179,37 @@ def parse_sexpr(e):
     return es
 
 
+def pretty_print(t):
+    print pretty(t)
+
+def pretty(t, initialindent=0):
+    "Pretty print tree as a tabbified s-expression."
+    f = StringIO()
+    out = f.write
+    def pp(t, indent=initialindent, indentme=True):
+        if indentme:
+            out(' '*indent)
+        if isinstance(t, basestring):                    # base case
+            return out('%s' % t)
+        if len(t) == 1:
+            if t[0]:
+                pp('%s' % t[0], indent, indentme)
+            return
+        label, children = t[0], t[1:]
+        label = '%s' % label
+        assert isinstance(label, basestring)
+        out('(%s ' % label)
+        n = len(children)
+        for i, child in enumerate(children):
+            pp(child, indent + len(label) + 2, i != 0)   # first child already indented
+            if i != n-1:                                 # no newline after last child
+                out('\n')
+        out(')')
+    pp(t)
+    out('\n')
+    return f.getvalue()
+
+
 class ANF(namedtuple('ANF', 'lines ruleix agg head evals unifs result')):
     pass
 
index 30cd48ccf8eb49a89050846a37407f5390517121..40d17a3812ea04c22d7cf8b93644508e8de3818c 100644 (file)
@@ -152,3 +152,5 @@ ntrees = 23.
 > query errors(S)
 errors(12) = ["(ROOT (S (NP Laura) (VP (VP (V (V say) -s) (SBAR that (S (NP George) (VP (Modal might) (VP (V sleep)))))) (PP (P on) (NP (Det the) (N floor))))) !)", "(ROOT (S (NP Laura) (VP (V (V say) -s) (SBAR that (S (NP George) (VP (VP (Modal might) (VP (V sleep))) (PP (P on) (NP (Det the) (N floor)))))))) !)"].
 errors(21) = ["(ROOT (S (NP (NP (Det the) (N (Adj (Adj fine) (@Adj and (Adj blue))) (N woman))) (@NP and (NP (Det every) (N man)))) (VP (VP (Modal must) (VP (V have) (VP (V (V eat) -ed) (NP (Det two) (N (N sandwich) -s))))) (@VP and (VP (VP (V (V sleep) -ed)) (PP (P on) (NP (Det the) (N floor))))))) .)", "(ROOT (S (NP (NP (Det the) (N (Adj (Adj fine) (@Adj and (Adj blue))) (N woman))) (@NP and (NP (Det every) (N man)))) (VP (VP (Modal must) (VP (V have) (VP (VP (V (V eat) -ed) (NP (Det two) (N (N sandwich) -s))) (@VP and (VP (V (V sleep) -ed)))))) (PP (P on) (NP (Det the) (N floor))))) .)"].
+
+%> *resume*
\ No newline at end of file
index 4c98d5f0acc123f649e9b0266323f371d675eedd..fbfc66cc704dfbe8cf478704780628dd81fb8783 100644 (file)
@@ -72,6 +72,12 @@ Changes
 b = true.
 c = true.
 
+
+
+> f(1,2). f(2,2).
+
+*ignore*
+
 > sol
 
 Solution
@@ -79,3 +85,8 @@ Solution
 a.
 b = true.
 c = true.
+
+f/2
+===
+f(1,2).
+f(2,2).
\ No newline at end of file
index adaa7e8f0aa6d98d9a826b0f45849846a2e045ca..3da43e51583869c9edd35f3349e100a3acd55147 100644 (file)
@@ -1,36 +1,41 @@
 
-:- a = 2.
-=============
-a := 2
+> a = 2.
 
+Changes
+=======
+a = 2.
 
 % It's ok to assign 2 again.
-
-:- a = 2.
-
+> a = 2.
 
 % but you can't set it to a different value, such as 1.
+> a = 1.
 
-:- a = 1.
-=============
-a := $error
+Changes
+=======
+a = $error.
 
-:- sol
+> sol
 
 Solution
 ========
-a => $error.
-
+a = $error.
 
 Errors
 ======
-because a is "failed to aggregate item `a` because `=` got conflicting values [1, 2]":
+Error(s) aggregating a/0:
+  AggregatorError:
+    `a`: `=` got conflicting values [1, 2]
+
 
+> retract_rule 2
 
-:- retract_rule 2
+Changes
+=======
+a = 2.
 
-:- sol
+> sol
 
 Solution
 ========
-a => 2.
+a = 2.
diff --git a/test/repl/list.dynadoc b/test/repl/list.dynadoc
new file mode 100644 (file)
index 0000000..fe8b061
--- /dev/null
@@ -0,0 +1,124 @@
+> x = cons(1, 2).
+
+DynaInitializerException:
+TypeError('Malformed list',) in ininitializer for rule
+    x = cons(1, 2).
+new rule(s) were not added to program.
+
+
+> s set= Y for Y in [3,2,1,[2,1],&f(1)].
+
+Changes
+=======
+s = [1, 2, 3, [2, 1], f(1)].
+
+> foo = 1 in s.
+
+Changes
+=======
+foo = true.
+
+% check comparison (sort order) of list and non-list.
+> f(s). f(1). f([]).
+
+Changes
+=======
+f(1) = true.
+f([1, 2, 3, [2, 1], f(1)]) = true.
+f([]) = true.
+
+% test for empty list
+> query 1 in nil
+
+1 in nil = false.
+
+> nothing set= X for X in [].
+
+
+
+
+> g([1,2]).
+
+Changes
+=======
+g([1, 2]) = true.
+
+> a := [1,2].
+
+Changes
+=======
+a = [1, 2].
+
+> goal(X) := g([1|X]).
+
+Changes
+=======
+goal([2]) = true.
+
+
+% list contains
+> b := &f("a") in [1,2,&f("a"),3].
+| c := 2 in [1,2,3].
+| d := 4 in [1,2,3].
+
+Changes
+=======
+b = true.
+c = true.
+d = false.
+
+
+% iteration of a complex list
+> things set= X for X in [1,[2,2],[3,4]].
+
+Changes
+=======
+things = [1, [2, 2], [3, 4]].
+
+% unpack structure requiring a check
+> d(&X) := true for [X,X] in [1,[2,2],[3,4],[4,4]].
+
+Changes
+=======
+d(2) = true.
+d(4) = true.
+
+% quote is important! or else we enumerate everything!
+> foo(A) := true for &f(A) in [1,2,&f("a"),3].
+|
+| % this one checks if the value of f(A) is in the list, (note: 1 == True, in python).
+| goo(A) := true for f(A) in [1,2,&f("a"),3].
+
+
+Changes
+=======
+foo("a") = true.
+goo(1) = true.
+goo([1, 2, 3, [2, 1], f(1)]) = true.
+goo([]) = true.
+
+
+% unfortunately 1 == true and 0 == false in python so the following is true
+> testbool := true in [1,2].
+
+Changes
+=======
+testbool = true.
+
+
+% fun with set= at bag=
+> thingsbag bag= "three".
+| thingsbag bag= 1.
+| thingsbag bag= 1.
+| thingsbag bag= 2.
+|
+| thingset set= "three".
+| thingset set= 1.
+| thingset set= 1.
+| thingset set= 2.
+
+Changes
+=======
+thingsbag = [1, 1, 2, "three"].
+thingset = [1, 2, "three"].
+
index 4444362ffe47f01e5dfb6e2ed5d7797c5098d1ea..d20302437a65fefb8487be18e46ed955c5e0c179 100644 (file)
@@ -97,3 +97,17 @@ bar(10,10) = 220
    └─ foo(10) = 11
       |
       └─ continue as before (shared structure)
+
+
+> x = [1,2,3].
+
+Changes
+=======
+x = [1, 2, 3].
+
+> trace x
+
+x = [1, 2, 3]
+|
+└─ = [1, 2, 3]
+   x = [1, 2, 3].
\ No newline at end of file