Skip to content

Commit 11184ed

Browse files
author
Legokichi Duckscallion
committed
update
1 parent 7b69982 commit 11184ed

1 file changed

Lines changed: 306 additions & 0 deletions

File tree

coffee-repl.js

Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
(function(global) {
2+
"use strict";
3+
4+
// --- dependency modules ----------------------------------
5+
var CoffeeScript = global["CoffeeScript"];
6+
7+
// --- class / interfaces ----------------------------------
8+
function CoffeeScriptREPL(){
9+
this["log"] = "";
10+
this["buffer"] = "coffee> ";
11+
this["defaultInput"] = "";
12+
this["inputQueue"] = [];
13+
this["outputQueue"] = [];
14+
}
15+
16+
CoffeeScriptREPL["help"] = (function(){/*
17+
.help show repl options
18+
.[n] revert last nth input
19+
.hist view input history
20+
.clear clear log
21+
22+
c[space][enter]
23+
cons[space][enter]
24+
console.[space][enter]
25+
console.lo[space][enter]
26+
autosuggestion
27+
28+
log(str) alt console.log()
29+
clear() alt console.clear()
30+
dir(obj [, depth])
31+
alt console.dir()
32+
type(obj) alt typeof()
33+
load(url) load js file
34+
$$[n] last nth result variable
35+
*/}).toString()//.match(/^function\s*\(\s*\)\s*\{\s*\/\*([\S\s]*?)\*\/\s*\}$/);
36+
37+
CoffeeScriptREPL["prototype"] = {
38+
"terminal": CoffeeScriptREPL_terminal, // Function(String):void
39+
"evaluate": CoffeeScriptREPL_evaluate, // Function(String):void
40+
"addLog": CoffeeScriptREPL_addLog, // Function(String):void
41+
"clearLog": CoffeeScriptREPL_clearLog // Function():void
42+
};
43+
44+
// --- implements ------------------------------------------
45+
function CoffeeScriptREPL_terminal(input){ // @arg String
46+
// @ret Void
47+
var n, that = this;
48+
this["defaultInput"] = "";
49+
if (n = (/^\.([123456789](?:\d+)?)/.exec(input) || ["", ""])[1]) {
50+
if(!!this["inputQueue"][this["inputQueue"]["length"] - n]){
51+
this["defaultInput"] = this["inputQueue"][this["inputQueue"]["length"] - n];
52+
} else {
53+
this["defaultInput"] = input;
54+
}
55+
} else if (/^\.hi/.test(input)) {
56+
this["buffer"] = "coffee> " + input + "\n" + this["inputQueue"]["map"](function(str, i){
57+
return that["inputQueue"]["length"] - i + ": " + str
58+
})["join"]("\n")
59+
} else if (/\s$/.test(input)) {
60+
var tmp = autocomplete(input["trimRight"]());
61+
if(tmp["results"]["length"] === 0){
62+
this["defaultInput"] = input["trimRight"]();
63+
} else if(tmp["results"]["length"] === 1){
64+
this["defaultInput"] = tmp["tokens"][0] + tmp["tokens"][1] + (tmp["tokens"][1]["length"] === 0 ? "" : ".") + tmp["results"][0];
65+
} else {
66+
this["buffer"] = "coffee> " + input + "\n" + tmp["results"]["join"](" \t");
67+
this["defaultInput"] = input["trimRight"]();
68+
}
69+
} else if (/^.c/.test(input)) {
70+
this["clearLog"]();
71+
} else if (/^.he/.test(input)) {
72+
this["buffer"] = "coffee> " + input + "\n" + CoffeeScriptREPL["help"];
73+
} else {
74+
this["buffer"] = "";
75+
this["log"] += "coffee> " + input + "\n";
76+
try{
77+
var _log = dump(this["evaluate"](input), 0) + "\n";
78+
}catch(err){
79+
var _log = err["stack"] + "\n";
80+
}
81+
this["log"] += _log;
82+
}
83+
}
84+
85+
function CoffeeScriptREPL_evaluate(input){ // @arg String
86+
// @ret Void
87+
this["inputQueue"]["push"](input);
88+
var that = this;
89+
var preprocessed = "do ->\n " + input["split"]("\n")["join"]("\n ");
90+
var expanded = macroexpand(preprocessed);
91+
var env = {
92+
"log": function(o){ that["addLog"](o); },
93+
"clear": function(){ that["clearLog"](); },
94+
"dir": function(o, i){ return dump(o, i); },
95+
"type": function(o){ return type(o); },
96+
"load": function(url){ load(url); }
97+
};
98+
this["outputQueue"]["forEach"](function(val, i){
99+
env["$$"+(that["outputQueue"]["length"] - 1 - i)] = val;
100+
});
101+
var output = evaluate(expanded, env);
102+
this["outputQueue"]["push"](output);
103+
return output;
104+
}
105+
106+
function CoffeeScriptREPL_addLog(o){
107+
this["log"] += dump(o) + "\n";
108+
}
109+
110+
function CoffeeScriptREPL_clearLog(){
111+
this["log"] = "";
112+
this["buffer"] = "coffee> ";
113+
this["defaultInput"] = "";
114+
}
115+
116+
// --- functions ------------------------------------------
117+
function load(url, // @arg URLString
118+
callback) { // @arg Function
119+
// @ret Void
120+
var script = document.createElement("script");
121+
script.src = url;
122+
script.onload = callback;
123+
document.body.appendChild(script);
124+
}
125+
126+
function macroexpand(code) { // @arg CoffeeScriptString
127+
// @ret JavaScriptString
128+
var compiled = CoffeeScript["compile"](code, {"bare": true});
129+
var replaced = compiled["replace"](/var[^\;]+;\n\n/, "");
130+
return replaced;
131+
}
132+
133+
function evaluate(code, // @arg String
134+
env) { // @arg Object
135+
// @ret Any
136+
env = env || {};
137+
var vars = Object.keys(env);
138+
var vals = vars.map(function(key){ return env[key]; });
139+
var args = vars.concat("return " + code + ";");
140+
var fn = Function.apply(this, args);
141+
return fn.apply(self, vals);
142+
}
143+
console.assert(evaluate("unko", {unko:0}) === 0, "evaluate");
144+
145+
function getPropertys(o){ // @arg Object
146+
// @ret StringArray
147+
/*
148+
var keys1 = (function(o){
149+
var results = [];
150+
for(key in o) results.push(key);
151+
return results;
152+
})(o);
153+
var keys2 = Object.keys(o);
154+
*/
155+
var keys3 = (function(o){
156+
var results = [];
157+
while(o) {
158+
results = results.concat(Object.getOwnPropertyNames(o));
159+
o = Object.getPrototypeOf(o);
160+
}
161+
return results;
162+
})(o);
163+
//var keys = [].concat(keys1, keys2, keys3);
164+
var keys = keys3;
165+
var merged = keys.reduce(function(_, key){
166+
if(!!_["keySet"][key]) return _;
167+
_["keySet"][key] = true;
168+
_["results"]["push"](key);
169+
return _;
170+
},{"keySet":{}, "results":[]})["results"];
171+
var sorted = merged.sort();
172+
return sorted;
173+
}
174+
console.assert(getPropertys({a:0, b:0}).length === 2, "getPropertys");
175+
176+
function suggest(env, // @arg Object
177+
keyword){ // @arg String
178+
// @ret StringArray
179+
var reg = new RegExp("^" + keyword + ".*");
180+
var keys = getPropertys(env);
181+
var candidates = keys.filter(function(key) {
182+
return reg.test(key) && key !== keyword;
183+
});
184+
return candidates;
185+
}
186+
console.assert(suggest(self, "sel").length === 1, "suggest");
187+
188+
function autocomplete(code) { // @arg String
189+
// @ret Object
190+
var reg = /((?:[A-Za-z0-9$_](?:\.(?:[A-Za-z0-9$_]+)?)?)+)$/;
191+
var exp = (reg.exec(code) || ["", ""])[1]
192+
var pre = code.replace(exp, "");
193+
var arr = exp.split(".");
194+
var env = arr.slice(0, arr.length-1).join(".");
195+
var key = arr.slice(arr.length-1)[0];
196+
if(key.length === 0){
197+
var results = getPropertys(evaluate(env));
198+
} else if (env.length === 0){
199+
var results = suggest(self, key);
200+
} else {
201+
var results = suggest(evaluate(env), key);
202+
}
203+
if(exp === key){
204+
return {"tokens": [pre, "", key], "results": results};
205+
} else{
206+
return {"tokens": [pre, env, key], "results": results};
207+
}
208+
}
209+
console.assert(autocomplete("if" ).results.length === 0, "autocomplete 1");
210+
console.assert(autocomplete("if win").results[0] === "window", "autocomplete 2");
211+
console.assert(autocomplete("if window.sel").results[0] === "self", "autocomplete 2");
212+
213+
function type(o) { // @arg Object
214+
// @ret String
215+
if (o === null) { return "null";
216+
} else if (o === void 0) { return "undefined";
217+
} else if (o === self) { return "global";
218+
} else if (o["nodeType"] != null) { return "node";
219+
} else if (typeof o !== "object") { return typeof o;
220+
} else {
221+
var str = Object.prototype.toString.call(o);
222+
return ((str === "[object Object]" ?
223+
/^\s*function\s+(\w+)/.exec("" + o["constructor"]) :
224+
/^\[object (\w+)\]$/.exec(str)
225+
) || ["", "object"])[1]["toLowerCase"]();
226+
}
227+
}
228+
console.assert(type(null) === "null", "type null");
229+
console.assert(type(void 0) === "undefined", "type undefined");
230+
console.assert(type(true) === "boolean", "type boolean");
231+
console.assert(type(0) === "number", "type number");
232+
console.assert(type("string") === "string", "type string");
233+
console.assert(type(function() {}) === "function", "type function");
234+
console.assert(type([]) === "array", "type array");
235+
console.assert(type({}) === "object", "type object");
236+
console.assert(type(new Date) === "date", "type date");
237+
console.assert(type(Math) === "math", "type math");
238+
console.assert(type(/0/) === "regexp", "type regexp");
239+
console.assert(type(window) === "global", "type global");
240+
console.assert(type(document.createElement("div")) === "node", "type node");
241+
console.assert(type(new (function Foo(){})) === "foo", "type foo");
242+
243+
244+
function dump(o, // @arg Object
245+
depth){ // @arg Number?
246+
// @ret String
247+
depth = depth || 0;
248+
return recur(o, depth, 0, []);
249+
function recur(o, depth, i, ancestors){
250+
switch (type(o)) {
251+
case "null":
252+
case "undefined":
253+
case "boolean":
254+
case "number": return "" + o;
255+
case "string": return "\"" + o.split('\n').join('\\n') + "\"";
256+
case "function": return Object.prototype.toString.call(o);
257+
case "date": return JSON.stringify(o);
258+
case "array":
259+
if (ancestors.some(function(_o){ return _o === o;})) {
260+
return Object.prototype.toString.call(o) + "// Recursive Definition";
261+
} else if (i >= depth) {
262+
return Object.prototype.toString.call(o);
263+
} else {
264+
var arr = o.map(function(val){
265+
return recur(val, depth, i + 1, ancestors.concat(o));
266+
}).join(", ");
267+
return "[" + arr + "]";
268+
}
269+
default:
270+
if (ancestors.some(function(_o){ return _o === o;})) {
271+
return Object.prototype.toString.call(o) + " <- Recursive Definition";
272+
} else if (i >= depth) {
273+
return Object.prototype.toString.call(o);
274+
} else {
275+
var keys = getPropertys(o);
276+
if (keys.length === 0) {
277+
return "{}";
278+
} else {
279+
var props = keys.map(function(key) {
280+
var val = recur(o[key], depth, i + 1, ancestors.concat(o));
281+
return "" + space(i+1) + key + ": " + val;
282+
}).join(",\n");
283+
return "{\n" + props + "\n" + space(i) + "}";
284+
}
285+
}
286+
}
287+
}
288+
}
289+
console.assert(dump({a:{b:{c:0,d:0}}}) === "[object Object]", "dump {a:{b:{c:0,d:0}}}");
290+
console.assert(dump({a:{b:{c:0,d:0}}},3) === "{\n a: {\n b: {\n c: 0,\n d: 0\n }\n }\n}", "dump {a:{b:{c:0,d:0}}}, 3");
291+
292+
293+
function space(i){ // @arg Number
294+
// @ret String
295+
var result = "";
296+
while(i--) result += " ";
297+
return result;
298+
}
299+
console.assert(space(0) === "", "space 0");
300+
console.assert(space(1) === " ", "space 1");
301+
console.assert(space(2) === " ", "space 2");
302+
303+
// --- exports ---------------------------------------------
304+
global["CoffeeScriptREPL" in global ? "CoffeeScriptREPL_" : "CoffeeScriptREPL"] = CoffeeScriptREPL;
305+
306+
})((this || 0).self || global);

0 commit comments

Comments
 (0)