import browser.document; // for the global document object (extern) declaration import std.conv; // delegate should work, as should global variables. void delegate(string) writeln; void main() { if(document) // detecting javascript features should work. FIXME: add test for &obj.func too // browser environment writeln = (string s) { document.write(s ~ "
"); }; // testing literal while we're at it else // dmdscript writeln = (string s) { println(s); }; assert(writeln); if(0) { // this doesn't have to be removed, but it would be nice if it was. string deadCode; deadCode = "was this eliminated by dmd?"; } // static variables assert(staticVariableTest() == 1); assert(staticVariableTest() == 2); assert(staticVariableTest() == 3); testScopeSuccess(true); try { testScopeSuccess(false); } catch(Exception e) {} // silence what it threw // note that local variables in our scopes are unique only thanks to D mangling, since JS doesn't have scope statements like we do here. // nevertheless, local variables should work like you expect. // test scope(exit) writeln("going into a new scope"); { // our own scope scope(exit) writeln("exiting our scope (print me second)"); writeln("inside the scope"); writeln("adding another scope exit"); scope(exit) writeln("exiting our scope (print me first)"); writeln("just about to leave"); } writeln("out of our scope"); // associative arrays string[string] associativeArray; associativeArray["cool"] = "sweet"; assert(associativeArray["cool"] == "sweet"); associativeArray["item.with.dot"] = "yay"; assert(associativeArray["item.with.dot"] == "yay"); associativeArray = ["a" : "first", "b" : "second"]; assert(associativeArray["a"] == "first"); assert(associativeArray["b"] == "second"); assert("cool" !in associativeArray); associativeArray = null; // should come out as = {}; to preserve type in JS int[int] intAa; intAa[4] = 10; intAa[9] = 20; assert(intAa[4] == 10); assert(intAa[9] == 20); assert(3 !in intAa); // string indexing and slicing string teststr = "hello, world"; assert(teststr == "hello, world"); assert(teststr[0 .. 5] == "hello"); assert(teststr[$ - 5 .. $] == "world"); assert(teststr[5] == ','); // integer math int b = 10; int c = 15; assert(c / b == 1); // explicit casts to int should truncate float e = 33.343; assert(cast(int) (e) == 33); e = 33.786; assert(cast(int) (e) == 33); // not round MyBase o2 = new MyOtherClass(); // constructors should work MyBase o = new MyClass(); // dynamic casting assert(cast(MyClass) o2 is null); // is null should work too btw assert(cast(MyClass) o !is null); // virtual functions assert(o.myName() == "my class"); // overridden assert(o2.overrideme() == "something"); // not overridden; this is the result of the base class // operators // FIXME: D apparently constant folded these already! Blast you, good compiler // int assert(10 < 30); assert(30 > 10); assert(10 == 10); assert(15 != 10); // bool // if it compiles as D, it should work like we typically expect assert(1 == true); assert(0 == false); assert(true == true); assert(false == false); // string (ought to use the native javascript operator) assert("hello" == "hello"); assert("hello" != "world"); // array (will have to use a runtime function since JS == doesn't work this way, but you don't need to know that to use it) assert([1,2,3] == [1,2,3]); assert([1,2,3] != [1,2]); // end of dmd being too eager to please // array semantics auto arr = [1, 2, 3]; appendToArray(arr); assert(arr.length == 3); assert(arr == [1,2,3]); // the append function should not have changed our slice assert(arr[0] == 1); assert(arr[$-1] == 3); arr = null; assert(arr.length == 0); // this should not throw; = null is implemented as = [] to preserve array properties //assert(arr is null); // this is a tricky one... it *should* pass, because it would in regular D, but should *not* actually === null in javascript, because then it isn't an array anymore. arr ~= 10; assert(arr.length == 1); assert(arr[0] == 10); arr.length = 0; assert(arr.length == 0); // assert(arr[0] throws RangeError); // FIXME: make this test actually work, and pass too. Though, is this really defined? I guess it is; D has bounds checked arrays so it should throw. If I can't make it happen easily though, meh, not a dealbreaker. // ref functions int refInt = 1; refTest(refInt); // order of declaration should NOT matter btw assert(refInt == 2); // we should have been updated // nested functions void nest() { // nested functions should have read/write access to the outer scope assert(refInt == 2); refInt++; assert(refInt == 3); } nest(); // the nested function should work here assert(refInt == 3); // and save to the outer scope // exceptions try { throw new Exception("test"); assert(0); // ensure throw works } catch(Error e) { // make sure we run the right catch block based on dynamic type assert(0); } catch(Exception e) { assert(e.msg == "test"); } catch(Throwable t) { assert(0); } // exception propagation try { exceptionTest(); } catch(Exception e) { assert(e.msg == "test 2"); } int finallyTest; try { finallyTest = 20; finallyTest += 40; } catch(Throwable t) { assert(0); // the try should not have thrown } finally { assert(finallyTest == 60); writeln("outer finally ran"); } try { finallyTest += 20; assert(finallyTest == 80); // try without catch should work } finally { writeln("naked finally"); } // struct tests testStructSemantics!StructSemanticTest(); testStructSemantics!StructSemanticTestWithPostBlit(); // nested structs too // FIXME: the compiler complains about forward declaration of init on nested struct /+ int someOuterInt = 100; struct NestedStruct { int a; int b = 10; string c; string d = "whoa"; void func() { a++; } void testOuter() { // we should be able to access the outer scope too... assert(someOuterInt == 100); someOuterInt++; assert(someOuterInt == 101); } } NestedStruct s; NestedStruct s2; assert(s.a == 0); // the values should be initialized properly assert(s.b == 10); assert(s.c == ""); assert(s.d == "whoa"); s.func(); // it should work to call the method assert(s.a == 1); // and save to our struct assert(s2.a == 0); // without affecting similar structs s.testOuter(); // and accessing the surrounding scope assert(someOuterInt == 101); // including saving to it +/ writeln("success"); // if we made it this far, we're good! } void testScopeSuccess(bool succeed) { scope(success) writeln("success showed"); scope(failure) writeln("failure showed"); writeln("testing scope success with " ~ (succeed ? "success requested" : "failure requested") ); if(!succeed) throw new Exception("failure requested"); } int staticVariableTest() { static int a; return ++a; } // BTW function templates should work void testStructSemantics(T)() { // this is where things really get interesting. The D struct is so simple on its face, // but is really a powerhouse of stuff that is very different than the closest thing we // have in Javascript to implement it on top of - the JS object. T test; assert(test.member == 0); // default initializer test.member++; assert(test.member == 1); // that does write to it T test2 = test; // should be a copy, not a reference assert(test2.member == 1); test2.member++; assert(test2.member == 2); assert(test.member == 1); // should be unchanged T test3; test3 = test2; // yet another copy assert(test3.member == 2); assert(test2.member == 2); test3.member += 10; assert(test3.member == 12); assert(test.member == 1); testStructByValue(test); assert(test.member == 1); // original should be unchanged testStructByReference(test); assert(test.member == 0); // original should indeed be changed writeln("Passed " ~ T.stringof); } void testStructByValue(T)(T test) { // unlike classes (and Javascript objects), D structs are passed by value. // thus variable test should be a shallow copy of what was passed in. // Changing things here should not affect the original struct. // since test is a shallow copy, the postblit and destructor should be called too assert(test.member == 1); --test.member; assert(test.member == 0); } void testStructByReference(T)(ref T test) { // this should affect the original in all ways assert(test.member == 1); --test.member; assert(test.member == 0); } struct StructSemanticTest { int member; ~this() { writeln("struct destructor"); } } struct StructSemanticTestWithPostBlit { int member; int refCount; this(this) { refCount++; writeln("postblit, refcount: " ~ to!string(refCount)); } ~this() { refCount--; writeln("struct destructor, refcount: " ~ to!string(refCount)); } } void refTest(ref int a) { assert(a == 1); // the input a = 2; assert(a == 2); // assignment and retrieval } void appendToArray(int[] arr) { arr ~= 4; assert(arr.length == 4); assert(arr == [1,2,3,4]); } void exceptionTest() { try { // this should be caught in the handler above throw new Exception("test 2"); } catch(Error e) { // should not be caught here, since !is(Exception : Error) assert(0); } finally { writeln("inner finally ran"); } assert(0); } class MyBase { string myName() { return "my base"; } string overrideme() { return "something"; } } class MyClass : MyBase { this() {} override string myName() { return "my class"; } void someMethod() { } override string overrideme() { return "roflcopter"; } } class MyOtherClass : MyBase { this() {} override string myName() { return "my other class"; } }