Index: runtime/vm/parser.cc |
=================================================================== |
--- runtime/vm/parser.cc (revision 9985) |
+++ 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; |
@@ -1065,6 +1067,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); |
@@ -2165,6 +2168,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(); |
} |
@@ -2293,6 +2303,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, |
@@ -2384,6 +2398,10 @@ |
ErrorMsg(method->name_pos, |
"abstract method '%s' may not have function body", |
method->name->ToCString()); |
+ } else if (method->has_external) { |
+ ErrorMsg(method->name_pos, |
+ "external method '%s' may not have function body", |
+ method->name->ToCString()); |
} else if (method->IsConstructor() && method->has_const) { |
ErrorMsg(method->name_pos, |
"const constructor '%s' may not have function body", |
@@ -2421,6 +2439,7 @@ |
} else if (CurrentToken() == Token::kSEMICOLON) { |
if (members->is_interface() || |
method->has_abstract || |
+ method->has_external || |
(method->redirect_name != NULL) || |
method->IsConstructor()) { |
ConsumeToken(); |
@@ -2432,6 +2451,7 @@ |
} else { |
if (members->is_interface() || |
method->has_abstract || |
+ method->has_external || |
(method->redirect_name != NULL) || |
(method->IsConstructor() && method->has_const)) { |
ExpectSemicolon(); |
@@ -2459,6 +2479,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); |
@@ -2530,7 +2551,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); |
@@ -2540,7 +2561,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()); |
@@ -2551,7 +2572,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()); |
@@ -2605,6 +2626,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(); |
@@ -2921,6 +2947,7 @@ |
RawFunction::kConstructor, |
/* is_static = */ false, |
/* is_const = */ false, |
+ /* is_external = */ false, |
class_desc->token_pos())); |
ParamList params; |
// Add implicit 'this' parameter. |
@@ -3039,6 +3066,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); |
@@ -3468,7 +3496,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) { |
@@ -3491,6 +3519,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(); |
@@ -3527,7 +3560,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) { |
@@ -3542,7 +3577,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); |
@@ -3624,7 +3659,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); |
@@ -4470,6 +4505,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. |
@@ -4488,7 +4529,8 @@ |
SkipToMatchingParenthesis(); |
if ((CurrentToken() == Token::kLBRACE) || |
(CurrentToken() == Token::kARROW) || |
- (is_top_level_ && IsLiteral("native"))) { |
+ (is_top_level_ && IsLiteral("native")) || |
+ (is_external && (CurrentToken() == Token::kSEMICOLON))) { |
hausner
2012/07/30 16:22:41
I don't think you need to check for the semicolon
Ivan Posva
2012/07/30 22:33:33
Done.
|
SetPosition(saved_pos); |
return true; |
} |