blob: d409f54433f13d12badd2403591fc39affcf402a [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/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/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.");
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::CreateExpressionTempVar(intptr_t token_pos) {
return new LocalVariable(token_pos,
Symbols::ExprTemp(),
Type::ZoneHandle(Type::DynamicType()));
}
LocalVariable* ParsedFunction::CreateArrayLiteralVar(intptr_t token_pos) {
return new LocalVariable(token_pos,
Symbols::ArrayLiteralVar(),
Type::ZoneHandle(Type::ArrayType()));
}
void ParsedFunction::SetNodeSequence(SequenceNode* node_sequence) {
ASSERT(node_sequence_ == NULL);
ASSERT(node_sequence != NULL);
node_sequence_ = node_sequence;
}
LocalVariable* ParsedFunction::GetSavedArgumentsDescriptorVar() const {
const int num_parameters = function().NumParameters();
LocalScope* scope = node_sequence()->scope();
if (scope->num_variables() > num_parameters) {
LocalVariable* saved_args_desc_var = scope->VariableAt(num_parameters);
ASSERT(saved_args_desc_var != NULL);
// The scope of the formal parameters may also contain at this position
// an alias for the saved arguments descriptor variable of the enclosing
// function (check its scope owner) or an internal variable such as the
// expression temp variable or the saved entry context variable (check its
// name).
if ((saved_args_desc_var->owner() == scope) &&
saved_args_desc_var->name().StartsWith(
Symbols::SavedArgDescVarPrefix())) {
return saved_args_desc_var;
}
}
return NULL;
}
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();
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[kLastParamSlotIndex + num_params - 1 - i] and
// local variable j will be at fp[kFirstLocalSlotIndex - j].
ASSERT(GetSavedArgumentsDescriptorVar() == NULL);
first_parameter_index_ = kLastParamSlotIndex + num_params - 1;
first_stack_local_index_ = kFirstLocalSlotIndex;
num_copied_params_ = 0;
} else {
// Parameter i will be at fp[kFirstLocalSlotIndex - i] and local variable
// j will be at fp[kFirstLocalSlotIndex - num_params - j].
// The saved arguments descriptor variable must be allocated similarly to
// a parameter, so that it gets both a frame slot and a context slot when
// captured.
if (GetSavedArgumentsDescriptorVar() != NULL) {
num_params += 1;
}
first_parameter_index_ = kFirstLocalSlotIndex;
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)
: try_block_(try_block),
inlined_finally_nodes_(),
outer_try_block_(outer_try_block) { }
TryBlocks* outer_try_block() const { return outer_try_block_; }
Block* try_block() const { return try_block_; }
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_;
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)
: script_(Script::Handle(script.raw())),
tokens_iterator_(TokenStream::Handle(script.tokens()), 0),
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()),
current_class_(Class::Handle()),
library_(Library::Handle(library.raw())),
try_blocks_list_(NULL) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!library.IsNull());
}
// For parsing a function.
Parser::Parser(const Script& script,
ParsedFunction* parsed_function,
intptr_t token_position)
: script_(Script::Handle(script.raw())),
tokens_iterator_(TokenStream::Handle(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(parsed_function->function().raw())),
current_class_(Class::Handle(parsed_function->function().Owner())),
library_(Library::Handle(Class::Handle(
parsed_function->function().origin()).library())),
try_blocks_list_(NULL) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!current_function().IsNull());
if (FLAG_enable_type_checks) {
EnsureExpressionTemp();
}
}
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);
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 {
LiteralToken& token = LiteralToken::Handle();
token ^= tokens_iterator_.CurrentToken();
ASSERT(token.kind() == Token::kDOUBLE);
return reinterpret_cast<RawDouble*>(token.value());
}
RawInteger* Parser::CurrentIntegerLiteral() const {
LiteralToken& token = LiteralToken::Handle();
token ^= tokens_iterator_.CurrentToken();
ASSERT(token.kind() == Token::kINTEGER);
return reinterpret_cast<RawInteger*>(token.value());
}
// 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 Type* receiver_type) {
ASSERT(this->parameters->is_empty());
AddFinalParameter(receiver_type->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;
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;
Token::Kind operator_token;
const AbstractType* type;
intptr_t name_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_;
}
RawClass* clazz() const {
return clazz_.raw();
}
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::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());
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::kConstImplicitGetter:
node_sequence = parser.ParseStaticConstGetter(func);
break;
case RawFunction::kMethodExtractor:
node_sequence = parser.ParseMethodExtractor(func);
break;
default:
UNREACHABLE();
}
parsed_function->set_array_literal_var(
ParsedFunction::CreateArrayLiteralVar(func.token_pos()));
node_sequence->scope()->AddVariable(parsed_function->array_literal_var());
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);
}
// TODO(regis): Since a const variable is implicitly final,
// rename ParseStaticConstGetter to ParseStaticFinalGetter and
// rename kConstImplicitGetter to kImplicitFinalGetter.
SequenceNode* Parser::ParseStaticConstGetter(const Function& func) {
TRACE_PARSER("ParseStaticConstGetter");
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));
// 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): 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(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(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(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::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::kTryResolve :
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::kConstImplicitGetter));
}
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);
}
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;
}
LocalVariable* Parser::BuildArrayTempLocal(intptr_t token_pos) {
char name[64];
OS::SNPrint(name, 64, ":arrlit%"Pd, token_pos);
LocalVariable* temp =
new LocalVariable(token_pos,
String::ZoneHandle(Symbols::New(name)),
Type::ZoneHandle(Type::ArrayType()));
current_block_->scope->AddVariable(temp);
return temp;
}
StaticCallNode* Parser::BuildInvocationMirrorAllocation(
intptr_t call_pos,
const String& function_name,
const ArgumentListNode& function_args) {
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()),
*BuildArrayTempLocal(call_pos));
for (intptr_t i = 0; i < function_args.length(); i++) {
args_array->AddElement(function_args.NodeAt(i));
}
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) {
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));
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) {
if (node->IsLiteralNode()) {
return true;
}
if (node->IsLoadLocalNode() && !node->AsLoadLocalNode()->HasPseudo()) {
return true;
}
return false;
}
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 if (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()) {
return new StaticGetterNode(
field_pos, implicit_argument, true, super_class, field_name);
}
}
if (super_getter.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) {
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& ctor_name = String::Handle(super_class.Name());
ctor_name = String::Concat(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);
const Function& super_ctor = Function::ZoneHandle(
super_class.LookupConstructor(ctor_name));
if (super_ctor.IsNull()) {
ErrorMsg(supercall_pos,
"unresolved implicit call to super constructor '%s()'",
String::Handle(super_class.Name()).ToCString());
}
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());
}
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);
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);
}
}
}
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);
}
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());
const intptr_t ctor_pos = TokenPos();
OpenFunctionBlock(func);
const Class& cls = Class::Handle(func.Owner());
LocalVariable* receiver = new LocalVariable(
ctor_pos,
Symbols::This(),
Type::ZoneHandle(Type::DynamicType()));
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(cls, receiver, &initialized_fields);
receiver->set_invisible(false);
GenerateSuperConstructorCall(cls, receiver);
CheckConstFieldsInitialized(cls);
// 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);
}
}
// 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());
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(TokenPos()));
// 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.
// 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(TokenPos(),
Smi::ZoneHandle(Smi::New(Function::kCtorPhaseInit))));
ArgumentListNode* super_call_args = new ArgumentListNode(TokenPos());
// First argument is the receiver.
super_call_args->Add(new LoadLocalNode(TokenPos(), receiver));
// Second argument is the construction phase argument.
AstNode* phase_parameter =
new LiteralNode(TokenPos(),
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(TokenPos(), lit->literal()));
} else {
ASSERT(arg->IsLoadLocalNode() || arg->IsStoreLocalNode());
if (arg->IsLoadLocalNode()) {
const LocalVariable& temp = arg->AsLoadLocalNode()->local();
super_call_args->Add(new LoadLocalNode(TokenPos(), &temp));
} else if (arg->IsStoreLocalNode()) {
const LocalVariable& temp = arg->AsStoreLocalNode()->local();
super_call_args->Add(new LoadLocalNode(TokenPos(), &temp));
}
}
}
ASSERT(super_ctor.AreValidArguments(super_call_args->length(),
super_call_args->names(),
NULL));
current_block_->statements->Add(
new StaticCallNode(TokenPos(), 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(TokenPos(), phase_param);
AstNode* phase_check =
new BinaryOpNode(TokenPos(), Token::kBIT_AND,
phase_value,
new LiteralNode(TokenPos(),
Smi::ZoneHandle(Smi::New(Function::kCtorPhaseBody))));
AstNode* comparison =
new ComparisonNode(TokenPos(), Token::kNE_STRICT,
phase_check,
new LiteralNode(TokenPos(),
Smi::ZoneHandle(Smi::New(0))));
AstNode* guarded_block_statements =
new IfNode(TokenPos(), 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();
// Check to ensure we don't have classes with native fields in libraries
// which do not have a native resolver. This check is delayed until the class
// is actually used. Invocation of a function in the class is the first point
// of use. Access of const static fields in the class do not trigger an error.
if (current_class().num_native_fields() != 0) {
const Library& lib = Library::Handle(current_class().library());
if (lib.native_entry_resolver() == NULL) {
const String& cls_name = String::Handle(current_class().Name());
const String& lib_name = String::Handle(lib.url());
ErrorMsg(current_class().token_pos(),
"class '%s' is trying to extend a native fields class, "
"but library '%s' has no native resolvers",
cls_name.ToCString(), lib_name.ToCString());
}
}
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(TokenPos()));
} 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();
}
SequenceNode* body = CloseBlock();
current_block_->statements->Add(body);
innermost_function_ = saved_innermost_function.raw();
return CloseBlock();
}
void Parser::SkipIf(Token::Kind token) {
if (CurrentToken() == token) {
ConsumeToken();
}
}
// Skips tokens up to matching closing parenthesis.
void Parser::SkipToMatchingParenthesis() {
ASSERT(CurrentToken() == Token::kLPAREN);
int level = 0;
do {
if (CurrentToken() == Token::kLPAREN) {
level++;
} else if (CurrentToken() == Token::kRPAREN) {
level--;
}
ConsumeToken();
} while ((level > 0) && (CurrentToken() != Token::kEOS));
}
void Parser::SkipInitializers() {
ASSERT(CurrentToken() == Token::kCOLON);
do {
ConsumeToken(); // Colon or comma.
if (CurrentToken() == Token::kSUPER) {
ConsumeToken();
if (CurrentToken() == Token::kPERIOD) {
ConsumeToken();
ExpectIdentifier("identifier expected");
}
if (CurrentToken() != Token::kLPAREN) {
ErrorMsg("'(' expected");
}
SkipToMatchingParenthesis();
} else {
SkipIf(Token::kTHIS);
SkipIf(Token::kPERIOD);
ExpectIdentifier("identifier expected");
ExpectToken(Token::kASSIGN);
SetAllowFunctionLiterals(false);
SkipExpr();
SetAllowFunctionLiterals(true);
}
} while (CurrentToken() == Token::kCOMMA);
}
void Parser::ParseQualIdent(QualIdent* qual_ident) {
TRACE_PARSER("ParseQualIdent");
ASSERT(IsIdentifier());
ASSERT(!current_class().IsNull());
qual_ident->ident_pos = TokenPos();
qual_ident->ident = CurrentLiteral();
qual_ident->lib_prefix = NULL;
ConsumeToken();
if (CurrentToken() == Token::kPERIOD) {
// An identifier cannot be resolved in a local scope when top level parsing.
if (is_top_level_ ||
!ResolveIdentInLocalScope(qual_ident->ident_pos,
*(qual_ident->ident),
NULL)) {
LibraryPrefix& lib_prefix = LibraryPrefix::ZoneHandle();
lib_prefix = current_class().LookupLibraryPrefix(*(qual_ident->ident));
if (!lib_prefix.IsNull()) {
// We have a library prefix qualified identifier, unless the prefix is
// shadowed by a type parameter in scope.
if (current_class().IsNull() ||
(current_class().LookupTypeParameter(*(qual_ident->ident),
TokenPos()) ==
TypeParameter::null())) {
ConsumeToken(); // Consume the kPERIOD token.
qual_ident->lib_prefix = &lib_prefix;
qual_ident->ident_pos = TokenPos();
qual_ident->ident =
ExpectIdentifier("identifier expected after '.'");
}
}
}
}
}
void Parser::ParseMethodOrConstructor(ClassDesc* members, MemberDesc* method) {
TRACE_PARSER("ParseMethodOrConstructor");
ASSERT(CurrentToken() == Token::kLPAREN || method->IsGetter());
intptr_t method_pos = this->TokenPos();
ASSERT(method->type != NULL);
ASSERT(method->name_pos > 0);
ASSERT(current_member_ == method);
if (method->has_var) {
ErrorMsg(method->name_pos, "keyword var not allowed for methods");
}
if (method->has_final) {
ErrorMsg(method->name_pos, "'final' not allowed for methods");
}
if (method->has_abstract && method->has_static) {
ErrorMsg(method->name_pos,
"static method '%s' cannot be abstract",
method->name->ToCString());
}
if (method->has_const && !method->IsFactoryOrConstructor()) {
ErrorMsg(method->name_pos, "'const' not allowed for methods");
}
if (method->has_abstract && method->IsFactoryOrConstructor()) {
ErrorMsg(method->name_pos, "constructor cannot be abstract");
}
if (method->has_const && method->IsConstructor()) {
Class& cls = Class::Handle(library_.LookupClass(members->class_name()));
cls.set_is_const();
}
// Parse the formal parameters.
const bool are_implicitly_final = method->has_const;
const bool allow_explicit_default_values = true;
const intptr_t formal_param_pos = TokenPos();
method->params.Clear();
// Static functions do not have a receiver.
// The first parameter of a factory is the AbstractTypeArguments vector of
// the type of the instance to be allocated.
if (!method->has_static || method->IsConstructor()) {
method->params.AddReceiver(ReceiverType(formal_param_pos));
} else if (method->IsFactory()) {
method->params.AddFinalParameter(
formal_param_pos,
&Symbols::TypeArgumentsParameter(),
&Type::ZoneHandle(Type::DynamicType()));
}
// Constructors have an implicit parameter for the construction phase.
if (method->IsConstructor()) {
method->params.AddFinalParameter(
TokenPos(),
&Symbols::PhaseParameter(),
&Type::ZoneHandle(Type::SmiType()));
}
if (are_implicitly_final) {
method->params.SetImplicitlyFinal();
}
if (!method->IsGetter()) {
ParseFormalParameterList(allow_explicit_default_values, &method->params);
}
// Now that we know the parameter list, we can distinguish between the
// unary and binary operator -.
if (method->has_operator) {
if ((method->operator_token == Token::kSUB) &&
(method->params.num_fixed_parameters == 1)) {
// Patch up name for unary operator - so it does not clash with the
// name for binary operator -.
method->operator_token = Token::kNEGATE;
*method->name = Symbols::New(Token::Str(Token::kNEGATE));
}
CheckOperatorArity(*method);
}
if (members->FunctionNameExists(*method->name, method->kind)) {
ErrorMsg(method->name_pos,
"field or method '%s' already defined", method->name->ToCString());
}
// Mangle the name for getter and setter functions and check function
// arity.
if (method->IsGetter() || method->IsSetter()) {
int expected_num_parameters = 0;
if (method->IsGetter()) {
expected_num_parameters = (method->has_static) ? 0 : 1;
method->name = &String::ZoneHandle(Field::GetterSymbol(*method->name));
} else {
ASSERT(method->IsSetter());
expected_num_parameters = (method->has_static) ? 1 : 2;
method->name = &String::ZoneHandle(Field::SetterSymbol(*method->name));
}
if ((method->params.num_fixed_parameters != expected_num_parameters) ||
(method->params.num_optional_parameters != 0)) {
ErrorMsg(method->name_pos, "illegal %s parameters",
method->IsGetter() ? "getter" : "setter");
}
}
// Parse redirecting factory constructor.
Type& redirection_type = Type::Handle();
String& redirection_identifier = String::Handle();
if (method->IsFactory() && (CurrentToken() == Token::kASSIGN)) {
ConsumeToken();
const intptr_t type_pos = TokenPos();
const AbstractType& type = AbstractType::Handle(
ParseType(ClassFinalizer::kTryResolve));
if (!type.IsMalformed() &&
(type.IsTypeParameter() || type.IsDynamicType())) {
// Replace the type with a malformed type and compile a throw when called.
redirection_type = ClassFinalizer::NewFinalizedMalformedType(
Error::Handle(), // No previous error.
current_class(),
type_pos,
ClassFinalizer::kTryResolve, // No compile-time error.
"factory '%s' may not redirect to %s'%s'",
method->name->ToCString(),
type.IsTypeParameter() ? "type parameter " : "",
type.IsTypeParameter() ?
String::Handle(type.UserVisibleName()).ToCString() : "dynamic");
} else {
redirection_type ^= type.raw();
}
if (CurrentToken() == Token::kPERIOD) {
// Named constructor or factory.
ConsumeToken();
redirection_identifier = ExpectIdentifier("identifier expected")->raw();
}
} else if (CurrentToken() == Token::kCOLON) {
// Parse initializers.
if (!method->IsConstructor()) {
ErrorMsg("initializers only allowed on constructors");
}
if ((LookaheadToken(1) == Token::kTHIS) &&
((LookaheadToken(2) == Token::kLPAREN) ||
LookaheadToken(4) == Token::kLPAREN)) {
// Redirected constructor: either this(...) or this.xxx(...).
if (method->params.has_field_initializer) {
// Constructors that redirect to another constructor must not
// initialize any fields using field initializer parameters.
ErrorMsg(formal_param_pos, "Redirecting constructor "
"may not use field initializer parameters");
}
ConsumeToken(); // Colon.
ExpectToken(Token::kTHIS);
String& redir_name = String::ZoneHandle(
String::Concat(members->class_name(), Symbols::Dot()));
if (CurrentToken() == Token::kPERIOD) {
ConsumeToken();
redir_name = String::Concat(redir_name,
*ExpectIdentifier("constructor name expected"));
}
method->redirect_name = &redir_name;
if (CurrentToken() != Token::kLPAREN) {
ErrorMsg("'(' expected");
}
SkipToMatchingParenthesis();
} else {
SkipInitializers();
}
}
// Only constructors can redirect to another method.
ASSERT((method->redirect_name == NULL) || method->IsConstructor());
intptr_t method_end_pos = method_pos;
if ((CurrentToken() == Token::kLBRACE) ||
(CurrentToken() == Token::kARROW)) {
if (method->has_abstract) {
ErrorMsg(method->name_pos,
"abstract method '%s' may not have a function body",
method->name->ToCString());
} else if (method->has_external) {
ErrorMsg(method->name_pos,
"external method '%s' may not have a function body",
method->name->ToCString());
} else if (method->IsFactoryOrConstructor() && method->has_const) {
ErrorMsg(method->name_pos,
"const constructor or factory '%s' may not have a function body",
method->name->ToCString());
}
if (method->redirect_name != NULL) {
ErrorMsg(method->name_pos,
"Constructor with redirection may not have a function body");
}
if (CurrentToken() == Token::kLBRACE) {
SkipBlock();
} else {
ConsumeToken();
SkipExpr();
ExpectSemicolon();
}
method_end_pos = TokenPos() - 1;
} else if (IsLiteral("native")) {
if (method->has_abstract) {
ErrorMsg(method->name_pos,
"abstract method '%s' may not have a function body",
method->name->ToCString());
} else if (method->IsFactoryOrConstructor() && method->has_const) {
ErrorMsg(method->name_pos,
"const constructor or factory '%s' may not be native",
method->name->ToCString());
}
if (method->redirect_name != NULL) {
ErrorMsg(method->name_pos,
"Constructor with redirection may not have a function body");
}
ParseNativeDeclaration();
} else {
// We haven't found a method body. Issue error if one is required.
const bool must_have_body =
method->has_static &&
!method->has_external &&
redirection_type.IsNull();
if (must_have_body) {
ErrorMsg(method->name_pos,
"function body expected for method '%s'",
method->name->ToCString());
}
if (CurrentToken() == Token::kSEMICOLON) {
ConsumeToken();
if (!method->has_static &&
!method->has_external &&
!method->IsConstructor()) {
// Methods, getters and setters without a body are
// implicitly abstract.
method->has_abstract = true;
<