Artifact Content
Not logged in

Artifact a4c75e644b34fb64b775972c419d0f8bc13ce0b3


     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  ///
    25  class IntValue : Value
    26  {
    27  	BigInt data;
    28  
    29  	mixin SimpleClass;
    30  	override string toString() const { return std.bigint.toDecimalString(cast(BigInt)data); }
    31  }
    32  
    33  ///
    34  class StrValue : Value
    35  {
    36  	string data;
    37  
    38  	mixin SimpleClass;
    39  	override string toString() const { return data; }
    40  }
    41  
    42  ///
    43  class FunValue : Value
    44  {
    45  	Value delegate(immutable LexPosition pos, string lay, Value[]) data;
    46  
    47  	mixin SimpleConstructor;
    48  	alias data call;
    49  	override string toString() const { return sprintf!"(function:%s:%s)"(data.ptr,data.funcptr); }
    50  }
    51  
    52  ///
    53  class UndValue : Value
    54  {
    55  	mixin SimpleClass;
    56  	override string toString() const { return "<undefined>"; }
    57  }
    58  
    59  /// Named Constructor for FunValue
    60  
    61  FunValue nativef(Value delegate(immutable LexPosition pos, Layer lay, Value[] args) dg)
    62  {
    63  	return new FunValue(dg);
    64  }
    65  
    66  /// Named Constructor for FunValue
    67  
    68  FunValue native(R,T...)(R delegate (T) dg)
    69  {
    70  	return nativef( delegate Value(immutable LexPosition pos, Layer lay, Value[] args) {
    71  		if( lay != "@v" )
    72  			throw genex!RuntimeException(pos, "only @v layer can call native function");
    73  		if( T.length != args.length )
    74  			throw genex!RuntimeException(pos, "argument number mismatch!");
    75  		T typed_args;
    76  		foreach(i, Ti; T)
    77  		{
    78  			typed_args[i] = cast(Ti) args[i];
    79  			if( typed_args[i] is null )
    80  				throw genex!RuntimeException(pos, sprintf!"type mismatch on the argument %d"(i+1));
    81  		}
    82  		try {
    83  			return dg(typed_args);
    84  		} catch( RuntimeException e ) {
    85  			throw e.pos is null ? new RuntimeException(pos, e.msg, e.file, e.line) : e;
    86  		}
    87  	});
    88  }
    89  
    90  /// Layer ID
    91  
    92  alias string Layer;
    93  
    94  /// Context (variable environment)
    95  /// Simlar to prototype chain of ECMAScript etc.
    96  /// But extended with the notion of "Layer"
    97  
    98  class Table : Value
    99  {
   100  	enum Kind {PropagateSet, NotPropagateSet};
   101  
   102  	this( Table proto=null, Kind k = Kind.PropagateSet )
   103  		{ this.prototype = proto; this.kind = k; }
   104  
   105  	void set(string i, Layer lay, Value v, in LexPosition pos=null)
   106  	{
   107  		if( setIfExist(i, lay, v) )
   108  			return;
   109  		data[i][lay] = v;
   110  	}
   111  
   112  	bool has(string i, Layer lay, in LexPosition pos=null)
   113  	{
   114  		if( i in data ) {
   115  			if( lay !in data[i] )
   116  				return false;
   117  			return true;
   118  		}
   119  		if( prototype is null )
   120  			return false;
   121  		return prototype.has(i, lay, pos);
   122  	}
   123  	
   124  	Value get(string i, Layer lay, in LexPosition pos=null)
   125  	{
   126  		if( i in data ) {
   127  			// [TODO] consider forwarding to proto also in this case
   128  			if( lay !in data[i] )
   129  				throw genex!RuntimeException(pos, sprintf!"variable %s is not set in layer %s"(i,lay));
   130  			return data[i][lay];
   131  		}
   132  		if( prototype is null )
   133  			throw new RuntimeException(pos, sprintf!"variable %s not found"(i));
   134  		return prototype.get(i, lay, pos);
   135  	}
   136  
   137  private:
   138  	Table                prototype;
   139  	Kind                 kind;
   140  	Value[Layer][string] data;
   141  
   142  	bool setIfExist(string i, Layer lay, Value v)
   143  	{
   144  		if( i in data )
   145  		{
   146  			data[i][lay] = v;
   147  			return true;
   148  		}
   149  		if( kind==Kind.PropagateSet && prototype !is null )
   150  			return prototype.setIfExist(i, lay, v);
   151  		return false;
   152  	}
   153  }
   154  
   155  unittest
   156  {
   157  	Table c0 = new Table;
   158  	Table c01 = new Table(c0, Table.Kind.NotPropagateSet);
   159  	Table c012 = new Table(c01, Table.Kind.PropagateSet);
   160  	Table c013 = new Table(c01, Table.Kind.PropagateSet);
   161  
   162  	assert_nothrow( c012.set("x", "@v", new IntValue(BigInt(12))) );
   163  	assert_throw!RuntimeException( c013.get("x", "@v") );
   164  	assert_nothrow( c013.set("x", "@v", new IntValue(BigInt(13))) );
   165  	assert_eq( c013.get("x", "@v"), new IntValue(BigInt(13)) );
   166  	assert_eq( c012.get("x", "@v"), new IntValue(BigInt(12)) );
   167  	assert_throw!RuntimeException( c01.get("x", "@v") );
   168  
   169  	assert_nothrow( c01.set("y", "@v", new IntValue(BigInt(1))) );
   170  	assert_eq( c013.get("y", "@v"), new IntValue(BigInt(1)) );
   171  	assert_eq( c012.get("y", "@v"), new IntValue(BigInt(1)) );
   172  	assert_eq( c01.get("y", "@v"), new IntValue(BigInt(1)) );
   173  
   174  	assert_nothrow( c0.set("z", "@v", new IntValue(BigInt(0))) );
   175  	assert_eq( c013.get("z", "@v"), new IntValue(BigInt(0)) );
   176  	assert_eq( c012.get("z", "@v"), new IntValue(BigInt(0)) );
   177  	assert_eq( c01.get("z", "@v"), new IntValue(BigInt(0)) );
   178  	assert_eq( c0.get("z", "@v"), new IntValue(BigInt(0)) );
   179  
   180  	assert_nothrow( c012.set("y", "@v", new IntValue(BigInt(444))) );
   181  	assert_eq( c013.get("y", "@v"), new IntValue(BigInt(444)) );
   182  	assert_eq( c012.get("y", "@v"), new IntValue(BigInt(444)) );
   183  	assert_eq( c01.get("y", "@v"), new IntValue(BigInt(444)) );
   184  
   185  	assert_nothrow( c012.set("z", "@v", new IntValue(BigInt(555))) );
   186  	assert_eq( c013.get("z", "@v"), new IntValue(BigInt(0)) );
   187  	assert_eq( c012.get("z", "@v"), new IntValue(BigInt(555)) );
   188  	assert_eq( c01.get("z", "@v"), new IntValue(BigInt(0)) );
   189  	assert_eq( c0.get("z", "@v"), new IntValue(BigInt(0)) );
   190  
   191  	// [TODO] define the semantics and test @layers
   192  }