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