@@ -78,14 +78,13 @@ class Table : Value { enum Kind {PropagateSet, NotPropagateSet}; - bool kill = false; // to refactor this( Table proto=null, Kind k = Kind.PropagateSet ) { this.prototype = proto; this.kind = k; } - void set(string i, Layer lay, Value v, LexPosition pos=null) + void set(string i, Layer lay, Value v) { if( setIfExist(i, lay, v) ) return; data[i][lay] = v; @@ -92,15 +91,10 @@ } bool has(string i, Layer lay) const { - if( i in data ) { - if( lay !in data[i] ) - return false; - if(kill) - return false; - return true; - } + if( i in data ) + return !!(lay in data[i]); if( prototype is null ) return false; return prototype.has(i, lay); } @@ -109,15 +103,13 @@ { if( i in data ) { // [TODO] consider forwarding to proto also in this case if( lay !in data[i] ) - throw genex!RuntimeException(pos, sprintf!"'%s' is not set in layer %s"(i,lay)); - if(kill) - throw genex!RuntimeException(pos, sprintf!"'%s' is killed in macro"(i)); + throw genex!RuntimeException(pos, sprintf!"'%s' is not set in %s layer"(i,lay)); return data[i][lay]; } if( prototype is null ) - throw new RuntimeException(pos, sprintf!"'%s' not found"(i)); + throw genex!RuntimeException(pos, sprintf!"'%s' not found in %s layer"(i,lay)); return prototype.get(i, lay, pos); } T access(T,S...)( Layer lay, string path, S rest ) @@ -157,13 +149,52 @@ result ~= prototype.toStringWithoutParen(); } return result; } - - string toString() const + + string toString() { + if( isList() ) + return text(toList()); return "{" ~ toStringWithoutParen() ~ "}"; } + +public: + /// Is this an empty table? + bool empty() + { + return data.length==0 && (prototype is null || prototype.empty); + } + + /// Can be seen as a cons-list? + bool isList() + { + Table t = this; + while(t.has("car", ValueLayer) && t.has("cdr", ValueLayer)) + if(auto tt = cast(Table)t.get("cdr", ValueLayer)) + t = tt; + else + return false; + return t.empty; + } + + /// Regard table as a cons-list and convert to an array + Value[] toList() + { + Value[] result; + Table t = this; + while(t.has("car", ValueLayer) && t.has("cdr", ValueLayer)) + { + result ~= t.get("car", ValueLayer); + if(auto tt = cast(Table)t.get("cdr", ValueLayer)) + t = tt; + else + throw genex!RuntimeException("this table is not a cons-list"); + } + if( t.empty ) + return result; + throw genex!RuntimeException("this table is not a cons-list"); + } private: Table prototype; Kind kind; @@ -188,35 +219,35 @@ Table c01 = new Table(c0, Table.Kind.NotPropagateSet); Table c012 = new Table(c01, Table.Kind.PropagateSet); Table c013 = new Table(c01, Table.Kind.PropagateSet); - assert_nothrow( c012.set("x", ValueLayer, new IntValue(BigInt(12))) ); + assert_nothrow( c012.set("x", ValueLayer, new IntValue(12)) ); assert_throw!RuntimeException( c013.get("x", ValueLayer) ); - assert_nothrow( c013.set("x", ValueLayer, new IntValue(BigInt(13))) ); - assert_eq( c013.get("x", ValueLayer), new IntValue(BigInt(13)) ); - assert_eq( c012.get("x", ValueLayer), new IntValue(BigInt(12)) ); + assert_nothrow( c013.set("x", ValueLayer, new IntValue(13)) ); + assert_eq( c013.get("x", ValueLayer), new IntValue(13) ); + assert_eq( c012.get("x", ValueLayer), new IntValue(12) ); assert_throw!RuntimeException( c01.get("x", ValueLayer) ); - assert_nothrow( c01.set("y", ValueLayer, new IntValue(BigInt(1))) ); - assert_eq( c013.get("y", ValueLayer), new IntValue(BigInt(1)) ); - assert_eq( c012.get("y", ValueLayer), new IntValue(BigInt(1)) ); - assert_eq( c01.get("y", ValueLayer), new IntValue(BigInt(1)) ); + assert_nothrow( c01.set("y", ValueLayer, new IntValue(1)) ); + assert_eq( c013.get("y", ValueLayer), new IntValue(1) ); + assert_eq( c012.get("y", ValueLayer), new IntValue(1) ); + assert_eq( c01.get("y", ValueLayer), new IntValue(1) ); + + assert_nothrow( c0.set("z", ValueLayer, new IntValue(0)) ); + assert_eq( c013.get("z", ValueLayer), new IntValue(0) ); + assert_eq( c012.get("z", ValueLayer), new IntValue(0) ); + assert_eq( c01.get("z", ValueLayer), new IntValue(0) ); + assert_eq( c0.get("z", ValueLayer), new IntValue(0) ); - assert_nothrow( c0.set("z", ValueLayer, new IntValue(BigInt(0))) ); - assert_eq( c013.get("z", ValueLayer), new IntValue(BigInt(0)) ); - assert_eq( c012.get("z", ValueLayer), new IntValue(BigInt(0)) ); - assert_eq( c01.get("z", ValueLayer), new IntValue(BigInt(0)) ); - assert_eq( c0.get("z", ValueLayer), new IntValue(BigInt(0)) ); + assert_nothrow( c012.set("y", ValueLayer, new IntValue(444)) ); + assert_eq( c013.get("y", ValueLayer), new IntValue(444) ); + assert_eq( c012.get("y", ValueLayer), new IntValue(444) ); + assert_eq( c01.get("y", ValueLayer), new IntValue(444) ); - assert_nothrow( c012.set("y", ValueLayer, new IntValue(BigInt(444))) ); - assert_eq( c013.get("y", ValueLayer), new IntValue(BigInt(444)) ); - assert_eq( c012.get("y", ValueLayer), new IntValue(BigInt(444)) ); - assert_eq( c01.get("y", ValueLayer), new IntValue(BigInt(444)) ); - - assert_nothrow( c012.set("z", ValueLayer, new IntValue(BigInt(555))) ); - assert_eq( c013.get("z", ValueLayer), new IntValue(BigInt(0)) ); - assert_eq( c012.get("z", ValueLayer), new IntValue(BigInt(555)) ); - assert_eq( c01.get("z", ValueLayer), new IntValue(BigInt(0)) ); - assert_eq( c0.get("z", ValueLayer), new IntValue(BigInt(0)) ); + assert_nothrow( c012.set("z", ValueLayer, new IntValue(555)) ); + assert_eq( c013.get("z", ValueLayer), new IntValue(0) ); + assert_eq( c012.get("z", ValueLayer), new IntValue(555) ); + assert_eq( c01.get("z", ValueLayer), new IntValue(0) ); + assert_eq( c0.get("z", ValueLayer), new IntValue(0) ); // [TODO] define the semantics and test @layers }