// 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/unit_test.h" namespace dart { void DumpFunction(const Library& lib, const char* cname, const char* fname) { const String& classname = String::Handle(String::NewSymbol(cname)); Class& cls = Class::Handle(lib.LookupClass(classname)); EXPECT(!cls.IsNull()); String& funcname = String::Handle(String::New(fname)); Function& function = Function::Handle(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(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(String::NewSymbol(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(String::NewSymbol(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 final 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::kSource)); 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); // No field entries are added for static const fields. String& fieldname = String::Handle(String::New("s3")); const String& classname = String::Handle(String::NewSymbol("A")); const Class& cls = Class::Handle(lib.LookupClass(classname)); const Field& field = Field::Handle(cls.LookupStaticField(fieldname)); EXPECT(!field.IsNull()); Object& val = Object::Handle(field.value()); // The static const field initializer is not evaluated and the field // value is not initialized until the field is referenced by code that // is compiled. EXPECT(val.raw() == Object::sentinel()); 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::kSource)); 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