browsercms 3.1.4 → 3.1.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (164) hide show
  1. data/app/controllers/cms/content_block_controller.rb +2 -2
  2. data/app/controllers/cms/section_nodes_controller.rb +6 -1
  3. data/app/controllers/cms/sections_controller.rb +1 -1
  4. data/app/helpers/cms/application_helper.rb +1 -1
  5. data/app/helpers/cms/content_block_helper.rb +27 -0
  6. data/app/helpers/cms/section_nodes_helper.rb +43 -5
  7. data/app/models/abstract_file_block.rb +16 -1
  8. data/app/models/attachment.rb +17 -35
  9. data/app/models/file_block.rb +0 -12
  10. data/app/models/image_block.rb +0 -12
  11. data/app/models/link.rb +4 -21
  12. data/app/models/page.rb +31 -34
  13. data/app/models/section.rb +82 -44
  14. data/app/models/section_node.rb +39 -24
  15. data/app/models/user.rb +5 -0
  16. data/app/views/cms/blocks/index.html.erb +4 -4
  17. data/app/views/cms/file_blocks/_form.html.erb +1 -1
  18. data/app/views/cms/image_blocks/_form.html.erb +1 -1
  19. data/app/views/cms/section_nodes/_link.html.erb +6 -3
  20. data/app/views/cms/section_nodes/_node.html.erb +11 -1
  21. data/app/views/cms/section_nodes/_page.html.erb +13 -7
  22. data/app/views/cms/section_nodes/_section.html.erb +24 -8
  23. data/app/views/cms/section_nodes/index.html.erb +28 -16
  24. data/app/views/layouts/templates/default.html.erb +17 -0
  25. data/browsercms.gemspec +28 -1413
  26. data/db/migrate/20120117144039_browsercms315.rb +94 -0
  27. data/db/migrate/{20081114172307_load_seed_data.rb → 20121114172307_load_seeds.rb} +8 -1
  28. data/lib/acts_as_list.rb +1 -1
  29. data/lib/browsercms.rb +2 -0
  30. data/lib/cms/addressable.rb +83 -0
  31. data/lib/cms/behaviors/attaching.rb +44 -24
  32. data/lib/cms/behaviors/connecting.rb +2 -1
  33. data/lib/cms/behaviors/publishing.rb +12 -3
  34. data/lib/cms/behaviors/versioning.rb +83 -53
  35. data/lib/cms/content_rendering_support.rb +3 -3
  36. data/lib/cms/error_pages.rb +8 -0
  37. data/lib/cms/init.rb +5 -3
  38. data/lib/cms/version.rb +1 -1
  39. data/templates/blank.rb +2 -0
  40. data/templates/demo.rb +2 -0
  41. data/templates/module.rb +2 -0
  42. data/test/custom_assertions.rb +7 -1
  43. data/test/factories.rb +3 -1
  44. data/test/factories/sitemap_factories.rb +28 -0
  45. data/test/fixtures/connectors.yml +97 -0
  46. data/test/fixtures/content_type_groups.yml +13 -0
  47. data/test/fixtures/content_types.yml +50 -0
  48. data/test/fixtures/dynamic_view_versions.yml +26 -0
  49. data/test/fixtures/dynamic_views.yml +26 -0
  50. data/test/fixtures/group_permissions.yml +16 -0
  51. data/test/fixtures/group_sections.yml +31 -0
  52. data/test/fixtures/group_type_permissions.yml +11 -0
  53. data/test/fixtures/group_types.yml +25 -0
  54. data/test/fixtures/groups.yml +25 -0
  55. data/test/fixtures/html_block_versions.yml +67 -0
  56. data/test/fixtures/html_blocks.yml +63 -0
  57. data/test/fixtures/page_versions.yml +265 -0
  58. data/test/fixtures/pages.yml +85 -0
  59. data/test/fixtures/permissions.yml +28 -0
  60. data/test/fixtures/section_nodes.yml +46 -0
  61. data/test/fixtures/sections.yml +19 -0
  62. data/test/fixtures/sites.yml +9 -0
  63. data/test/fixtures/user_group_memberships.yml +11 -0
  64. data/test/fixtures/users.yml +15 -0
  65. data/test/functional/cms/content_controller_test.rb +6 -1
  66. data/test/functional/cms/file_blocks_controller_test.rb +1 -0
  67. data/test/functional/cms/html_blocks_controller_test.rb +1 -0
  68. data/test/functional/cms/image_blocks_controller_test.rb +39 -32
  69. data/test/functional/cms/section_nodes_controller_test.rb +48 -20
  70. data/test/functional/cms/sections_controller_test.rb +3 -1
  71. data/test/functional/tests/pretend_controller_test.rb +6 -3
  72. data/test/integration/cms/ckeditor_test.rb +5 -2
  73. data/test/integration/sitemap_performance_test.rb +26 -0
  74. data/test/selenium-core/Blank.html +7 -0
  75. data/test/selenium-core/InjectedRemoteRunner.html +8 -0
  76. data/test/selenium-core/RemoteRunner.html +110 -0
  77. data/test/selenium-core/SeleniumLog.html +109 -0
  78. data/test/selenium-core/TestPrompt.html +145 -0
  79. data/test/selenium-core/TestRunner-splash.html +55 -0
  80. data/test/selenium-core/TestRunner.hta +176 -0
  81. data/test/selenium-core/TestRunner.html +176 -0
  82. data/test/selenium-core/domviewer/butmin.gif +0 -0
  83. data/test/selenium-core/domviewer/butplus.gif +0 -0
  84. data/test/selenium-core/domviewer/domviewer.css +298 -0
  85. data/test/selenium-core/domviewer/domviewer.html +16 -0
  86. data/test/selenium-core/domviewer/selenium-domviewer.js +205 -0
  87. data/test/selenium-core/icons/all.png +0 -0
  88. data/test/selenium-core/icons/continue.png +0 -0
  89. data/test/selenium-core/icons/continue_disabled.png +0 -0
  90. data/test/selenium-core/icons/pause.png +0 -0
  91. data/test/selenium-core/icons/pause_disabled.png +0 -0
  92. data/test/selenium-core/icons/selected.png +0 -0
  93. data/test/selenium-core/icons/step.png +0 -0
  94. data/test/selenium-core/icons/step_disabled.png +0 -0
  95. data/test/selenium-core/iedoc-core.xml +1515 -0
  96. data/test/selenium-core/iedoc.xml +1469 -0
  97. data/test/selenium-core/lib/cssQuery/cssQuery-p.js +6 -0
  98. data/test/selenium-core/lib/cssQuery/src/cssQuery-level2.js +142 -0
  99. data/test/selenium-core/lib/cssQuery/src/cssQuery-level3.js +150 -0
  100. data/test/selenium-core/lib/cssQuery/src/cssQuery-standard.js +53 -0
  101. data/test/selenium-core/lib/cssQuery/src/cssQuery.js +356 -0
  102. data/test/selenium-core/lib/prototype.js +2006 -0
  103. data/test/selenium-core/lib/scriptaculous/builder.js +101 -0
  104. data/test/selenium-core/lib/scriptaculous/controls.js +815 -0
  105. data/test/selenium-core/lib/scriptaculous/dragdrop.js +915 -0
  106. data/test/selenium-core/lib/scriptaculous/effects.js +958 -0
  107. data/test/selenium-core/lib/scriptaculous/scriptaculous.js +47 -0
  108. data/test/selenium-core/lib/scriptaculous/slider.js +283 -0
  109. data/test/selenium-core/lib/scriptaculous/unittest.js +383 -0
  110. data/test/selenium-core/scripts/find_matching_child.js +69 -0
  111. data/test/selenium-core/scripts/htmlutils.js +894 -0
  112. data/test/selenium-core/scripts/injection.html +72 -0
  113. data/test/selenium-core/scripts/js2html.js +70 -0
  114. data/test/selenium-core/scripts/narcissus-defs.js +175 -0
  115. data/test/selenium-core/scripts/narcissus-exec.js +1054 -0
  116. data/test/selenium-core/scripts/narcissus-parse.js +1003 -0
  117. data/test/selenium-core/scripts/se2html.js +63 -0
  118. data/test/selenium-core/scripts/selenium-api.js +2409 -0
  119. data/test/selenium-core/scripts/selenium-browserbot.js +2203 -0
  120. data/test/selenium-core/scripts/selenium-browserdetect.js +150 -0
  121. data/test/selenium-core/scripts/selenium-commandhandlers.js +377 -0
  122. data/test/selenium-core/scripts/selenium-executionloop.js +175 -0
  123. data/test/selenium-core/scripts/selenium-logging.js +147 -0
  124. data/test/selenium-core/scripts/selenium-remoterunner.js +571 -0
  125. data/test/selenium-core/scripts/selenium-testrunner.js +1333 -0
  126. data/test/selenium-core/scripts/selenium-version.js +5 -0
  127. data/test/selenium-core/scripts/user-extensions.js +3 -0
  128. data/test/selenium-core/scripts/user-extensions.js.sample +75 -0
  129. data/test/selenium-core/scripts/xmlextras.js +153 -0
  130. data/test/selenium-core/selenium-logo.png +0 -0
  131. data/test/selenium-core/selenium-test.css +43 -0
  132. data/test/selenium-core/selenium.css +299 -0
  133. data/test/selenium-core/xpath/dom.js +428 -0
  134. data/test/selenium-core/xpath/misc.js +252 -0
  135. data/test/selenium-core/xpath/xpath.js +2223 -0
  136. data/test/selenium/_login_as_cmsadmin.rsel +4 -0
  137. data/test/selenium/dashboard.rsel +5 -0
  138. data/test/selenium/html_blocks.rsel +4 -0
  139. data/test/selenium/login/failed_login.rsel +8 -0
  140. data/test/selenium/login/successful_login.rsel +9 -0
  141. data/test/selenium/page_templates.rsel +12 -0
  142. data/test/selenium/pages/edit_properties.rsel +5 -0
  143. data/test/selenium/site/view_home_page.rsel +4 -0
  144. data/test/selenium/sitemap/move_page.rsel +9 -0
  145. data/test/selenium/sitemap/open_section.rsel +6 -0
  146. data/test/selenium/sitemap/select_page.rsel +12 -0
  147. data/test/selenium/sitemap/select_section.rsel +17 -0
  148. data/test/test_helper.rb +30 -12
  149. data/test/unit/behaviors/attaching_test.rb +4 -6
  150. data/test/unit/behaviors/connectable_test.rb +29 -0
  151. data/test/unit/behaviors/publishable_test.rb +40 -9
  152. data/test/unit/behaviors/versioning_test.rb +36 -0
  153. data/test/unit/helpers/menu_helper_test.rb +5 -2
  154. data/test/unit/helpers/page_helper_test.rb +2 -0
  155. data/test/unit/lib/cms/sitemap_test.rb +206 -0
  156. data/test/unit/models/attachment_test.rb +51 -31
  157. data/test/unit/models/file_block_test.rb +74 -55
  158. data/test/unit/models/link_test.rb +44 -0
  159. data/test/unit/models/page_test.rb +290 -224
  160. data/test/unit/models/sections_test.rb +144 -44
  161. data/test/unit/models/user_test.rb +28 -18
  162. metadata +581 -350
  163. data/app/views/cms/section_nodes/_section_node.html.erb +0 -10
  164. data/test/unit/models/section_node_test.rb +0 -92
