blob: 1e9691724f11931c94601d221c1b42c153ca76d4 [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "vm/parser.h"
#include "lib/invocation_mirror.h"
#include "vm/bigint_operations.h"
#include "vm/bootstrap.h"
#include "vm/class_finalizer.h"
#include "vm/compiler.h"
#include "vm/compiler_stats.h"
#include "vm/dart_api_impl.h"
#include "vm/dart_entry.h"
#include "vm/flags.h"
#include "vm/growable_array.h"
#include "vm/longjump.h"
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/resolver.h"
#include "vm/scopes.h"
#include "vm/stack_frame.h"
#include "vm/symbols.h"
namespace dart {
DEFINE_FLAG(bool, enable_asserts, false, "Enable assert statements.");
DEFINE_FLAG(bool, enable_type_checks, false, "Enable type checks.");
DEFINE_FLAG(bool, trace_parser, false, "Trace parser operations.");
DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors.");
DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings.");
DECLARE_FLAG(bool, error_on_malformed_type);
DECLARE_FLAG(bool, throw_on_javascript_int_overflow);
static void CheckedModeHandler(bool value) {
FLAG_enable_asserts = value;
FLAG_enable_type_checks = value;
}
// --enable-checked-mode and --checked both enable checked mode which is
// equivalent to setting --enable-asserts and --enable-type-checks.
DEFINE_FLAG_HANDLER(CheckedModeHandler,
enable_checked_mode,
"Enable checked mode.");
DEFINE_FLAG_HANDLER(CheckedModeHandler,
checked,
"Enable checked mode.");
#if defined(DEBUG)
class TraceParser : public ValueObject {
public:
TraceParser(intptr_t token_pos, const Script& script, const char* msg) {
if (FLAG_trace_parser) {
// Skips tracing of bootstrap libraries.
if (script.HasSource()) {
intptr_t line, column;
script.GetTokenLocation(token_pos, &line, &column);
PrintIndent();
OS::Print("%s (line %" Pd ", col %" Pd ", token %" Pd ")\n",
msg, line, column, token_pos);
}
indent_++;
}
}
~TraceParser() { indent_--; }
private:
void PrintIndent() {
for (int i = 0; i < indent_; i++) { OS::Print(". "); }
}
static int indent_;
};
int TraceParser::indent_ = 0;
#define TRACE_PARSER(s) \
TraceParser __p__(this->TokenPos(), this->script_, s)
#else // not DEBUG
#define TRACE_PARSER(s)
#endif // DEBUG
static RawTypeArguments* NewTypeArguments(const GrowableObjectArray& objs) {
const TypeArguments& a =
TypeArguments::Handle(TypeArguments::New(objs.Length()));
AbstractType& type = AbstractType::Handle();
for (int i = 0; i < objs.Length(); i++) {
type ^= objs.At(i);
a.SetTypeAt(i, type);
}
// Cannot canonicalize TypeArgument yet as its types may not have been
// finalized yet.
return a.raw();
}
static ThrowNode* GenerateRethrow(intptr_t token_pos, const Object& obj) {
const UnhandledException& excp = UnhandledException::Cast(obj);
Instance& exception = Instance::ZoneHandle(excp.exception());
if (exception.IsNew()) {
exception ^= Object::Clone(exception, Heap::kOld);
}
Instance& stack_trace = Instance::ZoneHandle(excp.stacktrace());
if (stack_trace.IsNew()) {
stack_trace ^= Object::Clone(stack_trace, Heap::kOld);
}
return new ThrowNode(token_pos,
new LiteralNode(token_pos, exception),
new LiteralNode(token_pos, stack_trace));
}
LocalVariable* ParsedFunction::EnsureExpressionTemp() {
if (!has_expression_temp_var()) {
LocalVariable* temp =
new LocalVariable(function_.token_pos(),
Symbols::ExprTemp(),
Type::ZoneHandle(Type::DynamicType()));
ASSERT(temp != NULL);
set_expression_temp_var(temp);
}
ASSERT(has_expression_temp_var());
return expression_temp_var();
}
void ParsedFunction::SetNodeSequence(SequenceNode* node_sequence) {
ASSERT(node_sequence_ == NULL);
ASSERT(node_sequence != NULL);
node_sequence_ = node_sequence;
}
void ParsedFunction::AllocateVariables() {
LocalScope* scope = node_sequence()->scope();
const intptr_t num_fixed_params = function().num_fixed_parameters();
const intptr_t num_opt_params = function().NumOptionalParameters();
const intptr_t num_params = num_fixed_params + num_opt_params;
// Compute start indices to parameters and locals, and the number of
// parameters to copy.
if (num_opt_params == 0) {
// Parameter i will be at fp[kParamEndSlotFromFp + num_params - i] and
// local variable j will be at fp[kFirstLocalSlotFromFp - j].
first_parameter_index_ = kParamEndSlotFromFp + num_params;
first_stack_local_index_ = kFirstLocalSlotFromFp;
num_copied_params_ = 0;
} else {
// Parameter i will be at fp[kFirstLocalSlotFromFp - i] and local variable
// j will be at fp[kFirstLocalSlotFromFp - num_params - j].
first_parameter_index_ = kFirstLocalSlotFromFp;
first_stack_local_index_ = first_parameter_index_ - num_params;
num_copied_params_ = num_params;
}
// Allocate parameters and local variables, either in the local frame or
// in the context(s).
LocalScope* context_owner = NULL; // No context needed yet.
int next_free_frame_index =
scope->AllocateVariables(first_parameter_index_,
num_params,
first_stack_local_index_,
scope,
&context_owner);
// If this function allocates context variables, but none of its enclosing
// functions do, the context on entry is not linked as parent of the allocated
// context but saved on entry and restored on exit as to prevent memory leaks.
// Add and allocate a local variable to this purpose.
if (context_owner != NULL) {
const ContextScope& context_scope =
ContextScope::Handle(function().context_scope());
if (context_scope.IsNull() || (context_scope.num_variables() == 0)) {
LocalVariable* context_var =
new LocalVariable(function().token_pos(),
Symbols::SavedEntryContextVar(),
Type::ZoneHandle(Type::DynamicType()));
context_var->set_index(next_free_frame_index--);
scope->AddVariable(context_var);
set_saved_entry_context_var(context_var);
}
}
// Frame indices are relative to the frame pointer and are decreasing.
ASSERT(next_free_frame_index <= first_stack_local_index_);
num_stack_locals_ = first_stack_local_index_ - next_free_frame_index;
}
struct Parser::Block : public ZoneAllocated {
Block(Block* outer_block, LocalScope* local_scope, SequenceNode* seq)
: parent(outer_block), scope(local_scope), statements(seq) {
ASSERT(scope != NULL);
ASSERT(statements != NULL);
}
Block* parent; // Enclosing block, or NULL if outermost.
LocalScope* scope;
SequenceNode* statements;
};
// Class which describes an inlined finally block which is used to generate
// inlined code for the finally blocks when there is an exit from a try
// block using 'return', 'break' or 'continue'.
class Parser::TryBlocks : public ZoneAllocated {
public:
TryBlocks(Block* try_block, TryBlocks* outer_try_block, intptr_t try_index)
: try_block_(try_block),
inlined_finally_nodes_(),
outer_try_block_(outer_try_block),
try_index_(try_index) { }
TryBlocks* outer_try_block() const { return outer_try_block_; }
Block* try_block() const { return try_block_; }
intptr_t try_index() const { return try_index_; }
void AddNodeForFinallyInlining(AstNode* node);
AstNode* GetNodeToInlineFinally(int index) {
if (0 <= index && index < inlined_finally_nodes_.length()) {
return inlined_finally_nodes_[index];
}
return NULL;
}
private:
Block* try_block_;
GrowableArray<AstNode*> inlined_finally_nodes_;
TryBlocks* outer_try_block_;
const intptr_t try_index_;
DISALLOW_COPY_AND_ASSIGN(TryBlocks);
};
void Parser::TryBlocks::AddNodeForFinallyInlining(AstNode* node) {
inlined_finally_nodes_.Add(node);
}
// For parsing a compilation unit.
Parser::Parser(const Script& script, const Library& library, intptr_t token_pos)
: isolate_(Isolate::Current()),
script_(Script::Handle(isolate_, script.raw())),
tokens_iterator_(TokenStream::Handle(isolate_, script.tokens()),
token_pos),
token_kind_(Token::kILLEGAL),
current_block_(NULL),
is_top_level_(false),
current_member_(NULL),
allow_function_literals_(true),
parsed_function_(NULL),
innermost_function_(Function::Handle(isolate_)),
literal_token_(LiteralToken::Handle(isolate_)),
current_class_(Class::Handle(isolate_)),
library_(Library::Handle(isolate_, library.raw())),
try_blocks_list_(NULL),
last_used_try_index_(CatchClauseNode::kInvalidTryIndex),
unregister_pending_function_(false) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!library.IsNull());
}
// For parsing a function.
Parser::Parser(const Script& script,
ParsedFunction* parsed_function,
intptr_t token_position)
: isolate_(Isolate::Current()),
script_(Script::Handle(isolate_, script.raw())),
tokens_iterator_(TokenStream::Handle(isolate_, script.tokens()),
token_position),
token_kind_(Token::kILLEGAL),
current_block_(NULL),
is_top_level_(false),
current_member_(NULL),
allow_function_literals_(true),
parsed_function_(parsed_function),
innermost_function_(Function::Handle(isolate_,
parsed_function->function().raw())),
literal_token_(LiteralToken::Handle(isolate_)),
current_class_(Class::Handle(isolate_,
parsed_function->function().Owner())),
library_(Library::Handle(Class::Handle(
isolate_,
parsed_function->function().origin()).library())),
try_blocks_list_(NULL),
last_used_try_index_(CatchClauseNode::kInvalidTryIndex),
unregister_pending_function_(false) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!current_function().IsNull());
if (FLAG_enable_type_checks) {
EnsureExpressionTemp();
}
}
Parser::~Parser() {
if (unregister_pending_function_) {
const GrowableObjectArray& pending_functions =
GrowableObjectArray::Handle(
isolate()->object_store()->pending_functions());
ASSERT(pending_functions.Length() > 0);
ASSERT(pending_functions.At(pending_functions.Length()-1) ==
current_function().raw());
pending_functions.RemoveLast();
}
}
void Parser::SetScript(const Script & script, intptr_t token_pos) {
script_ = script.raw();
tokens_iterator_.SetStream(TokenStream::Handle(script.tokens()), token_pos);
token_kind_ = Token::kILLEGAL;
}
bool Parser::SetAllowFunctionLiterals(bool value) {
bool current_value = allow_function_literals_;
allow_function_literals_ = value;
return current_value;
}
const Function& Parser::current_function() const {
ASSERT(parsed_function() != NULL);
return parsed_function()->function();
}
const Function& Parser::innermost_function() const {
return innermost_function_;
}
const Class& Parser::current_class() const {
return current_class_;
}
void Parser::set_current_class(const Class& value) {
current_class_ = value.raw();
}
void Parser::SetPosition(intptr_t position) {
if (position < TokenPos() && position != 0) {
CompilerStats::num_tokens_rewind += (TokenPos() - position);
}
tokens_iterator_.SetCurrentPosition(position);
token_kind_ = Token::kILLEGAL;
}
void Parser::ParseCompilationUnit(const Library& library,
const Script& script) {
ASSERT(Isolate::Current()->long_jump_base()->IsSafeToJump());
TimerScope timer(FLAG_compiler_stats, &CompilerStats::parser_timer);
Parser parser(script, library, 0);
parser.ParseTopLevel();
}
Token::Kind Parser::CurrentToken() {
if (token_kind_ == Token::kILLEGAL) {
token_kind_ = tokens_iterator_.CurrentTokenKind();
if (token_kind_ == Token::kERROR) {
ErrorMsg(TokenPos(), "%s", CurrentLiteral()->ToCString());
}
}
CompilerStats::num_token_checks++;
return token_kind_;
}
Token::Kind Parser::LookaheadToken(int num_tokens) {
CompilerStats::num_tokens_lookahead++;
CompilerStats::num_token_checks++;
return tokens_iterator_.LookaheadTokenKind(num_tokens);
}
String* Parser::CurrentLiteral() const {
String& result = String::ZoneHandle();
result = tokens_iterator_.CurrentLiteral();
return &result;
}
RawDouble* Parser::CurrentDoubleLiteral() const {
literal_token_ ^= tokens_iterator_.CurrentToken();
ASSERT(literal_token_.kind() == Token::kDOUBLE);
return Double::RawCast(literal_token_.value());
}
RawInteger* Parser::CurrentIntegerLiteral() const {
literal_token_ ^= tokens_iterator_.CurrentToken();
ASSERT(literal_token_.kind() == Token::kINTEGER);
RawInteger* ri = Integer::RawCast(literal_token_.value());
if (FLAG_throw_on_javascript_int_overflow) {
const Integer& i = Integer::Handle(ri);
if (i.CheckJavascriptIntegerOverflow()) {
ErrorMsg(TokenPos(),
"Integer literal does not fit in a Javascript integer: %s.",
i.ToCString());
}
}
return ri;
}
// A QualIdent is an optionally qualified identifier.
struct QualIdent {
QualIdent() {
Clear();
}
void Clear() {
lib_prefix = NULL;
ident_pos = 0;
ident = NULL;
}
LibraryPrefix* lib_prefix;
intptr_t ident_pos;
String* ident;
};
struct ParamDesc {
ParamDesc()
: type(NULL),
name_pos(0),
name(NULL),
default_value(NULL),
is_final(false),
is_field_initializer(false) { }
const AbstractType* type;
intptr_t name_pos;
const String* name;
const Object* default_value; // NULL if not an optional parameter.
bool is_final;
bool is_field_initializer;
};
struct ParamList {
ParamList() {
Clear();
}
void Clear() {
num_fixed_parameters = 0;
num_optional_parameters = 0;
has_optional_positional_parameters = false;
has_optional_named_parameters = false;
has_field_initializer = false;
implicitly_final = false;
skipped = false;
this->parameters = new ZoneGrowableArray<ParamDesc>();
}
void AddFinalParameter(intptr_t name_pos,
const String* name,
const AbstractType* type) {
this->num_fixed_parameters++;
ParamDesc param;
param.name_pos = name_pos;
param.name = name;
param.is_final = true;
param.type = type;
this->parameters->Add(param);
}
void AddReceiver(const AbstractType* receiver_type, intptr_t token_pos) {
ASSERT(this->parameters->is_empty());
AddFinalParameter(token_pos, &Symbols::This(), receiver_type);
}
void SetImplicitlyFinal() {
implicitly_final = true;
}
int num_fixed_parameters;
int num_optional_parameters;
bool has_optional_positional_parameters;
bool has_optional_named_parameters;
bool has_field_initializer;
bool implicitly_final;
bool skipped;
ZoneGrowableArray<ParamDesc>* parameters;
};
struct MemberDesc {
MemberDesc() {
Clear();
}
void Clear() {
has_abstract = false;
has_external = false;
has_final = false;
has_const = false;
has_static = false;
has_var = false;
has_factory = false;
has_operator = false;
metadata_pos = -1;
operator_token = Token::kILLEGAL;
type = NULL;
name_pos = 0;
name = NULL;
redirect_name = NULL;
constructor_name = NULL;
params.Clear();
kind = RawFunction::kRegularFunction;
}
bool IsConstructor() const {
return (kind == RawFunction::kConstructor) && !has_static;
}
bool IsFactory() const {
return (kind == RawFunction::kConstructor) && has_static;
}
bool IsFactoryOrConstructor() const {
return (kind == RawFunction::kConstructor);
}
bool IsGetter() const {
return kind == RawFunction::kGetterFunction;
}
bool IsSetter() const {
return kind == RawFunction::kSetterFunction;
}
bool has_abstract;
bool has_external;
bool has_final;
bool has_const;
bool has_static;
bool has_var;
bool has_factory;
bool has_operator;
intptr_t metadata_pos;
Token::Kind operator_token;
const AbstractType* type;
intptr_t name_pos;
intptr_t decl_begin_pos;
String* name;
// For constructors: NULL or name of redirected to constructor.
String* redirect_name;
// For constructors: NULL for unnamed constructor,
// identifier after classname for named constructors.
String* constructor_name;
ParamList params;
RawFunction::Kind kind;
};
class ClassDesc : public ValueObject {
public:
ClassDesc(const Class& cls,
const String& cls_name,
bool is_interface,
intptr_t token_pos)
: clazz_(cls),
class_name_(cls_name),
token_pos_(token_pos),
functions_(GrowableObjectArray::Handle(GrowableObjectArray::New())),
fields_(GrowableObjectArray::Handle(GrowableObjectArray::New())) {
}
// Parameter 'name' is the unmangled name, i.e. without the setter
// name mangling.
bool FunctionNameExists(const String& name, RawFunction::Kind kind) const {
// First check if a function or field of same name exists.
if ((kind != RawFunction::kSetterFunction) && FunctionExists(name)) {
return true;
}
// Now check whether there is a field and whether its implicit getter
// or setter collides with the name.
Field* field = LookupField(name);
if (field != NULL) {
if (kind == RawFunction::kSetterFunction) {
// It's ok to have an implicit getter, it does not collide with
// this setter function.
if (!field->is_final()) {
return true;
}
} else {
// The implicit getter of the field collides with the name.
return true;
}
}
String& accessor_name = String::Handle();
if (kind == RawFunction::kSetterFunction) {
// Check if a setter function of same name exists.
accessor_name = Field::SetterName(name);
if (FunctionExists(accessor_name)) {
return true;
}
} else {
// Check if a getter function of same name exists.
accessor_name = Field::GetterName(name);
if (FunctionExists(accessor_name)) {
return true;
}
}
return false;
}
bool FieldNameExists(const String& name, bool check_setter) const {
// First check if a function or field of same name exists.
if (FunctionExists(name) || FieldExists(name)) {
return true;
}
// Now check if a getter/setter function of same name exists.
String& getter_name = String::Handle(Field::GetterName(name));
if (FunctionExists(getter_name)) {
return true;
}
if (check_setter) {
String& setter_name = String::Handle(Field::SetterName(name));
if (FunctionExists(setter_name)) {
return true;
}
}
return false;
}
void AddFunction(const Function& function) {
ASSERT(!FunctionExists(String::Handle(function.name())));
functions_.Add(function);
}
const GrowableObjectArray& functions() const {
return functions_;
}
void AddField(const Field& field) {
ASSERT(!FieldExists(String::Handle(field.name())));
fields_.Add(field);
}
const GrowableObjectArray& fields() const {
return fields_;
}
const Class& clazz() const {
return clazz_;
}
const String& class_name() const {
return class_name_;
}
bool has_constructor() const {
Function& func = Function::Handle();
for (int i = 0; i < functions_.Length(); i++) {
func ^= functions_.At(i);
if (func.kind() == RawFunction::kConstructor) {
return true;
}
}
return false;
}
intptr_t token_pos() const {
return token_pos_;
}
void AddMember(const MemberDesc& member) {
members_.Add(member);
}
const GrowableArray<MemberDesc>& members() const {
return members_;
}
MemberDesc* LookupMember(const String& name) const {
for (int i = 0; i < members_.length(); i++) {
if (name.Equals(*members_[i].name)) {
return &members_[i];
}
}
return NULL;
}
private:
Field* LookupField(const String& name) const {
String& test_name = String::Handle();
Field& field = Field::Handle();
for (int i = 0; i < fields_.Length(); i++) {
field ^= fields_.At(i);
test_name = field.name();
if (name.Equals(test_name)) {
return &field;
}
}
return NULL;
}
bool FieldExists(const String& name) const {
return LookupField(name) != NULL;
}
Function* LookupFunction(const String& name) const {
String& test_name = String::Handle();
Function& func = Function::Handle();
for (int i = 0; i < functions_.Length(); i++) {
func ^= functions_.At(i);
test_name = func.name();
if (name.Equals(test_name)) {
return &func;
}
}
return NULL;
}
bool FunctionExists(const String& name) const {
return LookupFunction(name) != NULL;
}
const Class& clazz_;
const String& class_name_;
intptr_t token_pos_; // Token index of "class" keyword.
GrowableObjectArray& functions_;
GrowableObjectArray& fields_;
GrowableArray<MemberDesc> members_;
};
struct TopLevel {
TopLevel() :
fields(GrowableObjectArray::Handle(GrowableObjectArray::New())),
functions(GrowableObjectArray::Handle(GrowableObjectArray::New())) { }
GrowableObjectArray& fields;
GrowableObjectArray& functions;
};
static bool HasReturnNode(SequenceNode* seq) {
if (seq->length() == 0) {
return false;
} else if ((seq->length()) == 1 &&
(seq->NodeAt(seq->length() - 1)->IsSequenceNode())) {
return HasReturnNode(seq->NodeAt(seq->length() - 1)->AsSequenceNode());
} else {
return seq->NodeAt(seq->length() - 1)->IsReturnNode();
}
}
void Parser::ParseClass(const Class& cls) {
if (!cls.is_synthesized_class()) {
TimerScope timer(FLAG_compiler_stats, &CompilerStats::parser_timer);
Isolate* isolate = Isolate::Current();
ASSERT(isolate->long_jump_base()->IsSafeToJump());
const Script& script = Script::Handle(isolate, cls.script());
const Library& lib = Library::Handle(isolate, cls.library());
Parser parser(script, lib, cls.token_pos());
parser.ParseClassDefinition(cls);
}
}
void Parser::ParseFunction(ParsedFunction* parsed_function) {
TimerScope timer(FLAG_compiler_stats, &CompilerStats::parser_timer);
Isolate* isolate = Isolate::Current();
ASSERT(isolate->long_jump_base()->IsSafeToJump());
ASSERT(parsed_function != NULL);
const Function& func = parsed_function->function();
const Script& script = Script::Handle(isolate, func.script());
Parser parser(script, parsed_function, func.token_pos());
SequenceNode* node_sequence = NULL;
Array& default_parameter_values = Array::ZoneHandle(isolate, Array::null());
switch (func.kind()) {
case RawFunction::kRegularFunction:
case RawFunction::kClosureFunction:
case RawFunction::kGetterFunction:
case RawFunction::kSetterFunction:
case RawFunction::kConstructor:
// The call to a redirecting factory is redirected.
ASSERT(!func.IsRedirectingFactory());
if (!func.IsImplicitConstructor()) {
parser.SkipFunctionPreamble();
}
node_sequence = parser.ParseFunc(func, default_parameter_values);
break;
case RawFunction::kImplicitGetter:
ASSERT(!func.is_static());
node_sequence = parser.ParseInstanceGetter(func);
break;
case RawFunction::kImplicitSetter:
ASSERT(!func.is_static());
node_sequence = parser.ParseInstanceSetter(func);
break;
case RawFunction::kImplicitStaticFinalGetter:
node_sequence = parser.ParseStaticFinalGetter(func);
break;
case RawFunction::kMethodExtractor:
node_sequence = parser.ParseMethodExtractor(func);
break;
case RawFunction::kNoSuchMethodDispatcher:
node_sequence =
parser.ParseNoSuchMethodDispatcher(func, default_parameter_values);
break;
case RawFunction::kInvokeFieldDispatcher:
node_sequence =
parser.ParseInvokeFieldDispatcher(func, default_parameter_values);
break;
default:
UNREACHABLE();
}
if (!HasReturnNode(node_sequence)) {
// Add implicit return node.
node_sequence->Add(new ReturnNode(func.end_token_pos()));
}
if (parsed_function->has_expression_temp_var()) {
node_sequence->scope()->AddVariable(parsed_function->expression_temp_var());
}
if (parsed_function->has_saved_current_context_var()) {
node_sequence->scope()->AddVariable(
parsed_function->saved_current_context_var());
}
parsed_function->SetNodeSequence(node_sequence);
// The instantiator may be required at run time for generic type checks or
// allocation of generic types.
if (parser.IsInstantiatorRequired()) {
// In the case of a local function, only set the instantiator if the
// receiver (or type arguments parameter of a factory) was captured.
LocalVariable* instantiator = NULL;
const bool kTestOnly = true;
if (parser.current_function().IsInFactoryScope()) {
instantiator = parser.LookupTypeArgumentsParameter(node_sequence->scope(),
kTestOnly);
} else {
instantiator = parser.LookupReceiver(node_sequence->scope(), kTestOnly);
}
if (!parser.current_function().IsLocalFunction() ||
((instantiator != NULL) && instantiator->is_captured())) {
parsed_function->set_instantiator(
new LoadLocalNode(node_sequence->token_pos(), instantiator));
}
}
parsed_function->set_default_parameter_values(default_parameter_values);
}
RawObject* Parser::ParseMetadata(const Class& cls, intptr_t token_pos) {
Isolate* isolate = Isolate::Current();
StackZone zone(isolate);
LongJump* base = isolate->long_jump_base();
LongJump jump;
isolate->set_long_jump_base(&jump);
if (setjmp(*jump.Set()) == 0) {
const Script& script = Script::Handle(cls.script());
const Library& lib = Library::Handle(cls.library());
Parser parser(script, lib, token_pos);
parser.set_current_class(cls);
return parser.EvaluateMetadata();
} else {
Error& error = Error::Handle();
error = isolate->object_store()->sticky_error();
isolate->object_store()->clear_sticky_error();
isolate->set_long_jump_base(base);
return error.raw();
}
UNREACHABLE();
return Object::null();
}
RawArray* Parser::EvaluateMetadata() {
if (CurrentToken() != Token::kAT) {
ErrorMsg("Metadata character '@' expected");
}
GrowableObjectArray& meta_values =
GrowableObjectArray::Handle(GrowableObjectArray::New());
while (CurrentToken() == Token::kAT) {
ConsumeToken();
intptr_t expr_pos = TokenPos();
if (!IsIdentifier()) {
ExpectIdentifier("identifier expected");
}
AstNode* expr = NULL;
if ((LookaheadToken(1) == Token::kLPAREN) ||
((LookaheadToken(1) == Token::kPERIOD) &&
(LookaheadToken(3) == Token::kLPAREN)) ||
((LookaheadToken(1) == Token::kPERIOD) &&
(LookaheadToken(3) == Token::kPERIOD) &&
(LookaheadToken(5) == Token::kLPAREN))) {
expr = ParseNewOperator(Token::kCONST);
} else {
expr = ParsePrimary();
}
if (expr->EvalConstExpr() == NULL) {
ErrorMsg(expr_pos, "expression must be a compile-time constant");
}
const Instance& val = EvaluateConstExpr(expr);
meta_values.Add(val);
}
return Array::MakeArray(meta_values);
}
SequenceNode* Parser::ParseStaticFinalGetter(const Function& func) {
TRACE_PARSER("ParseStaticFinalGetter");
ParamList params;
ASSERT(func.num_fixed_parameters() == 0); // static.
ASSERT(!func.HasOptionalParameters());
ASSERT(AbstractType::Handle(func.result_type()).IsResolved());
// Build local scope for function and populate with the formal parameters.
OpenFunctionBlock(func);
AddFormalParamsToScope(&params, current_block_->scope);
intptr_t ident_pos = TokenPos();
const String& field_name = *ExpectIdentifier("field name expected");
const Class& field_class = Class::Handle(func.Owner());
const Field& field =
Field::ZoneHandle(field_class.LookupStaticField(field_name));
if (!field.is_const() &&
(field.value() != Object::transition_sentinel().raw()) &&
(field.value() != Object::sentinel().raw())) {
// The field has already been initialized at compile time (this can
// happen, e.g., if we are recompiling for optimization). There is no
// need to check for initialization and compile the potentially very
// large initialization code. By skipping this code, the deoptimization
// ids will not line up with the original code, but this is safe because
// LoadStaticField does not deoptimize.
LoadStaticFieldNode* load_node = new LoadStaticFieldNode(ident_pos, field);
ReturnNode* return_node = new ReturnNode(ident_pos, load_node);
current_block_->statements->Add(return_node);
return CloseBlock();
}
// Static const fields must have an initializer.
ExpectToken(Token::kASSIGN);
// We don't want to use ParseConstExpr() here because we don't want
// the constant folding code to create, compile and execute a code
// fragment to evaluate the expression. Instead, we just make sure
// the static const field initializer is a constant expression and
// leave the evaluation to the getter function.
const intptr_t expr_pos = TokenPos();
AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades);
if (field.is_const()) {
// This getter will only be called once at compile time.
if (expr->EvalConstExpr() == NULL) {
ErrorMsg(expr_pos, "initializer must be a compile-time constant");
}
ReturnNode* return_node = new ReturnNode(ident_pos, expr);
current_block_->statements->Add(return_node);
} else {
// This getter may be called each time the static field is accessed.
// The following generated code lazily initializes the field:
// if (field.value === transition_sentinel) {
// field.value = null;
// throw("circular dependency in field initialization");
// }
// if (field.value === sentinel) {
// field.value = transition_sentinel;
// field.value = expr;
// }
// return field.value; // Type check is executed here in checked mode.
// Generate code checking for circular dependency in field initialization.
AstNode* compare_circular = new ComparisonNode(
ident_pos,
Token::kEQ_STRICT,
new LoadStaticFieldNode(ident_pos, field),
new LiteralNode(ident_pos, Object::transition_sentinel()));
// Set field to null prior to throwing exception, so that subsequent
// accesses to the field do not throw again, since initializers should only
// be executed once.
SequenceNode* report_circular = new SequenceNode(ident_pos, NULL);
report_circular->Add(
new StoreStaticFieldNode(
ident_pos,
field,
new LiteralNode(ident_pos, Instance::ZoneHandle())));
// TODO(regis, 5802): Exception to throw is not specified by spec.
const String& circular_error = String::ZoneHandle(
Symbols::New("circular dependency in field initialization"));
report_circular->Add(
new ThrowNode(ident_pos,
new LiteralNode(ident_pos, circular_error),
NULL));
AstNode* circular_check =
new IfNode(ident_pos, compare_circular, report_circular, NULL);
current_block_->statements->Add(circular_check);
// Generate code checking for uninitialized field.
AstNode* compare_uninitialized = new ComparisonNode(
ident_pos,
Token::kEQ_STRICT,
new LoadStaticFieldNode(ident_pos, field),
new LiteralNode(ident_pos, Object::sentinel()));
SequenceNode* initialize_field = new SequenceNode(ident_pos, NULL);
initialize_field->Add(
new StoreStaticFieldNode(
ident_pos,
field,
new LiteralNode(ident_pos, Object::transition_sentinel())));
// TODO(hausner): If evaluation of the field value throws an exception,
// we leave the field value as 'transition_sentinel', which is wrong.
// A second reference to the field later throws a circular dependency
// exception. The field should instead be set to null after an exception.
initialize_field->Add(new StoreStaticFieldNode(ident_pos, field, expr));
AstNode* uninitialized_check =
new IfNode(ident_pos, compare_uninitialized, initialize_field, NULL);
current_block_->statements->Add(uninitialized_check);
// Generate code returning the field value.
ReturnNode* return_node =
new ReturnNode(ident_pos,
new LoadStaticFieldNode(ident_pos, field));
current_block_->statements->Add(return_node);
}
return CloseBlock();
}
// Create AstNodes for an implicit instance getter method:
// LoadLocalNode 0 ('this');
// LoadInstanceFieldNode (field_name);
// ReturnNode (field's value);
SequenceNode* Parser::ParseInstanceGetter(const Function& func) {
TRACE_PARSER("ParseInstanceGetter");
ParamList params;
// func.token_pos() points to the name of the field.
intptr_t ident_pos = func.token_pos();
ASSERT(current_class().raw() == func.Owner());
params.AddReceiver(ReceiverType(current_class()), ident_pos);
ASSERT(func.num_fixed_parameters() == 1); // receiver.
ASSERT(!func.HasOptionalParameters());
ASSERT(AbstractType::Handle(func.result_type()).IsResolved());
// Build local scope for function and populate with the formal parameters.
OpenFunctionBlock(func);
AddFormalParamsToScope(&params, current_block_->scope);
// Receiver is local 0.
LocalVariable* receiver = current_block_->scope->VariableAt(0);
LoadLocalNode* load_receiver = new LoadLocalNode(ident_pos, receiver);
ASSERT(IsIdentifier());
const String& field_name = *CurrentLiteral();
const Class& field_class = Class::Handle(func.Owner());
const Field& field =
Field::ZoneHandle(field_class.LookupInstanceField(field_name));
LoadInstanceFieldNode* load_field =
new LoadInstanceFieldNode(ident_pos, load_receiver, field);
ReturnNode* return_node = new ReturnNode(ident_pos, load_field);
current_block_->statements->Add(return_node);
return CloseBlock();
}
// Create AstNodes for an implicit instance setter method:
// LoadLocalNode 0 ('this')
// LoadLocalNode 1 ('value')
// SetInstanceField (field_name);
// ReturnNode (void);
SequenceNode* Parser::ParseInstanceSetter(const Function& func) {
TRACE_PARSER("ParseInstanceSetter");
// func.token_pos() points to the name of the field.
intptr_t ident_pos = func.token_pos();
const String& field_name = *CurrentLiteral();
const Class& field_class = Class::ZoneHandle(func.Owner());
const Field& field =
Field::ZoneHandle(field_class.LookupInstanceField(field_name));
const AbstractType& field_type = AbstractType::ZoneHandle(field.type());
ParamList params;
ASSERT(current_class().raw() == func.Owner());
params.AddReceiver(ReceiverType(current_class()), ident_pos);
params.AddFinalParameter(ident_pos,
&Symbols::Value(),
&field_type);
ASSERT(func.num_fixed_parameters() == 2); // receiver, value.
ASSERT(!func.HasOptionalParameters());
ASSERT(AbstractType::Handle(func.result_type()).IsVoidType());
// Build local scope for function and populate with the formal parameters.
OpenFunctionBlock(func);
AddFormalParamsToScope(&params, current_block_->scope);
LoadLocalNode* receiver =
new LoadLocalNode(ident_pos, current_block_->scope->VariableAt(0));
LoadLocalNode* value =
new LoadLocalNode(ident_pos, current_block_->scope->VariableAt(1));
EnsureExpressionTemp();
StoreInstanceFieldNode* store_field =
new StoreInstanceFieldNode(ident_pos, receiver, field, value);
current_block_->statements->Add(store_field);
current_block_->statements->Add(new ReturnNode(ident_pos));
return CloseBlock();
}
SequenceNode* Parser::ParseMethodExtractor(const Function& func) {
TRACE_PARSER("ParseMethodExtractor");
ParamList params;
const intptr_t ident_pos = func.token_pos();
ASSERT(func.token_pos() == 0);
ASSERT(current_class().raw() == func.Owner());
params.AddReceiver(ReceiverType(current_class()), ident_pos);
ASSERT(func.num_fixed_parameters() == 1); // Receiver.
ASSERT(!func.HasOptionalParameters());
// Build local scope for function and populate with the formal parameters.
OpenFunctionBlock(func);
AddFormalParamsToScope(&params, current_block_->scope);
// Receiver is local 0.
LocalVariable* receiver = current_block_->scope->VariableAt(0);
LoadLocalNode* load_receiver = new LoadLocalNode(ident_pos, receiver);
ClosureNode* closure = new ClosureNode(
ident_pos,
Function::ZoneHandle(func.extracted_method_closure()),
load_receiver,
NULL);
ReturnNode* return_node = new ReturnNode(ident_pos, closure);
current_block_->statements->Add(return_node);
return CloseBlock();
}
void Parser::BuildDispatcherScope(const Function& func,
const ArgumentsDescriptor& desc,
Array& default_values) {
ParamList params;
// Receiver first.
intptr_t token_pos = func.token_pos();
params.AddReceiver(ReceiverType(current_class()), token_pos);
// Remaining positional parameters.
intptr_t i = 1;
for (; i < desc.PositionalCount(); ++i) {
ParamDesc p;
char name[64];
OS::SNPrint(name, 64, ":p%" Pd, i);
p.name = &String::ZoneHandle(Symbols::New(name));
p.type = &Type::ZoneHandle(Type::DynamicType());
params.parameters->Add(p);
params.num_fixed_parameters++;
}
ASSERT(desc.PositionalCount() == params.num_fixed_parameters);
// Named parameters.
for (; i < desc.Count(); ++i) {
ParamDesc p;
intptr_t index = i - desc.PositionalCount();
p.name = &String::ZoneHandle(desc.NameAt(index));
p.type = &Type::ZoneHandle(Type::DynamicType());
p.default_value = &Object::ZoneHandle();
params.parameters->Add(p);
params.num_optional_parameters++;
params.has_optional_named_parameters = true;
}
ASSERT(desc.NamedCount() == params.num_optional_parameters);
SetupDefaultsForOptionalParams(&params, default_values);
// Build local scope for function and populate with the formal parameters.
OpenFunctionBlock(func);
AddFormalParamsToScope(&params, current_block_->scope);
}
SequenceNode* Parser::ParseNoSuchMethodDispatcher(const Function& func,
Array& default_values) {
TRACE_PARSER("ParseNoSuchMethodDispatcher");
ASSERT(func.IsNoSuchMethodDispatcher());
intptr_t token_pos = func.token_pos();
ASSERT(func.token_pos() == 0);
ASSERT(current_class().raw() == func.Owner());
ArgumentsDescriptor desc(Array::Handle(func.saved_args_desc()));
ASSERT(desc.Count() > 0);
// Set up scope for this function.
BuildDispatcherScope(func, desc, default_values);
// Receiver is local 0.
LocalScope* scope = current_block_->scope;
ArgumentListNode* func_args = new ArgumentListNode(token_pos);
for (intptr_t i = 0; i < desc.Count(); ++i) {
func_args->Add(new LoadLocalNode(token_pos, scope->VariableAt(i)));
}
if (desc.NamedCount() > 0) {
const Array& arg_names =
Array::ZoneHandle(Array::New(desc.NamedCount()));
for (intptr_t i = 0; i < arg_names.Length(); ++i) {
arg_names.SetAt(i, String::Handle(desc.NameAt(i)));
}
func_args->set_names(arg_names);
}
const String& func_name = String::ZoneHandle(func.name());
ArgumentListNode* arguments = BuildNoSuchMethodArguments(token_pos,
func_name,
*func_args);
const Function& no_such_method = Function::ZoneHandle(
Resolver::ResolveDynamicAnyArgs(Class::Handle(func.Owner()),
Symbols::NoSuchMethod()));
StaticCallNode* call =
new StaticCallNode(token_pos, no_such_method, arguments);
ReturnNode* return_node = new ReturnNode(token_pos, call);
current_block_->statements->Add(return_node);
return CloseBlock();
}
SequenceNode* Parser::ParseInvokeFieldDispatcher(const Function& func,
Array& default_values) {
TRACE_PARSER("ParseInvokeFieldDispatcher");
ASSERT(func.IsInvokeFieldDispatcher());
intptr_t token_pos = func.token_pos();
ASSERT(func.token_pos() == 0);
ASSERT(current_class().raw() == func.Owner());
const Array& args_desc = Array::Handle(func.saved_args_desc());
ArgumentsDescriptor desc(args_desc);
ASSERT(desc.Count() > 0);
// Set up scope for this function.
BuildDispatcherScope(func, desc, default_values);
// Receiver is local 0.
LocalScope* scope = current_block_->scope;
ArgumentListNode* no_args = new ArgumentListNode(token_pos);
LoadLocalNode* receiver = new LoadLocalNode(token_pos, scope->VariableAt(0));
const String& name = String::Handle(func.name());
const String& getter_name =
String::ZoneHandle(Symbols::New(String::Handle(Field::GetterName(name))));
InstanceCallNode* getter_call = new InstanceCallNode(token_pos,
receiver,
getter_name,
no_args);
// Pass arguments 1..n to the closure call.
ArgumentListNode* closure_args = new ArgumentListNode(token_pos);
const Array& names = Array::Handle(Array::New(desc.NamedCount(), Heap::kOld));
// Positional parameters.
intptr_t i = 1;
for (; i < desc.PositionalCount(); ++i) {
closure_args->Add(new LoadLocalNode(token_pos, scope->VariableAt(i)));
}
// Named parameters.
for (; i < desc.Count(); i++) {
closure_args->Add(new LoadLocalNode(token_pos, scope->VariableAt(i)));
intptr_t index = i - desc.PositionalCount();
names.SetAt(index, String::Handle(desc.NameAt(index)));
}
closure_args->set_names(names);
EnsureSavedCurrentContext();
ClosureCallNode* closure_call = new ClosureCallNode(token_pos,
getter_call,
closure_args);
ReturnNode* return_node = new ReturnNode(token_pos, closure_call);
current_block_->statements->Add(return_node);
return CloseBlock();
}
void Parser::SkipBlock() {
ASSERT(CurrentToken() == Token::kLBRACE);
GrowableArray<Token::Kind> token_stack(8);
const intptr_t block_start_pos = TokenPos();
bool is_match = true;
bool unexpected_token_found = false;
Token::Kind token;
intptr_t token_pos;
do {
token = CurrentToken();
token_pos = TokenPos();
switch (token) {
case Token::kLBRACE:
case Token::kLPAREN:
case Token::kLBRACK:
token_stack.Add(token);
break;
case Token::kRBRACE:
is_match = token_stack.RemoveLast() == Token::kLBRACE;
break;
case Token::kRPAREN:
is_match = token_stack.RemoveLast() == Token::kLPAREN;
break;
case Token::kRBRACK:
is_match = token_stack.RemoveLast() == Token::kLBRACK;
break;
case Token::kEOS:
unexpected_token_found = true;
break;
default:
// nothing.
break;
}
ConsumeToken();
} while (!token_stack.is_empty() && is_match && !unexpected_token_found);
if (!is_match) {
ErrorMsg(token_pos, "unbalanced '%s'", Token::Str(token));
} else if (unexpected_token_found) {
ErrorMsg(block_start_pos, "unterminated block");
}
}
void Parser::ParseFormalParameter(bool allow_explicit_default_value,
ParamList* params) {
TRACE_PARSER("ParseFormalParameter");
ParamDesc parameter;
bool var_seen = false;
bool this_seen = false;
SkipMetadata();
if (CurrentToken() == Token::kFINAL) {
ConsumeToken();
parameter.is_final = true;
} else if (CurrentToken() == Token::kVAR) {
ConsumeToken();
var_seen = true;
// The parameter type is the 'dynamic' type.
parameter.type = &Type::ZoneHandle(Type::DynamicType());
}
if (CurrentToken() == Token::kTHIS) {
ConsumeToken();
ExpectToken(Token::kPERIOD);
this_seen = true;
parameter.is_field_initializer = true;
}
if (params->implicitly_final) {
parameter.is_final = true;
}
if ((parameter.type == NULL) && (CurrentToken() == Token::kVOID)) {
ConsumeToken();
// This must later be changed to a closure type if we recognize
// a closure/function type parameter. We check this at the end
// of ParseFormalParameter.
parameter.type = &Type::ZoneHandle(Type::VoidType());
}
if (parameter.type == NULL) {
// At this point, we must see an identifier for the type or the
// function parameter.
if (!IsIdentifier()) {
ErrorMsg("parameter name or type expected");
}
// We have not seen a parameter type yet, so we check if the next
// identifier could represent a type before parsing it.
Token::Kind follower = LookaheadToken(1);
// We have an identifier followed by a 'follower' token.
// We either parse a type or assume that no type is specified.
if ((follower == Token::kLT) || // Parameterized type.
(follower == Token::kPERIOD) || // Qualified class name of type.
Token::IsIdentifier(follower) || // Parameter name following a type.
(follower == Token::kTHIS)) { // Field parameter following a type.
// The types of formal parameters are never ignored, even in unchecked
// mode, because they are part of the function type of closurized
// functions appearing in type tests with typedefs.
parameter.type = &AbstractType::ZoneHandle(
ParseType(is_top_level_ ? ClassFinalizer::kResolveTypeParameters :
ClassFinalizer::kCanonicalize));
} else {
parameter.type = &Type::ZoneHandle(Type::DynamicType());
}
}
if (!this_seen && (CurrentToken() == Token::kTHIS)) {
ConsumeToken();
ExpectToken(Token::kPERIOD);
this_seen = true;
parameter.is_field_initializer = true;
}
// At this point, we must see an identifier for the parameter name.
parameter.name_pos = TokenPos();
parameter.name = ExpectIdentifier("parameter name expected");
if (parameter.is_field_initializer) {
params->has_field_initializer = true;
}
// Check for duplicate formal parameters.
const intptr_t num_existing_parameters =
params->num_fixed_parameters + params->num_optional_parameters;
for (intptr_t i = 0; i < num_existing_parameters; i++) {
ParamDesc& existing_parameter = (*params->parameters)[i];
if (existing_parameter.name->Equals(*parameter.name)) {
ErrorMsg(parameter.name_pos, "duplicate formal parameter '%s'",
parameter.name->ToCString());
}
}
if (CurrentToken() == Token::kLPAREN) {
// This parameter is probably a closure. If we saw the keyword 'var'
// or 'final', a closure is not legal here and we ignore the
// opening parens.
if (!var_seen && !parameter.is_final) {
// The parsed parameter type is actually the function result type.
const AbstractType& result_type =
AbstractType::Handle(parameter.type->raw());
// Finish parsing the function type parameter.
ParamList func_params;
// Add implicit closure object parameter.
func_params.AddFinalParameter(
TokenPos(),
&Symbols::ClosureParameter(),
&Type::ZoneHandle(Type::DynamicType()));
const bool no_explicit_default_values = false;
ParseFormalParameterList(no_explicit_default_values, &func_params);
// The field 'is_static' has no meaning for signature functions.
const Function& signature_function = Function::Handle(
Function::New(*parameter.name,
RawFunction::kSignatureFunction,
/* is_static = */ false,
/* is_const = */ false,
/* is_abstract = */ false,
/* is_external = */ false,
current_class(),
parameter.name_pos));
signature_function.set_result_type(result_type);
AddFormalParamsToFunction(&func_params, signature_function);
const String& signature = String::Handle(signature_function.Signature());
// Lookup the signature class, i.e. the class whose name is the signature.
// We only lookup in the current library, but not in its imports, and only
// create a new canonical signature class if it does not exist yet.
Class& signature_class = Class::ZoneHandle(
library_.LookupLocalClass(signature));
if (signature_class.IsNull()) {
signature_class = Class::NewSignatureClass(signature,
signature_function,
script_,
parameter.name_pos);
// Record the function signature class in the current library, unless
// we are currently skipping a formal parameter list, in which case
// the signature class could remain unfinalized.
if (!params->skipped) {
library_.AddClass(signature_class);
}
} else {
signature_function.set_signature_class(signature_class);
}
ASSERT(signature_function.signature_class() == signature_class.raw());
Type& signature_type = Type::ZoneHandle(signature_class.SignatureType());
if (!is_top_level_ && !signature_type.IsFinalized()) {
signature_type ^= ClassFinalizer::FinalizeType(
signature_class, signature_type, ClassFinalizer::kCanonicalize);
}
// The type of the parameter is now the signature type.
parameter.type = &signature_type;
}
}
if ((CurrentToken() == Token::kASSIGN) || (CurrentToken() == Token::kCOLON)) {
if ((!params->has_optional_positional_parameters &&
!params->has_optional_named_parameters) ||
!allow_explicit_default_value) {
ErrorMsg("parameter must not specify a default value");
}
if (params->has_optional_positional_parameters) {
ExpectToken(Token::kASSIGN);
} else {
ExpectToken(Token::kCOLON);
}
params->num_optional_parameters++;
if (is_top_level_) {
// Skip default value parsing.
SkipExpr();
} else {
const Object& const_value = ParseConstExpr()->literal();
parameter.default_value = &const_value;
}
} else {
if (params->has_optional_positional_parameters ||
params->has_optional_named_parameters) {
// Implicit default value is null.
params->num_optional_parameters++;
parameter.default_value = &Object::ZoneHandle();
} else {
params->num_fixed_parameters++;
ASSERT(params->num_optional_parameters == 0);
}
}
if (parameter.type->IsVoidType()) {
ErrorMsg("parameter '%s' may not be 'void'", parameter.name->ToCString());
}
params->parameters->Add(parameter);
}
// Parses a sequence of normal or optional formal parameters.
void Parser::ParseFormalParameters(bool allow_explicit_default_values,
ParamList* params) {
TRACE_PARSER("ParseFormalParameters");
do {
ConsumeToken();
if (!params->has_optional_positional_parameters &&
!params->has_optional_named_parameters &&
(CurrentToken() == Token::kLBRACK)) {
// End of normal parameters, start of optional positional parameters.
params->has_optional_positional_parameters = true;
return;
}
if (!params->has_optional_positional_parameters &&
!params->has_optional_named_parameters &&
(CurrentToken() == Token::kLBRACE)) {
// End of normal parameters, start of optional named parameters.
params->has_optional_named_parameters = true;
return;
}
ParseFormalParameter(allow_explicit_default_values, params);
} while (CurrentToken() == Token::kCOMMA);
}
void Parser::ParseFormalParameterList(bool allow_explicit_default_values,
ParamList* params) {
TRACE_PARSER("ParseFormalParameterList");
ASSERT(CurrentToken() == Token::kLPAREN);
if (LookaheadToken(1) != Token::kRPAREN) {
// Parse fixed parameters.
ParseFormalParameters(allow_explicit_default_values, params);
if (params->has_optional_positional_parameters ||
params->has_optional_named_parameters) {
// Parse optional parameters.
ParseFormalParameters(allow_explicit_default_values, params);
if (params->has_optional_positional_parameters) {
if (CurrentToken() != Token::kRBRACK) {
ErrorMsg("',' or ']' expected");
}
} else {
if (CurrentToken() != Token::kRBRACE) {
ErrorMsg("',' or '}' expected");
}
}
ConsumeToken(); // ']' or '}'.
}
if ((CurrentToken() != Token::kRPAREN) &&
!params->has_optional_positional_parameters &&
!params->has_optional_named_parameters) {
ErrorMsg("',' or ')' expected");
}
} else {
ConsumeToken();
}
ExpectToken(Token::kRPAREN);
}
String& Parser::ParseNativeDeclaration() {
TRACE_PARSER("ParseNativeDeclaration");
ASSERT(IsLiteral("native"));
ConsumeToken();
if (CurrentToken() != Token::kSTRING) {
ErrorMsg("string literal expected");
}
String& native_name = *CurrentLiteral();
ConsumeToken();
ExpectSemicolon();
return native_name;
}
// Resolve and return the dynamic function of the given name in the superclass.
// If it is not found, and resolve_getter is true, try to resolve a getter of
// the same name. If it is still not found, return noSuchMethod and
// set is_no_such_method to true..
RawFunction* Parser::GetSuperFunction(intptr_t token_pos,
const String& name,
ArgumentListNode* arguments,
bool resolve_getter,
bool* is_no_such_method) {
const Class& super_class = Class::Handle(current_class().SuperClass());
if (super_class.IsNull()) {
ErrorMsg(token_pos, "class '%s' does not have a superclass",
String::Handle(current_class().Name()).ToCString());
}
Function& super_func = Function::Handle(
Resolver::ResolveDynamicAnyArgs(super_class, name));
if (!super_func.IsNull() &&
!super_func.AreValidArguments(arguments->length(),
arguments->names(),
NULL)) {
super_func = Function::null();
} else if (super_func.IsNull() && resolve_getter) {
const String& getter_name = String::ZoneHandle(Field::GetterName(name));
super_func = Resolver::ResolveDynamicAnyArgs(super_class, getter_name);
ASSERT(super_func.IsNull() ||
(super_func.kind() != RawFunction::kImplicitStaticFinalGetter));
}
if (super_func.IsNull()) {
super_func =
Resolver::ResolveDynamicAnyArgs(super_class, Symbols::NoSuchMethod());
ASSERT(!super_func.IsNull());
*is_no_such_method = true;
} else {
*is_no_such_method = false;
}
return super_func.raw();
}
// Lookup class in the core lib which also contains various VM
// helper methods and classes. Allow look up of private classes.
static RawClass* LookupCoreClass(const String& class_name) {
const Library& core_lib = Library::Handle(Library::CoreLibrary());
String& name = String::Handle(class_name.raw());
if (class_name.CharAt(0) == Scanner::kPrivateIdentifierStart) {
// Private identifiers are mangled on a per script basis.
name = String::Concat(name, String::Handle(core_lib.private_key()));
name = Symbols::New(name);
}
return core_lib.LookupClass(name, NULL); // No ambiguity error expected.
}
static const String& PrivateCoreLibName(const String& str) {
const Library& core_lib = Library::Handle(Library::CoreLibrary());
const String& private_name = String::ZoneHandle(core_lib.PrivateName(str));
return private_name;
}
StaticCallNode* Parser::BuildInvocationMirrorAllocation(
intptr_t call_pos,
const String& function_name,
const ArgumentListNode& function_args,
const LocalVariable* temp_for_last_arg) {
const intptr_t args_pos = function_args.token_pos();
// Build arguments to the call to the static
// InvocationMirror._allocateInvocationMirror method.
ArgumentListNode* arguments = new ArgumentListNode(args_pos);
// The first argument is the original function name.
arguments->Add(new LiteralNode(args_pos, function_name));
// The second argument is the arguments descriptor of the original function.
const Array& args_descriptor =
Array::ZoneHandle(ArgumentsDescriptor::New(function_args.length(),
function_args.names()));
arguments->Add(new LiteralNode(args_pos, args_descriptor));
// The third argument is an array containing the original function arguments,
// including the receiver.
ArrayNode* args_array =
new ArrayNode(args_pos, Type::ZoneHandle(Type::ArrayType()));
for (intptr_t i = 0; i < function_args.length(); i++) {
AstNode* arg = function_args.NodeAt(i);
if ((temp_for_last_arg != NULL) && (i == function_args.length() - 1)) {
LetNode* store_arg = new LetNode(arg->token_pos());
store_arg->AddNode(new StoreLocalNode(arg->token_pos(),
temp_for_last_arg,
arg));
store_arg->AddNode(new LoadLocalNode(arg->token_pos(),
temp_for_last_arg));
args_array->AddElement(store_arg);
} else {
args_array->AddElement(arg);
}
}
arguments->Add(args_array);
// Lookup the static InvocationMirror._allocateInvocationMirror method.
const Class& mirror_class =
Class::Handle(LookupCoreClass(Symbols::InvocationMirror()));
ASSERT(!mirror_class.IsNull());
const Function& allocation_function = Function::ZoneHandle(
mirror_class.LookupStaticFunction(
PrivateCoreLibName(Symbols::AllocateInvocationMirror())));
ASSERT(!allocation_function.IsNull());
return new StaticCallNode(call_pos, allocation_function, arguments);
}
ArgumentListNode* Parser::BuildNoSuchMethodArguments(
intptr_t call_pos,
const String& function_name,
const ArgumentListNode& function_args,
const LocalVariable* temp_for_last_arg) {
ASSERT(function_args.length() >= 1); // The receiver is the first argument.
const intptr_t args_pos = function_args.token_pos();
ArgumentListNode* arguments = new ArgumentListNode(args_pos);
arguments->Add(function_args.NodeAt(0));
// The second argument is the invocation mirror.
arguments->Add(BuildInvocationMirrorAllocation(
call_pos, function_name, function_args, temp_for_last_arg));
return arguments;
}
AstNode* Parser::ParseSuperCall(const String& function_name) {
TRACE_PARSER("ParseSuperCall");
ASSERT(CurrentToken() == Token::kLPAREN);
const intptr_t supercall_pos = TokenPos();
// 'this' parameter is the first argument to super call.
ArgumentListNode* arguments = new ArgumentListNode(supercall_pos);
AstNode* receiver = LoadReceiver(supercall_pos);
arguments->Add(receiver);
ParseActualParameters(arguments, kAllowConst);
const bool kResolveGetter = true;
bool is_no_such_method = false;
const Function& super_function = Function::ZoneHandle(
GetSuperFunction(supercall_pos,
function_name,
arguments,
kResolveGetter,
&is_no_such_method));
if (super_function.IsGetterFunction() ||
super_function.IsImplicitGetterFunction()) {
const Class& super_class = Class::ZoneHandle(current_class().SuperClass());
AstNode* closure = new StaticGetterNode(supercall_pos,
LoadReceiver(supercall_pos),
/* is_super_getter */ true,
super_class,
function_name);
EnsureSavedCurrentContext();
// 'this' is not passed as parameter to the closure.
ArgumentListNode* closure_arguments = new ArgumentListNode(supercall_pos);
for (int i = 1; i < arguments->length(); i++) {
closure_arguments->Add(arguments->NodeAt(i));
}
return new ClosureCallNode(supercall_pos, closure, closure_arguments);
}
if (is_no_such_method) {
arguments = BuildNoSuchMethodArguments(
supercall_pos, function_name, *arguments);
}
return new StaticCallNode(supercall_pos, super_function, arguments);
}
// Simple test if a node is side effect free.
static bool IsSimpleLocalOrLiteralNode(AstNode* node) {
return node->IsLiteralNode() || node->IsLoadLocalNode();
}
AstNode* Parser::BuildUnarySuperOperator(Token::Kind op, PrimaryNode* super) {
ASSERT(super->IsSuper());
AstNode* super_op = NULL;
const intptr_t super_pos = super->token_pos();
if ((op == Token::kNEGATE) ||
(op == Token::kBIT_NOT)) {
// Resolve the operator function in the superclass.
const String& operator_function_name =
String::ZoneHandle(Symbols::New(Token::Str(op)));
ArgumentListNode* op_arguments = new ArgumentListNode(super_pos);
AstNode* receiver = LoadReceiver(super_pos);
op_arguments->Add(receiver);
const bool kResolveGetter = false;
bool is_no_such_method = false;
const Function& super_operator = Function::ZoneHandle(
GetSuperFunction(super_pos,
operator_function_name,
op_arguments,
kResolveGetter,
&is_no_such_method));
if (is_no_such_method) {
op_arguments = BuildNoSuchMethodArguments(
super_pos, operator_function_name, *op_arguments);
}
super_op = new StaticCallNode(super_pos, super_operator, op_arguments);
} else {
ErrorMsg(super_pos, "illegal super operator call");
}
return super_op;
}
AstNode* Parser::ParseSuperOperator() {
TRACE_PARSER("ParseSuperOperator");
AstNode* super_op = NULL;
const intptr_t operator_pos = TokenPos();
if (CurrentToken() == Token::kLBRACK) {
ConsumeToken();
AstNode* index_expr = ParseExpr(kAllowConst, kConsumeCascades);
ExpectToken(Token::kRBRACK);
AstNode* receiver = LoadReceiver(operator_pos);
const Class& super_class = Class::ZoneHandle(current_class().SuperClass());
ASSERT(!super_class.IsNull());
super_op =
new LoadIndexedNode(operator_pos, receiver, index_expr, super_class);
} else {
ASSERT(Token::CanBeOverloaded(CurrentToken()) ||
(CurrentToken() == Token::kNE));
Token::Kind op = CurrentToken();
ConsumeToken();
bool negate_result = false;
if (op == Token::kNE) {
op = Token::kEQ;
negate_result = true;
}
ASSERT(Token::Precedence(op) >= Token::Precedence(Token::kBIT_OR));
AstNode* other_operand = ParseBinaryExpr(Token::Precedence(op) + 1);
ArgumentListNode* op_arguments = new ArgumentListNode(operator_pos);
AstNode* receiver = LoadReceiver(operator_pos);
op_arguments->Add(receiver);
op_arguments->Add(other_operand);
// Resolve the operator function in the superclass.
const String& operator_function_name =
String::ZoneHandle(Symbols::New(Token::Str(op)));
const bool kResolveGetter = false;
bool is_no_such_method = false;
const Function& super_operator = Function::ZoneHandle(
GetSuperFunction(operator_pos,
operator_function_name,
op_arguments,
kResolveGetter,
&is_no_such_method));
if (is_no_such_method) {
op_arguments = BuildNoSuchMethodArguments(
operator_pos, operator_function_name, *op_arguments);
}
super_op = new StaticCallNode(operator_pos, super_operator, op_arguments);
if (negate_result) {
super_op = new UnaryOpNode(operator_pos, Token::kNOT, super_op);
}
}
return super_op;
}
AstNode* Parser::CreateImplicitClosureNode(const Function& func,
intptr_t token_pos,
AstNode* receiver) {
Function& implicit_closure_function =
Function::ZoneHandle(func.ImplicitClosureFunction());
if (receiver != NULL) {
// If we create an implicit instance closure from inside a closure of a
// parameterized class, make sure that the receiver is captured as
// instantiator.
if (current_block_->scope->function_level() > 0) {
const Class& signature_class = Class::Handle(
implicit_closure_function.signature_class());
if (signature_class.NumTypeParameters() > 0) {
CaptureInstantiator();
}
}
}
return new ClosureNode(token_pos, implicit_closure_function, receiver, NULL);
}
AstNode* Parser::ParseSuperFieldAccess(const String& field_name) {
TRACE_PARSER("ParseSuperFieldAccess");
const intptr_t field_pos = TokenPos();
const Class& super_class = Class::ZoneHandle(current_class().SuperClass());
if (super_class.IsNull()) {
ErrorMsg("class '%s' does not have a superclass",
String::Handle(current_class().Name()).ToCString());
}
AstNode* implicit_argument = LoadReceiver(field_pos);
const String& getter_name =
String::ZoneHandle(Field::GetterName(field_name));
const Function& super_getter = Function::ZoneHandle(
Resolver::ResolveDynamicAnyArgs(super_class, getter_name));
if (super_getter.IsNull()) {
const String& setter_name =
String::ZoneHandle(Field::SetterName(field_name));
const Function& super_setter = Function::ZoneHandle(
Resolver::ResolveDynamicAnyArgs(super_class, setter_name));
if (super_setter.IsNull()) {
// Check if this is an access to an implicit closure using 'super'.
// If a function exists of the specified field_name then try
// accessing it as a getter, at runtime we will handle this by
// creating an implicit closure of the function and returning it.
const Function& super_function = Function::ZoneHandle(
Resolver::ResolveDynamicAnyArgs(super_class, field_name));
if (!super_function.IsNull()) {
// In case CreateAssignmentNode is called later on this
// CreateImplicitClosureNode, it will be replaced by a StaticSetterNode.
return CreateImplicitClosureNode(super_function,
field_pos,
implicit_argument);
}
// No function or field exists of the specified field_name.
// Emit a StaticGetterNode anyway, so that noSuchMethod gets called.
}
}
return new StaticGetterNode(
field_pos, implicit_argument, true, super_class, field_name);
}
void Parser::GenerateSuperConstructorCall(const Class& cls,
LocalVariable* receiver,
ArgumentListNode* forwarding_args) {
const intptr_t supercall_pos = TokenPos();
const Class& super_class = Class::Handle(cls.SuperClass());
// Omit the implicit super() if there is no super class (i.e.
// we're not compiling class Object), or if the super class is an
// artificially generated "wrapper class" that has no constructor.
if (super_class.IsNull() ||
(super_class.num_native_fields() > 0 &&
Class::Handle(super_class.SuperClass()).IsObjectClass())) {
return;
}
String& super_ctor_name = String::Handle(super_class.Name());
super_ctor_name = String::Concat(super_ctor_name, Symbols::Dot());
ArgumentListNode* arguments = new ArgumentListNode(supercall_pos);
// Implicit 'this' parameter is the first argument.
AstNode* implicit_argument = new LoadLocalNode(supercall_pos, receiver);
arguments->Add(implicit_argument);
// Implicit construction phase parameter is second argument.
AstNode* phase_parameter =
new LiteralNode(supercall_pos,
Smi::ZoneHandle(Smi::New(Function::kCtorPhaseAll)));
arguments->Add(phase_parameter);
// If this is a super call in a forwarding constructor, add the user-
// defined arguments to the super call and adjust the the super
// constructor name to the respective named constructor if necessary.
if (forwarding_args != NULL) {
for (int i = 0; i < forwarding_args->length(); i++) {
arguments->Add(forwarding_args->NodeAt(i));
}
String& ctor_name = String::Handle(current_function().name());
String& class_name = String::Handle(cls.Name());
if (ctor_name.Length() > class_name.Length() + 1) {
// Generating a forwarding call to a named constructor 'C.n'.
// Add the constructor name 'n' to the super constructor.
ctor_name = String::SubString(ctor_name, class_name.Length() + 1);
super_ctor_name = String::Concat(super_ctor_name, ctor_name);
}
}
// Resolve super constructor function and check arguments.
const Function& super_ctor = Function::ZoneHandle(
super_class.LookupConstructor(super_ctor_name));
if (super_ctor.IsNull()) {
ErrorMsg(supercall_pos,
"unresolved implicit call to super constructor '%s()'",
String::Handle(super_class.Name()).ToCString());
}
if (current_function().is_const() && !super_ctor.is_const()) {
ErrorMsg(supercall_pos, "implicit call to non-const super constructor");
}
String& error_message = String::Handle();
if (!super_ctor.AreValidArguments(arguments->length(),
arguments->names(),
&error_message)) {
ErrorMsg(supercall_pos,
"invalid arguments passed to super constructor '%s()': %s",
String::Handle(super_class.Name()).ToCString(),
error_message.ToCString());
}
current_block_->statements->Add(
new StaticCallNode(supercall_pos, super_ctor, arguments));
}
AstNode* Parser::ParseSuperInitializer(const Class& cls,
LocalVariable* receiver) {
TRACE_PARSER("ParseSuperInitializer");
ASSERT(CurrentToken() == Token::kSUPER);
const intptr_t supercall_pos = TokenPos();
ConsumeToken();
const Class& super_class = Class::Handle(cls.SuperClass());
ASSERT(!super_class.IsNull());
String& ctor_name = String::Handle(super_class.Name());
ctor_name = String::Concat(ctor_name, Symbols::Dot());
if (CurrentToken() == Token::kPERIOD) {
ConsumeToken();
ctor_name = String::Concat(ctor_name,
*ExpectIdentifier("constructor name expected"));
}
if (CurrentToken() != Token::kLPAREN) {
ErrorMsg("parameter list expected");
}
ArgumentListNode* arguments = new ArgumentListNode(supercall_pos);
// 'this' parameter is the first argument to super class constructor.
AstNode* implicit_argument = new LoadLocalNode(supercall_pos, receiver);
arguments->Add(implicit_argument);
// Second implicit parameter is the construction phase. We optimistically
// assume that we can execute both the super initializer and the super
// constructor body. We may later change this to only execute the
// super initializer.
AstNode* phase_parameter =
new LiteralNode(supercall_pos,
Smi::ZoneHandle(Smi::New(Function::kCtorPhaseAll)));
arguments->Add(phase_parameter);
// 'this' parameter must not be accessible to the other super call arguments.
receiver->set_invisible(true);
ParseActualParameters(arguments, kAllowConst);
receiver->set_invisible(false);
// Resolve the constructor.
const Function& super_ctor = Function::ZoneHandle(
super_class.LookupConstructor(ctor_name));
if (super_ctor.IsNull()) {
ErrorMsg(supercall_pos,
"super class constructor '%s' not found",
ctor_name.ToCString());
}
if (current_function().is_const() && !super_ctor.is_const()) {
ErrorMsg(supercall_pos, "super constructor must be const");
}
String& error_message = String::Handle();
if (!super_ctor.AreValidArguments(arguments->length(),
arguments->names(),
&error_message)) {
ErrorMsg(supercall_pos,
"invalid arguments passed to super class constructor '%s': %s",
ctor_name.ToCString(),
error_message.ToCString());
}
return new StaticCallNode(supercall_pos, super_ctor, arguments);
}
AstNode* Parser::ParseInitializer(const Class& cls,
LocalVariable* receiver,
GrowableArray<Field*>* initialized_fields) {
TRACE_PARSER("ParseInitializer");
const intptr_t field_pos = TokenPos();
if (CurrentToken() == Token::kTHIS) {
ConsumeToken();
ExpectToken(Token::kPERIOD);
}
const String& field_name = *ExpectIdentifier("field name expected");
ExpectToken(Token::kASSIGN);
const bool saved_mode = SetAllowFunctionLiterals(false);
// "this" must not be accessible in initializer expressions.
receiver->set_invisible(true);
AstNode* init_expr = ParseConditionalExpr();
if (CurrentToken() == Token::kCASCADE) {
init_expr = ParseCascades(init_expr);
}
receiver->set_invisible(false);
SetAllowFunctionLiterals(saved_mode);
if (current_function().is_const() && !init_expr->IsPotentiallyConst()) {
ErrorMsg(field_pos,
"initializer expression must be compile time constant.");
}
Field& field = Field::ZoneHandle(cls.LookupInstanceField(field_name));
if (field.IsNull()) {
ErrorMsg(field_pos, "unresolved reference to instance field '%s'",
field_name.ToCString());
}
CheckDuplicateFieldInit(field_pos, initialized_fields, &field);
AstNode* instance = new LoadLocalNode(field_pos, receiver);
EnsureExpressionTemp();
return new StoreInstanceFieldNode(field_pos, instance, field, init_expr);
}
void Parser::CheckConstFieldsInitialized(const Class& cls) {
const Array& fields = Array::Handle(cls.fields());
Field& field = Field::Handle();
SequenceNode* initializers = current_block_->statements;
for (int field_num = 0; field_num < fields.Length(); field_num++) {
field ^= fields.At(field_num);
if (field.is_static()) {
continue;
}
bool found = false;
for (int i = 0; i < initializers->length(); i++) {
found = false;
if (initializers->NodeAt(i)->IsStoreInstanceFieldNode()) {
StoreInstanceFieldNode* initializer =
initializers->NodeAt(i)->AsStoreInstanceFieldNode();
if (initializer->field().raw() == field.raw()) {
found = true;
break;
}
}
}
if (found) continue;
if (field.is_final()) {
ErrorMsg("final field '%s' not initialized",
String::Handle(field.name()).ToCString());
} else {
field.UpdateCid(kNullCid);
field.UpdateLength(Field::kNoFixedLength);
}
}
}
AstNode* Parser::ParseExternalInitializedField(const Field& field) {
// Only use this function if the initialized field originates
// from a different class. We need to save and restore current
// class, library, and token stream (script).
ASSERT(current_class().raw() != field.origin());
const Class& saved_class = Class::Handle(current_class().raw());
const Library& saved_library = Library::Handle(library().raw());
const Script& saved_script = Script::Handle(script().raw());
const intptr_t saved_token_pos = TokenPos();
set_current_class(Class::Handle(field.origin()));
set_library(Library::Handle(current_class().library()));
SetScript(Script::Handle(current_class().script()), field.token_pos());
ASSERT(IsIdentifier());
ConsumeToken();
ExpectToken(Token::kASSIGN);
AstNode* init_expr = NULL;
if (field.is_const()) {
init_expr = ParseConstExpr();
} else {
init_expr = ParseExpr(kAllowConst, kConsumeCascades);
if (init_expr->EvalConstExpr() != NULL) {
init_expr =
new LiteralNode(field.token_pos(), EvaluateConstExpr(init_expr));
}
}
set_current_class(saved_class);
set_library(saved_library);
SetScript(saved_script, saved_token_pos);
return init_expr;
}
void Parser::ParseInitializedInstanceFields(const Class& cls,
LocalVariable* receiver,
GrowableArray<Field*>* initialized_fields) {
TRACE_PARSER("ParseInitializedInstanceFields");
const Array& fields = Array::Handle(cls.fields());
Field& f = Field::Handle();
const intptr_t saved_pos = TokenPos();
for (int i = 0; i < fields.Length(); i++) {
f ^= fields.At(i);
if (!f.is_static() && f.has_initializer()) {
Field& field = Field::ZoneHandle();
field ^= fields.At(i);
if (field.is_final()) {
// Final fields with initializer expression may not be initialized
// again by constructors. Remember that this field is already
// initialized.
initialized_fields->Add(&field);
}
AstNode* init_expr = NULL;
if (current_class().raw() != field.origin()) {
init_expr = ParseExternalInitializedField(field);
} else {
SetPosition(field.token_pos());
ASSERT(IsIdentifier());
ConsumeToken();
ExpectToken(Token::kASSIGN);
if (field.is_const()) {
init_expr = ParseConstExpr();
} else {
init_expr = ParseExpr(kAllowConst, kConsumeCascades);
if (init_expr->EvalConstExpr() != NULL) {
init_expr = new LiteralNode(field.token_pos(),
EvaluateConstExpr(init_expr));
}
}
}
ASSERT(init_expr != NULL);
AstNode* instance = new LoadLocalNode(field.token_pos(), receiver);
EnsureExpressionTemp();
AstNode* field_init =
new StoreInstanceFieldNode(field.token_pos(),
instance,
field,
init_expr);
current_block_->statements->Add(field_init);
}
}
SetPosition(saved_pos);
}
void Parser::CheckDuplicateFieldInit(intptr_t init_pos,
GrowableArray<Field*>* initialized_fields,
Field* field) {
ASSERT(!field->is_static());
for (int i = 0; i < initialized_fields->length(); i++) {
Field* initialized_field = (*initialized_fields)[i];
if (initialized_field->raw() == field->raw()) {
ErrorMsg(init_pos,
"duplicate initialization for field %s",
String::Handle(field->name()).ToCString());
}
}
initialized_fields->Add(field);
}
void Parser::ParseInitializers(const Class& cls,
LocalVariable* receiver,
GrowableArray<Field*>* initialized_fields) {
TRACE_PARSER("ParseInitializers");
bool super_init_seen = false;
if (CurrentToken() == Token::kCOLON) {
if ((LookaheadToken(1) == Token::kTHIS) &&
((LookaheadToken(2) == Token::kLPAREN) ||
((LookaheadToken(2) == Token::kPERIOD) &&
(LookaheadToken(4) == Token::kLPAREN)))) {
// Either we see this(...) or this.xxx(...) which is a
// redirected constructor. We don't need to check whether
// const fields are initialized. The other constructor will
// guarantee that.
ConsumeToken(); // Colon.
ParseConstructorRedirection(cls, receiver);
return;
}
do {
ConsumeToken(); // Colon or comma.
AstNode* init_statement;
if (CurrentToken() == Token::kSUPER) {
if (super_init_seen) {
ErrorMsg("duplicate call to super constructor");
}
init_statement = ParseSuperInitializer(cls, receiver);
super_init_seen = true;
} else {
init_statement = ParseInitializer(cls, receiver, initialized_fields);
}
current_block_->statements->Add(init_statement);
} while (CurrentToken() == Token::kCOMMA);
}
if (!super_init_seen) {
// Generate implicit super() if we haven't seen an explicit super call
// or constructor redirection.
GenerateSuperConstructorCall(cls, receiver, NULL);
}
CheckConstFieldsInitialized(cls);
}
void Parser::ParseConstructorRedirection(const Class& cls,
LocalVariable* receiver) {
TRACE_PARSER("ParseConstructorRedirection");
ASSERT(CurrentToken() == Token::kTHIS);
const intptr_t call_pos = TokenPos();
ConsumeToken();
String& ctor_name = String::Handle(cls.Name());
ctor_name = String::Concat(ctor_name, Symbols::Dot());
if (CurrentToken() == Token::kPERIOD) {
ConsumeToken();
ctor_name = String::Concat(ctor_name,
*ExpectIdentifier("constructor name expected"));
}
if (CurrentToken() != Token::kLPAREN) {
ErrorMsg("parameter list expected");
}
ArgumentListNode* arguments = new ArgumentListNode(call_pos);
// 'this' parameter is the first argument to constructor.
AstNode* implicit_argument = new LoadLocalNode(call_pos, receiver);
arguments->Add(implicit_argument);
// Construction phase parameter is second argument.
LocalVariable* phase_param = LookupPhaseParameter();
ASSERT(phase_param != NULL);
AstNode* phase_argument = new LoadLocalNode(call_pos, phase_param);
arguments->Add(phase_argument);
receiver->set_invisible(true);
ParseActualParameters(arguments, kAllowConst);
receiver->set_invisible(false);
// Resolve the constructor.
const Function& redirect_ctor = Function::ZoneHandle(
cls.LookupConstructor(ctor_name));
if (redirect_ctor.IsNull()) {
ErrorMsg(call_pos, "constructor '%s' not found", ctor_name.ToCString());
}
String& error_message = String::Handle();
if (!redirect_ctor.AreValidArguments(arguments->length(),
arguments->names(),
&error_message)) {
ErrorMsg(call_pos,
"invalid arguments passed to constructor '%s': %s",
ctor_name.ToCString(),
error_message.ToCString());
}
current_block_->statements->Add(
new StaticCallNode(call_pos, redirect_ctor, arguments));
}
SequenceNode* Parser::MakeImplicitConstructor(const Function& func) {
ASSERT(func.IsConstructor());
ASSERT(func.Owner() == current_class().raw());
const intptr_t ctor_pos = TokenPos();
OpenFunctionBlock(func);
LocalVariable* receiver = new LocalVariable(
ctor_pos, Symbols::This(), *ReceiverType(current_class()));
current_block_->scope->AddVariable(receiver);
LocalVariable* phase_parameter = new LocalVariable(
ctor_pos, Symbols::PhaseParameter(), Type::ZoneHandle(Type::SmiType()));
current_block_->scope->AddVariable(phase_parameter);
// Parse expressions of instance fields that have an explicit
// initializer expression.
// The receiver must not be visible to field initializer expressions.
receiver->set_invisible(true);
GrowableArray<Field*> initialized_fields;
ParseInitializedInstanceFields(
current_class(), receiver, &initialized_fields);
receiver->set_invisible(false);
// If the class of this implicit constructor is a mixin application class,
// it is a forwarding constructor of the mixin. The forwarding
// constructor initializes the instance fields that have initializer
// expressions and then calls the respective super constructor with
// the same name and number of parameters.
ArgumentListNode* forwarding_args = NULL;
if (current_class().mixin() != Type::null()) {
// At this point we don't support forwarding constructors
// that have optional parameters because we don't know the default
// values of the optional parameters. We would have to compile the super
// constructor to get the default values. Also, the spec is not clear
// whether optional parameters are even allowed in this situation.
// TODO(hausner): Remove this limitation if the language spec indeed
// allows optional parameters.
if (func.HasOptionalParameters()) {
ErrorMsg(ctor_pos,
"forwarding constructors must not have optional parameters");
}
// Prepare user-defined arguments to be forwarded to super call.
// The first user-defined argument is at position 2.
forwarding_args = new ArgumentListNode(ctor_pos);
for (int i = 2; i < func.NumParameters(); i++) {
LocalVariable* param = new LocalVariable(
ctor_pos,
String::ZoneHandle(func.ParameterNameAt(i)),
Type::ZoneHandle(Type::DynamicType()));
current_block_->scope->AddVariable(param);
forwarding_args->Add(new LoadLocalNode(ctor_pos, param));
}
}
GenerateSuperConstructorCall(current_class(), receiver, forwarding_args);
CheckConstFieldsInitialized(current_class());
// Empty constructor body.
SequenceNode* statements = CloseBlock();
return statements;
}
// Helper function to make the first num_variables variables in the
// given scope visible/invisible.
static void SetInvisible(LocalScope* scope, int num_variables, bool invisible) {
ASSERT(num_variables <= scope->num_variables());
for (int i = 0; i < num_variables; i++) {
scope->VariableAt(i)->set_invisible(invisible);
}
}
void Parser::CheckRecursiveInvocation() {
const GrowableObjectArray& pending_functions =
GrowableObjectArray::Handle(
isolate()->object_store()->pending_functions());
for (int i = 0; i < pending_functions.Length(); i++) {
if (pending_functions.At(i) == current_function().raw()) {
const String& fname =
String::Handle(current_function().UserVisibleName());
ErrorMsg("circular dependency for function %s", fname.ToCString());
}
}
ASSERT(!unregister_pending_function_);
pending_functions.Add(current_function());
unregister_pending_function_ = true;
}
// Parser is at the opening parenthesis of the formal parameter declaration
// of function. Parse the formal parameters, initializers and code.
SequenceNode* Parser::ParseConstructor(const Function& func,
Array& default_parameter_values) {
TRACE_PARSER("ParseConstructor");
ASSERT(func.IsConstructor());
ASSERT(!func.IsFactory());
ASSERT(!func.is_static());
ASSERT(!func.IsLocalFunction());
const Class& cls = Class::Handle(func.Owner());
ASSERT(!cls.IsNull());
CheckRecursiveInvocation();
if (func.IsImplicitConstructor()) {
// Special case: implicit constructor.
// The parser adds an implicit default constructor when a class
// does not have any explicit constructor or factory (see
// Parser::AddImplicitConstructor).
// There is no source text to parse. We just build the
// sequence node by hand.
return MakeImplicitConstructor(func);
}
OpenFunctionBlock(func);
ParamList params;
const bool allow_explicit_default_values = true;
ASSERT(CurrentToken() == Token::kLPAREN);
// Add implicit receiver parameter which is passed the allocated
// but uninitialized instance to construct.
ASSERT(current_class().raw() == func.Owner());
params.AddReceiver(ReceiverType(current_class()), func.token_pos());
// Add implicit parameter for construction phase.
params.AddFinalParameter(
TokenPos(),
&Symbols::PhaseParameter(),
&Type::ZoneHandle(Type::SmiType()));
if (func.is_const()) {
params.SetImplicitlyFinal();
}
ParseFormalParameterList(allow_explicit_default_values, &params);
SetupDefaultsForOptionalParams(&params, default_parameter_values);
ASSERT(AbstractType::Handle(func.result_type()).IsResolved());
ASSERT(func.NumParameters() == params.parameters->length());
// Now populate function scope with the formal parameters.
AddFormalParamsToScope(&params, current_block_->scope);
// Initialize instance fields that have an explicit initializer expression.
// The formal parameter names must not be visible to the instance
// field initializer expressions, yet the parameters must be added to
// the scope so the expressions use the correct offsets for 'this' when
// storing values. We make the formal parameters temporarily invisible
// while parsing the instance field initializer expressions.
SetInvisible(current_block_->scope, params.parameters->length(), true);
GrowableArray<Field*> initialized_fields;
LocalVariable* receiver = current_block_->scope->VariableAt(0);
OpenBlock();
ParseInitializedInstanceFields(cls, receiver, &initialized_fields);
// Make the parameters (which are in the outer scope) visible again.
SetInvisible(current_block_->scope->parent(),
params.parameters->length(), false);
// Turn formal field parameters into field initializers or report error
// if the function is not a constructor.
if (params.has_field_initializer) {
for (int i = 0; i < params.parameters->length(); i++) {
ParamDesc& param = (*params.parameters)[i];
if (param.is_field_initializer) {
const String& field_name = *param.name;
Field& field = Field::ZoneHandle(cls.LookupInstanceField(field_name));
if (field.IsNull()) {
ErrorMsg(param.name_pos,
"unresolved reference to instance field '%s'",
field_name.ToCString());
}
CheckDuplicateFieldInit(param.name_pos, &initialized_fields, &field);
AstNode* instance = new LoadLocalNode(param.name_pos, receiver);
LocalVariable* p =
current_block_->scope->LookupVariable(*param.name, false);
ASSERT(p != NULL);
// Initializing formals cannot be used in the explicit initializer
// list, nor can they be used in the constructor body.
// Thus, make the parameter invisible.
p->set_invisible(true);
AstNode* value = new LoadLocalNode(param.name_pos, p);
EnsureExpressionTemp();
AstNode* initializer = new StoreInstanceFieldNode(
param.name_pos, instance, field, value);
current_block_->statements->Add(initializer);
}
}
}
// Now parse the explicit initializer list or constructor redirection.
ParseInitializers(cls, receiver, &initialized_fields);
SequenceNode* init_statements = CloseBlock();
if (init_statements->length() > 0) {
// Generate guard around the initializer code.
LocalVariable* phase_param = LookupPhaseParameter();
AstNode* phase_value = new LoadLocalNode(TokenPos(), phase_param);
AstNode* phase_check = new BinaryOpNode(
TokenPos(), Token::kBIT_AND, phase_value,
new LiteralNode(TokenPos(),
Smi::ZoneHandle(Smi::New(Function::kCtorPhaseInit))));
AstNode* comparison =
new ComparisonNode(TokenPos(), Token::kNE_STRICT,
phase_check,
new LiteralNode(TokenPos(),
Smi::ZoneHandle(Smi::New(0))));
AstNode* guarded_init_statements =
new IfNode(TokenPos(), comparison, init_statements, NULL);
current_block_->statements->Add(guarded_init_statements);
}
// Parsing of initializers done. Now we parse the constructor body
// and add the implicit super call to the super constructor's body
// if necessary.
StaticCallNode* super_call = NULL;
// Look for the super initializer call in the sequence of initializer
// statements. If it exists and is not the last initializer statement,
// we need to create an implicit super call to the super constructor's
// body.
// Thus, iterate over all but the last initializer to see whether
// it's a super constructor call.
for (int i = 0; i < init_statements->length() - 1; i++) {
if (init_statements->NodeAt(i)->IsStaticCallNode()) {
StaticCallNode* static_call =
init_statements->NodeAt(i)->AsStaticCallNode();
if (static_call->function().IsConstructor()) {
super_call = static_call;
break;
}
}
}
if (super_call != NULL) {
// Generate an implicit call to the super constructor's body.
// We need to patch the super _initializer_ call so that it
// saves the evaluated actual arguments in temporary variables.
// The temporary variables are necessary so that the argument
// expressions are not evaluated twice.
ArgumentListNode* ctor_args = super_call->arguments();
// The super initializer call has at least 2 arguments: the
// implicit receiver, and the hidden construction phase.
ASSERT(ctor_args->length() >= 2);
for (int i = 2; i < ctor_args->length(); i++) {
AstNode* arg = ctor_args->NodeAt(i);
if (!IsSimpleLocalOrLiteralNode(arg)) {
LocalVariable* temp =
CreateTempConstVariable(arg->token_pos(), "sca");
AstNode* save_temp = new StoreLocalNode(arg->token_pos(), temp, arg);
ctor_args->SetNodeAt(i, save_temp);
}
}
}
OpenBlock(); // Block to collect constructor body nodes.
intptr_t body_pos = TokenPos();
// Insert the implicit super call to the super constructor body.
if (super_call != NULL) {
ArgumentListNode* initializer_args = super_call->arguments();
const Function& super_ctor = super_call->function();
// Patch the initializer call so it only executes the super initializer.
initializer_args->SetNodeAt(1,
new LiteralNode(body_pos,
Smi::ZoneHandle(Smi::New(Function::kCtorPhaseInit))));
ArgumentListNode* super_call_args = new ArgumentListNode(body_pos);
// First argument is the receiver.
super_call_args->Add(new LoadLocalNode(body_pos, receiver));
// Second argument is the construction phase argument.
AstNode* phase_parameter =
new LiteralNode(body_pos,
Smi::ZoneHandle(Smi::New(Function::kCtorPhaseBody)));
super_call_args->Add(phase_parameter);
super_call_args->set_names(initializer_args->names());
for (int i = 2; i < initializer_args->length(); i++) {
AstNode* arg = initializer_args->NodeAt(i);
if (arg->IsLiteralNode()) {
LiteralNode* lit = arg->AsLiteralNode();
super_call_args->Add(new LiteralNode(body_pos, lit->literal()));
} else {
ASSERT(arg->IsLoadLocalNode() || arg->IsStoreLocalNode());
if (arg->IsLoadLocalNode()) {
const LocalVariable& temp = arg->AsLoadLocalNode()->local();
super_call_args->Add(new LoadLocalNode(body_pos, &temp));
} else if (arg->IsStoreLocalNode()) {
const LocalVariable& temp = arg->AsStoreLocalNode()->local();
super_call_args->Add(new LoadLocalNode(body_pos, &temp));
}
}
}
ASSERT(super_ctor.AreValidArguments(super_call_args->length(),
super_call_args->names(),
NULL));
current_block_->statements->Add(
new StaticCallNode(body_pos, super_ctor, super_call_args));
}
if (CurrentToken() == Token::kLBRACE) {
ConsumeToken();
ParseStatementSequence();
ExpectToken(Token::kRBRACE);
} else if (CurrentToken() == Token::kARROW) {
ErrorMsg("constructors may not return a value");
} else if (IsLiteral("native")) {
ErrorMsg("native constructors not supported");
} else if (CurrentToken() == Token::kSEMICOLON) {
// Some constructors have no function body.
ConsumeToken();
} else {
UnexpectedToken();
}
SequenceNode* ctor_block = CloseBlock();
if (ctor_block->length() > 0) {
// Generate guard around the constructor body code.
LocalVariable* phase_param = LookupPhaseParameter();
AstNode* phase_value = new LoadLocalNode(body_pos, phase_param);
AstNode* phase_check =
new BinaryOpNode(body_pos, Token::kBIT_AND,
phase_value,
new LiteralNode(body_pos,
Smi::ZoneHandle(Smi::New(Function::kCtorPhaseBody))));
AstNode* comparison =
new ComparisonNode(body_pos, Token::kNE_STRICT,
phase_check,
new LiteralNode(body_pos,
Smi::ZoneHandle(Smi::New(0))));
AstNode* guarded_block_statements =
new IfNode(body_pos, comparison, ctor_block, NULL);
current_block_->statements->Add(guarded_block_statements);
}
SequenceNode* statements = CloseBlock();
return statements;
}
// Parser is at the opening parenthesis of the formal parameter
// declaration of the function or constructor.
// Parse the formal parameters and code.
SequenceNode* Parser::ParseFunc(const Function& func,
Array& default_parameter_values) {
TRACE_PARSER("ParseFunc");
Function& saved_innermost_function =
Function::Handle(innermost_function().raw());
innermost_function_ = func.raw();
// TODO(12455) : Need better validation mechanism.
if (func.IsConstructor()) {
SequenceNode* statements = ParseConstructor(func, default_parameter_values);
innermost_function_ = saved_innermost_function.raw();
return statements;
}
ASSERT(!func.IsConstructor());
OpenFunctionBlock(func); // Build local scope for function.
ParamList params;
// An instance closure function may capture and access the receiver, but via
// the context and not via the first formal parameter.
if (func.IsClosureFunction()) {
// The first parameter of a closure function is the closure object.
ASSERT(!func.is_const()); // Closure functions cannot be const.
params.AddFinalParameter(
TokenPos(),
&Symbols::ClosureParameter(),
&Type::ZoneHandle(Type::DynamicType()));
} else if (!func.is_static()) {
// Static functions do not have a receiver.
ASSERT(current_class().raw() == func.Owner());
params.AddReceiver(ReceiverType(current_class()), func.token_pos());
} else if (func.IsFactory()) {
// The first parameter of a factory is the AbstractTypeArguments vector of
// the type of the instance to be allocated.
params.AddFinalParameter(
TokenPos(),
&Symbols::TypeArgumentsParameter(),
&Type::ZoneHandle(Type::DynamicType()));
}
ASSERT((CurrentToken() == Token::kLPAREN) || func.IsGetterFunction());
const bool allow_explicit_default_values = true;
if (!func.IsGetterFunction()) {
ParseFormalParameterList(allow_explicit_default_values, &params);
} else {
// TODO(hausner): Remove this once we no longer support the old
// getter syntax with explicit empty parameter list.
if (CurrentToken() == Token::kLPAREN) {
ConsumeToken();
ExpectToken(Token::kRPAREN);
}
}
// The number of parameters and their type are not yet set in local functions,
// since they are not 'top-level' parsed.
if (func.IsLocalFunction()) {
AddFormalParamsToFunction(&params, func);
}
SetupDefaultsForOptionalParams(&params, default_parameter_values);
ASSERT(AbstractType::Handle(func.result_type()).IsResolved());
ASSERT(func.NumParameters() == params.parameters->length());
// Check whether the function has any field initializer formal parameters,
// which are not allowed in non-constructor functions.
if (params.has_field_initializer) {
for (int i = 0; i < params.parameters->length(); i++) {
ParamDesc& param = (*params.parameters)[i];
if (param.is_field_initializer) {
ErrorMsg(param.name_pos,
"field initializer only allowed in constructors");
}
}
}
// Populate function scope with the formal parameters.
AddFormalParamsToScope(&params, current_block_->scope);
if (FLAG_enable_type_checks &&
(current_block_->scope->function_level() > 0)) {
// We are parsing, but not compiling, a local function.
// The instantiator may be required at run time for generic type checks.
if (IsInstantiatorRequired()) {
// Make sure that the receiver of the enclosing instance function
// (or implicit first parameter of an enclosing factory) is marked as
// captured if type checks are enabled, because they may access it to
// instantiate types.
CaptureInstantiator();
}
}
OpenBlock(); // Open a nested scope for the outermost function block.
if (CurrentToken() == Token::kLBRACE) {
ConsumeToken();
ParseStatementSequence();
ExpectToken(Token::kRBRACE);
} else if (CurrentToken() == Token::kARROW) {
ConsumeToken();
const intptr_t expr_pos = TokenPos();
AstNode* expr = ParseExpr(kAllowConst, kConsumeCascades);
ASSERT(expr != NULL);
current_block_->statements->Add(new ReturnNode(expr_pos, expr));
} else if (IsLiteral("native")) {
ParseNativeFunctionBlock(&params, func);
} else if (func.is_external()) {
// Body of an external method contains a single throw.
const String& function_name = String::ZoneHandle(func.name());
// TODO(regis): For an instance function, pass the receiver to
// NoSuchMethodError.
current_block_->statements->Add(
ThrowNoSuchMethodError(TokenPos(),
current_class(),
function_name,
func.is_static() ?
InvocationMirror::kStatic :
InvocationMirror::kDynamic,
InvocationMirror::kMethod));
} else {
UnexpectedToken();
}