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; |
} |