/**
* Authors: k.inaba
* License: NYSL 0.9982 http://www.kmonos.net/nysl/
*
* Runtime data structures for Polemy programming language.
*/
module polemy.value;
import polemy._common;
import polemy.lex;
/// Raised when something went wrong in runtime
class RuntimeException : Exception
{
const LexPosition pos;
this( const LexPosition pos, string msg )
{ super(sprintf!"%s [%s]"(msg, pos)); this.pos = pos; }
this( string msg ) { super(msg); this.pos = null; }
}
/// Runtime values of Polemy
abstract class Value
{
}
class IntValue : Value
{
BigInt data;
mixin SimpleConstructor;
mixin SimpleCompare;
override string toString() const { return std.bigint.toDecimalString(cast(BigInt)data); }
}
class StrValue : Value
{
string data;
mixin SimpleConstructor;
mixin SimpleCompare;
override string toString() const { return data; }
}
class FunValue : Value
{
Value delegate(immutable LexPosition pos, Value[]) data;
mixin SimpleConstructor;
alias data call;
override string toString() const { return sprintf!"(function:%s:%s)"(data.ptr,data.funcptr); }
}
/// Layer ID
alias string Layer;
/// Context (variable environment)
/// Simlar to prototype chain of ECMAScript etc.
/// But extended with the notion of "Layer"
class Table : Value
{
enum Kind {PropagateSet, NotPropagateSet};
this( Table proto=null, Kind k = Kind.PropagateSet )
{ this.prototype = proto; this.kind = k; }
void set(string i, Layer lay, Value v)
{
if( !setIfExist(i, lay, v) )
data[i][lay] = v;
}
Value get(string i, Layer lay)
{
if( i in data )
return data[i][lay];
if( prototype is null )
throw new RuntimeException(sprintf!"variable %s not found"(i));
return prototype.get(i, lay);
}
private:
Table prototype;
Kind kind;
Value[Layer][string] data;
bool setIfExist(string i, Layer lay, Value v)
{
if( i in data )
{
data[i][lay] = v;
return true;
}
if( kind==Kind.PropagateSet && prototype !is null )
return prototype.setIfExist(i, lay, v);
return false;
}
}
unittest
{
Table c0 = new Table;
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", "@val", new IntValue(BigInt(12))) );
assert_throw!RuntimeException( c013.get("x", "@val") );
assert_nothrow( c013.set("x", "@val", new IntValue(BigInt(13))) );
assert_eq( c013.get("x", "@val"), new IntValue(BigInt(13)) );
assert_eq( c012.get("x", "@val"), new IntValue(BigInt(12)) );
assert_throw!RuntimeException( c01.get("x", "@val") );
assert_nothrow( c01.set("y", "@val", new IntValue(BigInt(1))) );
assert_eq( c013.get("y", "@val"), new IntValue(BigInt(1)) );
assert_eq( c012.get("y", "@val"), new IntValue(BigInt(1)) );
assert_eq( c01.get("y", "@val"), new IntValue(BigInt(1)) );
assert_nothrow( c0.set("z", "@val", new IntValue(BigInt(0))) );
assert_eq( c013.get("z", "@val"), new IntValue(BigInt(0)) );
assert_eq( c012.get("z", "@val"), new IntValue(BigInt(0)) );
assert_eq( c01.get("z", "@val"), new IntValue(BigInt(0)) );
assert_eq( c0.get("z", "@val"), new IntValue(BigInt(0)) );
assert_nothrow( c012.set("y", "@val", new IntValue(BigInt(444))) );
assert_eq( c013.get("y", "@val"), new IntValue(BigInt(444)) );
assert_eq( c012.get("y", "@val"), new IntValue(BigInt(444)) );
assert_eq( c01.get("y", "@val"), new IntValue(BigInt(444)) );
assert_nothrow( c012.set("z", "@val", new IntValue(BigInt(555))) );
assert_eq( c013.get("z", "@val"), new IntValue(BigInt(0)) );
assert_eq( c012.get("z", "@val"), new IntValue(BigInt(555)) );
assert_eq( c01.get("z", "@val"), new IntValue(BigInt(0)) );
assert_eq( c0.get("z", "@val"), new IntValue(BigInt(0)) );
// [TODO] define the semantics and test @layers
}