Files
sdk/runtime/vm/parser_test.cc
T
hausner@google.com 8e29370a1b BREAKING CHANGE: enforce part of directive
For historical reasons, the VM is currently too lenient when parsing library parts. Files that get loaded through a 'part' directive must start with a 'part of libraryname;' clause. The VM so far has not reported an error if the clause is missing.

This change enforces the grammar as the Spec mandates it. Library parts that do not start with 'part of' will no longer compile.

R=srdjan@google.com

Review URL: https://codereview.chromium.org//14791005

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@22278 260f80e4-7a28-3924-810f-c04153c831b5
2013-05-01 20:46:48 +00:00

170 lines
5.7 KiB
C++

// Copyright (c) 2011, 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/ast_printer.h"
#include "vm/class_finalizer.h"
#include "vm/longjump.h"
#include "vm/object.h"
#include "vm/parser.h"
#include "vm/symbols.h"
#include "vm/unit_test.h"
namespace dart {
void DumpFunction(const Library& lib, const char* cname, const char* fname) {
const String& classname = String::Handle(Symbols::New(cname));
Class& cls = Class::Handle(lib.LookupClass(classname));
EXPECT(!cls.IsNull());
String& funcname = String::Handle(String::New(fname));
Function& function = Function::ZoneHandle(cls.LookupStaticFunction(funcname));
EXPECT(!function.IsNull());
bool retval;
Isolate* isolate = Isolate::Current();
EXPECT(isolate != NULL);
LongJump* base = isolate->long_jump_base();
LongJump jump;
isolate->set_long_jump_base(&jump);
if (setjmp(*jump.Set()) == 0) {
ParsedFunction* parsed_function = new ParsedFunction(function);
Parser::ParseFunction(parsed_function);
EXPECT(parsed_function->node_sequence() != NULL);
printf("Class %s function %s:\n", cname, fname);
AstPrinter::PrintFunctionNodes(*parsed_function);
retval = true;
} else {
retval = false;
}
EXPECT(retval);
isolate->set_long_jump_base(base);
}
void CheckField(const Library& lib,
const char* class_name,
const char* field_name,
bool expect_static,
bool is_final) {
const String& classname = String::Handle(Symbols::New(class_name));
Class& cls = Class::Handle(lib.LookupClass(classname));
EXPECT(!cls.IsNull());
String& fieldname = String::Handle(String::New(field_name));
String& functionname = String::Handle();
Function& function = Function::Handle();
Field& field = Field::Handle();
if (expect_static) {
field ^= cls.LookupStaticField(fieldname);
functionname ^= Field::GetterName(fieldname);
function ^= cls.LookupStaticFunction(functionname);
EXPECT(function.IsNull());
functionname ^= Field::SetterName(fieldname);
function ^= cls.LookupStaticFunction(functionname);
EXPECT(function.IsNull());
} else {
field ^= cls.LookupInstanceField(fieldname);
functionname ^= Field::GetterName(fieldname);
function ^= cls.LookupDynamicFunction(functionname);
EXPECT(!function.IsNull());
functionname ^= Field::SetterName(fieldname);
function ^= cls.LookupDynamicFunction(functionname);
EXPECT(is_final ? function.IsNull() : !function.IsNull());
}
EXPECT(!field.IsNull());
EXPECT_EQ(field.is_static(), expect_static);
}
void CheckFunction(const Library& lib,
const char* class_name,
const char* function_name,
bool expect_static) {
const String& classname = String::Handle(Symbols::New(class_name));
Class& cls = Class::Handle(lib.LookupClass(classname));
EXPECT(!cls.IsNull());
String& functionname = String::Handle(String::New(function_name));
Function& function = Function::Handle();
if (expect_static) {
function ^= cls.LookupStaticFunction(functionname);
} else {
function ^= cls.LookupDynamicFunction(functionname);
}
EXPECT(!function.IsNull());
}
TEST_CASE(ParseClassDefinition) {
const char* script_chars =
"class C { } \n"
"class A { \n"
" var f0; \n"
" int f1; \n"
" final f2; \n"
" final int f3, f4; \n"
" static String s1, s2; \n"
" static const int s3 = 8675309; \n"
" static bar(i, [var d = 5]) { return 77; } \n"
" static foo() native \"native_function_name\"; \n"
"} \n";
String& url = String::Handle(String::New("dart-test:Parser_TopLevel"));
String& source = String::Handle(String::New(script_chars));
Script& script = Script::Handle(Script::New(url,
source,
RawScript::kScriptTag));
Library& lib = Library::ZoneHandle(Library::CoreLibrary());
script.Tokenize(String::Handle(String::New("")));
Parser::ParseCompilationUnit(lib, script);
EXPECT(ClassFinalizer::FinalizePendingClasses());
CheckField(lib, "A", "f1", false, false);
CheckField(lib, "A", "f2", false, true);
CheckField(lib, "A", "f3", false, true);
CheckField(lib, "A", "f4", false, true);
CheckField(lib, "A", "s1", true, false);
CheckField(lib, "A", "s2", true, false);
CheckField(lib, "A", "s3", true, true);
CheckFunction(lib, "A", "bar", true);
CheckFunction(lib, "A", "foo", true);
}
TEST_CASE(Parser_TopLevel) {
const char* script_chars =
"class A extends B { \n"
" static bar(var i, [var d = 5]) { return 77; } \n"
" static foo() { return 42; } \n"
" static baz(var i) { var q = 5; return i + q; } \n"
"} \n"
" \n"
"class B { \n"
" static bam(k) { return A.foo(); } \n"
"} \n";
String& url = String::Handle(String::New("dart-test:Parser_TopLevel"));
String& source = String::Handle(String::New(script_chars));
Script& script = Script::Handle(Script::New(url,
source,
RawScript::kScriptTag));
Library& lib = Library::ZoneHandle(Library::CoreLibrary());
script.Tokenize(String::Handle(String::New("")));
Parser::ParseCompilationUnit(lib, script);
EXPECT(ClassFinalizer::FinalizePendingClasses());
DumpFunction(lib, "A", "foo");
DumpFunction(lib, "A", "bar");
DumpFunction(lib, "A", "baz");
DumpFunction(lib, "B", "bam");
}
} // namespace dart