Commits

catseye  committed 693c0cc

Flesh out implementation enough to fail a bunch of Falderal tests.

  • Participants
  • Parent commits b4b9a24

Comments (0)

Files changed (2)

File README.markdown

 -------
 
     Exanoke     ::= {FunDef} Expr.
-    FunDef      ::= "def" name<lowercase> "(" "#" {"," Arg} ")" Expr.
-    Arg         ::= name<lowercase>.
+    FunDef      ::= "def" Ident "(" "#" {"," Ident} ")" Expr.
     Expr        ::= "cons" "(" Expr "," Expr ")"
                   | "if" Expr "then" Expr "else" Expr
                   | "self" "(" Smaller {"," Expr} ")"
                   | "eq?" "(" Expr "," Expr")"
                   | "cons?" "(" Expr ")"
                   | "not" "(" Expr ")"
-                  | "(" Expr ")"
-                  | name<lowercase> "(" Expr {"," Expr} ")"
                   | "#"
-                  | Arg
                   | Atom
+                  | Ident ["(" Expr {"," Expr} ")"]
                   | Smaller.
     Smaller     ::= "<head" SmallerTerm
                   | "<tail" SmallerTerm
                   | "<if" Expr "then" Smaller "else" Smaller.
-    SmallerTerm ::= Smaller
-                  | FirstArg.
+    SmallerTerm ::= "#"
+                  | Smaller.
+    Ident       ::= name<lowercase>.
     Atom        ::= name<uppercase>.
 
 The first argument to a function does not have a user-defined name; it is
 Examples
 --------
 
+    -> Tests for functionality "Evaluate Exanoke program"
+    
+    -> Functionality "Evaluate Exanoke program" is implemented by
+    -> shell command "script/exanoke %(test-file)"
+
+Basic examples.
+
     | cons(HI, THERE)
     = (HI THERE)
     
     ? Arity mismatch
 
     | def id(#)
-    |     ##
+    |     woo
     | id(WOO)
-    ? Arity mismatch
+    ? Undefined argument 'woo'
+
+    | def wat(#, woo)
+    |     woo(#)
+    | wat(WOO)
+    ? Undefined function 'woo'
 
     | def snd(#, another)
     |     another
     = NIL
 
     | def last(#)
-    |     if not cons? # then # else self(<tail #)
+    |     if not(cons?(#)) then # else self(<tail #)
     | last(cons(A cons(B GRAAAP)))
     = GRAAAP
 
     | def count(#, acc)
-    |     if eq?(#, NIL) then ## else self(<tail #, cons(ONE, acc))
+    |     if eq?(#, NIL) then acc else self(<tail #, cons(ONE, acc))
     | count(cons(A, cons(B, NIL)), NIL)
     = (ONE (ONE NIL))
 
     | def double(#)
     |     cons(#, #)
     | MEOW
-    ? Undefined function
+    ? Undefined function 'double'
 
     | def urff(#)
     |     self(cons(#, #))
     ? head: Not a cons cell
 
     | def urff(#)
-    |     self(if self(<tail #) then <head # else <tail #)
-    | urff(cons(GRAAAAP FARRRRP))
+    |     self(<if self(<tail #) then <head # else <tail #)
+    | urff(cons(GRAAAAP, FARRRRP))
     ? tail: Not a cons cell
 
 TODO more examples here...

File script/exanoke

 #!/usr/bin/env python
 
+# Exanoke reference interpreter
+
 from optparse import OptionParser
-import random
 import re
 import sys
 
             args.append(e1)
             while self.scanner.consume(','):
                 args.append(self.expr())
+            self.scanner.expect(")")
             return AST('Self', args)
         elif self.scanner.consume("eq?"):
             self.scanner.expect("(")
             e1 = self.expr()
             self.scanner.expect(")")
             return AST('Cons?', [e1])
-            # and so forth
+        elif self.scanner.consume("not"):
+            self.scanner.expect("(")
+            e1 = self.expr()
+            self.scanner.expect(")")
+            return AST('Not', [e1])
+        elif self.scanner.consume("#"):
+            return AST('ArgRef', value=0)
+        elif self.scanner.on_type("atom"):
+            atom = self.scanner.token
+            self.scanner.scan()
+            return AST('Atom', value=atom)
+        elif self.scanner.on_type("identifier"):
+            ident = self.scanner.token
+            self.scanner.scan()
+            if self.scanner.on('('):
+                self.scanner.expect('(')
+                args = [self.expr()]
+                while self.scanner.consume(','):
+                    args.append(self.expr())
+                self.scanner.expect(')')
+                return AST('Call', args, value=ident)
+            else:
+                return AST('ArgRef', value=ident)
         else:
-            raise SyntaxError
+            return self.smaller()
 
     def smaller(self):
         if self.scanner.consume("<head"):
             e3 = self.smallerterm()
             return AST('If', [e1, e2, e3])
         else:
-            raise SyntaxError
+            raise SyntaxError('Unrecognized term "%s"' % self.scanner.token)
 
     def smallerterm(self):
         if self.scanner.consume("#"):
             return AST('ArgRef', value=0)
         else:
             return self.smaller()
+
+
+def main(argv):
+    optparser = OptionParser(__doc__)
+    optparser.add_option("-a", "--show-ast",
+                         action="store_true", dest="show_ast", default=False,
+                         help="show parsed AST instead of evaluating")
+    optparser.add_option("-t", "--test",
+                         action="store_true", dest="test", default=False,
+                         help="run test cases and exit")
+    (options, args) = optparser.parse_args(argv[1:])
+    if options.test:
+        import doctest
+        (fails, something) = doctest.testmod()
+        if fails == 0:
+            print "All tests passed."
+            sys.exit(0)
+        else:
+            sys.exit(1)
+    file = open(args[0])
+    text = file.read()
+    file.close()
+    p = Parser(text)
+    prog = p.program()
+    if options.show_ast:
+        from pprint import pprint
+        pprint(prog)
+        sys.exit(0)
+    # eval prog
+    sys.exit(0)
+
+
+if __name__ == "__main__":
+    main(sys.argv)