8de5b49cdf 2010-11-09 kinaba: /** b0d8d7875b 2010-11-08 kinaba: * Authors: k.inaba b0d8d7875b 2010-11-08 kinaba: * License: NYSL 0.9982 http://www.kmonos.net/nysl/ b0d8d7875b 2010-11-08 kinaba: * b0d8d7875b 2010-11-08 kinaba: * Runtime data structures for Polemy programming language. b0d8d7875b 2010-11-08 kinaba: */ b0d8d7875b 2010-11-08 kinaba: module polemy.value; b0d8d7875b 2010-11-08 kinaba: import polemy._common; 3464a035ec 2010-11-20 kinaba: import polemy.failure; 3f6f41b558 2010-11-20 kinaba: import polemy.ast; 435fa085ec 2010-11-21 kinaba: import polemy.layer; b0d8d7875b 2010-11-08 kinaba: aa770610d3 2010-11-08 kinaba: /// Runtime values of Polemy b0d8d7875b 2010-11-08 kinaba: b0d8d7875b 2010-11-08 kinaba: abstract class Value b0d8d7875b 2010-11-08 kinaba: { b97bd4f713 2010-11-23 kinaba: override bool opEquals(Object rhs) { return 0==opCmp(rhs); } b0d8d7875b 2010-11-08 kinaba: } b0d8d7875b 2010-11-08 kinaba: 515502e8d1 2010-11-20 kinaba: /// b0d8d7875b 2010-11-08 kinaba: class IntValue : Value b0d8d7875b 2010-11-08 kinaba: { b0d8d7875b 2010-11-08 kinaba: BigInt data; aa770610d3 2010-11-08 kinaba: b993a8ad16 2010-11-24 kinaba: this(bool n) { this.data = n?1:0; } b993a8ad16 2010-11-24 kinaba: this(int n) { this.data = n; } b993a8ad16 2010-11-24 kinaba: this(long n) { this.data = n; } b97bd4f713 2010-11-23 kinaba: this(BigInt n) { this.data = n; } b97bd4f713 2010-11-23 kinaba: this(string n) { this.data = BigInt(n); } b97bd4f713 2010-11-23 kinaba: override string toString() const { return toDecimalString(cast(BigInt)data); } b97bd4f713 2010-11-23 kinaba: override int opCmp(Object rhs) { b97bd4f713 2010-11-23 kinaba: if(auto r = cast(IntValue)rhs) return data.opCmp(r.data); b97bd4f713 2010-11-23 kinaba: if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); 20be503cae 2010-11-24 kinaba: throw genex!RuntimeException("comparison with value and somithing other"); b97bd4f713 2010-11-23 kinaba: } b97bd4f713 2010-11-23 kinaba: mixin SimpleToHash; b0d8d7875b 2010-11-08 kinaba: } b0d8d7875b 2010-11-08 kinaba: 515502e8d1 2010-11-20 kinaba: /// b0d8d7875b 2010-11-08 kinaba: class StrValue : Value b0d8d7875b 2010-11-08 kinaba: { b0d8d7875b 2010-11-08 kinaba: string data; aa770610d3 2010-11-08 kinaba: b97bd4f713 2010-11-23 kinaba: mixin SimpleConstructor; b0d8d7875b 2010-11-08 kinaba: override string toString() const { return data; } b97bd4f713 2010-11-23 kinaba: override int opCmp(Object rhs) { b97bd4f713 2010-11-23 kinaba: if(auto r = cast(StrValue)rhs) return typeid(string).compare(&data, &r.data); b97bd4f713 2010-11-23 kinaba: if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); 20be503cae 2010-11-24 kinaba: throw genex!RuntimeException("comparison with value and somithing other"); b97bd4f713 2010-11-23 kinaba: } b97bd4f713 2010-11-23 kinaba: mixin SimpleToHash; b0d8d7875b 2010-11-08 kinaba: } b0d8d7875b 2010-11-08 kinaba: 515502e8d1 2010-11-20 kinaba: /// b97bd4f713 2010-11-23 kinaba: class UndefinedValue : Value b0d8d7875b 2010-11-08 kinaba: { b97bd4f713 2010-11-23 kinaba: mixin SimpleConstructor; a5fe6233c1 2010-11-21 kinaba: override string toString() const { return "<undefined>"; } b97bd4f713 2010-11-23 kinaba: override int opCmp(Object rhs) { b97bd4f713 2010-11-23 kinaba: if(auto r = cast(StrValue)rhs) return 0; b97bd4f713 2010-11-23 kinaba: if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); 20be503cae 2010-11-24 kinaba: throw genex!RuntimeException("comparison with value and somithing other"); b97bd4f713 2010-11-23 kinaba: } b97bd4f713 2010-11-23 kinaba: mixin SimpleToHash; aa770610d3 2010-11-08 kinaba: } aa770610d3 2010-11-08 kinaba: 515502e8d1 2010-11-20 kinaba: /// a5fe6233c1 2010-11-21 kinaba: abstract class FunValue : Value 5afe8e3f26 2010-11-13 kinaba: { a5fe6233c1 2010-11-21 kinaba: const(Parameter[]) params(); a5fe6233c1 2010-11-21 kinaba: Table definitionContext(); b97bd4f713 2010-11-23 kinaba: Value invoke(Layer lay, Table ctx, LexPosition pos); 5afe8e3f26 2010-11-13 kinaba: } aa770610d3 2010-11-08 kinaba: aa770610d3 2010-11-08 kinaba: /// Context (variable environment) aa770610d3 2010-11-08 kinaba: /// Simlar to prototype chain of ECMAScript etc. aa770610d3 2010-11-08 kinaba: /// But extended with the notion of "Layer" aa770610d3 2010-11-08 kinaba: aa770610d3 2010-11-08 kinaba: class Table : Value b0d8d7875b 2010-11-08 kinaba: { aa770610d3 2010-11-08 kinaba: enum Kind {PropagateSet, NotPropagateSet}; aa770610d3 2010-11-08 kinaba: aa770610d3 2010-11-08 kinaba: this( Table proto=null, Kind k = Kind.PropagateSet ) aa770610d3 2010-11-08 kinaba: { this.prototype = proto; this.kind = k; } aa770610d3 2010-11-08 kinaba: b993a8ad16 2010-11-24 kinaba: /// Set the value v to the index i of layer lay 2134cd44cc 2010-11-23 kinaba: void set(string i, Layer lay, Value v) aa770610d3 2010-11-08 kinaba: { 8de5b49cdf 2010-11-09 kinaba: if( setIfExist(i, lay, v) ) 8de5b49cdf 2010-11-09 kinaba: return; 8de5b49cdf 2010-11-09 kinaba: data[i][lay] = v; aa770610d3 2010-11-08 kinaba: } aa770610d3 2010-11-08 kinaba: b993a8ad16 2010-11-24 kinaba: /// True if index i has value in layer lay 6ac127ddd0 2010-11-23 kinaba: bool has(string i, Layer lay) const 6ac127ddd0 2010-11-23 kinaba: { 2134cd44cc 2010-11-23 kinaba: if( i in data ) 2134cd44cc 2010-11-23 kinaba: return !!(lay in data[i]); 6ac127ddd0 2010-11-23 kinaba: if( prototype is null ) 6ac127ddd0 2010-11-23 kinaba: return false; 6ac127ddd0 2010-11-23 kinaba: return prototype.has(i, lay); 6ac127ddd0 2010-11-23 kinaba: } 6ac127ddd0 2010-11-23 kinaba: b993a8ad16 2010-11-24 kinaba: /// Return the value of index i at layer lay. Throws if it is not set 6ac127ddd0 2010-11-23 kinaba: Value get(string i, Layer lay, LexPosition pos=null) 5afe8e3f26 2010-11-13 kinaba: { 5afe8e3f26 2010-11-13 kinaba: if( i in data ) { 5afe8e3f26 2010-11-13 kinaba: if( lay !in data[i] ) 2134cd44cc 2010-11-23 kinaba: throw genex!RuntimeException(pos, sprintf!"'%s' is not set in %s layer"(i,lay)); aa770610d3 2010-11-08 kinaba: return data[i][lay]; 5afe8e3f26 2010-11-13 kinaba: } aa770610d3 2010-11-08 kinaba: if( prototype is null ) 2134cd44cc 2010-11-23 kinaba: throw genex!RuntimeException(pos, sprintf!"'%s' not found in %s layer"(i,lay)); 5afe8e3f26 2010-11-13 kinaba: return prototype.get(i, lay, pos); 5afe8e3f26 2010-11-13 kinaba: } 5afe8e3f26 2010-11-13 kinaba: b993a8ad16 2010-11-24 kinaba: /// t.access!T(lay,a,b,...) returns t.get(a,lay).get(b,lay).... if exists b993a8ad16 2010-11-24 kinaba: /// and has type T. Returns null otherwise 3f6f41b558 2010-11-20 kinaba: T access(T,S...)( Layer lay, string path, S rest ) 3f6f41b558 2010-11-20 kinaba: { 3f6f41b558 2010-11-20 kinaba: static if( rest.length == 0 ) 3f6f41b558 2010-11-20 kinaba: { 3f6f41b558 2010-11-20 kinaba: if( this.has(path, lay) ) 3f6f41b558 2010-11-20 kinaba: return cast(T) this.get(path, lay); 3f6f41b558 2010-11-20 kinaba: } 3f6f41b558 2010-11-20 kinaba: else 3f6f41b558 2010-11-20 kinaba: { 3f6f41b558 2010-11-20 kinaba: if(auto next = this.access!Table(lay,path)) 3f6f41b558 2010-11-20 kinaba: return next.access!T(lay,rest); 3f6f41b558 2010-11-20 kinaba: } 3f6f41b558 2010-11-20 kinaba: return null; 3f6f41b558 2010-11-20 kinaba: } 2134cd44cc 2010-11-23 kinaba: 2134cd44cc 2010-11-23 kinaba: /// Is this an empty table? 2134cd44cc 2010-11-23 kinaba: bool empty() 2134cd44cc 2010-11-23 kinaba: { 2134cd44cc 2010-11-23 kinaba: return data.length==0 && (prototype is null || prototype.empty); 2134cd44cc 2010-11-23 kinaba: } 2134cd44cc 2010-11-23 kinaba: 2134cd44cc 2010-11-23 kinaba: /// Can be seen as a cons-list? 2134cd44cc 2010-11-23 kinaba: bool isList() 2134cd44cc 2010-11-23 kinaba: { 2134cd44cc 2010-11-23 kinaba: Table t = this; 2134cd44cc 2010-11-23 kinaba: while(t.has("car", ValueLayer) && t.has("cdr", ValueLayer)) 2134cd44cc 2010-11-23 kinaba: if(auto tt = cast(Table)t.get("cdr", ValueLayer)) 2134cd44cc 2010-11-23 kinaba: t = tt; 2134cd44cc 2010-11-23 kinaba: else 2134cd44cc 2010-11-23 kinaba: return false; 2134cd44cc 2010-11-23 kinaba: return t.empty; 2134cd44cc 2010-11-23 kinaba: } 2134cd44cc 2010-11-23 kinaba: 2134cd44cc 2010-11-23 kinaba: /// Regard table as a cons-list and convert to an array 2134cd44cc 2010-11-23 kinaba: Value[] toList() 2134cd44cc 2010-11-23 kinaba: { 2134cd44cc 2010-11-23 kinaba: Value[] result; 2134cd44cc 2010-11-23 kinaba: Table t = this; 2134cd44cc 2010-11-23 kinaba: while(t.has("car", ValueLayer) && t.has("cdr", ValueLayer)) 2134cd44cc 2010-11-23 kinaba: { 2134cd44cc 2010-11-23 kinaba: result ~= t.get("car", ValueLayer); 2134cd44cc 2010-11-23 kinaba: if(auto tt = cast(Table)t.get("cdr", ValueLayer)) 2134cd44cc 2010-11-23 kinaba: t = tt; 2134cd44cc 2010-11-23 kinaba: else 2134cd44cc 2010-11-23 kinaba: throw genex!RuntimeException("this table is not a cons-list"); 2134cd44cc 2010-11-23 kinaba: } 2134cd44cc 2010-11-23 kinaba: if( t.empty ) 2134cd44cc 2010-11-23 kinaba: return result; 2134cd44cc 2010-11-23 kinaba: throw genex!RuntimeException("this table is not a cons-list"); 2134cd44cc 2010-11-23 kinaba: } 2134cd44cc 2010-11-23 kinaba: b993a8ad16 2010-11-24 kinaba: /// Get the list of direct entries ignoring prototypes in sorted order b993a8ad16 2010-11-24 kinaba: Tuple!(string,Layer,Value)[] direct_entries() b993a8ad16 2010-11-24 kinaba: { b993a8ad16 2010-11-24 kinaba: Tuple!(string,Layer,Value)[] arr; b993a8ad16 2010-11-24 kinaba: foreach(k, l2d; data) b993a8ad16 2010-11-24 kinaba: foreach(l,d; l2d) b993a8ad16 2010-11-24 kinaba: arr ~= tuple(k,l,d); b993a8ad16 2010-11-24 kinaba: arr.sort(); b993a8ad16 2010-11-24 kinaba: return arr; b993a8ad16 2010-11-24 kinaba: } b993a8ad16 2010-11-24 kinaba: b993a8ad16 2010-11-24 kinaba: /// Get the whole list of observable entries in unspecified order b993a8ad16 2010-11-24 kinaba: Tuple!(string,Layer,Value)[] entries() b993a8ad16 2010-11-24 kinaba: { b993a8ad16 2010-11-24 kinaba: bool[string] hidden; b993a8ad16 2010-11-24 kinaba: Tuple!(string,Layer,Value)[] arr; b993a8ad16 2010-11-24 kinaba: enumerateEntries(hidden, arr); b993a8ad16 2010-11-24 kinaba: return arr; b993a8ad16 2010-11-24 kinaba: } b993a8ad16 2010-11-24 kinaba: b993a8ad16 2010-11-24 kinaba: private void enumerateEntries( ref bool[string] hidden, ref Tuple!(string,Layer,Value)[] arr ) b993a8ad16 2010-11-24 kinaba: { b993a8ad16 2010-11-24 kinaba: foreach(k, l2d; data) b993a8ad16 2010-11-24 kinaba: if( k !in hidden ) b993a8ad16 2010-11-24 kinaba: { b993a8ad16 2010-11-24 kinaba: foreach(l,d; l2d) b993a8ad16 2010-11-24 kinaba: arr ~= tuple(k,l,d); b993a8ad16 2010-11-24 kinaba: hidden[k] = true; b993a8ad16 2010-11-24 kinaba: } b993a8ad16 2010-11-24 kinaba: if(prototype !is null) b993a8ad16 2010-11-24 kinaba: prototype.enumerateEntries(hidden, arr); b993a8ad16 2010-11-24 kinaba: } b993a8ad16 2010-11-24 kinaba: b993a8ad16 2010-11-24 kinaba: override string toString() b993a8ad16 2010-11-24 kinaba: { b993a8ad16 2010-11-24 kinaba: if( isList() ) b993a8ad16 2010-11-24 kinaba: return text(toList()); b993a8ad16 2010-11-24 kinaba: return "{" ~ toStringWithoutParen() ~ "}"; b993a8ad16 2010-11-24 kinaba: } b993a8ad16 2010-11-24 kinaba: b993a8ad16 2010-11-24 kinaba: override int opCmp(Object rhs) b993a8ad16 2010-11-24 kinaba: { b993a8ad16 2010-11-24 kinaba: if(auto r = cast(Table)rhs) { b993a8ad16 2010-11-24 kinaba: Tuple!(string,Layer,Value)[] ls = this.entries(); b993a8ad16 2010-11-24 kinaba: Tuple!(string,Layer,Value)[] rs = r.entries(); b993a8ad16 2010-11-24 kinaba: if( ls.length != rs.length ) b993a8ad16 2010-11-24 kinaba: return (ls.length < rs.length ? -1 : +1); b993a8ad16 2010-11-24 kinaba: ls.sort(); b993a8ad16 2010-11-24 kinaba: rs.sort(); b993a8ad16 2010-11-24 kinaba: foreach(i,_; ls) b993a8ad16 2010-11-24 kinaba: if(auto c = ls[i].opCmp(rs[i])) b993a8ad16 2010-11-24 kinaba: return c; b993a8ad16 2010-11-24 kinaba: return 0; b993a8ad16 2010-11-24 kinaba: } b993a8ad16 2010-11-24 kinaba: if(auto r = cast(Value)rhs) return typeid(this).opCmp(typeid(r)); b993a8ad16 2010-11-24 kinaba: throw genex!RuntimeException("comparison with value and somithing other"); b993a8ad16 2010-11-24 kinaba: } b993a8ad16 2010-11-24 kinaba: b993a8ad16 2010-11-24 kinaba: override hash_t toHash() b993a8ad16 2010-11-24 kinaba: { b993a8ad16 2010-11-24 kinaba: Tuple!(string,Layer,Value)[] ls = this.entries(); b993a8ad16 2010-11-24 kinaba: ls.sort(); b993a8ad16 2010-11-24 kinaba: hash_t h; b993a8ad16 2010-11-24 kinaba: foreach(e; ls) b993a8ad16 2010-11-24 kinaba: h += structuralHash(e[0])+structuralHash(e[1])+structuralHash(e[2]); b993a8ad16 2010-11-24 kinaba: return h; b993a8ad16 2010-11-24 kinaba: } b993a8ad16 2010-11-24 kinaba: 2134cd44cc 2010-11-23 kinaba: private: 2134cd44cc 2010-11-23 kinaba: Table prototype; 2134cd44cc 2010-11-23 kinaba: Kind kind; 2134cd44cc 2010-11-23 kinaba: Value[Layer][string] data; b993a8ad16 2010-11-24 kinaba: b993a8ad16 2010-11-24 kinaba: string toStringWithoutParen() const b993a8ad16 2010-11-24 kinaba: { b993a8ad16 2010-11-24 kinaba: string result; b993a8ad16 2010-11-24 kinaba: bool first = true; b993a8ad16 2010-11-24 kinaba: foreach(k, l2d; data) b993a8ad16 2010-11-24 kinaba: foreach(l,d; l2d) b993a8ad16 2010-11-24 kinaba: { b993a8ad16 2010-11-24 kinaba: if(first) first=false; else result~=", "; b993a8ad16 2010-11-24 kinaba: result ~= k; b993a8ad16 2010-11-24 kinaba: if( l.empty ) b993a8ad16 2010-11-24 kinaba: result ~= "(emptylayer)"; b993a8ad16 2010-11-24 kinaba: else if( l != ValueLayer ) b993a8ad16 2010-11-24 kinaba: result ~= l; b993a8ad16 2010-11-24 kinaba: result ~= ":"; b993a8ad16 2010-11-24 kinaba: result ~= text(cast(Value)d); b993a8ad16 2010-11-24 kinaba: } b993a8ad16 2010-11-24 kinaba: if( prototype !is null ) b993a8ad16 2010-11-24 kinaba: { b993a8ad16 2010-11-24 kinaba: result ~= " / "; b993a8ad16 2010-11-24 kinaba: result ~= prototype.toStringWithoutParen(); b993a8ad16 2010-11-24 kinaba: } b993a8ad16 2010-11-24 kinaba: return result; b993a8ad16 2010-11-24 kinaba: } b0d8d7875b 2010-11-08 kinaba: aa770610d3 2010-11-08 kinaba: bool setIfExist(string i, Layer lay, Value v) b0d8d7875b 2010-11-08 kinaba: { aa770610d3 2010-11-08 kinaba: if( i in data ) aa770610d3 2010-11-08 kinaba: { aa770610d3 2010-11-08 kinaba: data[i][lay] = v; aa770610d3 2010-11-08 kinaba: return true; aa770610d3 2010-11-08 kinaba: } aa770610d3 2010-11-08 kinaba: if( kind==Kind.PropagateSet && prototype !is null ) aa770610d3 2010-11-08 kinaba: return prototype.setIfExist(i, lay, v); aa770610d3 2010-11-08 kinaba: return false; b0d8d7875b 2010-11-08 kinaba: } aa770610d3 2010-11-08 kinaba: } aa770610d3 2010-11-08 kinaba: aa770610d3 2010-11-08 kinaba: unittest aa770610d3 2010-11-08 kinaba: { aa770610d3 2010-11-08 kinaba: Table c0 = new Table; aa770610d3 2010-11-08 kinaba: Table c01 = new Table(c0, Table.Kind.NotPropagateSet); aa770610d3 2010-11-08 kinaba: Table c012 = new Table(c01, Table.Kind.PropagateSet); aa770610d3 2010-11-08 kinaba: Table c013 = new Table(c01, Table.Kind.PropagateSet); aa770610d3 2010-11-08 kinaba: 2134cd44cc 2010-11-23 kinaba: assert_nothrow( c012.set("x", ValueLayer, new IntValue(12)) ); 435fa085ec 2010-11-21 kinaba: assert_throw!RuntimeException( c013.get("x", ValueLayer) ); 2134cd44cc 2010-11-23 kinaba: assert_nothrow( c013.set("x", ValueLayer, new IntValue(13)) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c013.get("x", ValueLayer), new IntValue(13) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c012.get("x", ValueLayer), new IntValue(12) ); 435fa085ec 2010-11-21 kinaba: assert_throw!RuntimeException( c01.get("x", ValueLayer) ); 435fa085ec 2010-11-21 kinaba: 2134cd44cc 2010-11-23 kinaba: assert_nothrow( c01.set("y", ValueLayer, new IntValue(1)) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c013.get("y", ValueLayer), new IntValue(1) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c012.get("y", ValueLayer), new IntValue(1) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c01.get("y", ValueLayer), new IntValue(1) ); 2134cd44cc 2010-11-23 kinaba: 2134cd44cc 2010-11-23 kinaba: assert_nothrow( c0.set("z", ValueLayer, new IntValue(0)) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c013.get("z", ValueLayer), new IntValue(0) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c012.get("z", ValueLayer), new IntValue(0) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c01.get("z", ValueLayer), new IntValue(0) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c0.get("z", ValueLayer), new IntValue(0) ); aa770610d3 2010-11-08 kinaba: 2134cd44cc 2010-11-23 kinaba: assert_nothrow( c012.set("y", ValueLayer, new IntValue(444)) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c013.get("y", ValueLayer), new IntValue(444) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c012.get("y", ValueLayer), new IntValue(444) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c01.get("y", ValueLayer), new IntValue(444) ); aa770610d3 2010-11-08 kinaba: 2134cd44cc 2010-11-23 kinaba: assert_nothrow( c012.set("z", ValueLayer, new IntValue(555)) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c013.get("z", ValueLayer), new IntValue(0) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c012.get("z", ValueLayer), new IntValue(555) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c01.get("z", ValueLayer), new IntValue(0) ); 2134cd44cc 2010-11-23 kinaba: assert_eq( c0.get("z", ValueLayer), new IntValue(0) ); aa770610d3 2010-11-08 kinaba: aa770610d3 2010-11-08 kinaba: // [TODO] define the semantics and test @layers b0d8d7875b 2010-11-08 kinaba: }