@@ -0,0 +1,72 @@
1
+ <script language="JavaScript">
2
+ if (window["selenium_has_been_loaded_into_this_window"]==null)
3
+ {
4
+
5
+ __SELENIUM_JS__
6
+ // Some background on the code below: broadly speaking, where we are relative to other windows
7
+ // when running in proxy injection mode depends on whether we are in a frame set file or not.
8
+ //
9
+ // In regular HTML files, the selenium JavaScript is injected into an iframe called "selenium"
10
+ // in order to reduce its impact on the JavaScript environment (through namespace pollution,
11
+ // etc.). So in regular HTML files, we need to look at the parent of the current window when we want
12
+ // a handle to, e.g., the application window.
13
+ //
14
+ // In frame set files, we can't use an iframe, so we put the JavaScript in the head element and share
15
+ // the window with the frame set. So in this case, we need to look at the current window, not the
16
+ // parent when looking for, e.g., the application window. (TODO: Perhaps I should have just
17
+ // assigned a regular frame for selenium?)
18
+ //
19
+ BrowserBot.prototype.getContentWindow = function() {
20
+ return window;
21
+ };
22
+
23
+ BrowserBot.prototype.getTargetWindow = function(windowName) {
24
+ return window;
25
+ };
26
+
27
+ BrowserBot.prototype.getCurrentWindow = function() {
28
+ return window;
29
+ };
30
+
31
+ LOG.openLogWindow = function(message, className) {
32
+ // disable for now
33
+ };
34
+
35
+ BrowserBot.prototype.relayToRC = function(name) {
36
+ var object = eval(name);
37
+ var s = 'state:' + serializeObject(name, object) + "\n";
38
+ sendToRC(s,"state=true");
39
+ }
40
+
41
+ function selenium_frameRunTest(oldOnLoadRoutine) {
42
+ if (oldOnLoadRoutine) {
43
+ eval(oldOnLoadRoutine);
44
+ }
45
+ runSeleniumTest();
46
+ }
47
+
48
+ function seleniumOnLoad() {
49
+ injectedSessionId = @SESSION_ID@;
50
+ window["selenium_has_been_loaded_into_this_window"] = true;
51
+ runSeleniumTest();
52
+ }
53
+
54
+ function seleniumOnUnload() {
55
+ sendToRC("Current window or frame is closed!", "closing=true");
56
+ }
57
+
58
+ if (window.addEventListener) {
59
+ window.addEventListener("load", seleniumOnLoad, false); // firefox
60
+ window.addEventListener("unload", seleniumOnUnload, false); // firefox
61
+ } else if (window.attachEvent){
62
+ window.attachEvent("onload", seleniumOnLoad); // IE
63
+ window.attachEvent("onunload", seleniumOnUnload); // IE
64
+ }
65
+ else {
66
+ throw "causing a JavaScript error to tell the world that I did not arrange to be run on load";
67
+ }
68
+
69
+ injectedSessionId = @SESSION_ID@;
70
+ proxyInjectionMode = true;
71
+ }
72
+ </script>
@@ -0,0 +1,70 @@
1
+ /*
2
+
3
+ This is an experiment in using the Narcissus JavaScript engine
4
+ to allow Selenium scripts to be written in plain JavaScript.
5
+
6
+ The 'jsparse' function will compile each high level block into a Selenium table script.
7
+
8
+
9
+ TODO:
10
+ 1) Test! (More browsers, more sample scripts)
11
+ 2) Stepping and walking lower levels of the parse tree
12
+ 3) Calling Selenium commands directly from JavaScript
13
+ 4) Do we want comments to appear in the TestRunner?
14
+ 5) Fix context so variables don't have to be global
15
+ For now, variables defined with "var" won't be found
16
+ if used later on in a script.
17
+ 6) Fix formatting
18
+ */
19
+
20
+
21
+ function jsparse() {
22
+ var script = document.getElementById('sejs')
23
+ var fname = 'javascript script';
24
+ parse_result = parse(script.text, fname, 0);
25
+
26
+ var x2 = new ExecutionContext(GLOBAL_CODE);
27
+ ExecutionContext.current = x2;
28
+
29
+
30
+ var new_test_source = '';
31
+ var new_line = '';
32
+
33
+ for (i=0;i<parse_result.$length;i++){
34
+ var the_start = parse_result[i].start;
35
+ var the_end;
36
+ if ( i == (parse_result.$length-1)) {
37
+ the_end = parse_result.tokenizer.source.length;
38
+ } else {
39
+ the_end = parse_result[i+1].start;
40
+ }
41
+
42
+ var script_fragment = parse_result.tokenizer.source.slice(the_start,the_end)
43
+
44
+ new_line = '<tr><td style="display:none;" class="js">getEval</td>' +
45
+ '<td style="display:none;">currentTest.doNextCommand()</td>' +
46
+ '<td style="white-space: pre;">' + script_fragment + '</td>' +
47
+ '<td></td></tr>\n';
48
+ new_test_source += new_line;
49
+ //eval(script_fragment);
50
+
51
+
52
+ };
53
+
54
+
55
+
56
+ execute(parse_result,x2)
57
+
58
+ // Create HTML Table
59
+ body = document.body
60
+ body.innerHTML += "<table class='selenium' id='se-js-table'>"+
61
+ "<tbody>" +
62
+ "<tr><td>// " + document.title + "</td></tr>" +
63
+ new_test_source +
64
+ "</tbody" +
65
+ "</table>";
66
+
67
+ //body.innerHTML = "<pre>" + parse_result + "</pre>"
68
+ }
69
+
70
+
@@ -0,0 +1,175 @@
1
+ /* ***** BEGIN LICENSE BLOCK *****
2
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3
+ *
4
+ * The contents of this file are subject to the Mozilla Public License Version
5
+ * 1.1 (the "License"); you may not use this file except in compliance with
6
+ * the License. You may obtain a copy of the License at
7
+ * http://www.mozilla.org/MPL/
8
+ *
9
+ * Software distributed under the License is distributed on an "AS IS" basis,
10
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11
+ * for the specific language governing rights and limitations under the
12
+ * License.
13
+ *
14
+ * The Original Code is the Narcissus JavaScript engine.
15
+ *
16
+ * The Initial Developer of the Original Code is
17
+ * Brendan Eich <brendan@mozilla.org>.
18
+ * Portions created by the Initial Developer are Copyright (C) 2004
19
+ * the Initial Developer. All Rights Reserved.
20
+ *
21
+ * Contributor(s):
22
+ *
23
+ * Alternatively, the contents of this file may be used under the terms of
24
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
25
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26
+ * in which case the provisions of the GPL or the LGPL are applicable instead
27
+ * of those above. If you wish to allow use of your version of this file only
28
+ * under the terms of either the GPL or the LGPL, and not to allow others to
29
+ * use your version of this file under the terms of the MPL, indicate your
30
+ * decision by deleting the provisions above and replace them with the notice
31
+ * and other provisions required by the GPL or the LGPL. If you do not delete
32
+ * the provisions above, a recipient may use your version of this file under
33
+ * the terms of any one of the MPL, the GPL or the LGPL.
34
+ *
35
+ * ***** END LICENSE BLOCK ***** */
36
+
37
+ /*
38
+ * Narcissus - JS implemented in JS.
39
+ *
40
+ * Well-known constants and lookup tables. Many consts are generated from the
41
+ * tokens table via eval to minimize redundancy, so consumers must be compiled
42
+ * separately to take advantage of the simple switch-case constant propagation
43
+ * done by SpiderMonkey.
44
+ */
45
+
46
+ // jrh
47
+ //module('JS.Defs');
48
+
49
+ GLOBAL = this;
50
+
51
+ var tokens = [
52
+ // End of source.
53
+ "END",
54
+
55
+ // Operators and punctuators. Some pair-wise order matters, e.g. (+, -)
56
+ // and (UNARY_PLUS, UNARY_MINUS).
57
+ "\n", ";",
58
+ ",",
59
+ "=",
60
+ "?", ":", "CONDITIONAL",
61
+ "||",
62
+ "&&",
63
+ "|",
64
+ "^",
65
+ "&",
66
+ "==", "!=", "===", "!==",
67
+ "<", "<=", ">=", ">",
68
+ "<<", ">>", ">>>",
69
+ "+", "-",
70
+ "*", "/", "%",
71
+ "!", "~", "UNARY_PLUS", "UNARY_MINUS",
72
+ "++", "--",
73
+ ".",
74
+ "[", "]",
75
+ "{", "}",
76
+ "(", ")",
77
+
78
+ // Nonterminal tree node type codes.
79
+ "SCRIPT", "BLOCK", "LABEL", "FOR_IN", "CALL", "NEW_WITH_ARGS", "INDEX",
80
+ "ARRAY_INIT", "OBJECT_INIT", "PROPERTY_INIT", "GETTER", "SETTER",
81
+ "GROUP", "LIST",
82
+
83
+ // Terminals.
84
+ "IDENTIFIER", "NUMBER", "STRING", "REGEXP",
85
+
86
+ // Keywords.
87
+ "break",
88
+ "case", "catch", "const", "continue",
89
+ "debugger", "default", "delete", "do",
90
+ "else", "enum",
91
+ "false", "finally", "for", "function",
92
+ "if", "in", "instanceof",
93
+ "new", "null",
94
+ "return",
95
+ "switch",
96
+ "this", "throw", "true", "try", "typeof",
97
+ "var", "void",
98
+ "while", "with",
99
+ // Extensions
100
+ "require", "bless", "mixin", "import"
101
+ ];
102
+
103
+ // Operator and punctuator mapping from token to tree node type name.
104
+ // NB: superstring tokens (e.g., ++) must come before their substring token
105
+ // counterparts (+ in the example), so that the opRegExp regular expression
106
+ // synthesized from this list makes the longest possible match.
107
+ var opTypeNames = {
108
+ '\n': "NEWLINE",
109
+ ';': "SEMICOLON",
110
+ ',': "COMMA",
111
+ '?': "HOOK",
112
+ ':': "COLON",
113
+ '||': "OR",
114
+ '&&': "AND",
115
+ '|': "BITWISE_OR",
116
+ '^': "BITWISE_XOR",
117
+ '&': "BITWISE_AND",
118
+ '===': "STRICT_EQ",
119
+ '==': "EQ",
120
+ '=': "ASSIGN",
121
+ '!==': "STRICT_NE",
122
+ '!=': "NE",
123
+ '<<': "LSH",
124
+ '<=': "LE",
125
+ '<': "LT",
126
+ '>>>': "URSH",
127
+ '>>': "RSH",
128
+ '>=': "GE",
129
+ '>': "GT",
130
+ '++': "INCREMENT",
131
+ '--': "DECREMENT",
132
+ '+': "PLUS",
133
+ '-': "MINUS",
134
+ '*': "MUL",
135
+ '/': "DIV",
136
+ '%': "MOD",
137
+ '!': "NOT",
138
+ '~': "BITWISE_NOT",
139
+ '.': "DOT",
140
+ '[': "LEFT_BRACKET",
141
+ ']': "RIGHT_BRACKET",
142
+ '{': "LEFT_CURLY",
143
+ '}': "RIGHT_CURLY",
144
+ '(': "LEFT_PAREN",
145
+ ')': "RIGHT_PAREN"
146
+ };
147
+
148
+ // Hash of keyword identifier to tokens index. NB: we must null __proto__ to
149
+ // avoid toString, etc. namespace pollution.
150
+ var keywords = {__proto__: null};
151
+
152
+ // Define const END, etc., based on the token names. Also map name to index.
153
+ var consts = " ";
154
+ for (var i = 0, j = tokens.length; i < j; i++) {
155
+ if (i > 0)
156
+ consts += "; ";
157
+ var t = tokens[i];
158
+ if (/^[a-z]/.test(t)) {
159
+ consts += t.toUpperCase();
160
+ keywords[t] = i;
161
+ } else {
162
+ consts += (/^\W/.test(t) ? opTypeNames[t] : t);
163
+ }
164
+ consts += " = " + i;
165
+ tokens[t] = i;
166
+ }
167
+ eval(consts + ";");
168
+
169
+ // Map assignment operators to their indexes in the tokens array.
170
+ var assignOps = ['|', '^', '&', '<<', '>>', '>>>', '+', '-', '*', '/', '%'];
171
+
172
+ for (i = 0, j = assignOps.length; i < j; i++) {
173
+ t = assignOps[i];
174
+ assignOps[t] = tokens[t];
175
+ }
@@ -0,0 +1,1054 @@
1
+ /* ***** BEGIN LICENSE BLOCK *****
2
+ * vim: set ts=4 sw=4 et tw=80:
3
+ *
4
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5
+ *
6
+ * The contents of this file are subject to the Mozilla Public License Version
7
+ * 1.1 (the "License"); you may not use this file except in compliance with
8
+ * the License. You may obtain a copy of the License at
9
+ * http://www.mozilla.org/MPL/
10
+ *
11
+ * Software distributed under the License is distributed on an "AS IS" basis,
12
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13
+ * for the specific language governing rights and limitations under the
14
+ * License.
15
+ *
16
+ * The Original Code is the Narcissus JavaScript engine.
17
+ *
18
+ * The Initial Developer of the Original Code is
19
+ * Brendan Eich <brendan@mozilla.org>.
20
+ * Portions created by the Initial Developer are Copyright (C) 2004
21
+ * the Initial Developer. All Rights Reserved.
22
+ *
23
+ * Contributor(s):
24
+ *
25
+ * Alternatively, the contents of this file may be used under the terms of
26
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
27
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28
+ * in which case the provisions of the GPL or the LGPL are applicable instead
29
+ * of those above. If you wish to allow use of your version of this file only
30
+ * under the terms of either the GPL or the LGPL, and not to allow others to
31
+ * use your version of this file under the terms of the MPL, indicate your
32
+ * decision by deleting the provisions above and replace them with the notice
33
+ * and other provisions required by the GPL or the LGPL. If you do not delete
34
+ * the provisions above, a recipient may use your version of this file under
35
+ * the terms of any one of the MPL, the GPL or the LGPL.
36
+ *
37
+ * ***** END LICENSE BLOCK ***** */
38
+
39
+ /*
40
+ * Narcissus - JS implemented in JS.
41
+ *
42
+ * Execution of parse trees.
43
+ *
44
+ * Standard classes except for eval, Function, Array, and String are borrowed
45
+ * from the host JS environment. Function is metacircular. Array and String
46
+ * are reflected via wrapping the corresponding native constructor and adding
47
+ * an extra level of prototype-based delegation.
48
+ */
49
+
50
+ // jrh
51
+ //module('JS.Exec');
52
+ // end jrh
53
+
54
+ GLOBAL_CODE = 0; EVAL_CODE = 1; FUNCTION_CODE = 2;
55
+
56
+ function ExecutionContext(type) {
57
+ this.type = type;
58
+ }
59
+
60
+ // jrh
61
+ var agenda = new Array();
62
+ var skip_setup = 0;
63
+ // end jrh
64
+
65
+ var global = {
66
+ // Value properties.
67
+ NaN: NaN, Infinity: Infinity, undefined: undefined,
68
+ alert : function(msg) { alert(msg) },
69
+ confirm : function(msg) { return confirm(msg) },
70
+ document : document,
71
+ window : window,
72
+ // jrh
73
+ //debug: window.open('','debugwindow','width=600,height=400,scrollbars=yes,resizable=yes'),
74
+ // end jrh
75
+ navigator : navigator,
76
+ XMLHttpRequest : function() { return new XMLHttpRequest() },
77
+ // Function properties.
78
+ eval: function(s) {
79
+ if (typeof s != "string") {
80
+ return s;
81
+ }
82
+
83
+ var x = ExecutionContext.current;
84
+ var x2 = new ExecutionContext(EVAL_CODE);
85
+ x2.thisObject = x.thisObject;
86
+ x2.caller = x.caller;
87
+ x2.callee = x.callee;
88
+ x2.scope = x.scope;
89
+ ExecutionContext.current = x2;
90
+ try {
91
+ execute(parse(s), x2);
92
+ } catch (e) {
93
+ x.result = x2.result;
94
+ throw e;
95
+ } finally {
96
+ ExecutionContext.current = x;
97
+ }
98
+ return x2.result;
99
+ },
100
+ parseInt: parseInt, parseFloat: parseFloat,
101
+ isNaN: isNaN, isFinite: isFinite,
102
+ decodeURI: decodeURI, encodeURI: encodeURI,
103
+ decodeURIComponent: decodeURIComponent,
104
+ encodeURIComponent: encodeURIComponent,
105
+
106
+ // Class constructors. Where ECMA-262 requires C.length == 1, we declare
107
+ // a dummy formal parameter.
108
+ Object: Object,
109
+ Function: function(dummy) {
110
+ var p = "", b = "", n = arguments.length;
111
+ if (n) {
112
+ var m = n - 1;
113
+ if (m) {
114
+ p += arguments[0];
115
+ for (var k = 1; k < m; k++)
116
+ p += "," + arguments[k];
117
+ }
118
+ b += arguments[m];
119
+ }
120
+
121
+ // XXX We want to pass a good file and line to the tokenizer.
122
+ // Note the anonymous name to maintain parity with Spidermonkey.
123
+ var t = new Tokenizer("anonymous(" + p + ") {" + b + "}");
124
+
125
+ // NB: Use the STATEMENT_FORM constant since we don't want to push this
126
+ // function onto the null compilation context.
127
+ var f = FunctionDefinition(t, null, false, STATEMENT_FORM);
128
+ var s = {object: global, parent: null};
129
+ return new FunctionObject(f, s);
130
+ },
131
+ Array: function(dummy) {
132
+ // Array when called as a function acts as a constructor.
133
+ return GLOBAL.Array.apply(this, arguments);
134
+ },
135
+ String: function(s) {
136
+ // Called as function or constructor: convert argument to string type.
137
+ s = arguments.length ? "" + s : "";
138
+ if (this instanceof String) {
139
+ // Called as constructor: save the argument as the string value
140
+ // of this String object and return this object.
141
+ this.value = s;
142
+ return this;
143
+ }
144
+ return s;
145
+ },
146
+ Boolean: Boolean, Number: Number, Date: Date, RegExp: RegExp,
147
+ Error: Error, EvalError: EvalError, RangeError: RangeError,
148
+ ReferenceError: ReferenceError, SyntaxError: SyntaxError,
149
+ TypeError: TypeError, URIError: URIError,
150
+
151
+ // Other properties.
152
+ Math: Math,
153
+
154
+ // Extensions to ECMA.
155
+ //snarf: snarf,
156
+ evaluate: evaluate,
157
+ load: function(s) {
158
+ if (typeof s != "string")
159
+ return s;
160
+ var req = new XMLHttpRequest();
161
+ req.open('GET', s, false);
162
+ req.send(null);
163
+
164
+ evaluate(req.responseText, s, 1)
165
+ },
166
+ print: print, version: null
167
+ };
168
+
169
+ // jrh
170
+ //global.debug.document.body.innerHTML = ''
171
+ // end jrh
172
+
173
+ // Helper to avoid Object.prototype.hasOwnProperty polluting scope objects.
174
+ function hasDirectProperty(o, p) {
175
+ return Object.prototype.hasOwnProperty.call(o, p);
176
+ }
177
+
178
+ // Reflect a host class into the target global environment by delegation.
179
+ function reflectClass(name, proto) {
180
+ var gctor = global[name];
181
+ gctor.prototype = proto;
182
+ proto.constructor = gctor;
183
+ return proto;
184
+ }
185
+
186
+ // Reflect Array -- note that all Array methods are generic.
187
+ reflectClass('Array', new Array);
188
+
189
+ // Reflect String, overriding non-generic methods.
190
+ var gSp = reflectClass('String', new String);
191
+ gSp.toSource = function () { return this.value.toSource(); };
192
+ gSp.toString = function () { return this.value; };
193
+ gSp.valueOf = function () { return this.value; };
194
+ global.String.fromCharCode = String.fromCharCode;
195
+
196
+ var XCp = ExecutionContext.prototype;
197
+ ExecutionContext.current = XCp.caller = XCp.callee = null;
198
+ XCp.scope = {object: global, parent: null};
199
+ XCp.thisObject = global;
200
+ XCp.result = undefined;
201
+ XCp.target = null;
202
+ XCp.ecmaStrictMode = false;
203
+
204
+ function Reference(base, propertyName, node) {
205
+ this.base = base;
206
+ this.propertyName = propertyName;
207
+ this.node = node;
208
+ }
209
+
210
+ Reference.prototype.toString = function () { return this.node.getSource(); }
211
+
212
+ function getValue(v) {
213
+ if (v instanceof Reference) {
214
+ if (!v.base) {
215
+ throw new ReferenceError(v.propertyName + " is not defined",
216
+ v.node.filename(), v.node.lineno);
217
+ }
218
+ return v.base[v.propertyName];
219
+ }
220
+ return v;
221
+ }
222
+
223
+ function putValue(v, w, vn) {
224
+ if (v instanceof Reference)
225
+ return (v.base || global)[v.propertyName] = w;
226
+ throw new ReferenceError("Invalid assignment left-hand side",
227
+ vn.filename(), vn.lineno);
228
+ }
229
+
230
+ function isPrimitive(v) {
231
+ var t = typeof v;
232
+ return (t == "object") ? v === null : t != "function";
233
+ }
234
+
235
+ function isObject(v) {
236
+ var t = typeof v;
237
+ return (t == "object") ? v !== null : t == "function";
238
+ }
239
+
240
+ // If r instanceof Reference, v == getValue(r); else v === r. If passed, rn
241
+ // is the node whose execute result was r.
242
+ function toObject(v, r, rn) {
243
+ switch (typeof v) {
244
+ case "boolean":
245
+ return new global.Boolean(v);
246
+ case "number":
247
+ return new global.Number(v);
248
+ case "string":
249
+ return new global.String(v);
250
+ case "function":
251
+ return v;
252
+ case "object":
253
+ if (v !== null)
254
+ return v;
255
+ }
256
+ var message = r + " (type " + (typeof v) + ") has no properties";
257
+ throw rn ? new TypeError(message, rn.filename(), rn.lineno)
258
+ : new TypeError(message);
259
+ }
260
+
261
+ function execute(n, x) {
262
+ if (!this.new_block)
263
+ new_block = new Array();
264
+ //alert (n)
265
+ var a, f, i, j, r, s, t, u, v;
266
+ switch (n.type) {
267
+ case FUNCTION:
268
+ if (n.functionForm != DECLARED_FORM) {
269
+ if (!n.name || n.functionForm == STATEMENT_FORM) {
270
+ v = new FunctionObject(n, x.scope);
271
+ if (n.functionForm == STATEMENT_FORM)
272
+ x.scope.object[n.name] = v;
273
+ } else {
274
+ t = new Object;
275
+ x.scope = {object: t, parent: x.scope};
276
+ try {
277
+ v = new FunctionObject(n, x.scope);
278
+ t[n.name] = v;
279
+ } finally {
280
+ x.scope = x.scope.parent;
281
+ }
282
+ }
283
+ }
284
+ break;
285
+
286
+ case SCRIPT:
287
+ t = x.scope.object;
288
+ a = n.funDecls;
289
+ for (i = 0, j = a.length; i < j; i++) {
290
+ s = a[i].name;
291
+ f = new FunctionObject(a[i], x.scope);
292
+ t[s] = f;
293
+ }
294
+ a = n.varDecls;
295
+ for (i = 0, j = a.length; i < j; i++) {
296
+ u = a[i];
297
+ s = u.name;
298
+ if (u.readOnly && hasDirectProperty(t, s)) {
299
+ throw new TypeError("Redeclaration of const " + s,
300
+ u.filename(), u.lineno);
301
+ }
302
+ if (u.readOnly || !hasDirectProperty(t, s)) {
303
+ t[s] = null;
304
+ }
305
+ }
306
+ // FALL THROUGH
307
+
308
+ case BLOCK:
309
+ for (i = 0, j = n.$length; i < j; i++) {
310
+ //jrh
311
+ //execute(n[i], x);
312
+ //new_block.unshift([n[i], x]);
313
+ new_block.push([n[i], x]);
314
+ }
315
+ new_block.reverse();
316
+ agenda = agenda.concat(new_block);
317
+ //agenda = new_block.concat(agenda)
318
+ // end jrh
319
+ break;
320
+
321
+ case IF:
322
+ if (getValue(execute(n.condition, x)))
323
+ execute(n.thenPart, x);
324
+ else if (n.elsePart)
325
+ execute(n.elsePart, x);
326
+ break;
327
+
328
+ case SWITCH:
329
+ s = getValue(execute(n.discriminant, x));
330
+ a = n.cases;
331
+ var matchDefault = false;
332
+ switch_loop:
333
+ for (i = 0, j = a.length; ; i++) {
334
+ if (i == j) {
335
+ if (n.defaultIndex >= 0) {
336
+ i = n.defaultIndex - 1; // no case matched, do default
337
+ matchDefault = true;
338
+ continue;
339
+ }
340
+ break; // no default, exit switch_loop
341
+ }
342
+ t = a[i]; // next case (might be default!)
343
+ if (t.type == CASE) {
344
+ u = getValue(execute(t.caseLabel, x));
345
+ } else {
346
+ if (!matchDefault) // not defaulting, skip for now
347
+ continue;
348
+ u = s; // force match to do default
349
+ }
350
+ if (u === s) {
351
+ for (;;) { // this loop exits switch_loop
352
+ if (t.statements.length) {
353
+ try {
354
+ execute(t.statements, x);
355
+ } catch (e) {
356
+ if (!(e == BREAK && x.target == n)) { throw e }
357
+ break switch_loop;
358
+ }
359
+ }
360
+ if (++i == j)
361
+ break switch_loop;
362
+ t = a[i];
363
+ }
364
+ // NOT REACHED
365
+ }
366
+ }
367
+ break;
368
+
369
+ case FOR:
370
+ // jrh
371
+ // added "skip_setup" so initialization doesn't get called
372
+ // on every call..
373
+ if (!skip_setup)
374
+ n.setup && getValue(execute(n.setup, x));
375
+ // FALL THROUGH
376
+ case WHILE:
377
+ // jrh
378
+ //while (!n.condition || getValue(execute(n.condition, x))) {
379
+ if (!n.condition || getValue(execute(n.condition, x))) {
380
+ try {
381
+ // jrh
382
+ //execute(n.body, x);
383
+ new_block.push([n.body, x]);
384
+ agenda.push([n.body, x])
385
+ //agenda.unshift([n.body, x])
386
+ // end jrh
387
+ } catch (e) {
388
+ if (e == BREAK && x.target == n) {
389
+ break;
390
+ } else if (e == CONTINUE && x.target == n) {
391
+ // jrh
392
+ // 'continue' is invalid inside an 'if' clause
393
+ // I don't know what commenting this out will break!
394
+ //continue;
395
+ // end jrh
396
+
397
+ } else {
398
+ throw e;
399
+ }
400
+ }
401
+ n.update && getValue(execute(n.update, x));
402
+ // jrh
403
+ new_block.unshift([n, x])
404
+ agenda.splice(agenda.length-1,0,[n, x])
405
+ //agenda.splice(1,0,[n, x])
406
+ skip_setup = 1
407
+ // end jrh
408
+ } else {
409
+ skip_setup = 0
410
+ }
411
+
412
+ break;
413
+
414
+ case FOR_IN:
415
+ u = n.varDecl;
416
+ if (u)
417
+ execute(u, x);
418
+ r = n.iterator;
419
+ s = execute(n.object, x);
420
+ v = getValue(s);
421
+
422
+ // ECMA deviation to track extant browser JS implementation behavior.
423
+ t = (v == null && !x.ecmaStrictMode) ? v : toObject(v, s, n.object);
424
+ a = [];
425
+ for (i in t)
426
+ a.push(i);
427
+ for (i = 0, j = a.length; i < j; i++) {
428
+ putValue(execute(r, x), a[i], r);
429
+ try {
430
+ execute(n.body, x);
431
+ } catch (e) {
432
+ if (e == BREAK && x.target == n) {
433
+ break;
434
+ } else if (e == CONTINUE && x.target == n) {
435
+ continue;
436
+ } else {
437
+ throw e;
438
+ }
439
+ }
440
+ }
441
+ break;
442
+
443
+ case DO:
444
+ do {
445
+ try {
446
+ execute(n.body, x);
447
+ } catch (e) {
448
+ if (e == BREAK && x.target == n) {
449
+ break;
450
+ } else if (e == CONTINUE && x.target == n) {
451
+ continue;
452
+ } else {
453
+ throw e;
454
+ }
455
+ }
456
+ } while (getValue(execute(n.condition, x)));
457
+ break;
458
+
459
+ case BREAK:
460
+ case CONTINUE:
461
+ x.target = n.target;
462
+ throw n.type;
463
+
464
+ case TRY:
465
+ try {
466
+ execute(n.tryBlock, x);
467
+ } catch (e) {
468
+ if (!(e == THROW && (j = n.catchClauses.length))) {
469
+ throw e;
470
+ }
471
+ e = x.result;
472
+ x.result = undefined;
473
+ for (i = 0; ; i++) {
474
+ if (i == j) {
475
+ x.result = e;
476
+ throw THROW;
477
+ }
478
+ t = n.catchClauses[i];
479
+ x.scope = {object: {}, parent: x.scope};
480
+ x.scope.object[t.varName] = e;
481
+ try {
482
+ if (t.guard && !getValue(execute(t.guard, x)))
483
+ continue;
484
+ execute(t.block, x);
485
+ break;
486
+ } finally {
487
+ x.scope = x.scope.parent;
488
+ }
489
+ }
490
+ } finally {
491
+ if (n.finallyBlock)
492
+ execute(n.finallyBlock, x);
493
+ }
494
+ break;
495
+
496
+ case THROW:
497
+ x.result = getValue(execute(n.exception, x));
498
+ throw THROW;
499
+
500
+ case RETURN:
501
+ x.result = getValue(execute(n.value, x));
502
+ throw RETURN;
503
+
504
+ case WITH:
505
+ r = execute(n.object, x);
506
+ t = toObject(getValue(r), r, n.object);
507
+ x.scope = {object: t, parent: x.scope};
508
+ try {
509
+ execute(n.body, x);
510
+ } finally {
511
+ x.scope = x.scope.parent;
512
+ }
513
+ break;
514
+
515
+ case VAR:
516
+ case CONST:
517
+ for (i = 0, j = n.$length; i < j; i++) {
518
+ u = n[i].initializer;
519
+ if (!u)
520
+ continue;
521
+ t = n[i].name;
522
+ for (s = x.scope; s; s = s.parent) {
523
+ if (hasDirectProperty(s.object, t))
524
+ break;
525
+ }
526
+ u = getValue(execute(u, x));
527
+ if (n.type == CONST)
528
+ s.object[t] = u;
529
+ else
530
+ s.object[t] = u;
531
+ }
532
+ break;
533
+
534
+ case DEBUGGER:
535
+ throw "NYI: " + tokens[n.type];
536
+
537
+ case REQUIRE:
538
+ var req = new XMLHttpRequest();
539
+ req.open('GET', n.filename, 'false');
540
+
541
+ case SEMICOLON:
542
+ if (n.expression)
543
+ // print debugging statements
544
+
545
+ var the_start = n.start
546
+ var the_end = n.end
547
+ var the_statement = parse_result.tokenizer.source.slice(the_start,the_end)
548
+ //global.debug.document.body.innerHTML += ('<pre>&gt;&gt;&gt; <b>' + the_statement + '</b></pre>')
549
+ LOG.info('>>>' + the_statement)
550
+ x.result = getValue(execute(n.expression, x));
551
+ //if (x.result)
552
+ //global.debug.document.body.innerHTML += ( '<pre>&gt;&gt;&gt; ' + x.result + '</pre>')
553
+
554
+ break;
555
+
556
+ case LABEL:
557
+ try {
558
+ execute(n.statement, x);
559
+ } catch (e) {
560
+ if (!(e == BREAK && x.target == n)) { throw e }
561
+ }
562
+ break;
563
+
564
+ case COMMA:
565
+ for (i = 0, j = n.$length; i < j; i++)
566
+ v = getValue(execute(n[i], x));
567
+ break;
568
+
569
+ case ASSIGN:
570
+ r = execute(n[0], x);
571
+ t = n[0].assignOp;
572
+ if (t)
573
+ u = getValue(r);
574
+ v = getValue(execute(n[1], x));
575
+ if (t) {
576
+ switch (t) {
577
+ case BITWISE_OR: v = u | v; break;
578
+ case BITWISE_XOR: v = u ^ v; break;
579
+ case BITWISE_AND: v = u & v; break;
580
+ case LSH: v = u << v; break;
581
+ case RSH: v = u >> v; break;
582
+ case URSH: v = u >>> v; break;
583
+ case PLUS: v = u + v; break;
584
+ case MINUS: v = u - v; break;
585
+ case MUL: v = u * v; break;
586
+ case DIV: v = u / v; break;
587
+ case MOD: v = u % v; break;
588
+ }
589
+ }
590
+ putValue(r, v, n[0]);
591
+ break;
592
+
593
+ case CONDITIONAL:
594
+ v = getValue(execute(n[0], x)) ? getValue(execute(n[1], x))
595
+ : getValue(execute(n[2], x));
596
+ break;
597
+
598
+ case OR:
599
+ v = getValue(execute(n[0], x)) || getValue(execute(n[1], x));
600
+ break;
601
+
602
+ case AND:
603
+ v = getValue(execute(n[0], x)) && getValue(execute(n[1], x));
604
+ break;
605
+
606
+ case BITWISE_OR:
607
+ v = getValue(execute(n[0], x)) | getValue(execute(n[1], x));
608
+ break;
609
+
610
+ case BITWISE_XOR:
611
+ v = getValue(execute(n[0], x)) ^ getValue(execute(n[1], x));
612
+ break;
613
+
614
+ case BITWISE_AND:
615
+ v = getValue(execute(n[0], x)) & getValue(execute(n[1], x));
616
+ break;
617
+
618
+ case EQ:
619
+ v = getValue(execute(n[0], x)) == getValue(execute(n[1], x));
620
+ break;
621
+
622
+ case NE:
623
+ v = getValue(execute(n[0], x)) != getValue(execute(n[1], x));
624
+ break;
625
+
626
+ case STRICT_EQ:
627
+ v = getValue(execute(n[0], x)) === getValue(execute(n[1], x));
628
+ break;
629
+
630
+ case STRICT_NE:
631
+ v = getValue(execute(n[0], x)) !== getValue(execute(n[1], x));
632
+ break;
633
+
634
+ case LT:
635
+ v = getValue(execute(n[0], x)) < getValue(execute(n[1], x));
636
+ break;
637
+
638
+ case LE:
639
+ v = getValue(execute(n[0], x)) <= getValue(execute(n[1], x));
640
+ break;
641
+
642
+ case GE:
643
+ v = getValue(execute(n[0], x)) >= getValue(execute(n[1], x));
644
+ break;
645
+
646
+ case GT:
647
+ v = getValue(execute(n[0], x)) > getValue(execute(n[1], x));
648
+ break;
649
+
650
+ case IN:
651
+ v = getValue(execute(n[0], x)) in getValue(execute(n[1], x));
652
+ break;
653
+
654
+ case INSTANCEOF:
655
+ t = getValue(execute(n[0], x));
656
+ u = getValue(execute(n[1], x));
657
+ if (isObject(u) && typeof u.__hasInstance__ == "function")
658
+ v = u.__hasInstance__(t);
659
+ else
660
+ v = t instanceof u;
661
+ break;
662
+
663
+ case LSH:
664
+ v = getValue(execute(n[0], x)) << getValue(execute(n[1], x));
665
+ break;
666
+
667
+ case RSH:
668
+ v = getValue(execute(n[0], x)) >> getValue(execute(n[1], x));
669
+ break;
670
+
671
+ case URSH:
672
+ v = getValue(execute(n[0], x)) >>> getValue(execute(n[1], x));
673
+ break;
674
+
675
+ case PLUS:
676
+ v = getValue(execute(n[0], x)) + getValue(execute(n[1], x));
677
+ break;
678
+
679
+ case MINUS:
680
+ v = getValue(execute(n[0], x)) - getValue(execute(n[1], x));
681
+ break;
682
+
683
+ case MUL:
684
+ v = getValue(execute(n[0], x)) * getValue(execute(n[1], x));
685
+ break;
686
+
687
+ case DIV:
688
+ v = getValue(execute(n[0], x)) / getValue(execute(n[1], x));
689
+ break;
690
+
691
+ case MOD:
692
+ v = getValue(execute(n[0], x)) % getValue(execute(n[1], x));
693
+ break;
694
+
695
+ case DELETE:
696
+ t = execute(n[0], x);
697
+ v = !(t instanceof Reference) || delete t.base[t.propertyName];
698
+ break;
699
+
700
+ case VOID:
701
+ getValue(execute(n[0], x));
702
+ break;
703
+
704
+ case TYPEOF:
705
+ t = execute(n[0], x);
706
+ if (t instanceof Reference)
707
+ t = t.base ? t.base[t.propertyName] : undefined;
708
+ v = typeof t;
709
+ break;
710
+
711
+ case NOT:
712
+ v = !getValue(execute(n[0], x));
713
+ break;
714
+
715
+ case BITWISE_NOT:
716
+ v = ~getValue(execute(n[0], x));
717
+ break;
718
+
719
+ case UNARY_PLUS:
720
+ v = +getValue(execute(n[0], x));
721
+ break;
722
+
723
+ case UNARY_MINUS:
724
+ v = -getValue(execute(n[0], x));
725
+ break;
726
+
727
+ case INCREMENT:
728
+ case DECREMENT:
729
+ t = execute(n[0], x);
730
+ u = Number(getValue(t));
731
+ if (n.postfix)
732
+ v = u;
733
+ putValue(t, (n.type == INCREMENT) ? ++u : --u, n[0]);
734
+ if (!n.postfix)
735
+ v = u;
736
+ break;
737
+
738
+ case DOT:
739
+ r = execute(n[0], x);
740
+ t = getValue(r);
741
+ u = n[1].value;
742
+ v = new Reference(toObject(t, r, n[0]), u, n);
743
+ break;
744
+
745
+ case INDEX:
746
+ r = execute(n[0], x);
747
+ t = getValue(r);
748
+ u = getValue(execute(n[1], x));
749
+ v = new Reference(toObject(t, r, n[0]), String(u), n);
750
+ break;
751
+
752
+ case LIST:
753
+ // Curse ECMA for specifying that arguments is not an Array object!
754
+ v = {};
755
+ for (i = 0, j = n.$length; i < j; i++) {
756
+ u = getValue(execute(n[i], x));
757
+ v[i] = u;
758
+ }
759
+ v.length = i;
760
+ break;
761
+
762
+ case CALL:
763
+ r = execute(n[0], x);
764
+ a = execute(n[1], x);
765
+ f = getValue(r);
766
+ if (isPrimitive(f) || typeof f.__call__ != "function") {
767
+ throw new TypeError(r + " is not callable",
768
+ n[0].filename(), n[0].lineno);
769
+ }
770
+ t = (r instanceof Reference) ? r.base : null;
771
+ if (t instanceof Activation)
772
+ t = null;
773
+ v = f.__call__(t, a, x);
774
+ break;
775
+
776
+ case NEW:
777
+ case NEW_WITH_ARGS:
778
+ r = execute(n[0], x);
779
+ f = getValue(r);
780
+ if (n.type == NEW) {
781
+ a = {};
782
+ a.length = 0;
783
+ } else {
784
+ a = execute(n[1], x);
785
+ }
786
+ if (isPrimitive(f) || typeof f.__construct__ != "function") {
787
+ throw new TypeError(r + " is not a constructor",
788
+ n[0].filename(), n[0].lineno);
789
+ }
790
+ v = f.__construct__(a, x);
791
+ break;
792
+
793
+ case ARRAY_INIT:
794
+ v = [];
795
+ for (i = 0, j = n.$length; i < j; i++) {
796
+ if (n[i])
797
+ v[i] = getValue(execute(n[i], x));
798
+ }
799
+ v.length = j;
800
+ break;
801
+
802
+ case OBJECT_INIT:
803
+ v = {};
804
+ for (i = 0, j = n.$length; i < j; i++) {
805
+ t = n[i];
806
+ if (t.type == PROPERTY_INIT) {
807
+ v[t[0].value] = getValue(execute(t[1], x));
808
+ } else {
809
+ f = new FunctionObject(t, x.scope);
810
+ /*
811
+ u = (t.type == GETTER) ? '__defineGetter__'
812
+ : '__defineSetter__';
813
+ v[u](t.name, thunk(f, x));
814
+ */
815
+ }
816
+ }
817
+ break;
818
+
819
+ case NULL:
820
+ v = null;
821
+ break;
822
+
823
+ case THIS:
824
+ v = x.thisObject;
825
+ break;
826
+
827
+ case TRUE:
828
+ v = true;
829
+ break;
830
+
831
+ case FALSE:
832
+ v = false;
833
+ break;
834
+
835
+ case IDENTIFIER:
836
+ for (s = x.scope; s; s = s.parent) {
837
+ if (n.value in s.object)
838
+ break;
839
+ }
840
+ v = new Reference(s && s.object, n.value, n);
841
+ break;
842
+
843
+ case NUMBER:
844
+ case STRING:
845
+ case REGEXP:
846
+ v = n.value;
847
+ break;
848
+
849
+ case GROUP:
850
+ v = execute(n[0], x);
851
+ break;
852
+
853
+ default:
854
+ throw "PANIC: unknown operation " + n.type + ": " + uneval(n);
855
+ }
856
+ return v;
857
+ }
858
+
859
+ function Activation(f, a) {
860
+ for (var i = 0, j = f.params.length; i < j; i++)
861
+ this[f.params[i]] = a[i];
862
+ this.arguments = a;
863
+ }
864
+
865
+ // Null Activation.prototype's proto slot so that Object.prototype.* does not
866
+ // pollute the scope of heavyweight functions. Also delete its 'constructor'
867
+ // property so that it doesn't pollute function scopes.
868
+
869
+ Activation.prototype.__proto__ = null;
870
+ delete Activation.prototype.constructor;
871
+
872
+ function FunctionObject(node, scope) {
873
+ this.node = node;
874
+ this.scope = scope;
875
+ this.length = node.params.length;
876
+ var proto = {};
877
+ this.prototype = proto;
878
+ proto.constructor = this;
879
+ }
880
+
881
+ var FOp = FunctionObject.prototype = {
882
+ // Internal methods.
883
+ __call__: function (t, a, x) {
884
+ var x2 = new ExecutionContext(FUNCTION_CODE);
885
+ x2.thisObject = t || global;
886
+ x2.caller = x;
887
+ x2.callee = this;
888
+ a.callee = this;
889
+ var f = this.node;
890
+ x2.scope = {object: new Activation(f, a), parent: this.scope};
891
+
892
+ ExecutionContext.current = x2;
893
+ try {
894
+ execute(f.body, x2);
895
+ } catch (e) {
896
+ if (!(e == RETURN)) { throw e } else if (e == RETURN) {
897
+ return x2.result;
898
+ }
899
+ if (e != THROW) { throw e }
900
+ x.result = x2.result;
901
+ throw THROW;
902
+ } finally {
903
+ ExecutionContext.current = x;
904
+ }
905
+ return undefined;
906
+ },
907
+
908
+ __construct__: function (a, x) {
909
+ var o = new Object;
910
+ var p = this.prototype;
911
+ if (isObject(p))
912
+ o.__proto__ = p;
913
+ // else o.__proto__ defaulted to Object.prototype
914
+
915
+ var v = this.__call__(o, a, x);
916
+ if (isObject(v))
917
+ return v;
918
+ return o;
919
+ },
920
+
921
+ __hasInstance__: function (v) {
922
+ if (isPrimitive(v))
923
+ return false;
924
+ var p = this.prototype;
925
+ if (isPrimitive(p)) {
926
+ throw new TypeError("'prototype' property is not an object",
927
+ this.node.filename(), this.node.lineno);
928
+ }
929
+ var o;
930
+ while ((o = v.__proto__)) {
931
+ if (o == p)
932
+ return true;
933
+ v = o;
934
+ }
935
+ return false;
936
+ },
937
+
938
+ // Standard methods.
939
+ toString: function () {
940
+ return this.node.getSource();
941
+ },
942
+
943
+ apply: function (t, a) {
944
+ // Curse ECMA again!
945
+ if (typeof this.__call__ != "function") {
946
+ throw new TypeError("Function.prototype.apply called on" +
947
+ " uncallable object");
948
+ }
949
+
950
+ if (t === undefined || t === null)
951
+ t = global;
952
+ else if (typeof t != "object")
953
+ t = toObject(t, t);
954
+
955
+ if (a === undefined || a === null) {
956
+ a = {};
957
+ a.length = 0;
958
+ } else if (a instanceof Array) {
959
+ var v = {};
960
+ for (var i = 0, j = a.length; i < j; i++)
961
+ v[i] = a[i];
962
+ v.length = i;
963
+ a = v;
964
+ } else if (!(a instanceof Object)) {
965
+ // XXX check for a non-arguments object
966
+ throw new TypeError("Second argument to Function.prototype.apply" +
967
+ " must be an array or arguments object",
968
+ this.node.filename(), this.node.lineno);
969
+ }
970
+
971
+ return this.__call__(t, a, ExecutionContext.current);
972
+ },
973
+
974
+ call: function (t) {
975
+ // Curse ECMA a third time!
976
+ var a = Array.prototype.splice.call(arguments, 1);
977
+ return this.apply(t, a);
978
+ }
979
+ };
980
+
981
+ // Connect Function.prototype and Function.prototype.constructor in global.
982
+ reflectClass('Function', FOp);
983
+
984
+ // Help native and host-scripted functions be like FunctionObjects.
985
+ var Fp = Function.prototype;
986
+ var REp = RegExp.prototype;
987
+
988
+ if (!('__call__' in Fp)) {
989
+ Fp.__call__ = function (t, a, x) {
990
+ // Curse ECMA yet again!
991
+ a = Array.prototype.splice.call(a, 0, a.length);
992
+ return this.apply(t, a);
993
+ };
994
+
995
+ REp.__call__ = function (t, a, x) {
996
+ a = Array.prototype.splice.call(a, 0, a.length);
997
+ return this.exec.apply(this, a);
998
+ };
999
+
1000
+ Fp.__construct__ = function (a, x) {
1001
+ switch (a.length) {
1002
+ case 0:
1003
+ return new this();
1004
+ case 1:
1005
+ return new this(a[0]);
1006
+ case 2:
1007
+ return new this(a[0], a[1]);
1008
+ case 3:
1009
+ return new this(a[0], a[1], a[2]);
1010
+ case 4:
1011
+ return new this(a[0], a[1], a[2], a[3]);
1012
+ case 5:
1013
+ return new this(a[0], a[1], a[2], a[3], a[4]);
1014
+ case 6:
1015
+ return new this(a[0], a[1], a[2], a[3], a[4], a[5]);
1016
+ case 7:
1017
+ return new this(a[0], a[1], a[2], a[3], a[4], a[5], a[6]);
1018
+ }
1019
+ throw "PANIC: too many arguments to constructor";
1020
+ }
1021
+
1022
+ // Since we use native functions such as Date along with host ones such
1023
+ // as global.eval, we want both to be considered instances of the native
1024
+ // Function constructor.
1025
+ Fp.__hasInstance__ = function (v) {
1026
+ return v instanceof Function || v instanceof global.Function;
1027
+ };
1028
+ }
1029
+
1030
+ function thunk(f, x) {
1031
+ return function () { return f.__call__(this, arguments, x); };
1032
+ }
1033
+
1034
+ function evaluate(s, f, l) {
1035
+ if (typeof s != "string")
1036
+ return s;
1037
+
1038
+ var x = ExecutionContext.current;
1039
+ var x2 = new ExecutionContext(GLOBAL_CODE);
1040
+ ExecutionContext.current = x2;
1041
+ try {
1042
+ execute(parse(s, f, l), x2);
1043
+ } catch (e) {
1044
+ if (e != THROW) { throw e }
1045
+ if (x) {
1046
+ x.result = x2.result;
1047
+ throw(THROW);
1048
+ }
1049
+ throw x2.result;
1050
+ } finally {
1051
+ ExecutionContext.current = x;
1052
+ }
1053
+ return x2.result;
1054
+ }