1
0
Files
otyaSMILEBASIC/SMILEBASIC/type.d
otya128 3eae20517a Fix
2017-07-23 19:13:43 +09:00

705 lines
18 KiB
D

module otya.smilebasic.type;
import otya.smilebasic.error;
import otya.smilebasic.compiler;
import otya.smilebasic.vm;
static import std.algorithm;
static import std.algorithm.comparison;
enum ValueType : byte
{
Void,//DEF A()ENDの返り値とか未初期化の変数とか
Integer,
Double,
String,
Array,
IntegerArray,
DoubleArray,
StringArray,
InternalAddress,
InternalSlotAddress,
Reference,
IntegerReference,
DoubleReference,
StringReference,
StringArrayReference,
Data,
Function,
}
struct Data
{
DataTable table;
int index;
void read(out Value value, VM vm)
{
if(index >= table.length)
throw new OutOfDATA();
value = table.read(index);
index++;
}
}
struct VMAddress
{
byte slot;
uint address;
}
struct Value
{
ValueType type;
union
{
int integerValue;
double doubleValue;
Array!wchar stringValue;
Array!int integerArray;
Array!double doubleArray;
Array!(Array!wchar) stringArray;
VMAddress internalAddress;
Value* reference;
ArrayReference!int integerReference;
ArrayReference!double doubleReference;
ArrayReference!wchar stringReference;
ArrayReference!(Array!wchar) stringArrayReference;
Data data;
Function func;
}
this(int value)
{
this.type = ValueType.Integer;
integerValue = value;
}
this(bool value)
{
this(cast(int)value);
}
this(double value)
{
this.type = ValueType.Double;
doubleValue = value;
}
this(wstring value)
{
this.type = ValueType.String;
stringValue = new Array!wchar(cast(wchar[])value.dup);
}
this(wchar[] value)
{
this.type = ValueType.String;
stringValue = new Array!wchar(value);
}
this(wchar value)
{
this.type = ValueType.String;
stringValue = new Array!wchar([value]);
}
this(Array!wchar value)
{
this.type = ValueType.String;
stringValue = value;
}
this(ValueType type)
{
this.type = type;
if(type == ValueType.String)
{
stringValue = new Array!wchar(0);
}
}
this(Value* r)
{
this.type = ValueType.Reference;
reference = r;
}
this(ArrayReference!int r)
{
this.type = ValueType.IntegerReference;
integerReference = r;
}
this(ArrayReference!double r)
{
this.type = ValueType.DoubleReference;
doubleReference = r;
}
this(ArrayReference!wchar r)
{
this.type = ValueType.StringReference;
stringReference = r;
}
this(ArrayReference!(Array!wchar) r)
{
this.type = ValueType.StringArrayReference;
stringArrayReference = r;
}
this(Data data)
{
this.type = ValueType.Data;
this.data = data;
}
this(Function func)
{
this.type = ValueType.Function;
this.func = func;
}
this(Array!int a)
{
this.type = ValueType.IntegerArray;
this.integerArray = a;
}
this(Array!double a)
{
this.type = ValueType.DoubleArray;
this.doubleArray = a;
}
this(Array!(Array!wchar) a)
{
this.type = ValueType.StringArray;
this.stringArray = a;
}
void castOp(ValueType type)
{
switch(type)
{
case ValueType.Double:
break;
default:
break;
}
}
int boolValue()
{
switch(type)
{
case ValueType.Double:
return this.doubleValue != 0;
case ValueType.Integer:
return this.integerValue != 0;
case ValueType.String:
return 3;//3.1現在では文字列はtrue(ただし!"A"などは動かない)
default:
//配列はtype mismatch
throw new TypeMismatch();
}
}
bool isArray()
{
return this.type == ValueType.IntegerArray || this.type == ValueType.DoubleArray ||
this.type == ValueType.StringArray || this.type == ValueType.String;
}
bool isNonStringArray()
{
return this.type == ValueType.IntegerArray || this.type == ValueType.DoubleArray ||
this.type == ValueType.StringArray;
}
bool isNumberArray()
{
return this.type == ValueType.IntegerArray || this.type == ValueType.DoubleArray;
}
bool isNumber()
{
return this.type == ValueType.Integer || this.type == ValueType.Double;
}
bool isInteger()
{
return this.type == ValueType.Integer;
}
bool isDouble()
{
return this.type == ValueType.Double;
}
bool isString()
{
return this.type == ValueType.String;
}
int castInteger()
{
if (this.type == ValueType.Integer)
{
return this.integerValue;
}
if (this.type == ValueType.Double)
{
return cast(int)this.doubleValue;
}
throw new TypeMismatch();
}
double castDouble()
{
if (this.type == ValueType.Integer)
{
return this.integerValue;
}
if (this.type == ValueType.Double)
{
return this.doubleValue;
}
throw new TypeMismatch();
}
Array!wchar castString()
{
if (this.type == ValueType.String)
return this.stringValue;
throw new TypeMismatch();
}
wstring castDString()
{
if (this.type == ValueType.String)
return cast(immutable)this.stringValue.array;
throw new TypeMismatch();
}
string toString()
{
import std.conv, std.format;
switch(this.type)
{
case ValueType.Void:
return "void";
case ValueType.Integer:
return this.integerValue.to!string;
case ValueType.String:
return this.stringValue.array.to!string;
case ValueType.IntegerArray:
return format("integerarray[%s]", length);
case ValueType.DoubleArray:
return format("doublearray[%s]", length);
case ValueType.StringArray:
return format("doublearray[%s]", length);
case ValueType.InternalAddress:
return format("internal address address=0x%x", integerValue);
case ValueType.InternalSlotAddress:
return format("internal address slot=%d, address=0x%x", internalAddress.slot, internalAddress.address);
default:
return type.to!string;
}
}
@property int length()
{
switch(this.type)
{
case ValueType.String:
return cast(int)stringValue.length;
case ValueType.IntegerArray:
return cast(int)integerArray.length;
case ValueType.DoubleArray:
return cast(int)doubleArray.length;
case ValueType.StringArray:
return cast(int)stringArray.length;
default:
throw new TypeMismatch();
}
}
@property void length(int len)
{
switch(this.type)
{
case ValueType.String:
stringValue.length = len;
return;
case ValueType.IntegerArray:
integerArray.length = len;
return;
case ValueType.DoubleArray:
doubleArray.length = len;
return;
case ValueType.StringArray:
stringArray.length = len;
return;
default:
throw new TypeMismatch();
}
}
@property int dimCount()
{
switch(this.type)
{
case ValueType.String:
return stringValue.dimCount;
case ValueType.IntegerArray:
return integerArray.dimCount;
case ValueType.DoubleArray:
return doubleArray.dimCount;
case ValueType.StringArray:
return stringArray.dimCount;
default:
throw new TypeMismatch();
}
}
void opIndexAssign(Value v, int i)
{
switch(this.type)
{
//とりあえず破壊的に書き換えた
//どのみちこれだと文字数を増やすことができないのでArray!wcharで管理させたい
case ValueType.String:
stringValue[i] = v.castString;
break;
case ValueType.IntegerArray:
integerArray.array[i] = v.castInteger;
break;
case ValueType.DoubleArray:
doubleArray.array[i] = v.castDouble;
break;
case ValueType.StringArray:
stringArray.array[i] = v.castString;
break;
default:
throw new TypeMismatch();
}
}
Value opIndex(int i)
{
switch(this.type)
{
//とりあえず破壊的に書き換えた
//どのみちこれだと文字数を増やすことができないのでArray!wcharで管理させたい
case ValueType.String:
return Value(stringValue[i]);
case ValueType.IntegerArray:
return Value(integerArray.array[i]);
case ValueType.DoubleArray:
return Value(doubleArray.array[i]);
case ValueType.StringArray:
return Value(stringArray.array[i]);
default:
throw new TypeMismatch();
}
}
ValueType elementType()
{
switch(this.type)
{
case ValueType.String:
return ValueType.String;
case ValueType.IntegerArray:
return ValueType.Integer;
case ValueType.DoubleArray:
return ValueType.Double;
case ValueType.StringArray:
return ValueType.String;
default:
throw new TypeMismatch();
}
}
bool canCast(ValueType t)
{
return t == this.type || ((t == ValueType.Integer || t == ValueType.Double) && isNumber);
}
}
//import std.experimental.ndslice;
//ndsliceがこれに相当?
class Array(T)
{
T[] array;
//最大要素数2^^31
//4次元配列
int[4] dim;
int dimCount;
this(int len)
{
dim[0] = len;
dim[1] = 0;
dim[2] = 0;
dim[3] = 0;
array = new T[len];
static if(is(T == double))
{
array[] = 0;
}
dimCount = 1;
}
static if (!is(T == int))
{
this(T[] array)
{
dim[0] = cast(int)array.length;
dim[1] = 0;
dim[2] = 0;
dim[3] = 0;
this.array = array;
dimCount = 1;
}
}
@property size_t length()
{
return array.length;
}
this(int[] dim)
{
int len = 1;
foreach(int i, j; dim)
{
len *= j;
this.dim[i] = dim[i];
}
array = new T[len];
static if(is(T == double))
{
array[] = 0;
}
dimCount = cast(int)dim.length;
}
T opIndexAssign(T v, int[] dim)
{
import core.exception;
switch(dim.length)
{
case 1:
return this[dim[0]] = v;
case 2:
return this[dim[0], dim[1]] = v;
case 3:
return this[dim[0], dim[1], dim[2]] = v;
case 4:
return this[dim[0], dim[1], dim[2], dim[3]] = v;
default:
throw new RangeError();
}
}
ref T opIndex(int[] dim)
{
import core.exception;
switch(dim.length)
{
case 1:
return this[dim[0]];
case 2:
return this[dim[0], dim[1]];
case 3:
return this[dim[0], dim[1], dim[2]];
case 4:
return this[dim[0], dim[1], dim[2], dim[3]];
default:
throw new RangeError();
}
}
ref T opIndex(int i1)
{
if(dimCount != 1) throw new SyntaxError();
if(i1 >= dim[0]) throw new SubscriptOutOfRange();
return array[i1];
}
ref T opIndex(int i1, int i2)
{
if(dimCount != 2) throw new SyntaxError();
if(i1 >= dim[1] || i2 >= dim[0]) throw new SubscriptOutOfRange();
return array[i1 * dim[0] + i2];
}
ref T opIndex(int i1, int i2, int i3)
{
if(dimCount != 3) throw new SyntaxError();
if(i1 >= dim[2] || i2 >= dim[1] || i3 >= dim[0]) throw new SubscriptOutOfRange();
return array[i1 * dim[0] * dim[1] + i2 * dim[0] + i3];
}
ref T opIndex(int i1, int i2, int i3, int i4)
{
if(dimCount != 4) throw new SyntaxError();
if(i1 >= dim[3] || i2 >= dim[2] || i3 >= dim[1] || i4 >= dim[0]) throw new SubscriptOutOfRange();
return array[i1 * dim[0] * dim[1] * dim[2] + i2 * dim[0] * dim[1] + i3 * dim[0] + i4];
}
T opIndexAssign(T v, int i1)
{
if(dimCount != 1) throw new SyntaxError();
if(i1 >= dim[0]) throw new SubscriptOutOfRange();
return array[i1] = v;
}
T opIndexAssign(T v, int i1, int i2)
{
if(dimCount != 2) throw new SyntaxError();
if(i1 >= dim[1] || i2 >= dim[0]) throw new SubscriptOutOfRange();
return array[i1 * dim[0] + i2] = v;
}
T opIndexAssign(T v, int i1, int i2, int i3)
{
if(dimCount != 3) throw new SyntaxError();
if(i1 >= dim[2] || i2 >= dim[1] || i3 >= dim[0]) throw new SubscriptOutOfRange();
return array[i1 * dim[0] * dim[1] + i2 * dim[0] + i3] = v;
}
T opIndexAssign(T v, int i1, int i2, int i3, int i4)
{
if(dimCount != 4) throw new SyntaxError();
if(i1 >= dim[3] || i2 >= dim[2] || i3 >= dim[1] || i4 >= dim[0]) throw new SubscriptOutOfRange();
return array[i1 * dim[0] * dim[1] * dim[2] + i2 * dim[0] * dim[1] + i3 * dim[0] + i4] = v;
}
void push(T v)
{
if (dimCount != 1)
{
throw new TypeMismatch();
}
array ~= v;
dim[0]++;
}
void push(Array!T v)
{
if (dimCount != 1)
{
throw new TypeMismatch();
}
array ~= v.array;
dim[0] = cast(int)length;
}
T pop()
{
if (dimCount != 1)
{
throw new TypeMismatch();
}
auto last = array[$ - 1];
array.length--;
dim[0]--;
return last;
}
void unshift(T v)
{
if (dimCount != 1)
{
throw new TypeMismatch();
}
array = v ~ array;
dim[0]++;
}
void unshift(Array!T v)
{
if (dimCount != 1)
{
throw new TypeMismatch();
}
array = v.array ~ array;
dim[0] = cast(int)length;
}
T shift()
{
if (dimCount != 1)
{
throw new TypeMismatch();
}
auto l = array[0];
array = array[1..$];
dim[0]--;
return l;
}
@property void length(int size)
{
if (dimCount != 1)
{
throw new TypeMismatch();
}
array.length = size;
static if (is(T == double))
{
array[array.length - size..$] = 0;
}
dim[0] = size;
}
void append(Array!T input)
{
if (dimCount != 1 || input.dimCount != 1)
{
throw new TypeMismatch();
}
array ~= input.array;
dim[0] = cast(int)array.length;
}
void opIndexAssign(Array!T v, int i1)
{
if(dimCount != 1 || v.dimCount != 1 ) throw new SyntaxError();
if(i1 >= dim[0]) throw new SubscriptOutOfRange();
array = array[0..i1] ~ v.array ~ array[i1 + 1..$];
dim[0] = cast(int)array.length;
}
Array!T opOpAssign(string op = "~")(Array!T v)
{
if(dimCount != 1 || v.dimCount != 1 ) throw new SyntaxError();
array ~= v.array;
dim[0] = cast(int)array.length;
return this;
}
int calcIndex(int[] index)
{
if(dimCount != index.length) throw new SyntaxError();
import core.exception;
switch(index.length)
{
case 1:
return index[0];
case 2:
return index[0] * dim[0] + index[1];
case 3:
return index[0] * dim[0] * dim[1] + index[1] * dim[0] + index[2];
case 4:
return index[0] * dim[0] * dim[1] * dim[2] + index[1] * dim[0] * dim[1] + index[2] * dim[0] + index[3];
default:
throw new RangeError();
}
}
ArrayReference!T reference(int[] index)
{
auto i = calcIndex(index);
return ArrayReference!T(this, i);
}
void insert(Array!T ary, int index)
{
if(dimCount != 1 || ary.dimCount != 1 ) throw new SyntaxError();
if(index >= dim[0]) throw new SubscriptOutOfRange();
array = array[0..index] ~ ary.array ~ array[index + 1..$];
dim[0] = cast(int)array.length;
}
protected this(Array!T a)
{
this.dim = a.dim;
this.dimCount = a.dimCount;
this.array = a.array.dup;
}
Array!T dup()
{
return new Array!T(this);
}
public override int opCmp(Object o)
{
Array!T array = cast(Array!T)o;
if (!array)
return super.opCmp(o);
return std.algorithm.comparison.cmp(this.array, array.array);
}
}
struct ArrayReference(T)
{
Array!T reference;
int index;
T opAssign(T v)
{
return reference.array[index] = v;
}
static if (is(T == wchar))
{
void opAssign(Array!T ary)
{
reference.insert(ary, index);
}
}
T opOpAssign(string op)(T v)
{
mixin("return reference.array[index]" ~ op ~ "=v;");
}
T opBinary(string op)(T v)
{
mixin("return reference.array[index]" ~ op ~ "v;");
}
T2 opCast(T2)()
{
return cast(T2)reference.array[index];
}
void swap(T2)(ArrayReference!T2 t2)
{
T temp = reference.array[index];
reference.array[index] = cast(T)t2;
t2 = cast(T2)temp;
}
void swap(T2)(ref T2 t2)
if (!is(T2 T3 == ArrayReference!T3))
{
T temp = reference[index];
reference[index] = t2;
t2 = temp;
}
}