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 /// Layer ID
50
51 alias string Layer;
52
53 /// Context (variable environment)
54 /// Simlar to prototype chain of ECMAScript etc.
55 /// But extended with the notion of "Layer"
56
57 class Table : Value
58 {
59 enum Kind {PropagateSet, NotPropagateSet};
60
61 this( Table proto=null, Kind k = Kind.PropagateSet )
62 { this.prototype = proto; this.kind = k; }
63
64 void set(string i, Layer lay, Value v, in LexPosition pos=null)
65 {
66 if( setIfExist(i, lay, v) )
67 return;
68 data[i][lay] = v;
69 }
70
71 Value get(string i, Layer lay, in LexPosition pos=null)
72 {
73 if( i in data )
74 return data[i][lay];
75 if( prototype is null )
76 throw new RuntimeException(pos, sprintf!"variable %s not found"(i));
77 return prototype.get(i, lay);
78 }
79
80 private:
81 Table prototype;
82 Kind kind;
83 Value[Layer][string] data;
84
85 bool setIfExist(string i, Layer lay, Value v)
86 {
87 if( i in data )
88 {
89 data[i][lay] = v;
90 return true;
91 }
92 if( kind==Kind.PropagateSet && prototype !is null )
93 return prototype.setIfExist(i, lay, v);
94 return false;
95 }
96 }
97
98 unittest
99 {
100 Table c0 = new Table;
101 Table c01 = new Table(c0, Table.Kind.NotPropagateSet);
102 Table c012 = new Table(c01, Table.Kind.PropagateSet);
103 Table c013 = new Table(c01, Table.Kind.PropagateSet);
104
105 assert_nothrow( c012.set("x", "@v", new IntValue(BigInt(12))) );
106 assert_throw!RuntimeException( c013.get("x", "@v") );
107 assert_nothrow( c013.set("x", "@v", new IntValue(BigInt(13))) );
108 assert_eq( c013.get("x", "@v"), new IntValue(BigInt(13)) );
109 assert_eq( c012.get("x", "@v"), new IntValue(BigInt(12)) );
110 assert_throw!RuntimeException( c01.get("x", "@v") );
111
112 assert_nothrow( c01.set("y", "@v", new IntValue(BigInt(1))) );
113 assert_eq( c013.get("y", "@v"), new IntValue(BigInt(1)) );
114 assert_eq( c012.get("y", "@v"), new IntValue(BigInt(1)) );
115 assert_eq( c01.get("y", "@v"), new IntValue(BigInt(1)) );
116
117 assert_nothrow( c0.set("z", "@v", new IntValue(BigInt(0))) );
118 assert_eq( c013.get("z", "@v"), new IntValue(BigInt(0)) );
119 assert_eq( c012.get("z", "@v"), new IntValue(BigInt(0)) );
120 assert_eq( c01.get("z", "@v"), new IntValue(BigInt(0)) );
121 assert_eq( c0.get("z", "@v"), new IntValue(BigInt(0)) );
122
123 assert_nothrow( c012.set("y", "@v", new IntValue(BigInt(444))) );
124 assert_eq( c013.get("y", "@v"), new IntValue(BigInt(444)) );
125 assert_eq( c012.get("y", "@v"), new IntValue(BigInt(444)) );
126 assert_eq( c01.get("y", "@v"), new IntValue(BigInt(444)) );
127
128 assert_nothrow( c012.set("z", "@v", new IntValue(BigInt(555))) );
129 assert_eq( c013.get("z", "@v"), new IntValue(BigInt(0)) );
130 assert_eq( c012.get("z", "@v"), new IntValue(BigInt(555)) );
131 assert_eq( c01.get("z", "@v"), new IntValue(BigInt(0)) );
132 assert_eq( c0.get("z", "@v"), new IntValue(BigInt(0)) );
133
134 // [TODO] define the semantics and test @layers
135 }