bb76d8c04dea3031d66ae4182b55780a5dc92ae9
[platform/upstream/nodejs.git] / lib / repl.js
1 // A repl library that you can include in your own code to get a runtime
2 // interface to your program. Just require("/repl.js").
3
4 var sys = require("/sys.js");
5
6 sys.puts("Type '.help' for options.");
7
8
9 var buffered_cmd = '';
10 var trimmer = /^\s*(.+)\s*$/m;
11 var scopedVar = /^\s*var\s*([_\w\$]+)(.*)$/m;
12 var scopeFunc = /^\s*function\s*([_\w\$]+)/;
13
14 exports.scope = {};
15 exports.prompt = "node> ";
16 exports.start = function (prompt) {
17   if (prompt !== undefined) {
18     exports.prompt = prompt;
19   }
20
21   node.stdio.open();
22   node.stdio.addListener("data", readline);
23   displayPrompt();
24 }
25
26 /**
27  * The main REPL function. This is called everytime the user enters
28  * data on the command line.
29  */
30 function readline (cmd) {
31   cmd = trimWhitespace(cmd);
32   
33   // Check to see if a REPL keyword was used. If it returns true,
34   // display next prompt and return.
35   if (parseREPLKeyword(cmd) === true) {
36     return;
37   }
38   
39   // The catchall for errors
40   try {
41     buffered_cmd += cmd;
42     // This try is for determining if the command is complete, or should
43     // continue onto the next line.
44     try {
45       buffered_cmd = convertToScope(buffered_cmd);
46       
47       // Scope the readline with exports.scope to provide "local" vars
48       with (exports.scope) {
49         var ret = eval(buffered_cmd);
50         if (ret !== undefined) {
51           exports.scope['_'] = ret;
52           sys.p(ret);
53         }
54       }
55         
56       buffered_cmd = '';
57     } catch (e) {
58       if (!(e instanceof SyntaxError)) throw e;
59     }
60   } catch (e) {
61     // On error: Print the error and clear the buffer
62     if (e.stack) {
63       sys.puts(e.stack);
64     } else {
65       sys.puts(e.toString());
66     }
67     buffered_cmd = '';
68   }
69   
70   displayPrompt();
71 }
72
73
74 /**
75  * Used to display the prompt. 
76  */
77 function displayPrompt () {
78   sys.print(buffered_cmd.length ? '...   ' : exports.prompt);
79 }
80
81 /**
82  * Used to parse and execute the Node REPL commands.
83  * 
84  * @param {cmd} cmd The command entered to check
85  * @returns {Boolean} If true it means don't continue parsing the command 
86  */
87 function parseREPLKeyword (cmd) {
88   switch (cmd) {
89   case ".break":
90     buffered_cmd = '';
91     displayPrompt();
92     return true;
93   case ".clear":
94     sys.puts("Clearing Scope...");
95     buffered_cmd = '';
96     exports.scope = {};
97     displayPrompt();
98     return true;
99   case ".exit":
100     node.stdio.close();
101     return true;
102   case ".help":
103     sys.puts(".break\tSometimes you get stuck in a place you can't get out... This will get you out.");
104     sys.puts(".clear\tBreak, and also clear the local scope.");
105     sys.puts(".exit\tExit the prompt");
106     sys.puts(".help\tShow repl options");
107     displayPrompt();
108     return true;
109   }
110   return false;
111 }
112
113 /**
114  * Trims Whitespace from a line.
115  * 
116  * @param {String} cmd The string to trim the whitespace from
117  * @returns {String} The trimmed string 
118  */
119 function trimWhitespace (cmd) {
120   var matches = trimmer.exec(cmd);
121   if (matches && matches.length == 2) {
122     return matches[1];
123   }
124 }
125
126 /**
127  * Converts commands that use var and function <name>() to use the
128  * local exports.scope when evaled. This provides a local scope
129  * on the REPL.
130  * 
131  * @param {String} cmd The cmd to convert
132  * @returns {String} The converted command
133  */
134 function convertToScope (cmd) {
135   var matches;
136   
137   // Replaces: var foo = "bar";  with: exports.scope.foo = bar;
138   matches = scopedVar.exec(cmd);
139   if (matches && matches.length == 3) {
140     return "exports.scope." + matches[1] + matches[2];
141   }
142   
143   // Replaces: function foo() {};  with: foo = function foo() {};
144   matches = scopeFunc.exec(buffered_cmd);
145   if (matches && matches.length == 2) {
146     return matches[1] + " = " + buffered_cmd;
147   }
148   
149   return cmd;
150 }