Index: .poseidon ================================================================== --- .poseidon +++ .poseidon @@ -34,12 +34,12 @@ polemy\_common.d polemy\ast.d polemy\eval.d polemy\lex.d polemy\parse.d - polemy\runtime.d polemy\tricks.d + polemy\value.d Index: polemy/eval.d ================================================================== --- polemy/eval.d +++ polemy/eval.d @@ -7,11 +7,11 @@ module polemy.eval; import polemy._common; import polemy.lex : LexPosition; import polemy.ast; import polemy.parse; -import polemy.runtime; +import polemy.value; import std.typecons; import std.stdio; Context createGlobalContext() { DELETED polemy/runtime.d Index: polemy/runtime.d ================================================================== --- polemy/runtime.d +++ polemy/runtime.d @@ -1,82 +0,0 @@ -/** - * Authors: k.inaba - * License: NYSL 0.9982 http://www.kmonos.net/nysl/ - * - * Runtime data structures for Polemy programming language. - */ -module polemy.runtime; -import polemy._common; -import polemy.lex : LexPosition; -import std.stdio; - -class PolemyRuntimeException : Exception -{ - this(string msg) { super(msg); } -} - -abstract class Value -{ -} - -class UndefinedValue : Value -{ - mixin SimpleConstructor; - mixin SimpleCompare; - override string toString() const { return "(undefined)"; } -} - -class IntValue : Value -{ - BigInt data; - mixin SimpleConstructor; - mixin SimpleCompare; - override string toString() const { - return std.bigint.toDecimalString(cast(BigInt)data); - } -} - -class StrValue : Value -{ - string data; - mixin SimpleConstructor; - mixin SimpleCompare; - override string toString() const { return data; } -} - -class FunValue : Value -{ - Value delegate(immutable LexPosition pos, Value[]) data; - mixin SimpleConstructor; - Value call(immutable LexPosition pos, Value[] args) { return data(pos,args); } - override string toString() const { return sprintf!"(function:%s:%s)"(data.ptr,data.funcptr); } -} -import std.stdio; -class Context -{ - Context parent; - Value[string] table; - this(Context parent = null) { this.parent = parent; } - - void add(string i, Value v) - { - table[i] = v; - } - - Value opIndex(string i) - { - if( i in table ) - return table[i]; - if( parent is null ) - throw new PolemyRuntimeException(sprintf!"variable %s not found"(i)); - return parent[i]; - } - - void opIndexAssign(Value v, string i) - { - if( i in table ) - return table[i] = v; - if( parent is null ) - throw new PolemyRuntimeException(sprintf!"variable %s not found"(i)); - return parent[i] = v; - } -} Index: polemy/tricks.d ================================================================== --- polemy/tricks.d +++ polemy/tricks.d @@ -3,28 +3,69 @@ * License: NYSL 0.9982 http://www.kmonos.net/nysl/ * * Common tricks and utilities for programming in D. */ module polemy.tricks; -static import std.array; -static import std.format; -static import core.exception; +import std.array : appender; +import std.format : formattedWrite; +import core.exception : onAssertErrorMsg, AssertError; /// Simple Wrapper for std.format.doFormat string sprintf(string fmt, T...)(T params) { - auto writer = std.array.appender!string(); - std.format.formattedWrite(writer, fmt, params); + auto writer = appender!string(); + formattedWrite(writer, fmt, params); return writer.data; } unittest { assert( sprintf!"%s == %d"("1+2", 3) == "1+2 == 3" ); assert( sprintf!"%s == %04d"("1+2", 3) == "1+2 == 0003" ); } + +/// Unittest helper that asserts an expression must throw something + +void assert_throw(ExceptionType, T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="") +{ + try { + t(); + } catch(ExceptionType) { + return; + } catch(Throwable e) { + onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e)); + } + onAssertErrorMsg(fn, ln, msg.length ? msg : "no execption"); +} + +/// Unittest helper that asserts an expression must not throw anything + +void assert_nothrow(T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="") +{ + try { + t(); + } catch(Throwable e) { + onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e)); + } +} + +unittest +{ + auto error = {throw new Error("hello");}; + auto nothing = (){}; + auto assertError = {assert(0);}; + + assert_nothrow ( assert_nothrow(nothing()) ); + assert_throw!AssertError( assert_nothrow(error()) ); + assert_throw!AssertError( assert_nothrow(assertError()) ); + + assert_nothrow ( assert_throw!Error(error()) ); + assert_throw!AssertError( assert_throw!Error(nothing()) ); + assert_nothrow ( assert_throw!Error(assertError()) ); + assert_throw!AssertError( assert_throw!AssertError(error()) ); +} /// Unittest helpers asserting two values are in some relation ==, !=, <, <=, >, >= template assertOp(string op) { @@ -31,13 +72,13 @@ void assertOp(A, B, string fn=__FILE__, int ln=__LINE__)(A a, B b, string msg="") { try { if( mixin("a"~op~"b") ) return; } catch(Throwable e) { - core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e)); + onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e)); } - core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"%s !%s %s"(a,op,b)); + onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"%s !%s %s"(a,op,b)); } } alias assertOp!(`==`) assert_eq; alias assertOp!(`!=`) assert_ne; @@ -44,33 +85,34 @@ alias assertOp!(`<`) assert_lt; alias assertOp!(`<=`) assert_le; alias assertOp!(`>`) assert_gt; alias assertOp!(`>=`) assert_ge; -/// Unittest helper that asserts an expression must throw something - -void assert_throw(ExceptionType, T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="") +unittest { - try { - t(); - } catch(ExceptionType) { - return; - } catch(Throwable e) { - core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e)); - } - core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : "no execption"); -} - -/// Unittest helper that asserts an expression must not throw anything - -void assert_nothrow(ExceptionType, T, string fn=__FILE__, int ln=__LINE__)(lazy T t, string msg="") -{ - try { - t(); - } catch(Throwable e) { - core.exception.onAssertErrorMsg(fn, ln, msg.length ? msg : sprintf!"exception [%s]"(e)); - } + assert_nothrow( assert_eq("foo", "foo") ); + assert_nothrow( assert_ne("foo", "bar") ); + assert_nothrow( assert_lt("bar", "foo") ); + assert_nothrow( assert_le("bar", "foo") ); + assert_nothrow( assert_le("bar", "bar") ); + assert_nothrow( assert_gt("foo", "bar") ); + assert_nothrow( assert_ge("foo", "bar") ); + assert_nothrow( assert_ge("bar", "bar") ); + + assert_throw!AssertError( assert_eq("foo", "bar") ); + assert_throw!AssertError( assert_ne("foo", "foo") ); + assert_throw!AssertError( assert_lt("foo", "foo") ); + assert_throw!AssertError( assert_lt("foo", "bar") ); + assert_throw!AssertError( assert_le("foo", "bar") ); + assert_throw!AssertError( assert_gt("bar", "bar") ); + assert_throw!AssertError( assert_gt("bar", "foo") ); + assert_throw!AssertError( assert_ge("bar", "foo") ); + + class Temp { bool opEquals(int x){return x/x==x;} } + assert_throw!AssertError( assert_eq(new Temp, 0) ); + assert_nothrow ( assert_eq(new Temp, 1) ); + assert_throw!AssertError( assert_eq(new Temp, 2) ); } /* [Todo] is there any way to clearnly implement "assert_compiles" and "assert_not_compile"? */ /// Mixing-in the bean constructor for a class @@ -105,10 +147,30 @@ assert_eq( (new Temp(1,"foo")).x, 1 ); assert_eq( (new Temp(1,"foo")).y, "foo" ); assert( !__traits(compiles, new Temp) ); assert( !__traits(compiles, new Temp(1)) ); assert( !__traits(compiles, new Temp("foo",1)) ); + + class Tomp : Temp + { + real z; + mixin SimpleConstructor; + } + assert_eq( (new Tomp(1,"foo",2.5)).x, 1 ); + assert_eq( (new Tomp(1,"foo",2.5)).y, "foo" ); + assert_eq( (new Tomp(1,"foo",2.5)).z, 2.5 ); + assert( !__traits(compiles, new Tomp(3.14)) ); + + // shiyo- desu. Don't use in this way. + // Tamp tries to call new Tomp(real) (because it only sees Tomp's members), + // but it fails because Tomp takes (int,string,real). + assert( !__traits(compiles, { + class Tamp : Tomp + { + mixin SimpleConstructor; + } + }) ); } /// Mixing-in the MOST-DERIVED-member-wise comparator for a class template SimpleCompare() @@ -159,6 +221,17 @@ assert_eq( (new Temp(1,"foo")).toHash, (new Temp(1,"foo")).toHash ); assert_ne( new Temp(1,"foo"), new Temp(2,"foo") ); assert_ne( new Temp(1,"foo"), new Temp(1,"bar") ); assert_gt( new Temp(1,"foo"), new Temp(1,"bar") ); assert_lt( new Temp(1,"foo"), new Temp(2,"bar") ); + assert_ge( new Temp(1,"foo"), new Temp(1,"foo") ); + + class TempDummy + { + int x; + string y; + mixin SimpleConstructor; + mixin SimpleCompare; + } + assert_throw!AssertError( new Temp(1,"foo") == new TempDummy(1,"foo") ); + assert_throw!AssertError( new Temp(1,"foo") <= new TempDummy(1,"foo") ); } ADDED polemy/value.d Index: polemy/value.d ================================================================== --- polemy/value.d +++ polemy/value.d @@ -0,0 +1,82 @@ +/** + * Authors: k.inaba + * License: NYSL 0.9982 http://www.kmonos.net/nysl/ + * + * Runtime data structures for Polemy programming language. + */ +module polemy.value; +import polemy._common; +import polemy.lex : LexPosition; +import std.stdio; + +class PolemyRuntimeException : Exception +{ + this(string msg) { super(msg); } +} + +abstract class Value +{ +} + +class UndefinedValue : Value +{ + mixin SimpleConstructor; + mixin SimpleCompare; + override string toString() const { return "(undefined)"; } +} + +class IntValue : Value +{ + BigInt data; + mixin SimpleConstructor; + mixin SimpleCompare; + override string toString() const { + return std.bigint.toDecimalString(cast(BigInt)data); + } +} + +class StrValue : Value +{ + string data; + mixin SimpleConstructor; + mixin SimpleCompare; + override string toString() const { return data; } +} + +class FunValue : Value +{ + Value delegate(immutable LexPosition pos, Value[]) data; + mixin SimpleConstructor; + Value call(immutable LexPosition pos, Value[] args) { return data(pos,args); } + override string toString() const { return sprintf!"(function:%s:%s)"(data.ptr,data.funcptr); } +} +import std.stdio; +class Context +{ + Context parent; + Value[string] table; + this(Context parent = null) { this.parent = parent; } + + void add(string i, Value v) + { + table[i] = v; + } + + Value opIndex(string i) + { + if( i in table ) + return table[i]; + if( parent is null ) + throw new PolemyRuntimeException(sprintf!"variable %s not found"(i)); + return parent[i]; + } + + void opIndexAssign(Value v, string i) + { + if( i in table ) + return table[i] = v; + if( parent is null ) + throw new PolemyRuntimeException(sprintf!"variable %s not found"(i)); + return parent[i] = v; + } +}