| Index: runtime/vm/parser.cc
|
| ===================================================================
|
| --- runtime/vm/parser.cc (revision 10018)
|
| +++ runtime/vm/parser.cc (working copy)
|
| @@ -452,6 +452,7 @@
|
| }
|
| void Clear() {
|
| has_abstract = false;
|
| + has_external = false;
|
| has_final = false;
|
| has_const = false;
|
| has_static = false;
|
| @@ -480,6 +481,7 @@
|
| return kind == RawFunction::kSetterFunction;
|
| }
|
| bool has_abstract;
|
| + bool has_external;
|
| bool has_final;
|
| bool has_const;
|
| bool has_static;
|
| @@ -1067,6 +1069,7 @@
|
| RawFunction::kSignatureFunction,
|
| /* is_static = */ false,
|
| /* is_const = */ false,
|
| + /* is_external = */ false,
|
| parameter.name_pos));
|
| signature_function.set_owner(current_class());
|
| signature_function.set_result_type(result_type);
|
| @@ -2167,6 +2170,13 @@
|
| current_block_->statements->Add(new ReturnNode(expr_pos, expr));
|
| } else if (IsLiteral("native")) {
|
| ParseNativeFunctionBlock(¶ms, func);
|
| + } else if (func.is_external()) {
|
| + // Body of an external method contains a single throw.
|
| + current_block_->statements->Add(
|
| + new ThrowNode(TokenPos(),
|
| + new LiteralNode(TokenPos(),
|
| + String::ZoneHandle(
|
| + Symbols::New("External implementation missing."))), NULL));
|
| } else {
|
| UnexpectedToken();
|
| }
|
| @@ -2295,6 +2305,10 @@
|
| ErrorMsg(method->name_pos,
|
| "'abstract' method only allowed in class definition");
|
| }
|
| + if (method->has_external && members->is_interface()) {
|
| + ErrorMsg(method->name_pos,
|
| + "'external' method only allowed in class definition");
|
| + }
|
|
|
| if (members->FunctionNameExists(*method->name, method->kind)) {
|
| ErrorMsg(method->name_pos,
|
| @@ -2386,6 +2400,10 @@
|
| 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->IsConstructor() && method->has_const) {
|
| ErrorMsg(method->name_pos,
|
| "const constructor '%s' may not have a function body",
|
| @@ -2431,6 +2449,7 @@
|
| } else if (CurrentToken() == Token::kSEMICOLON) {
|
| if (members->is_interface() ||
|
| method->has_abstract ||
|
| + method->has_external ||
|
| (method->redirect_name != NULL) ||
|
| method->IsConstructor()) {
|
| ConsumeToken();
|
| @@ -2442,6 +2461,7 @@
|
| } else {
|
| if (members->is_interface() ||
|
| method->has_abstract ||
|
| + method->has_external ||
|
| (method->redirect_name != NULL) ||
|
| (method->IsConstructor() && method->has_const)) {
|
| ExpectSemicolon();
|
| @@ -2469,6 +2489,7 @@
|
| function_kind,
|
| method->has_static,
|
| method->has_const,
|
| + method->has_external,
|
| method_pos));
|
| func.set_result_type(*method->type);
|
| func.set_end_token_pos(method_end_pos);
|
| @@ -2495,6 +2516,9 @@
|
| if (field->has_abstract) {
|
| ErrorMsg("keyword 'abstract' not allowed in field declaration");
|
| }
|
| + if (field->has_external) {
|
| + ErrorMsg("keyword 'external' not allowed in field declaration");
|
| + }
|
| if (field->has_factory) {
|
| ErrorMsg("keyword 'factory' not allowed in field declaration");
|
| }
|
| @@ -2543,7 +2567,7 @@
|
| class_field.set_value(Instance::Handle(Object::sentinel()));
|
| String& getter_name = String::Handle(Field::GetterSymbol(*field->name));
|
| getter = Function::New(getter_name, RawFunction::kConstImplicitGetter,
|
| - field->has_static, field->has_final,
|
| + field->has_static, field->has_final, false,
|
| field->name_pos);
|
| getter.set_result_type(*field->type);
|
| members->AddFunction(getter);
|
| @@ -2553,7 +2577,7 @@
|
| if (!field->has_static) {
|
| String& getter_name = String::Handle(Field::GetterSymbol(*field->name));
|
| getter = Function::New(getter_name, RawFunction::kImplicitGetter,
|
| - field->has_static, field->has_final,
|
| + field->has_static, field->has_final, false,
|
| field->name_pos);
|
| ParamList params;
|
| params.AddReceiver(TokenPos());
|
| @@ -2564,7 +2588,7 @@
|
| // Build a setter accessor for non-const fields.
|
| String& setter_name = String::Handle(Field::SetterSymbol(*field->name));
|
| setter = Function::New(setter_name, RawFunction::kImplicitSetter,
|
| - field->has_static, field->has_final,
|
| + field->has_static, field->has_final, false,
|
| field->name_pos);
|
| ParamList params;
|
| params.AddReceiver(TokenPos());
|
| @@ -2618,6 +2642,11 @@
|
| ConsumeToken();
|
| member.has_abstract = true;
|
| }
|
| + if ((CurrentToken() == Token::kEXTERNAL) &&
|
| + (LookaheadToken(1) != Token::kLPAREN)) {
|
| + ConsumeToken();
|
| + member.has_external = true;
|
| + }
|
| if ((CurrentToken() == Token::kSTATIC) &&
|
| (LookaheadToken(1) != Token::kLPAREN)) {
|
| ConsumeToken();
|
| @@ -2939,6 +2968,7 @@
|
| RawFunction::kConstructor,
|
| /* is_static = */ false,
|
| /* is_const = */ false,
|
| + /* is_external = */ false,
|
| class_desc->token_pos()));
|
| ParamList params;
|
| // Add implicit 'this' parameter.
|
| @@ -3057,6 +3087,7 @@
|
| RawFunction::kSignatureFunction,
|
| /* is_static = */ false,
|
| /* is_const = */ false,
|
| + /* is_external = */ false,
|
| alias_name_pos));
|
| signature_function.set_owner(alias_owner);
|
| signature_function.set_result_type(result_type);
|
| @@ -3488,7 +3519,7 @@
|
| // Create a static const getter.
|
| String& getter_name = String::ZoneHandle(Field::GetterSymbol(var_name));
|
| getter = Function::New(getter_name, RawFunction::kConstImplicitGetter,
|
| - is_static, is_final, name_pos);
|
| + is_static, is_final, false, name_pos);
|
| getter.set_result_type(type);
|
| top_level->functions.Add(getter);
|
| } else if (is_final || is_const) {
|
| @@ -3511,6 +3542,11 @@
|
| TRACE_PARSER("ParseTopLevelFunction");
|
| AbstractType& result_type = Type::Handle(Type::DynamicType());
|
| const bool is_static = true;
|
| + bool is_external = false;
|
| + if (CurrentToken() == Token::kEXTERNAL) {
|
| + ConsumeToken();
|
| + is_external = true;
|
| + }
|
| if (CurrentToken() == Token::kVOID) {
|
| ConsumeToken();
|
| result_type = Type::VoidType();
|
| @@ -3547,7 +3583,9 @@
|
| ParseFormalParameterList(allow_explicit_default_values, ¶ms);
|
|
|
| intptr_t function_end_pos = function_pos;
|
| - if (CurrentToken() == Token::kLBRACE) {
|
| + if (is_external) {
|
| + ExpectSemicolon();
|
| + } else if (CurrentToken() == Token::kLBRACE) {
|
| SkipBlock();
|
| function_end_pos = TokenPos();
|
| } else if (CurrentToken() == Token::kARROW) {
|
| @@ -3562,7 +3600,7 @@
|
| }
|
| Function& func = Function::Handle(
|
| Function::New(func_name, RawFunction::kRegularFunction,
|
| - is_static, false, function_pos));
|
| + is_static, false, is_external, function_pos));
|
| func.set_result_type(result_type);
|
| func.set_end_token_pos(function_end_pos);
|
| AddFormalParamsToFunction(¶ms, func);
|
| @@ -3644,7 +3682,7 @@
|
| Function::New(accessor_name,
|
| is_getter? RawFunction::kGetterFunction :
|
| RawFunction::kSetterFunction,
|
| - is_static, false, accessor_pos));
|
| + is_static, false, false, accessor_pos));
|
| func.set_result_type(result_type);
|
| AddFormalParamsToFunction(¶ms, func);
|
| top_level->functions.Add(func);
|
| @@ -4513,6 +4551,12 @@
|
| // a function declaration. Token position remains unchanged.
|
| bool Parser::IsFunctionDeclaration() {
|
| const intptr_t saved_pos = TokenPos();
|
| + bool is_external = false;
|
| + if (is_top_level_ && (CurrentToken() == Token::kEXTERNAL)) {
|
| + // Skip over 'external' for top-level function declarations.
|
| + is_external = true;
|
| + ConsumeToken();
|
| + }
|
| if (IsIdentifier() && (LookaheadToken(1) == Token::kLPAREN)) {
|
| // Possibly a function without explicit return type.
|
| ConsumeToken(); // Consume function identifier.
|
| @@ -4531,7 +4575,8 @@
|
| SkipToMatchingParenthesis();
|
| if ((CurrentToken() == Token::kLBRACE) ||
|
| (CurrentToken() == Token::kARROW) ||
|
| - (is_top_level_ && IsLiteral("native"))) {
|
| + (is_top_level_ && IsLiteral("native")) ||
|
| + is_external) {
|
| SetPosition(saved_pos);
|
| return true;
|
| }
|
|
|