From 2b22f725f317af729a94bcfca134713aa04cff54 Mon Sep 17 00:00:00 2001
From: Sebastien Binet <binet@cern.ch>
Date: Thu, 30 Aug 2018 14:53:38 +0200
Subject: [PATCH] builtin: add dir builtin

Fixes go-python/gpython#12.
---
 builtin/builtin.go       | 35 ++++++++++++++++++++++++++++++++++-
 builtin/tests/builtin.py | 16 ++++++++++++++++
 2 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/builtin/builtin.go b/builtin/builtin.go
index 4e9ca18d..ae89147f 100644
--- a/builtin/builtin.go
+++ b/builtin/builtin.go
@@ -31,7 +31,7 @@ func init() {
 		py.MustNewMethod("chr", builtin_chr, 0, chr_doc),
 		py.MustNewMethod("compile", builtin_compile, 0, compile_doc),
 		// py.MustNewMethod("delattr", builtin_delattr, 0, delattr_doc),
-		// py.MustNewMethod("dir", builtin_dir, 0, dir_doc),
+		py.MustNewMethod("dir", builtin_dir, 0, dir_doc),
 		py.MustNewMethod("divmod", builtin_divmod, 0, divmod_doc),
 		py.MustNewMethod("eval", py.InternalMethodEval, 0, eval_doc),
 		py.MustNewMethod("exec", py.InternalMethodExec, 0, exec_doc),
@@ -642,6 +642,39 @@ func builtin_compile(self py.Object, args py.Tuple, kwargs py.StringDict) (py.Ob
 	return result, nil
 }
 
+const dir_doc = `dir([object]) -> list of strings
+
+If called without an argument, return the names in the current scope.
+Else, return an alphabetized list of names comprising (some of) the attributes
+of the given object, and of attributes reachable from it.
+If the object supplies a method named __dir__, it will be used; otherwise
+the default dir() logic is used and returns:
+  for a module object: the module's attributes.
+  for a class object:  its attributes, and recursively the attributes
+    of its bases.
+  for any other object: its attributes, its class's attributes, and
+    recursively the attributes of its class's base classes.
+`
+
+func builtin_dir(self py.Object, args py.Tuple) (py.Object, error) {
+	n, err := args.M__len__()
+	if err != nil {
+		return nil, err
+	}
+
+	nn := n.(py.Int)
+	if nn == 0 {
+		// list current scope.
+		panic("dir() not implemented")
+	}
+
+	if nn > 1 {
+		return nil, py.ExceptionNewf(py.TypeError, "dir expected at most 1 arguments, got %d", nn)
+	}
+
+	panic("dir(n) not implemented")
+}
+
 const divmod_doc = `divmod(x, y) -> (quotient, remainder)
 
 Return the tuple ((x-x%y)/y, x%y).  Invariant: div*y + mod == x.`
diff --git a/builtin/tests/builtin.py b/builtin/tests/builtin.py
index 995a652b..41404e6c 100644
--- a/builtin/tests/builtin.py
+++ b/builtin/tests/builtin.py
@@ -29,6 +29,22 @@
 assert code is not None
 # FIXME
 
+doc="dir"
+def testDir():
+    a = 1
+    assert dir() == ["a"]
+    b = 2
+    assert dir() == ["a", "b"]
+    class A:
+        def method(self): pass
+    assert "method" in dir(A())
+testDir()
+try:
+    dir(1,2,3)
+    ok=False
+except TypeError: ok=True
+assert ok, "no exception raised"
+
 doc="divmod"
 assert divmod(34,7) == (4, 6)