aboutsummaryrefslogtreecommitdiff
path: root/ClojureCLR/Clojure
diff options
context:
space:
mode:
Diffstat (limited to 'ClojureCLR/Clojure')
-rw-r--r--ClojureCLR/Clojure/Clojure.Console/ClojureConsole.cs23
-rw-r--r--ClojureCLR/Clojure/Clojure.Tests/Clojure.Tests.csproj1
-rw-r--r--ClojureCLR/Clojure/Clojure.Tests/LibTests/EnumeratorSeqTests.cs12
-rw-r--r--ClojureCLR/Clojure/Clojure/Bootstrap/core.clj2
-rw-r--r--ClojureCLR/Clojure/Clojure/Clojure.csproj1
-rw-r--r--ClojureCLR/Clojure/Clojure/Lib/ArrayStream.cs40
-rw-r--r--ClojureCLR/Clojure/Clojure/Lib/EnumeratorSeq.cs118
-rw-r--r--ClojureCLR/Clojure/Clojure/Lib/PersistentHashMap.cs2
-rw-r--r--ClojureCLR/Clojure/Clojure/Lib/RT.cs1534
-rw-r--r--ClojureCLR/Clojure/Clojure/Runtime/ClojureContext.cs3
-rw-r--r--ClojureCLR/Clojure/Clojure/Runtime/ClojureParser.cs2
-rw-r--r--ClojureCLR/Clojure/ClojureCLR.sln1004
12 files changed, 1592 insertions, 1150 deletions
diff --git a/ClojureCLR/Clojure/Clojure.Console/ClojureConsole.cs b/ClojureCLR/Clojure/Clojure.Console/ClojureConsole.cs
index f0f88869..93ba2062 100644
--- a/ClojureCLR/Clojure/Clojure.Console/ClojureConsole.cs
+++ b/ClojureCLR/Clojure/Clojure.Console/ClojureConsole.cs
@@ -70,6 +70,17 @@ namespace clojure.console
return new ClojureCommandLine();
}
+ protected override ScriptRuntimeSetup CreateRuntimeSetup()
+ {
+ ScriptRuntimeSetup setup = base.CreateRuntimeSetup();
+
+ // Set this to true to force snippets to be written out.
+ // Or you can put -D on the command line.
+ setup.DebugMode = false;
+
+ return setup;
+ }
+
#endregion
#region Main routine
@@ -98,7 +109,8 @@ namespace clojure.console
try
{
Snippets.SetSaveAssemblies(true, ".");
- MaybeInitialize();
+ MaybeInitialize();
+ RT.PostBootstrapInit();
Snippets.SaveAndVerifyAssemblies();
base.ExecuteInternal();
}
@@ -163,7 +175,7 @@ namespace clojure.console
public object LoadFromStream(TextReader rdr)
{
- ScriptSource scriptSource = Engine.CreateScriptSourceFromString("<already opened TextReader>");
+ ScriptSource scriptSource = Engine.CreateScriptSourceFromString("<already opened TextReader>",".");
//PushbackReader pbr = new PushbackReader(rdr);
return LoadFromPushbackReader(scriptSource, rdr, false);
@@ -206,12 +218,5 @@ namespace clojure.console
}
#endregion
-
- protected override ScriptRuntimeSetup CreateRuntimeSetup()
- {
- ScriptRuntimeSetup setup = base.CreateRuntimeSetup();
- setup.DebugMode = true;
- return setup;
- }
}
}
diff --git a/ClojureCLR/Clojure/Clojure.Tests/Clojure.Tests.csproj b/ClojureCLR/Clojure/Clojure.Tests/Clojure.Tests.csproj
index 9bf437a0..146e87ea 100644
--- a/ClojureCLR/Clojure/Clojure.Tests/Clojure.Tests.csproj
+++ b/ClojureCLR/Clojure/Clojure.Tests/Clojure.Tests.csproj
@@ -61,6 +61,7 @@
<Reference Include="vjslib" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="LibTests\EnumeratorSeqTests.cs" />
<Compile Include="LibTests\AFnImplTests.cs" />
<Compile Include="LibTests\AgentTests.cs" />
<Compile Include="LibTests\APersistentVectorTests.cs" />
diff --git a/ClojureCLR/Clojure/Clojure.Tests/LibTests/EnumeratorSeqTests.cs b/ClojureCLR/Clojure/Clojure.Tests/LibTests/EnumeratorSeqTests.cs
new file mode 100644
index 00000000..48b4216f
--- /dev/null
+++ b/ClojureCLR/Clojure/Clojure.Tests/LibTests/EnumeratorSeqTests.cs
@@ -0,0 +1,12 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace Clojure.Tests
+{
+ // TODO: Add tests for EnumeratorSeq
+ class EnumeratorSeqTests
+ {
+ }
+}
diff --git a/ClojureCLR/Clojure/Clojure/Bootstrap/core.clj b/ClojureCLR/Clojure/Clojure/Bootstrap/core.clj
index 5a1c829b..b5ffc314 100644
--- a/ClojureCLR/Clojure/Clojure/Bootstrap/core.clj
+++ b/ClojureCLR/Clojure/Clojure/Bootstrap/core.clj
@@ -2307,7 +2307,7 @@
"Returns a map of the public intern mappings for the namespace."
[ns]
(let [ns (the-ns ns)]
- (filter-key val (fn [#^clojure.lang.Var v] (and (instance? clojure.lang.Var v)
+ (filter-key val (fn [ v] (and (instance? clojure.lang.Var v) ;;; removed the tag on v: #^clojure.lang.Var
(= ns (.ns v))
(.isPublic v)))
(ns-map ns))))
diff --git a/ClojureCLR/Clojure/Clojure/Clojure.csproj b/ClojureCLR/Clojure/Clojure/Clojure.csproj
index 597466e3..7a2c2f99 100644
--- a/ClojureCLR/Clojure/Clojure/Clojure.csproj
+++ b/ClojureCLR/Clojure/Clojure/Clojure.csproj
@@ -49,6 +49,7 @@
</ItemGroup>
<ItemGroup>
<Compile Include="Lib\Counted.cs" />
+ <Compile Include="Lib\EnumeratorSeq.cs" />
<Compile Include="Lib\IDeref.cs" />
<Compile Include="Readers\LineNumberingReader.cs" />
<Compile Include="Runtime\ClojureBinder.cs" />
diff --git a/ClojureCLR/Clojure/Clojure/Lib/ArrayStream.cs b/ClojureCLR/Clojure/Clojure/Lib/ArrayStream.cs
index cc30bc1b..88853917 100644
--- a/ClojureCLR/Clojure/Clojure/Lib/ArrayStream.cs
+++ b/ClojureCLR/Clojure/Clojure/Lib/ArrayStream.cs
@@ -16,7 +16,45 @@ using System.Text;
namespace clojure.lang
{
// TODO: ArrayStream needs some thought.
- public class ArrayStream
+ public class ArrayStream : IStream
{
+ #region Data
+
+ readonly AtomicInteger _idx = new AtomicInteger(0);
+ readonly Array _array;
+
+ #endregion
+
+ #region C-tors & factory methods
+
+ public ArrayStream(Array array)
+ {
+ _array = array;
+ }
+
+ public static IStream createFromObject(object array)
+ {
+ if (array.GetType().IsArray)
+ return new ArrayStream((Array)array);
+ // TODO: Decide if we want all the specialized types.
+ // TODO: make sure we don't have a multi-dim array
+
+ throw new ArgumentException(String.Format("Unsupported array type %s", array.GetType()));
+ }
+
+
+ #endregion
+
+ #region IStream Members
+
+ public object next()
+ {
+ int i = _idx.getAndIncrement();
+ if (i < _array.Length)
+ return _array.GetValue(i);
+ return RT.eos();
+ }
+
+ #endregion
}
}
diff --git a/ClojureCLR/Clojure/Clojure/Lib/EnumeratorSeq.cs b/ClojureCLR/Clojure/Clojure/Lib/EnumeratorSeq.cs
new file mode 100644
index 00000000..b05a7e72
--- /dev/null
+++ b/ClojureCLR/Clojure/Clojure/Lib/EnumeratorSeq.cs
@@ -0,0 +1,118 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Collections;
+
+namespace clojure.lang
+{
+ public class EnumeratorSeq : ASeq
+ {
+ #region Nested classes
+
+ sealed class State
+ {
+ internal volatile object _val;
+ internal volatile object _rest;
+ }
+
+ #endregion
+
+ #region Data
+
+ readonly IEnumerator _enumerator;
+ readonly State _state;
+
+ #endregion
+
+ #region C-tors & factory methods
+
+ // There's no way to do this properly.
+ // If the enumerator is uninitialized, we have to do a move next to see if there is an element.
+ // If the enumerator is initialized, we should see if calling Current throws an exception. Sigh.
+ // Okay, try this: access Current. If it blows, assume we are not initialized.
+ // Okay, that takes a _long_ time. Lots of Exceptions thrown/caught.
+ // Maybe the new lazy version will solve this.
+ public static EnumeratorSeq create(IEnumerator enumerator)
+ {
+ //bool hasElement = true;
+
+ //try {
+
+ // object o = enumerator.Current;
+ //}
+ //catch ( InvalidOperationException )
+ //{
+ // // we are before the beginning.
+ // hasElement = enumerator.MoveNext();
+ //}
+
+ bool hasElement = enumerator.MoveNext();
+
+ return hasElement
+ ? new EnumeratorSeq(enumerator)
+ : null;
+ }
+
+ public EnumeratorSeq(IEnumerator enumerator)
+ {
+ _enumerator = enumerator;
+ _state = new State();
+ _state._val = _state;
+ _state._rest = _state;
+ }
+
+ EnumeratorSeq(IPersistentMap meta, IEnumerator enumerator, State state)
+ : base(meta)
+ {
+ _enumerator = enumerator;
+ _state = state;
+ }
+
+ #endregion
+
+
+ #region ISeq members
+
+ public override object first()
+ {
+ if (_state._val == _state)
+ lock (_state)
+ {
+ if (_state._val == _state)
+ _state._val = _enumerator.Current;
+ }
+ return _state._val;
+ }
+
+ public override ISeq rest()
+ {
+ if ( _state._rest == _state )
+ lock (_state)
+ {
+ if (_state._rest == _state)
+ {
+ first();
+ _state._rest = _enumerator.MoveNext() ? new EnumeratorSeq(_enumerator) : null;
+ // Java: _state._rest = create(_enumerator);
+
+ }
+ }
+ return (ISeq)_state._rest;
+ }
+
+ #endregion
+
+ #region IObj members
+
+ public override IObj withMeta(IPersistentMap meta)
+ {
+ // Java: no check
+ return meta == _meta
+ ? this
+ : new EnumeratorSeq(meta, _enumerator, _state);
+ }
+
+ #endregion
+ }
+}
diff --git a/ClojureCLR/Clojure/Clojure/Lib/PersistentHashMap.cs b/ClojureCLR/Clojure/Clojure/Lib/PersistentHashMap.cs
index f0f9324d..4716d9c0 100644
--- a/ClojureCLR/Clojure/Clojure/Lib/PersistentHashMap.cs
+++ b/ClojureCLR/Clojure/Clojure/Lib/PersistentHashMap.cs
@@ -88,7 +88,7 @@ namespace clojure.lang
/// </summary>
/// <param name="init">An IList of alternating keys and values.</param>
/// <returns>A <see cref="PersistentHashMap">PersistentHashMap</see>.</returns>
- public static PersistentHashMap create(IList init)
+ public static PersistentHashMap create1(IList init)
{
IPersistentMap ret = EMPTY;
for (IEnumerator i = init.GetEnumerator(); i.MoveNext(); )
diff --git a/ClojureCLR/Clojure/Clojure/Lib/RT.cs b/ClojureCLR/Clojure/Clojure/Lib/RT.cs
index 20da5381..4495bf70 100644
--- a/ClojureCLR/Clojure/Clojure/Lib/RT.cs
+++ b/ClojureCLR/Clojure/Clojure/Lib/RT.cs
@@ -23,13 +23,9 @@ using System.Diagnostics;
namespace clojure.lang
{
- public class RT
+ public static class RT
{
-
- #region Some constants
-
- public static readonly Boolean T = true;//Keyword.intern(Symbol.create(null, "t"));
- public static readonly Boolean F = false;//Keyword.intern(Symbol.create(null, "t"));
+ #region Default symbol-to-class map
//simple-symbol->class
internal static readonly IPersistentMap DEFAULT_IMPORTS = map(
@@ -221,7 +217,7 @@ namespace clojure.lang
// Symbol.create(""),typeof(Func<T,TResult>/
// Symbol.create(""),typeof(Func<T1, T2, TResult>/
// Symbol.create(""),typeof(Func<T1, T2, T3, TResult>/
- // FSymbol.create(""),typeof(unc<T1, T2, T3, T4, TResult>/
+ // FSymbol.create(""),typeof(Func<T1, T2, T3, T4, TResult>/
// Symbol.create(""),typeof(Predicate<T>),
Symbol.create("ResolveEventHandler"), typeof(ResolveEventHandler),
Symbol.create("UnhandledExceptionEventHandler"), typeof(UnhandledExceptionEventHandler),
@@ -254,24 +250,132 @@ namespace clojure.lang
Symbol.create("UriPartial"), typeof(UriPartial),
// ADDED THESE TO SUPPORT THE BOOTSTRAPPING IN THE JAVA CORE.CLJ
Symbol.create("StringBuilder"), typeof(StringBuilder),
- Symbol.create("BigInteger"),typeof(java.math.BigInteger),
- Symbol.create("BigDecimal"),typeof(java.math.BigDecimal)
+ Symbol.create("BigInteger"), typeof(java.math.BigInteger),
+ Symbol.create("BigDecimal"), typeof(java.math.BigDecimal)
);
- public static readonly Namespace CLOJURE_NS = Namespace.findOrCreate(Symbol.create("clojure.core"));
+ #endregion
+
+ #region Some misc. goodies
+
+ static public readonly object[] EMPTY_ARRAY = new Object[] { };
+
+ #endregion
+
+ #region It's true (or not)
+
+ // TODO: Should these really be object? In ClojureJVM, we would be trying to avoid boxing.
+
+ public static readonly Boolean T = true;//Keyword.intern(Symbol.create(null, "t"));
+ public static readonly Boolean F = false;//Keyword.intern(Symbol.create(null, "t"));
+
+ public static bool IsTrue(object o)
+ {
+ if (o == null)
+ return false;
+ if (o is Boolean)
+ return (Boolean)o;
+ else
+ return true;
+ }
+
+ #endregion
+
+ #region Predefined namespaces
+
+ // We need this initialization to happen earlier than most of the Var inits.
+ public static readonly Namespace CLOJURE_NS
+ = Namespace.findOrCreate(Symbol.create("clojure.core"));
+
+ #endregion
+
+ #region Useful Keywords
+
+ public static readonly Keyword TAG_KEY
+ = Keyword.intern(null, "tag");
+
+ public static readonly Keyword LINE_KEY
+ = Keyword.intern(null, "line");
+
+ public static readonly Keyword FILE_KEY
+ = Keyword.intern(null, "file");
- public static readonly Keyword TAG_KEY = Keyword.intern(null, "tag");
- public static readonly Keyword LINE_KEY = Keyword.intern(null, "line");
+ #endregion
+
+ #region Vars (namespace-related)
+
+ public static readonly Var CURRENT_NS
+ = Var.intern(CLOJURE_NS, Symbol.create("*ns*"),CLOJURE_NS);
- public static readonly Var CURRENT_NS = Var.intern(CLOJURE_NS, Symbol.create("*ns*"),
- CLOJURE_NS);
+ public static readonly Var IN_NS_VAR
+ = Var.intern(CLOJURE_NS, Symbol.create("in-ns"), F);
+ public static readonly Var NS_VAR
+ = Var.intern(CLOJURE_NS, Symbol.create("ns"), F);
+
+ #endregion
- public static readonly Var IN_NS_VAR = Var.intern(CLOJURE_NS, Symbol.create("in-ns"), F);
- public static readonly Var NS_VAR = Var.intern(CLOJURE_NS, Symbol.create("ns"), F);
+ #region Vars (I/O-related)
+
+ // TODO: These need to be tied into the DLR IO subsystem
+
+ public static readonly Var OUT
+ = Var.intern(CLOJURE_NS, Symbol.create("*out*"), System.Console.Out);
+
+ public static readonly Var ERR
+ = Var.intern(CLOJURE_NS, Symbol.create("*err*"), System.Console.Error);
+
+ public static readonly Var IN =
+ Var.intern(CLOJURE_NS, Symbol.create("*in*"),
+ new clojure.lang.Readers.LineNumberingReader(System.Console.In));
+
+ static readonly Var PRINT_READABLY
+ = Var.intern(CLOJURE_NS, Symbol.create("*print-readably*"), T);
+
+ static readonly Var PRINT_META
+ = Var.intern(CLOJURE_NS, Symbol.create("*print-meta*"), F);
+
+ static readonly Var PRINT_DUP
+ = Var.intern(CLOJURE_NS, Symbol.create("*print-dup*"), F);
+
+ static readonly Var FLUSH_ON_NEWLINE
+ = Var.intern(CLOJURE_NS, Symbol.create("*flush-on-newline*"), T);
+
+ static readonly Var PRINT_INITIALIZED
+ = Var.intern(CLOJURE_NS, Symbol.create("print-initialized"));
+
+ static readonly Var PR_ON
+ = Var.intern(CLOJURE_NS, Symbol.create("pr-on"));
+
+ #endregion
+
+ #region Vars (miscellaneous)
+
+ public static readonly Var ALLOW_UNRESOLVED_VARS
+ = Var.intern(CLOJURE_NS, Symbol.create("*allow-unresolved-vars*"), F);
+
+ public static readonly Var WARN_ON_REFLECTION
+ = Var.intern(CLOJURE_NS, Symbol.create("*warn-on-reflection*"), F);
+
+ public static readonly Var MACRO_META
+ = Var.intern(CLOJURE_NS, Symbol.create("*macro-meta*"), null);
+
+ public static readonly Var MATH_CONTEXT
+ = Var.intern(CLOJURE_NS, Symbol.create("*math-context*"), null);
+
+ public static readonly Var AGENT
+ = Var.intern(CLOJURE_NS, Symbol.create("*agent*"), null);
+
+ public static readonly Var CMD_LINE_ARGS
+ = Var.intern(CLOJURE_NS, Symbol.create("*command-line-args*"), null);
+
+ #endregion
+
+ #region Clojure-environment IFns needing support
static readonly Symbol IN_NAMESPACE = Symbol.create("in-ns");
+
sealed class InNamespaceFn : AFn
{
public override object invoke(object arg1)
@@ -284,7 +388,7 @@ namespace clojure.lang
}
static readonly Symbol NAMESPACE = Symbol.create("ns");
-
+
static readonly Symbol IDENTICAL = Symbol.create("identical?");
sealed class IdenticalFn : AFn
@@ -295,56 +399,196 @@ namespace clojure.lang
}
}
+ static readonly Symbol LOAD_FILE = Symbol.create("load-file");
+ sealed class LoadFileFn : AFn
+ {
+ public override object invoke(object arg1)
+ {
+ // TODO: Hook in loading here.
+ return base.invoke(arg1);
+ }
+ }
- public static readonly Var ALLOW_UNRESOLVED_VARS = Var.intern(CLOJURE_NS, Symbol.create("*allow-unresolved-vars*"), F);
- public static readonly Var WARN_ON_REFLECTION = Var.intern(CLOJURE_NS, Symbol.create("*warn-on-reflection*"), F);
+ #endregion
- public static readonly Var MACRO_META = Var.intern(CLOJURE_NS, Symbol.create("*macro-meta*"), null);
+ #region Initialization
- public static readonly Var MATH_CONTEXT = Var.intern(CLOJURE_NS, Symbol.create("*math-context*"), null);
-
- public static readonly Var AGENT = Var.intern(CLOJURE_NS, Symbol.create("*agent*"), null);
+ static RT()
+ {
+ Keyword dockw = Keyword.intern(null, "doc");
+ Keyword arglistskw = Keyword.intern(null, "arglists");
+ Symbol namesym = Symbol.create("name");
- public static readonly Var CMD_LINE_ARGS = Var.intern(CLOJURE_NS, Symbol.create("*command-line-args*"), null);
+ OUT.Tag = Symbol.create("System.IO.TextWriter");
- // TODO: These need to be tied into the DLR IO subsystem
- public static readonly Var OUT = Var.intern(CLOJURE_NS, Symbol.create("*out*"), System.Console.Out);
- public static readonly Var ERR = Var.intern(CLOJURE_NS, Symbol.create("*err*"), System.Console.Error);
- public static readonly Var IN =
- Var.intern(CLOJURE_NS, Symbol.create("*in*"),
- new clojure.lang.Readers.LineNumberingReader(System.Console.In));
- static readonly Var PRINT_READABLY = Var.intern(CLOJURE_NS, Symbol.create("*print-readably*"), T);
- static readonly Var PRINT_META = Var.intern(CLOJURE_NS, Symbol.create("*print-meta*"), F);
- static readonly Var PRINT_DUP = Var.intern(CLOJURE_NS, Symbol.create("*print-dup*"), F);
- static readonly Var FLUSH_ON_NEWLINE = Var.intern(CLOJURE_NS, Symbol.create("*flush-on-newline*"), T);
- static readonly Var PRINT_INITIALIZED = Var.intern(CLOJURE_NS, Symbol.create("print-initialized"));
- static readonly Var PR_ON = Var.intern(CLOJURE_NS, Symbol.create("pr-on"));
+ CURRENT_NS.Tag = Symbol.create("closure.lang.Namespace");
- #endregion
+ AGENT.SetMeta(map(dockw, "The agent currently running an action on this thread, else nil."));
+ AGENT.Tag = Symbol.create("clojure.lang.Agent");
- public static bool IsTrue(object o)
+ // We don't have MathContext (yet)
+ //MATH_CONTEXT.Tag = Symbol.create("java.math.MathContext");
+
+ // during bootstrap, ns same as in-ns
+ Var nv = Var.intern(CLOJURE_NS, NAMESPACE, new InNamespaceFn());
+ nv.setMacro();
+
+ Var v;
+ v = Var.intern(CLOJURE_NS, IN_NAMESPACE, new InNamespaceFn());
+ v.SetMeta(map(dockw, "Sets *ns* to the namespace named by the symbol, creating it if needed.",
+ arglistskw, list(vector(namesym))));
+
+ v = Var.intern(CLOJURE_NS, LOAD_FILE, new LoadFileFn());
+ v.SetMeta(map(dockw, "Sequentially read and evaluate the set of forms contained in the file.",
+ arglistskw, list(vector(namesym))));
+
+ v = Var.intern(CLOJURE_NS, IDENTICAL, new IdenticalFn());
+ v.SetMeta(map(dockw, "tests if 2 arguments are the same object",
+ arglistskw, list(vector(Symbol.create("x"), Symbol.create("y")))));
+
+ DoInit();
+ }
+
+ // The original Java is doing this here.
+ // We're pushing this over to the console, for now.
+ // Eventually, we'll push it back here because it is always needed.
+ static void DoInit()
{
- if ( o == null )
- return false;
- if (o is Boolean)
- return (Boolean)o;
- else
- return true;
+ // Eventually, load core.clj and other support files from here (?)
+ //load("clojure/core");
+ //load("clojure/zip", false);
+ //load("clojure/xml", false);
+ //load("clojure/set", false);
+
+ //PostBootstrapInit();
}
- public static int BoundedLength(ISeq list, int limit)
+ public static void PostBootstrapInit()
{
- int i = 0;
- for (ISeq c = list; c != null && i <= limit; c = c.rest())
+ Var.pushThreadBindings(
+ RT.map(CURRENT_NS, CURRENT_NS.deref(),
+ WARN_ON_REFLECTION, WARN_ON_REFLECTION.deref()));
+ try
{
- i++;
+ Symbol USER = Symbol.create("user");
+ Symbol CLOJURE = Symbol.create("clojure.core");
+
+ Var in_ns = var("clojure.core", "in-ns");
+ Var refer = var("clojure.core", "refer");
+ in_ns.invoke(USER);
+ refer.invoke(CLOJURE);
+ //maybeLoadResourceScript("user.clj");
}
- return i;
+ finally
+ {
+ Var.popThreadBindings();
+ }
+ }
+
+ #endregion
+
+ #region Id generation
+
+ // This is AtomicInteger in the JVM version.
+ // The only place accessed is in nextID, so seems unnecessary.
+ private static int _id;
+
+ // initial-lowercase name, used in core.clj
+ static public int nextID()
+ {
+ return Interlocked.Increment(ref _id);
}
- // TODO: Handle generic collections?
- public static int count(Object o)
+ #endregion
+
+ #region Var support
+
+ static public Var var(String ns, String name)
+ {
+ return Var.intern(Namespace.findOrCreate(Symbol.intern(null, ns)), Symbol.intern(null, name));
+ }
+
+ static public Var var(String ns, String name, Object init)
+ {
+ return Var.intern(Namespace.findOrCreate(Symbol.intern(null, ns)), Symbol.intern(null, name), init);
+ }
+
+ #endregion
+
+ #region Collections support
+
+ public static ISeq seq(object coll)
+ {
+ if (coll == null)
+ return null;
+ else if (coll is ISeq)
+ return (ISeq)coll;
+ else if (coll is IPersistentCollection)
+ return ((IPersistentCollection)coll).seq();
+ else
+ return seqFrom(coll);
+ }
+
+ private static ISeq seqFrom(object coll)
+ {
+ if (coll is IEnumerable) // java: Iterable
+ return EnumeratorSeq.create(((IEnumerable)coll).GetEnumerator()); // IteratorSeq
+ else if (coll.GetType().IsArray)
+ return ArraySeq.createFromObject(coll);
+ else if (coll is string)
+ return StringSeq.create((string)coll);
+ // The equivalent for Java:Map is IDictionary. IDictionary is IEnumerable, so is handled above.
+ //else if(coll isntanceof Map)
+ // return seq(((Map) coll).entrySet());
+ else if (coll is IEnumerator) // java: Iterator
+ return EnumeratorSeq.create((IEnumerator)coll);
+ else
+ throw new ArgumentException("Don't know how to create ISeq from: " + coll.GetType().Name);
+ }
+
+
+
+ static public IStream stream(object coll) {
+ if (coll == null)
+ return EMPTY_STREAM;
+ else if (coll is IStream)
+ return (IStream)coll;
+ else if (coll is Streamable)
+ return ((Streamable)coll).stream();
+ else if (coll is Fn) // TODO: Note use of Fn to imply castable to IFn. Should we do this? Why not just check for IFn?
+ return new FnStream((IFn)coll);
+ else if (coll is IEnumerable) // java: Iterable
+ return new IteratorStream(((IEnumerable)coll).GetEnumerator()); // java: IteratorStream
+ else if (coll.GetType().IsArray)
+ return ArrayStream.createFromObject(coll);
+ else if (coll is String)
+ return ArrayStream.createFromObject(((String)coll).ToCharArray());
+
+ throw new ArgumentException("Don't know how to create IStream from: " + coll.GetType().Name);
+ }
+
+
+
+ public static ISeq keys(object coll)
+ {
+ return APersistentMap.KeySeq.create(seq(coll));
+ }
+
+ public static ISeq vals(object coll)
+ {
+ return APersistentMap.ValSeq.create(seq(coll));
+ }
+
+ public static IPersistentMap meta(object x)
+ {
+ return x is IMeta
+ ? ((IMeta)x).meta()
+ : null;
+ }
+
+
+ public static int count(object o)
{
if (o == null)
return 0;
@@ -354,10 +598,10 @@ namespace clojure.lang
{
ISeq s = seq(o);
o = null;
- int i=0;
- for ( ; s != null; s = s.rest())
+ int i = 0;
+ for (; s != null; s = s.rest())
{
- if ( s is Counted )
+ if (s is Counted)
return i + s.count();
i++;
}
@@ -375,41 +619,6 @@ namespace clojure.lang
throw new InvalidOperationException("count not supported on this type: " + o.GetType().Name);
}
-
- public static ISeq seq(object coll)
- {
- if (coll == null)
- return null;
- else if (coll is ISeq)
- return (ISeq)coll;
- else if (coll is IPersistentCollection)
- return ((IPersistentCollection)coll).seq();
- else
- return seqFrom(coll);
- }
-
- // TODO: Handle Arrays (ArraySeq), Iterable, generics, etc.
- static private ISeq seqFrom(object coll)
- {
- //if(coll is Iterable)
- // return IteratorSeq.create(((Iterable) coll).iterator());
- //else
- if (coll.GetType().IsArray)
- return ArraySeq.createFromObject(coll);
- else
-
- if (coll is string)
- return StringSeq.create((string)coll);
- // else if(coll instanceof Map)
- // return seq(((Map) coll).entrySet());
- //// else if(coll instanceof Iterator)
- //// return IteratorSeq.create((Iterator) coll);
- //// else if(coll instanceof Enumeration)
- //// return EnumerationSeq.create(((Enumeration) coll));
- else
- throw new ArgumentException("Don't know how to create ISeq from: " + coll.GetType().Name);
- }
-
public static IPersistentCollection conj(IPersistentCollection coll, Object x)
{
if (coll == null)
@@ -435,16 +644,6 @@ namespace clojure.lang
: seq.first();
}
- public static ISeq rest(object x)
- {
- if (x is ISeq)
- return ((ISeq)x).rest();
- ISeq seq = RT.seq(x);
- if (seq == null)
- return null;
- return seq.rest();
- }
-
public static object second(object x)
{
return first(rest(x));
@@ -460,256 +659,35 @@ namespace clojure.lang
return first(rest(rest(rest(x))));
}
- public static ISeq rrest(object x)
- {
- return rest(rest(x));
- }
-
- public static Associative assoc(object coll, object key, Object val)
- {
- if (coll == null)
- return new PersistentArrayMap(new object[] { key, val });
- return ((Associative)coll).assoc(key, val);
- }
-
- // do we need this
- //static Boolean HasTag(object o, object tag)
- //{
- // return Util.equals(tag,,RT.get(RT.meta(o),TAG_KEY);
- //}
-
-
- static public readonly object[] EMPTY_ARRAY = new Object[] { };
-
-
-
- static public Object readString(String s)
- {
- TextReader r = new StringReader(s);
- return LispReader.read(r, true, null, false);
- }
-
-
-
-
- static public void print(Object x, TextWriter w)
- {
- //call multimethod
- if (PRINT_INITIALIZED.IsBound && RT.booleanCast(PRINT_INITIALIZED.deref()))
- {
- PR_ON.invoke(x, w);
- return;
- }
-
- bool readably = booleanCast(PRINT_READABLY.deref());
-
- // Print meta, if exists & should be printed
- if ( x is Obj )
- {
- Obj o = x as Obj;
- if (RT.count(o.meta()) > 0 && readably && booleanCast(PRINT_META.deref()))
- {
- IPersistentMap meta = o.meta();
- w.Write("#^");
- if ( meta.count() == 1 && meta.containsKey(TAG_KEY))
- print(meta.valAt(TAG_KEY),w);
- else
- print(meta,w);
- w.Write(' ');
- }
- }
-
- if (x == null)
- w.Write("nil");
- else if (x is ISeq || x is IPersistentList)
- {
- w.Write('(');
- printInnerSeq(seq(x), w);
- w.Write(')');
- }
- else if ( x is string)
- {
- string s = x as string;
- if ( !readably)
- w.Write(s);
- else{
- w.Write('"');
- foreach (char c in s)
- {
- switch (c)
- {
- case '\n':
- w.Write("\\n");
- break;
- case '\t':
- w.Write("\\t");
- break;
- case '\r':
- w.Write("\\r");
- break;
- case '"':
- w.Write("\\\"");
- break;
- case '\\':
- w.Write("\\\\");
- break;
- case '\f':
- w.Write("\\f");
- break;
- case '\b':
- w.Write("\\b");
- break;
- default:
- w.Write(c);
- break;
- }
- }
- w.Write('"');
- }
- }
- else if ( x is IPersistentMap )
- {
- w.Write('{');
- for ( ISeq s = seq(x); s != null; s = s.rest() )
- {
- IMapEntry e = (IMapEntry) s.first();
- print(e.key(),w); </