1 | // Copyright 2015 the V8 project authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style license that can be |
3 | // found in the LICENSE file. |
4 | |
5 | #include "src/pending-compilation-error-handler.h" |
6 | |
7 | #include "src/ast/ast-value-factory.h" |
8 | #include "src/debug/debug.h" |
9 | #include "src/handles.h" |
10 | #include "src/isolate.h" |
11 | #include "src/messages.h" |
12 | #include "src/objects-inl.h" |
13 | |
14 | namespace v8 { |
15 | namespace internal { |
16 | |
17 | Handle<String> PendingCompilationErrorHandler::MessageDetails::ArgumentString( |
18 | Isolate* isolate) const { |
19 | if (arg_ != nullptr) return arg_->string(); |
20 | if (char_arg_ != nullptr) { |
21 | return isolate->factory() |
22 | ->NewStringFromUtf8(CStrVector(char_arg_)) |
23 | .ToHandleChecked(); |
24 | } |
25 | return isolate->factory()->undefined_string(); |
26 | } |
27 | |
28 | MessageLocation PendingCompilationErrorHandler::MessageDetails::GetLocation( |
29 | Handle<Script> script) const { |
30 | return MessageLocation(script, start_position_, end_position_); |
31 | } |
32 | |
33 | void PendingCompilationErrorHandler::ReportMessageAt( |
34 | int start_position, int end_position, MessageTemplate message, |
35 | const char* arg, ParseErrorType error_type) { |
36 | if (has_pending_error_) return; |
37 | has_pending_error_ = true; |
38 | |
39 | error_details_ = |
40 | MessageDetails(start_position, end_position, message, nullptr, arg); |
41 | error_type_ = error_type; |
42 | } |
43 | |
44 | void PendingCompilationErrorHandler::ReportMessageAt( |
45 | int start_position, int end_position, MessageTemplate message, |
46 | const AstRawString* arg, ParseErrorType error_type) { |
47 | if (has_pending_error_) return; |
48 | has_pending_error_ = true; |
49 | |
50 | error_details_ = |
51 | MessageDetails(start_position, end_position, message, arg, nullptr); |
52 | error_type_ = error_type; |
53 | } |
54 | |
55 | void PendingCompilationErrorHandler::ReportWarningAt(int start_position, |
56 | int end_position, |
57 | MessageTemplate message, |
58 | const char* arg) { |
59 | warning_messages_.emplace_front( |
60 | MessageDetails(start_position, end_position, message, nullptr, arg)); |
61 | } |
62 | |
63 | void PendingCompilationErrorHandler::ReportWarnings(Isolate* isolate, |
64 | Handle<Script> script) { |
65 | DCHECK(!has_pending_error()); |
66 | |
67 | for (const MessageDetails& warning : warning_messages_) { |
68 | MessageLocation location = warning.GetLocation(script); |
69 | Handle<String> argument = warning.ArgumentString(isolate); |
70 | Handle<JSMessageObject> message = |
71 | MessageHandler::MakeMessageObject(isolate, warning.message(), &location, |
72 | argument, Handle<FixedArray>::null()); |
73 | message->set_error_level(v8::Isolate::kMessageWarning); |
74 | MessageHandler::ReportMessage(isolate, &location, message); |
75 | } |
76 | } |
77 | |
78 | void PendingCompilationErrorHandler::ReportErrors( |
79 | Isolate* isolate, Handle<Script> script, |
80 | AstValueFactory* ast_value_factory) { |
81 | if (stack_overflow()) { |
82 | isolate->StackOverflow(); |
83 | } else { |
84 | DCHECK(has_pending_error()); |
85 | // Internalize ast values for throwing the pending error. |
86 | ast_value_factory->Internalize(isolate); |
87 | ThrowPendingError(isolate, script); |
88 | } |
89 | } |
90 | |
91 | void PendingCompilationErrorHandler::ThrowPendingError(Isolate* isolate, |
92 | Handle<Script> script) { |
93 | if (!has_pending_error_) return; |
94 | |
95 | MessageLocation location = error_details_.GetLocation(script); |
96 | Handle<String> argument = error_details_.ArgumentString(isolate); |
97 | isolate->debug()->OnCompileError(script); |
98 | |
99 | Factory* factory = isolate->factory(); |
100 | Handle<Object> error; |
101 | switch (error_type_) { |
102 | case kReferenceError: |
103 | error = factory->NewReferenceError(error_details_.message(), argument); |
104 | break; |
105 | case kSyntaxError: |
106 | error = factory->NewSyntaxError(error_details_.message(), argument); |
107 | break; |
108 | default: |
109 | UNREACHABLE(); |
110 | break; |
111 | } |
112 | |
113 | if (!error->IsJSObject()) { |
114 | isolate->Throw(*error, &location); |
115 | return; |
116 | } |
117 | |
118 | Handle<JSObject> jserror = Handle<JSObject>::cast(error); |
119 | |
120 | Handle<Name> key_start_pos = factory->error_start_pos_symbol(); |
121 | Object::SetProperty(isolate, jserror, key_start_pos, |
122 | handle(Smi::FromInt(location.start_pos()), isolate), |
123 | StoreOrigin::kMaybeKeyed, |
124 | Just(ShouldThrow::kThrowOnError)) |
125 | .Check(); |
126 | |
127 | Handle<Name> key_end_pos = factory->error_end_pos_symbol(); |
128 | Object::SetProperty(isolate, jserror, key_end_pos, |
129 | handle(Smi::FromInt(location.end_pos()), isolate), |
130 | StoreOrigin::kMaybeKeyed, |
131 | Just(ShouldThrow::kThrowOnError)) |
132 | .Check(); |
133 | |
134 | Handle<Name> key_script = factory->error_script_symbol(); |
135 | Object::SetProperty(isolate, jserror, key_script, script, |
136 | StoreOrigin::kMaybeKeyed, |
137 | Just(ShouldThrow::kThrowOnError)) |
138 | .Check(); |
139 | |
140 | isolate->Throw(*error, &location); |
141 | } |
142 | |
143 | Handle<String> PendingCompilationErrorHandler::FormatErrorMessageForTest( |
144 | Isolate* isolate) const { |
145 | return MessageFormatter::Format(isolate, error_details_.message(), |
146 | error_details_.ArgumentString(isolate)); |
147 | } |
148 | |
149 | } // namespace internal |
150 | } // namespace v8 |
151 | |