public void SetArrayElement(int memoryIndex, int offset, RuntimeValue value) { _process.MemoryHeap[memoryIndex + offset] = value; }
public void SetGlobalVariable(string identifier, RuntimeValue value) { _process.MemoryHeap[((VariableSymbol)_process.GlobalScope.FindSymbol(identifier, SymbolType.Variable)).MemoryIndex] = value.Clone(); }
/// <summary> /// Pushs an empty element onto the stack. /// </summary> /// <param name="type">Type of empty value to push onto stack.</param> public RuntimeValue PushEmpty(RuntimeValueType type) { if (_topIndex >= _stack.Length - 1) Resize(_stack.Length + 1); _stack[_topIndex] = new RuntimeValue(type); return _stack[_topIndex++]; }
/// <summary> /// Copys this value to another. /// </summary> public void CopyTo(RuntimeValue value) { value._booleanLiteral = _booleanLiteral; value._byteLiteral = _byteLiteral; value._doubleLiteral = _doubleLiteral; value._floatLiteral = _floatLiteral; value._integerLiteral = _integerLiteral; value._longLiteral = _longLiteral; value._memoryIndex = _memoryIndex; value._shortLiteral = _shortLiteral; value._stringLiteral = _stringLiteral; value._objectIndex = _objectIndex; value._instrIndex = _instrIndex; value._symbolIndex = _symbolIndex; value._symbol = _symbol; value._stackIndex = _stackIndex; value._register = _register; value._offsetRegister = _offsetRegister; value._valueType = _valueType; value._dataType = _dataType; value._referenceCount = _referenceCount; }
/// <summary> /// Sets the object value of a runtime value. This is used to keep reference counts up to date. /// </summary> /// <param name="value">Runtime value to set.</param> /// <param name="objectIndex">New object index.</param> private void SetObjectValue(RuntimeValue value, int objectIndex) { if (_process == null || value.ObjectIndex == objectIndex) return; for (int i = 0; i < _registers.Length; i++) if (value == _registers[i]) { value.ObjectIndex = objectIndex; return; // Don't bother about registers, they will loose there value soon. } if (value.ObjectIndex != -1 && _process.ObjectHeap[value.ObjectIndex] != null) { _process.ObjectHeap[value.ObjectIndex].ReferenceCount--; //System.Console.WriteLine("Reduced reference of (" + value.ObjectIndex + ", " + _process.ObjectHeap[value.ObjectIndex].ToString() + ") to " + _process.ObjectHeap[value.ObjectIndex].ReferenceCount); } value.ObjectIndex = objectIndex; if (value.ObjectIndex != -1 && _process.ObjectHeap[value.ObjectIndex] != null) { _process.ObjectHeap[value.ObjectIndex].ReferenceCount++; //System.Console.WriteLine("Increased reference of (" + value.ObjectIndex + ", " + _process.ObjectHeap[value.ObjectIndex].ToString() + ") to " + _process.ObjectHeap[value.ObjectIndex].ReferenceCount); } }
/// <summary> /// Clears all elements out of this stack. /// </summary> public void Clear() { for (int i = 0; i < _stack.Length; i++) _stack[i] = new RuntimeValue(0); _topIndex = 0; _frameIndex = 0; }
/// <summary> /// Copies a runtime array value from one thread to another whilst keeping track of objects and memory allocations. /// </summary> /// <param name="value">Value to copy.</param> /// <param name="toThread">Thread to copy from.</param> /// <param name="fromThread">Thread to copy to.</param> /// <returns>Memory index of new array.</returns> public int CopyValueArrayFromThread(RuntimeValue value, ScriptThread toThread, ScriptThread fromThread) { // Create the array. int arraySize = GetArrayLength(value.MemoryIndex); int arrayIndex = toThread.AllocateArray(value.DataType.DataType, arraySize); // Array of objects, how fun. if (value.DataType.DataType == DataType.Object) { for (int j = 0; j < arraySize; j++) { RuntimeValue elementValue = fromThread._process.MemoryHeap[arrayIndex + j]; if (elementValue.ObjectIndex == -1) toThread.SetArrayElement(arrayIndex, j, (RuntimeObject)null); else toThread.SetArrayElement(arrayIndex, j, fromThread._process.ObjectHeap[elementValue.ObjectIndex]); } } // Yay, an array of normal stuff. else { for (int j = 0; j < arraySize; j++) toThread.SetArrayElement(arrayIndex, j, fromThread._process.MemoryHeap[arrayIndex + j]); } return arrayIndex; }
/// <summary> /// If the given value directly or indirectly points to another /// value it will be resolved and returned. /// </summary> /// <param name="value">Value to resolve.</param> /// <returns>Resolved value.</returns> private RuntimeValue ResolveValue(RuntimeValue value) { switch (value.ValueType) { case RuntimeValueType.Register: return _registers[(int)value.Register]; case RuntimeValueType.DirectStack: return _runtimeStack[value.StackIndex]; case RuntimeValueType.DirectStackIndexed: return _runtimeStack[value.StackIndex + _registers[(int)value.OffsetRegister].IntegerLiteral]; case RuntimeValueType.IndirectStack: return _runtimeStack[_registers[(int)value.Register].StackIndex]; case RuntimeValueType.IndirectStackIndexed: return _runtimeStack[_registers[(int)value.Register].StackIndex + _registers[(int)value.OffsetRegister].IntegerLiteral]; case RuntimeValueType.DirectMemory: return _process.MemoryHeap[value.MemoryIndex]; case RuntimeValueType.DirectMemoryIndexed: return _process.MemoryHeap[value.MemoryIndex + _registers[(int)value.OffsetRegister].IntegerLiteral]; case RuntimeValueType.IndirectMemory: return _process.MemoryHeap[_registers[(int)value.Register].MemoryIndex]; case RuntimeValueType.IndirectMemoryIndexed: return _process.MemoryHeap[_registers[(int)value.Register].MemoryIndex + _registers[(int)value.OffsetRegister].IntegerLiteral]; default: return value; } }
/// <summary> /// Allocates a chunk of data on the heap. /// </summary> /// <param name="size">Size of data to allocate.</param> /// <param name="type">Data type the allocated memory should store.</param> /// <param name="value">Data type this heap is stored as (differs from the type paramter 'type' as it keeps track of arrays and references to)</param> /// <returns>Starting index of data on the heap.</returns> public int AllocateHeap(int size, RuntimeValueType type, DataTypeValue value) { // Check if there is any space on the stack. // Ignore the constant and global memory index as they are persistant. int allocatableIndex = 0, allocatableSize = 0; // First element is reserved to capture null-to-zero-cast-to-memory-index (XD) errors. for (int i = 1; i < _memoryHeap.Length; i++) { if (_memoryHeap[i] != null) { allocatableSize = 0; allocatableIndex = i + 1; if (_memoryHeap[i].ValueType == RuntimeValueType.MemoryBoundry) { i += _memoryHeap[i].IntegerLiteral; allocatableIndex = i + 1; continue; } i++; continue; } else allocatableSize++; if (allocatableSize >= (size + 1)) break; } if (allocatableSize < (size + 1))// || (allocatableIndex + allocatableSize) >= _memoryHeap.Length) { CollectGarbage(); // Desperatly try and free some space :S. if (allocatableSize + _lastCollectionMemoryCount < (size + 1)) { // If all else fails, resize. Its better than crashing. Array.Resize(ref _memoryHeap, _memoryHeap.Length * 2 < _memoryHeap.Length + size ? _memoryHeap.Length + size : _memoryHeap.Length * 2); // Double the size. DebugLogger.WriteLog("Memory heap of script '"+_url.ToString()+"' was resized due to overflow."); return AllocateHeap(size, type, value); } else return AllocateHeap(size, type, value); } // Actually allocate the data. for (int i = allocatableIndex; i <= (allocatableIndex + allocatableSize); i++) _memoryHeap[i] = new RuntimeValue(type); // Set the first data block as a memory boundry so the GC can look after it. _memoryHeap[allocatableIndex].ValueType = RuntimeValueType.MemoryBoundry; _memoryHeap[allocatableIndex].IntegerLiteral = size; _memoryHeap[allocatableIndex].ReferenceCount = 0; _memoryHeap[allocatableIndex].DataType = value; return allocatableIndex + 1; }
/// <summary> /// Loads the byte code from a given binary reader. /// </summary> /// <param name="reader">BinaryReader to load byte code from.</param> private void LoadByteCode(BinaryReader reader) { // Check the header is correct if (reader.ReadByte() == 'C' && reader.ReadByte() == 'R' && reader.ReadByte() == 'X') { // Read in header variables. _compileFlags = (CompileFlags)reader.ReadInt32(); _internalVariableIndex = reader.ReadInt32(); _memorySize = reader.ReadInt32(); int globalScopeIndex = reader.ReadInt32(); int memberScopeIndex = reader.ReadInt32(); _defaultEngineStateIndex = reader.ReadInt32(); _defaultEditorStateIndex = reader.ReadInt32(); // Create a new memory heap of the correct size if (_memorySize > _memoryHeap.Length) _memoryHeap = new RuntimeValue[_memorySize]; for (int i = 0; i < _memorySize; i++) _memoryHeap[i] = new RuntimeValue(RuntimeValueType.Invalid); // Set the 'special' globals to their appropriate values. _memoryHeap[0].ValueType = RuntimeValueType.Object; _memoryHeap[0].ObjectIndex = 0; int defineCount = reader.ReadInt32(); int symbolCount = reader.ReadInt32(); int instructionCount = reader.ReadInt32(); int debugFileCount = 0; if ((_compileFlags & CompileFlags.Debug) != 0) debugFileCount = reader.ReadInt32(); // Read in debug file list. string[] debugFiles = new string[debugFileCount]; if ((_compileFlags & CompileFlags.Debug) != 0) { for (int i = 0; i < debugFileCount; i++) debugFiles[i] = reader.ReadString(); } // Read in the define list. for (int i = 0; i < defineCount; i++) { string ident = reader.ReadString(); TokenID valueID = (TokenID)reader.ReadInt32(); string value = reader.ReadString(); Define define = new Define(ident, value, valueID); _defineList.Add(define); } // Read in symbol list. _symbolList = new Symbol[symbolCount]; for (int i = 0; i < symbolCount; i++) { // Read in general details about symbol. SymbolType type = (SymbolType)reader.ReadByte(); string identifier = reader.ReadString(); int scopeIndex = reader.ReadInt32(); Symbol scope = null; Symbol symbol = null; if (scopeIndex != -1) scope = (Symbol)_symbolList[scopeIndex]; // Read in specialized details about symbol. switch (type) { case SymbolType.JumpTarget: continue; // Ignore jump targets. case SymbolType.Namespace: NamespaceSymbol namespaceSymbol = new NamespaceSymbol(scope); symbol = namespaceSymbol; break; case SymbolType.Enumeration: EnumerationSymbol enumSymbol = new EnumerationSymbol(scope); symbol = enumSymbol; break; case SymbolType.String: StringSymbol stringSymbol = new StringSymbol(scope, identifier); symbol = stringSymbol; break; case SymbolType.Function: FunctionSymbol functionSymbol = new FunctionSymbol(identifier, scope); symbol = functionSymbol; functionSymbol.EntryPoint = reader.ReadInt32(); functionSymbol.LocalDataSize = reader.ReadInt16(); functionSymbol.IsEvent = reader.ReadBoolean(); functionSymbol.IsConsole = reader.ReadBoolean(); functionSymbol.IsExport = reader.ReadBoolean(); functionSymbol.IsImport = reader.ReadBoolean(); functionSymbol.IsThreadSpawner = reader.ReadBoolean(); functionSymbol.IsMember = reader.ReadBoolean(); functionSymbol.ParameterCount = reader.ReadByte(); bool isArray = reader.ReadBoolean(); bool isReference = reader.ReadBoolean(); functionSymbol.ReturnType = new DataTypeValue((DataType)reader.ReadByte(), isArray, isReference); functionSymbol.AccessModifier = (SymbolAccessModifier)reader.ReadByte(); break; case SymbolType.State: StateSymbol stateSymbol = new StateSymbol(scope); symbol = stateSymbol; stateSymbol.IsEngineDefault = reader.ReadBoolean(); stateSymbol.IsEditorDefault = reader.ReadBoolean(); break; case SymbolType.Variable: VariableSymbol variableSymbol = new VariableSymbol(scope); symbol = variableSymbol; variableSymbol.DataType = new DataTypeValue((DataType)reader.ReadByte(), false, false); variableSymbol.DataType.IsReference = reader.ReadBoolean(); variableSymbol.IsArray = reader.ReadBoolean(); variableSymbol.DataType.IsArray = variableSymbol.IsArray; variableSymbol.IsConstant = reader.ReadBoolean(); variableSymbol.MemoryIndex = reader.ReadInt32(); variableSymbol.StackIndex = reader.ReadInt32(); variableSymbol.VariableType = (VariableType)reader.ReadByte(); variableSymbol.IsProperty = reader.ReadBoolean(); variableSymbol.AccessModifier = (SymbolAccessModifier)reader.ReadByte(); variableSymbol.ConstToken = new Token(TokenID.TypeIdentifier, reader.ReadString(), 0, 0, ""); break; case SymbolType.MetaData: MetaDataSymbol metaDataSymbol = new MetaDataSymbol(scope, identifier, ""); symbol = metaDataSymbol; metaDataSymbol.Value = reader.ReadString(); break; } symbol.Identifier = identifier; symbol.Index = i; _symbolList[i] = symbol; } // Retrieve global scope. _globalScope = _symbolList[globalScopeIndex] as FunctionSymbol; _memberScope = _symbolList[memberScopeIndex] as FunctionSymbol; //_currentState = _symbolList[_defaultEngineStateIndex] as StateSymbol; // Force this to be declared in the engine / editor. // Read in instruction list. _instructionList = new RuntimeInstruction[instructionCount]; for (int i = 0; i < instructionCount; i++) { // Read in instruction details and create a new instruction. OpCode opCode = (OpCode)reader.ReadByte(); int operandCount = reader.ReadByte(); RuntimeInstruction instruction = new RuntimeInstruction(opCode); _instructionList[i] = instruction; if ((_compileFlags & CompileFlags.Debug) != 0) { int fileIndex = reader.ReadSByte(); if (fileIndex != -1) instruction.File = debugFiles[fileIndex]; instruction.Offset = reader.ReadInt16(); instruction.Line = reader.ReadInt16(); } // Read in each operand attached to this instruction for (int k = 0; k < operandCount; k++) { // Read in general details about this operand and create // a new runtime value instance. RuntimeValueType opType = (RuntimeValueType)reader.ReadInt32(); RuntimeValue operand = new RuntimeValue(opType); instruction.Operands[instruction.OperandCount] = operand; instruction.OperandCount++; // Read in specialized info about this operand. switch(opType) { case RuntimeValueType.BooleanLiteral: operand.BooleanLiteral = reader.ReadBoolean(); break; case RuntimeValueType.ByteLiteral: operand.ByteLiteral = reader.ReadByte(); break; case RuntimeValueType.DirectMemory: operand.MemoryIndex = reader.ReadInt32(); break; case RuntimeValueType.DirectMemoryIndexed: operand.MemoryIndex = reader.ReadInt32(); operand.OffsetRegister = (Register)reader.ReadByte(); break; case RuntimeValueType.DirectStack: operand.StackIndex = reader.ReadInt32(); break; case RuntimeValueType.DirectStackIndexed: operand.StackIndex = reader.ReadInt32(); operand.OffsetRegister = (Register)reader.ReadByte(); break; case RuntimeValueType.DoubleLiteral: operand.DoubleLiteral = reader.ReadDouble(); break; case RuntimeValueType.FloatLiteral: operand.FloatLiteral = reader.ReadSingle(); break; case RuntimeValueType.IndirectMemory: operand.Register = (Register)reader.ReadByte(); break; case RuntimeValueType.IndirectMemoryIndexed: operand.Register = (Register)reader.ReadByte(); operand.OffsetRegister = (Register)reader.ReadByte(); break; case RuntimeValueType.IndirectStack: operand.Register = (Register)reader.ReadByte(); break; case RuntimeValueType.IndirectStackIndexed: operand.Register = (Register)reader.ReadByte(); operand.OffsetRegister = (Register)reader.ReadByte(); break; case RuntimeValueType.InstrIndex: operand.InstrIndex = reader.ReadInt32(); break; case RuntimeValueType.IntegerLiteral: operand.IntegerLiteral = reader.ReadInt32(); break; case RuntimeValueType.LongLiteral: operand.LongLiteral = reader.ReadInt64(); break; case RuntimeValueType.Register: operand.Register = (Register)reader.ReadByte(); break; case RuntimeValueType.ShortLiteral: operand.ShortLiteral = reader.ReadInt16(); break; case RuntimeValueType.SymbolIndex: operand.SymbolIndex = reader.ReadInt32(); operand.Symbol = (Symbol)_symbolList[operand.SymbolIndex]; if (operand.Symbol is StringSymbol) { operand.StringLiteral = operand.Symbol.Identifier; operand.ValueType = RuntimeValueType.StringLiteral; } break; } } } // Fill the member-function hash table. foreach (Symbol symbol in GlobalScope.Symbols) if (symbol != null && symbol.Type == SymbolType.Function && ((FunctionSymbol)symbol).AccessModifier == SymbolAccessModifier.Public) _memberFunctionHashTable.Add(symbol.ToString().ToLower(), symbol); } else throw new Exception("Unable to load script byte code, header is invalid."); }
/// <summary> /// Copys this value to another. /// </summary> public void CopyTo(RuntimeValue value) { value._values = _values; value._stringLiteralValue = _stringLiteralValue; value._memoryIndex = _memoryIndex; value._objectIndex = _objectIndex; value._instrIndex = _instrIndex; value._symbolIndex = _symbolIndex; value._symbol = _symbol; value._stackIndex = _stackIndex; value._register = _register; value._offsetRegister = _offsetRegister; value._valueType = _valueType; value._dataType = _dataType; value._referenceCount = _referenceCount; }
/// <summary> /// Creates an exact clone of this value. /// </summary> /// <returns>Exact clone of this value.</returns> public RuntimeValue Clone() { RuntimeValue value = new RuntimeValue(RuntimeValueType.Invalid); CopyTo(value); return value; }
/// <summary> /// Sets the memory inde value of a runtime value. This is used to keep reference counts up to date. /// </summary> /// <param name="value">Runtime value to set.</param> /// <param name="memoryIndex">New memory index.</param> private void SetMemoryIndexValue(RuntimeValue value, int memoryIndex) { for (int i = 0; i < _registers.Length; i++) if (value == _registers[i]) { value.MemoryIndex = memoryIndex; return; // Don't bother about registers, they will loose there value soon. } if (value.MemoryIndex != -1 && _process.MemoryHeap[value.MemoryIndex - 1] != null) _process.MemoryHeap[value.MemoryIndex - 1].ReferenceCount--; value.MemoryIndex = memoryIndex; if (value.MemoryIndex != -1 && _process.MemoryHeap[value.MemoryIndex - 1] != null) _process.MemoryHeap[value.MemoryIndex - 1].ReferenceCount++; }
public void SetLocalVariable(string identifier, RuntimeValue value) { RuntimeValue localValue = ResolveLocal(identifier); value.CopyTo(localValue); }
/// <summary> /// Copies a runtime value from one thread to another whilst keeping track of objects and memory allocations. /// </summary> /// <param name="value">Value to copy.</param> /// <param name="toThread">Thread to copy from.</param> /// <param name="fromThread">Thread to copy to.</param> /// <returns>New value.</returns> public RuntimeValue CopyValueFromThread(RuntimeValue value, ScriptThread toThread, ScriptThread fromThread) { if (value.ValueType == RuntimeValueType.Object) { int index = (value.ObjectIndex != -1) ? toThread._process.AllocateObjectIndex(fromThread._process.ObjectHeap[value.ObjectIndex]) : -1; RuntimeValue stackValue = new RuntimeValue(RuntimeValueType.Object); stackValue.DataType = value.DataType; SetObjectValue(stackValue, index); return stackValue; } else { return value; } }
/// <summary> /// Sets the return value as a given value. /// </summary> /// <param name="value">Value to move into return value.</param> public void SetReturnValue(RuntimeValue value) { _registers[(int)Register.Return] = value.Clone(); }
public void PassParameter(string value) { RuntimeValue stackValue = new RuntimeValue(RuntimeValueType.StringLiteral); stackValue.StringLiteral = value; _runtimeStack.Push(stackValue); _passedParameterCount++; _passedParameterMask.Add(new DataTypeValue(DataType.String, false, false)); }
/// <summary> /// Sets the memory inde value of a runtime value. This is used to keep reference counts up to date. /// </summary> /// <param name="value">Runtime value to set.</param> /// <param name="memoryIndex">New memory index.</param> private void SetMemoryIndexValue(RuntimeValue value, int memoryIndex) { if (_process == null || value.MemoryIndex == memoryIndex) return; for (int i = 0; i < _registers.Length; i++) if (value == _registers[i]) { value.MemoryIndex = memoryIndex; return; // Don't bother about registers, they will loose there value soon. } // System.Console.WriteLine(_process.Instructions[_instructionPointer].OpCode + ": " + value.MemoryIndex + " to " + memoryIndex); if (value.MemoryIndex != -1 && _process.MemoryHeap[value.MemoryIndex - 1] != null) { _process.MemoryHeap[value.MemoryIndex - 1].ReferenceCount--; // System.Console.WriteLine("Decreased ref count of " + value.MemoryIndex + " to " + _process.MemoryHeap[value.MemoryIndex - 1].ReferenceCount); } value.MemoryIndex = memoryIndex; if (value.MemoryIndex != -1 && _process.MemoryHeap[value.MemoryIndex - 1] != null) { _process.MemoryHeap[value.MemoryIndex - 1].ReferenceCount++; // System.Console.WriteLine("Increased ref count of " + value.MemoryIndex + " to " + _process.MemoryHeap[value.MemoryIndex - 1].ReferenceCount); } }
public void PassParameter(RuntimeObject value) { int index = _process.AllocateObjectIndex(value); RuntimeValue stackValue = new RuntimeValue(RuntimeValueType.Object); SetObjectValue(stackValue, index); _runtimeStack.Push(stackValue); _passedParameterCount++; _passedParameterMask.Add(new DataTypeValue(DataType.Object, false, false)); }
/// <summary> /// Invoked when a script wants to set the value of an indexed member of this object. /// </summary> /// <param name="thread">Script thread that invoked this function.</param> /// <param name="variable">Symbol describing the member that it wants set.</param> /// <param name="value">Value it wants the member to be set to.</param> /// <param name="index">Index of member to it wants set.</param> /// <returns>True if successfull or false if not.</returns> public virtual bool SetMember(ScriptThread thread, VariableSymbol variable, RuntimeValue value, RuntimeValue indexer) { return false; }
public void PassParameter(RuntimeValue value) { _runtimeStack.Push(value); _passedParameterCount++; _passedParameterMask.Add(value.DataType); }
/// <summary> /// Pushs a new value onto the top of the stack. /// </summary> /// <param name="value">Value to push onto stack.</param> public RuntimeValue Push(RuntimeValue value) { if (_topIndex >= _stack.Length - 1) Resize(_stack.Length + 1); _stack[_topIndex++] = value; return value; }
public void PassParameterArray(int memoryIndex) { RuntimeValue stackValue = new RuntimeValue(RuntimeValueType.DirectMemory); SetMemoryIndexValue(stackValue, memoryIndex); _runtimeStack.Push(stackValue); _passedParameterCount++; _passedParameterMask.Add(_process.MemoryHeap[memoryIndex].DataType); }
/// <summary> /// Resizes the stack so it can store a given capacity /// of runtime values. /// </summary> /// <param name="capacity">New capacity of stack.</param> public void Resize(int capacity) { if (_stack == null) _stack = new RuntimeValue[capacity]; else Array.Resize<RuntimeValue>(ref _stack, capacity); for (int i = 0; i < _stack.Length; i++) if (_stack[i] == null) _stack[i] = new RuntimeValue(0); }
/// <summary> /// Invoked when a script wants to get the value of an indexed member of this object. /// </summary> /// <param name="thread">Script thread that invoked this function.</param> /// <param name="variable">Symbol describing the member that it wants get.</param> /// <param name="index">Index of member it want to get.</param> /// <returns>True if successfull or false if not.</returns> public override bool SetMember(ScriptThread thread, VariableSymbol variable, RuntimeValue value, RuntimeValue indexer) { if (_nativeObject is ScriptedEntityNode) { // Check the script process is valid. ScriptProcess process = ((ScriptedEntityNode)_nativeObject).ScriptProcess; if (process == null) return false; // See if we can get the symbol they are after. VariableSymbol processSymbol = process.GetSymbol(variable.Identifier, SymbolType.Variable) as VariableSymbol; if (processSymbol == null) return false; // Grab the variable runtime value. (This can probably be optimized). RuntimeValue runtimeValue = process[0].GetRuntimeValueGlobal(processSymbol.Identifier); // Check its public. if (processSymbol.AccessModifier != SymbolAccessModifier.Public) return false; // Check data types are correct. if (variable.DataType.DataType != processSymbol.DataType.DataType || processSymbol.DataType.IsArray != true) return false; // Grab the arrays variable. RuntimeValue indexValue = process[0].GetRuntimeValueArrayElement(runtimeValue.MemoryIndex, indexer.IntegerLiteral); // Copy value. RuntimeValue copiedValue = process[0].CopyValueFromThread(value, process[0], thread); // Set value (this can be optimized). process[0].SetGlobalVariable(processSymbol.Identifier, copiedValue); } else if (_nativeObject is EntityNode) { } else if (_nativeObject is EmitterNode) { } else if (_nativeObject is TilemapSegmentNode) { } else if ((_nativeObject as SceneNode) != null) { } return false; }