blob: 5ddd04416d7de384248743fee88a3abe033236ae [file] [log] [blame]
Steve Blockd0582a62009-12-15 09:54:21 +00001// Copyright 2006-2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "token.h"
33#include "scanner.h"
Iain Merrick9ac36c92010-09-13 15:29:50 +010034#include "parser.h"
Steve Blockd0582a62009-12-15 09:54:21 +000035#include "utils.h"
Iain Merrick9ac36c92010-09-13 15:29:50 +010036#include "execution.h"
Steve Blockd0582a62009-12-15 09:54:21 +000037
38#include "cctest.h"
39
40namespace i = ::v8::internal;
41
42TEST(KeywordMatcher) {
43 struct KeywordToken {
44 const char* keyword;
45 i::Token::Value token;
46 };
47
48 static const KeywordToken keywords[] = {
49#define KEYWORD(t, s, d) { s, i::Token::t },
50#define IGNORE(t, s, d) /* */
51 TOKEN_LIST(IGNORE, KEYWORD, IGNORE)
52#undef KEYWORD
53 { NULL, i::Token::IDENTIFIER }
54 };
55
56 static const char* future_keywords[] = {
57#define FUTURE(t, s, d) s,
58 TOKEN_LIST(IGNORE, IGNORE, FUTURE)
59#undef FUTURE
60#undef IGNORE
61 NULL
62 };
63
64 KeywordToken key_token;
65 for (int i = 0; (key_token = keywords[i]).keyword != NULL; i++) {
66 i::KeywordMatcher matcher;
67 const char* keyword = key_token.keyword;
68 int length = i::StrLength(keyword);
69 for (int j = 0; j < length; j++) {
70 if (key_token.token == i::Token::INSTANCEOF && j == 2) {
71 // "in" is a prefix of "instanceof". It's the only keyword
72 // that is a prefix of another.
73 CHECK_EQ(i::Token::IN, matcher.token());
74 } else {
75 CHECK_EQ(i::Token::IDENTIFIER, matcher.token());
76 }
77 matcher.AddChar(keyword[j]);
78 }
79 CHECK_EQ(key_token.token, matcher.token());
80 // Adding more characters will make keyword matching fail.
81 matcher.AddChar('z');
82 CHECK_EQ(i::Token::IDENTIFIER, matcher.token());
83 // Adding a keyword later will not make it match again.
84 matcher.AddChar('i');
85 matcher.AddChar('f');
86 CHECK_EQ(i::Token::IDENTIFIER, matcher.token());
87 }
88
89 // Future keywords are not recognized.
90 const char* future_keyword;
91 for (int i = 0; (future_keyword = future_keywords[i]) != NULL; i++) {
92 i::KeywordMatcher matcher;
93 int length = i::StrLength(future_keyword);
94 for (int j = 0; j < length; j++) {
95 matcher.AddChar(future_keyword[j]);
96 }
97 CHECK_EQ(i::Token::IDENTIFIER, matcher.token());
98 }
99
100 // Zero isn't ignored at first.
101 i::KeywordMatcher bad_start;
102 bad_start.AddChar(0);
103 CHECK_EQ(i::Token::IDENTIFIER, bad_start.token());
104 bad_start.AddChar('i');
105 bad_start.AddChar('f');
106 CHECK_EQ(i::Token::IDENTIFIER, bad_start.token());
107
108 // Zero isn't ignored at end.
109 i::KeywordMatcher bad_end;
110 bad_end.AddChar('i');
111 bad_end.AddChar('f');
112 CHECK_EQ(i::Token::IF, bad_end.token());
113 bad_end.AddChar(0);
114 CHECK_EQ(i::Token::IDENTIFIER, bad_end.token());
115
116 // Case isn't ignored.
117 i::KeywordMatcher bad_case;
118 bad_case.AddChar('i');
119 bad_case.AddChar('F');
120 CHECK_EQ(i::Token::IDENTIFIER, bad_case.token());
121
122 // If we mark it as failure, continuing won't help.
123 i::KeywordMatcher full_stop;
124 full_stop.AddChar('i');
125 CHECK_EQ(i::Token::IDENTIFIER, full_stop.token());
126 full_stop.Fail();
127 CHECK_EQ(i::Token::IDENTIFIER, full_stop.token());
128 full_stop.AddChar('f');
129 CHECK_EQ(i::Token::IDENTIFIER, full_stop.token());
130}
131
Iain Merrick9ac36c92010-09-13 15:29:50 +0100132
133TEST(ScanHTMLEndComments) {
134 // Regression test. See:
135 // http://code.google.com/p/chromium/issues/detail?id=53548
136 // Tests that --> is correctly interpreted as comment-to-end-of-line if there
137 // is only whitespace before it on the line, even after a multiline-comment
138 // comment. This was not the case if it occurred before the first real token
139 // in the input.
140 const char* tests[] = {
141 // Before first real token.
142 "--> is eol-comment\nvar y = 37;\n",
143 "\n --> is eol-comment\nvar y = 37;\n",
144 "/* precomment */ --> is eol-comment\nvar y = 37;\n",
145 "\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
146 // After first real token.
147 "var x = 42;\n--> is eol-comment\nvar y = 37;\n",
148 "var x = 42;\n/* precomment */ --> is eol-comment\nvar y = 37;\n",
149 NULL
150 };
151
152 // Parser/Scanner needs a stack limit.
153 int marker;
154 i::StackGuard::SetStackLimit(
155 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
156
157 for (int i = 0; tests[i]; i++) {
158 v8::ScriptData* data =
159 v8::ScriptData::PreCompile(tests[i], strlen(tests[i]));
160 CHECK(data != NULL && !data->HasError());
161 delete data;
162 }
163}
164
165
166class ScriptResource : public v8::String::ExternalAsciiStringResource {
167 public:
168 ScriptResource(const char* data, size_t length)
169 : data_(data), length_(length) { }
170
171 const char* data() const { return data_; }
172 size_t length() const { return length_; }
173
174 private:
175 const char* data_;
176 size_t length_;
177};
178
179
180TEST(Preparsing) {
181 v8::HandleScope handles;
182 v8::Persistent<v8::Context> context = v8::Context::New();
183 v8::Context::Scope context_scope(context);
184 int marker;
185 i::StackGuard::SetStackLimit(
186 reinterpret_cast<uintptr_t>(&marker) - 128 * 1024);
187
188 // Source containing functions that might be lazily compiled and all types
189 // of symbols (string, propertyName, regexp).
190 const char* source =
191 "var x = 42;"
192 "function foo(a) { return function nolazy(b) { return a + b; } }"
193 "function bar(a) { if (a) return function lazy(b) { return b; } }"
194 "var z = {'string': 'string literal', bareword: 'propertyName', "
195 " 42: 'number literal', for: 'keyword as propertyName', "
196 " f\\u006fr: 'keyword propertyname with escape'};"
197 "var v = /RegExp Literal/;"
198 "var w = /RegExp Literal\\u0020With Escape/gin;"
199 "var y = { get getter() { return 42; }, "
200 " set setter(v) { this.value = v; }};";
201 int source_length = strlen(source);
202 const char* error_source = "var x = y z;";
203 int error_source_length = strlen(error_source);
204
205 v8::ScriptData* preparse =
206 v8::ScriptData::PreCompile(source, source_length);
207 CHECK(!preparse->HasError());
208 bool lazy_flag = i::FLAG_lazy;
209 {
210 i::FLAG_lazy = true;
211 ScriptResource* resource = new ScriptResource(source, source_length);
212 v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
213 v8::Script::Compile(script_source, NULL, preparse);
214 }
215
216 {
217 i::FLAG_lazy = false;
218
219 ScriptResource* resource = new ScriptResource(source, source_length);
220 v8::Local<v8::String> script_source = v8::String::NewExternal(resource);
221 v8::Script::New(script_source, NULL, preparse, v8::Local<v8::String>());
222 }
223 delete preparse;
224 i::FLAG_lazy = lazy_flag;
225
226 // Syntax error.
227 v8::ScriptData* error_preparse =
228 v8::ScriptData::PreCompile(error_source, error_source_length);
229 CHECK(error_preparse->HasError());
230 i::ScriptDataImpl *pre_impl =
231 reinterpret_cast<i::ScriptDataImpl*>(error_preparse);
232 i::Scanner::Location error_location =
233 pre_impl->MessageLocation();
234 // Error is at "z" in source, location 10..11.
235 CHECK_EQ(10, error_location.beg_pos);
236 CHECK_EQ(11, error_location.end_pos);
237 // Should not crash.
238 const char* message = pre_impl->BuildMessage();
239 i::Vector<const char*> args = pre_impl->BuildArgs();
240 CHECK_GT(strlen(message), 0);
241}