TypeScript: setup initial environment
[jackhill/mal.git] / js / core.js
index 7addc49..01dad97 100644 (file)
@@ -4,7 +4,10 @@ if (typeof module === 'undefined') {
     var exports = core;
 } else {
     var types = require('./types'),
-        printer = require('./printer');
+        readline = require('./node_readline'),
+        reader = require('./reader'),
+        printer = require('./printer'),
+        interop = require('./interop');
 }
 
 // Errors/Exceptions
@@ -36,6 +39,25 @@ function println() {
     }));
 }
 
+function slurp(f) {
+    if (typeof require !== 'undefined') {
+        return require('fs').readFileSync(f, 'utf-8');
+    } else {
+        var req = new XMLHttpRequest();
+        req.open("GET", f, false);
+        req.send();
+        if (req.status == 200) {
+            return req.responseText;
+        } else {
+            throw new Error("Failed to slurp file: " + f);
+        }
+    }
+}
+
+
+// Number functions
+function time_ms() { return new Date().getTime(); }
+
 
 // Hash Map functions
 function assoc(src_hm) {
@@ -74,17 +96,21 @@ function concat(lst) {
     return lst.concat.apply(lst, Array.prototype.slice.call(arguments, 1));
 }
 
-function nth(lst, idx) { return lst[idx]; }
+function nth(lst, idx) {
+    if (idx < lst.length) { return lst[idx]; }
+    else                  { throw new Error("nth: index out of range"); }
+}
 
-function first(lst) { return lst[0]; }
+function first(lst) { return (lst === null) ? null : lst[0]; }
 
-function rest(lst) { return lst.slice(1); }
+function rest(lst) { return (lst == null) ? [] : lst.slice(1); }
 
 function empty_Q(lst) { return lst.length === 0; }
 
 function count(s) {
     if (Array.isArray(s)) { return s.length; }
-    else {                  return Object.keys(s).length; }
+    else if (s === null)  { return 0; }
+    else                  { return Object.keys(s).length; }
 }
 
 function conj(lst) {
@@ -97,6 +123,21 @@ function conj(lst) {
     }
 }
 
+function seq(obj) {
+    if (types._list_Q(obj)) {
+        return obj.length > 0 ? obj : null;
+    } else if (types._vector_Q(obj)) {
+        return obj.length > 0 ? Array.prototype.slice.call(obj, 0): null;
+    } else if (types._string_Q(obj)) {
+        return obj.length > 0 ? obj.split('') : null;
+    } else if (obj === null) {
+        return null;
+    } else {
+        throw new Error("seq: called on non-sequence");
+    }
+}
+
+
 function apply(f) {
     var args = Array.prototype.slice.call(arguments, 1);
     return f.apply(f, args.slice(0, args.length-1).concat(args[args.length-1]));
@@ -134,6 +175,17 @@ function swap_BANG(atm, f) {
     return atm.val;
 }
 
+function js_eval(str) {
+    return interop.js_to_mal(eval(str.toString()));
+}
+
+function js_method_call(object_method_str) {
+    var args = Array.prototype.slice.call(arguments, 1),
+        r = interop.resolve_js(object_method_str),
+        obj = r[0], f = r[1];
+    var res = f.apply(obj, args);
+    return interop.js_to_mal(res);
+}
 
 // types.ns is namespace of type functions
 var ns = {'type': types._obj_type,
@@ -142,12 +194,19 @@ var ns = {'type': types._obj_type,
           'nil?': types._nil_Q,
           'true?': types._true_Q,
           'false?': types._false_Q,
+          'string?': types._string_Q,
           'symbol': types._symbol,
           'symbol?': types._symbol_Q,
+          'keyword': types._keyword,
+          'keyword?': types._keyword_Q,
+
           'pr-str': pr_str,
           'str': str,
           'prn': prn,
           'println': println,
+          'readline': readline.readline,
+          'read-string': reader.read_str,
+          'slurp': slurp,
           '<'  : function(a,b){return a<b;},
           '<=' : function(a,b){return a<=b;},
           '>'  : function(a,b){return a>b;},
@@ -156,6 +215,7 @@ var ns = {'type': types._obj_type,
           '-'  : function(a,b){return a-b;},
           '*'  : function(a,b){return a*b;},
           '/'  : function(a,b){return a/b;},
+          "time-ms": time_ms,
 
           'list': types._list,
           'list?': types._list_Q,
@@ -178,16 +238,22 @@ var ns = {'type': types._obj_type,
           'rest': rest,
           'empty?': empty_Q,
           'count': count,
-          'conj': conj,
           'apply': apply,
           'map': map,
 
+          'conj': conj,
+          'seq': seq,
+
           'with-meta': with_meta,
           'meta': meta,
           'atom': types._atom,
           'atom?': types._atom_Q,
           "deref": deref,
           "reset!": reset_BANG,
-          "swap!": swap_BANG};
+          "swap!": swap_BANG,
+
+          'js-eval': js_eval,
+          '.': js_method_call
+};
 
 exports.ns = core.ns = ns;