1 /**
2 * Authors: k.inaba
3 * License: NYSL 0.9982 http://www.kmonos.net/nysl/
4 *
5 * Runtime data structures for Polemy programming language.
6 */
7 module polemy.value;
8 import polemy._common;
9 import polemy.lex;
10
11 /// Raised when something went wrong in runtime
12
13 class RuntimeException : Exception
14 {
15 const LexPosition pos;
16
17 this( const LexPosition pos, string msg )
18 { super(sprintf!"%s at [%s]"(msg, pos)); this.pos = pos; }
19 }
20
21 /// Runtime values of Polemy
22
23 abstract class Value
24 {
25 }
26
27 class IntValue : Value
28 {
29 BigInt data;
30
31 mixin SimpleConstructor;
32 mixin SimpleCompare;
33 override string toString() const { return std.bigint.toDecimalString(cast(BigInt)data); }
34 }
35
36 class StrValue : Value
37 {
38 string data;
39
40 mixin SimpleConstructor;
41 mixin SimpleCompare;
42 override string toString() const { return data; }
43 }
44
45 class FunValue : Value
46 {
47 Value delegate(immutable LexPosition pos, Value[]) data;
48
49 mixin SimpleConstructor;
50 alias data call;
51 override string toString() const { return sprintf!"(function:%s:%s)"(data.ptr,data.funcptr); }
52 }
53
54 /// Layer ID
55
56 alias string Layer;
57
58 /// Context (variable environment)
59 /// Simlar to prototype chain of ECMAScript etc.
60 /// But extended with the notion of "Layer"
61
62 class Table : Value
63 {
64 enum Kind {PropagateSet, NotPropagateSet};
65
66 this( Table proto=null, Kind k = Kind.PropagateSet )
67 { this.prototype = proto; this.kind = k; }
68
69 void set(string i, Layer lay, Value v, in LexPosition pos=null)
70 {
71 if( setIfExist(i, lay, v) )
72 return;
73 data[i][lay] = v;
74 }
75
76 Value get(string i, Layer lay, in LexPosition pos=null)
77 {
78 if( i in data )
79 return data[i][lay];
80 if( prototype is null )
81 throw new RuntimeException(pos, sprintf!"variable %s not found"(i));
82 return prototype.get(i, lay);
83 }
84
85 private:
86 Table prototype;
87 Kind kind;
88 Value[Layer][string] data;
89
90 bool setIfExist(string i, Layer lay, Value v)
91 {
92 if( i in data )
93 {
94 data[i][lay] = v;
95 return true;
96 }
97 if( kind==Kind.PropagateSet && prototype !is null )
98 return prototype.setIfExist(i, lay, v);
99 return false;
100 }
101 }
102
103 unittest
104 {
105 Table c0 = new Table;
106 Table c01 = new Table(c0, Table.Kind.NotPropagateSet);
107 Table c012 = new Table(c01, Table.Kind.PropagateSet);
108 Table c013 = new Table(c01, Table.Kind.PropagateSet);
109
110 assert_nothrow( c012.set("x", "@val", new IntValue(BigInt(12))) );
111 assert_throw!RuntimeException( c013.get("x", "@val") );
112 assert_nothrow( c013.set("x", "@val", new IntValue(BigInt(13))) );
113 assert_eq( c013.get("x", "@val"), new IntValue(BigInt(13)) );
114 assert_eq( c012.get("x", "@val"), new IntValue(BigInt(12)) );
115 assert_throw!RuntimeException( c01.get("x", "@val") );
116
117 assert_nothrow( c01.set("y", "@val", new IntValue(BigInt(1))) );
118 assert_eq( c013.get("y", "@val"), new IntValue(BigInt(1)) );
119 assert_eq( c012.get("y", "@val"), new IntValue(BigInt(1)) );
120 assert_eq( c01.get("y", "@val"), new IntValue(BigInt(1)) );
121
122 assert_nothrow( c0.set("z", "@val", new IntValue(BigInt(0))) );
123 assert_eq( c013.get("z", "@val"), new IntValue(BigInt(0)) );
124 assert_eq( c012.get("z", "@val"), new IntValue(BigInt(0)) );
125 assert_eq( c01.get("z", "@val"), new IntValue(BigInt(0)) );
126 assert_eq( c0.get("z", "@val"), new IntValue(BigInt(0)) );
127
128 assert_nothrow( c012.set("y", "@val", new IntValue(BigInt(444))) );
129 assert_eq( c013.get("y", "@val"), new IntValue(BigInt(444)) );
130 assert_eq( c012.get("y", "@val"), new IntValue(BigInt(444)) );
131 assert_eq( c01.get("y", "@val"), new IntValue(BigInt(444)) );
132
133 assert_nothrow( c012.set("z", "@val", new IntValue(BigInt(555))) );
134 assert_eq( c013.get("z", "@val"), new IntValue(BigInt(0)) );
135 assert_eq( c012.get("z", "@val"), new IntValue(BigInt(555)) );
136 assert_eq( c01.get("z", "@val"), new IntValue(BigInt(0)) );
137 assert_eq( c0.get("z", "@val"), new IntValue(BigInt(0)) );
138
139 // [TODO] define the semantics and test @layers
140 }