/// <summary> /// Parses a function declaration. A function is a way of isolating code that you want /// to be able to call multiple times without rewriting it each time. /// Syntax: /// ReturnType Identifier "(" { Identifier ["=" Expression] [ "," ] } ")" Statement /// </summary> private void ParseFunction() { // Make sure we are in a state's scope. if (_currentToken.ID == TokenID.KeywordEvent && _currentScope.Type != SymbolType.State) Error(ErrorCode.InvalidScope, "Events can only be declared within a state block.", false, 0); // Make sure we are in the global scopes as functions can't // be declared anywhere else. if (_currentScope.Type != SymbolType.State && _currentScope.Type != SymbolType.Function && _currentScope.Type != SymbolType.Namespace) Error(ErrorCode.InvalidScope, "Functions can only be declared in a function's, state's or event's scope.", false, 0); // Read in each flag. bool isThread = false; bool isEvent = false; bool isConsole = false; bool isExport = false; bool isImport = false; SymbolAccessModifier modifier = SymbolAccessModifier.Private; bool gotModifier = false; while (_currentToken.IsDataType == false && EndOfTokenStream() != true) { switch (_currentToken.ID) { case TokenID.KeywordThread: if (isThread == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0); isThread = true; break; case TokenID.KeywordEvent: if (isEvent == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0); isEvent = true; break; case TokenID.KeywordConsole: if (isConsole == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0); isConsole = true; break; case TokenID.KeywordImport: if (isImport == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0); isImport = true; break; case TokenID.KeywordExport: if (isExport == true) Error(ErrorCode.DuplicateFlag, "\"" + _currentToken.Ident + "\" flag declared multiple times.", false, 0); isExport = true; break; case TokenID.KeywordPublic: if (gotModifier == true) Error(ErrorCode.DuplicateFlag, "Access modifier has already been declared.", false, 0); modifier = SymbolAccessModifier.Public; gotModifier = true; break; case TokenID.KeywordPrivate: if (gotModifier == true) Error(ErrorCode.DuplicateFlag, "Access modifier has already been declared.", false, 0); modifier = SymbolAccessModifier.Private; gotModifier = true; break; case TokenID.KeywordProtected: if (gotModifier == true) Error(ErrorCode.DuplicateFlag, "Access modifier has already been declared.", false, 0); modifier = SymbolAccessModifier.Protected; gotModifier = true; break; } NextToken(); } if (isEvent == true && (isThread == true || isExport == true || isImport == true || isConsole == true)) Error(ErrorCode.InvalidFlag, "Events can't be declared as native, threaded, exported, imported or console."); // Store the return type for later. DataTypeValue returnDataType = new DataTypeValue(DataTypeFromKeywordToken(_currentToken.ID), false, false); if (returnDataType.DataType == DataType.Invalid) Error(ErrorCode.InvalidDataType, "Functions can't be declared as \"" + _currentToken.Ident + "\".", false, 0); // Check for an array reference if (LookAheadToken().ID == TokenID.CharOpenBracket) { NextToken(); returnDataType.IsArray = true; ExpectToken(TokenID.CharCloseBracket); } // Read in the functions identifier and store it // for layer use. ExpectToken(TokenID.TypeIdentifier); string functionIdentifier = _currentToken.Ident; // Read in the opening parenthesis used to define the paremeter list. ExpectToken(TokenID.CharOpenParenthesis); // Read in each paremeter. ArrayList functionParameterMask = new ArrayList(); int parameterCount = 0; ArrayList paramList = new ArrayList(); if (LookAheadToken().ID != TokenID.CharCloseParenthesis) { // Read in each parameter while (true) { // Check if there is a constant keyword before this variable. bool paramIsConst = false; if (LookAheadToken().ID == TokenID.KeywordConst) { NextToken(); paramIsConst = true; } // Read in the data type keyword and store it. NextToken(); DataTypeValue paramDataType = new DataTypeValue(DataTypeFromKeywordToken(_currentToken.ID), false, false); if (paramDataType.DataType == DataType.Invalid) Error(ErrorCode.InvalidDataType, "Expecting data type keyword.", false, 0); // Read in array declaration. bool paramIsArray = false; if (LookAheadToken().ID == TokenID.CharOpenBracket) { NextToken(); paramIsArray = true; paramDataType.IsArray = true; ExpectToken(TokenID.CharCloseBracket); } // Increase the parameter mask functionParameterMask.Add(paramDataType); parameterCount++; // Read in the parameters identifier. ExpectToken(TokenID.TypeIdentifier); string paramIdentifier = _currentToken.Ident; // Process parameters depending on current pass. if (_currentPass == 0) { VariableSymbol variableSymbol = new VariableSymbol(null); variableSymbol.DataType = paramDataType; variableSymbol.Identifier = paramIdentifier; variableSymbol.VariableType = VariableType.Parameter; variableSymbol.IsArray = paramIsArray; variableSymbol.IsConstant = paramIsConst; paramList.Add(variableSymbol); } // Read in comma if it exists. if (LookAheadToken().ID == TokenID.CharComma) NextToken(); else break; } } // *looks arounds shiftily* ... Ok its hack like but it works. functionParameterMask.Reverse(); // Create a new function symbol. FunctionSymbol functionSymbol; if (_currentPass == 0) { if (_currentScope.FindFunctionByMask(functionIdentifier, functionParameterMask) != null) Error(ErrorCode.DuplicateSymbol, "Function \"" + functionIdentifier + "\" redefinition.", false, 0); functionSymbol = new FunctionSymbol(functionIdentifier, _currentScope); functionSymbol.ReturnType = returnDataType; functionSymbol.ParameterCount = parameterCount; functionSymbol.IsThreadSpawner = isThread; functionSymbol.IsEvent = isEvent; functionSymbol.IsConsole = isConsole; functionSymbol.IsImport = isImport; functionSymbol.IsExport = isExport; functionSymbol.AccessModifier = modifier; if (isConsole == true && functionSymbol.ReturnType.DataType != DataType.Void) Error(ErrorCode.InvalidDataType, "Console variables cannot return a value."); paramList.Reverse(); int parameterIndex = 0; foreach (VariableSymbol variableSymbol in paramList) { if (functionSymbol.FindSymbol(variableSymbol.Identifier, SymbolType.Variable) != null) Error(ErrorCode.DuplicateSymbol, "Variable redefinition \"" + variableSymbol.Identifier + "\""); // If we're a console function we can only accept bool, int, string or float if (isConsole == true && (variableSymbol.DataType.IsArray == true || variableSymbol.DataType.DataType == DataType.Byte || variableSymbol.DataType.DataType == DataType.Double || variableSymbol.DataType.DataType == DataType.Object || variableSymbol.DataType.DataType == DataType.Short)) Error(ErrorCode.InvalidDataType, "Console variables can only accept bool, integer, string or float parameters."); functionSymbol.AddSymbol(variableSymbol); variableSymbol.Scope = functionSymbol; parameterIndex++; } } else { functionSymbol = _currentScope.FindFunctionByMask(functionIdentifier, functionParameterMask) as FunctionSymbol; if (functionSymbol == null) functionSymbol = _globalScope.FindFunctionByMask(functionIdentifier, functionParameterMask) as FunctionSymbol; if (functionSymbol == null) Error(ErrorCode.InvalidFunction, "Attempt to call undeclared function \"" + functionIdentifier + "(" + functionParameterMask + ")\"."); for (int i = 0; i < parameterCount; i++) { VariableSymbol variableSymbol = (VariableSymbol)functionSymbol.Symbols[i]; variableSymbol.StackIndex = -(functionSymbol.LocalDataSize + 2 + (i + 1)); } } _lastMetaDataSymbol = functionSymbol; // Read in the closing parenthesis used to define the end of the paremeter list. ExpectToken(TokenID.CharCloseParenthesis); // Read in this function's statement block. if (functionSymbol.IsImport == false) { Symbol scope = _currentScope; Instruction instruction = null; _currentScope = functionSymbol; ParseStatement(); _currentScope = scope; // Append a mandatory return instruction if we are in pass 2. if (_currentPass == 1) { // Cast the return registered into the return type. if (functionSymbol.ReturnType.DataType != DataType.Void) { instruction = CreateInstruction(OpCodeByType(functionSymbol.ReturnType, OpCodeType.CAST), functionSymbol, _currentToken); new Operand(instruction, Register.Return); } // Return from function. instruction = CreateInstruction(OpCode.RETURN, functionSymbol, _currentToken); } } else ExpectToken(TokenID.CharSemiColon); }
/// <summary> /// Invoked when a script wants to call a method of this object. /// </summary> /// <param name="thread">Script thread that invoked this function.</param> /// <param name="method">Symbol describing the method that it wants called.</param> /// <returns>True if successfull or false if not.</returns> public virtual bool InvokeMethod(ScriptThread thread, FunctionSymbol method) { return false; }
/// <summary> /// Compiles a script from a string into byte code. /// </summary> /// <param name="data">Data of script to compile.</param> /// <param name="flags">Bitmask of flags defining how the script should be compiled.</param> /// <param name="defineList">A list of defines to use while preprocessing script.</param> /// <param name="includePaths">A list of directory paths to use when looking for include files.</param> /// <param name="fileUrl">Contains the url of the file this data comes from.</param> /// <returns>The number of errors or warning this script has generated duren compilation.</returns> public int CompileString(string data, CompileFlags flags, Define[] defineList, object[] includePaths, string fileUrl) { #if !DEBUG try { #endif // Reset all variables used to store compilation details. _errorList.Clear(); _compiledSymbolList.Clear(); _compiledInstructionList.Clear(); _compiledDebugFileList.Clear(); _compiledDefineList.Clear(); _loopTrackerStack.Clear(); _metaDataList.Clear(); _currentToken = null; _currentPass = 0; _currentScope = null; _globalScope = new FunctionSymbol("$global", null); // Initialize global scope here. _memberScope = new FunctionSymbol("$member", null); // Initialize member scope here. _compileFlags = flags; _tokenList = null; _tokenIndex = 0; _memorySize = 1; // Reserve space for 'special' globals like 'this'. _internalVariableIndex = 0; _defaultEngineState = _defaultEditorState = null; _errorsOccured = false; _overrideInstructionScope = null; // Create the 'this' variable. VariableSymbol thisSymbol = new VariableSymbol(_globalScope); thisSymbol.DataType = new DataTypeValue(DataType.Object, false, false); thisSymbol.Identifier = "this"; thisSymbol.IsConstant = true; thisSymbol.IsUsed = true; thisSymbol.MemoryIndex = 0; thisSymbol.VariableType = VariableType.Constant; // Create a lexer and convert script into a list // of tokens. DebugLogger.WriteLog("Preforming lexical analysis on script."); Lexer lexer = new Lexer(); if (lexer.Analyse(data, _compileFlags, fileUrl) > 0) { foreach (CompileError error in lexer.ErrorList) _errorList.Add(error); } _tokenList = lexer.TokenList; // Add the script directory into the include path array. string includePath = Path.GetDirectoryName(fileUrl); string[] newIncludePaths = new string[includePaths.Length + 1]; includePaths.CopyTo(newIncludePaths, 0); newIncludePaths[newIncludePaths.Length - 1] = includePath; includePaths = newIncludePaths; // Create a pre-processor and process the token list DebugLogger.WriteLog("Preforming preprocessing on script."); PreProcessor preProcessor = new PreProcessor(); if (preProcessor.Process(_tokenList, _compileFlags, defineList, includePaths) > 0) { foreach (CompileError error in preProcessor.ErrorList) _errorList.Add(error); } _compiledDefineList = preProcessor.DefineList; _tokenList = preProcessor.TokenList; try { // Pass 0: Collect infomation. // Pass 1: Generate byte code. DebugLogger.WriteLog("Compiling script in 2 passes."); // Go over the source code in 2 passes. for (int pass = 0; pass < 2; pass++) { _currentPass = pass; _currentToken = null; _tokenIndex = 0; _currentScope = _globalScope; _internalVariableIndex = 0; // This needs to be reset so statements using // an internal variables can find them on the second pass. while (!EndOfTokenStream()) { try { ParseStatement(); } catch (CompilePanicModeException) { DebugLogger.WriteLog("Panic mode initialized in script."); // Don't do anything here, just allow the error to be // forgoten and carry on as normal. } // If there are any errors quit compilation now. if (_errorsOccured == true) throw new CompileBreakException(); } } // Yell at user if no default state has been declared. if (_defaultEngineState == null && (_compileFlags & CompileFlags.Library) == 0) Error(ErrorCode.MissingDefaultState, "Default engine state is missing."); } catch (CompileBreakException) { DebugLogger.WriteLog("Script compilation broken via CompileBreakException."); } // Check what errors occured. int fatalErrorCount = 0; int errorCount = 0; int warningCount = 0; int messageCount = 0; foreach (CompileError error in _errorList) { switch (error.AlertLevel) { case ErrorAlertLevel.Error: errorCount++; break; case ErrorAlertLevel.FatalError: fatalErrorCount++; break; case ErrorAlertLevel.Message: messageCount++; break; case ErrorAlertLevel.Warning: warningCount++; break; } DebugLogger.WriteLog(error.ToString(), LogAlertLevel.Warning); } DebugLogger.WriteLog("Script compiled with "+fatalErrorCount+" fatal errors, "+errorCount+" errors, "+warningCount+" warnings and "+messageCount+" messages."); // If there are any errors quit compilation now. if (_errorsOccured == true) return _errorList.Count; // Append an exit symbol onto the global scopes instruction list. CreateInstruction(OpCode.EXIT, _globalScope, _currentToken); DebugLogger.WriteLog("Optimizing and tweeking symbols and instructions."); // Compile symbol list. CompileSymbol(_globalScope); CompileSymbol(_memberScope); // Go through instruction list and replace placeholders with their values. int symbolIndex = 0; foreach (Symbol symbol in _compiledSymbolList) { symbol.Index = symbolIndex; symbolIndex++; // Update the entry point if this is a function or event. switch (symbol.Type) { case SymbolType.Function: ((FunctionSymbol)symbol).EntryPoint = _compiledInstructionList.Count; break; case SymbolType.Variable: bool check = true; if (symbol.Scope.Type == SymbolType.Function) if (((FunctionSymbol)symbol.Scope).IsImport == true) check = false; // Should we remove it rather than warning? if (((VariableSymbol)symbol).IsUsed == false && ((VariableSymbol)symbol).IsConstant == false && check == true) Warning(ErrorCode.UnusedVariable, "Variable \"" + symbol.Identifier + "\" is declared but never used."); break; } foreach (Instruction instruction in symbol.Instructions) { // Create a new debug file entry if this instruction // was generated in a previously unknown file. if (instruction.File != null && instruction.File != "") { bool found = false; foreach (string file in _compiledDebugFileList) if (file == instruction.File) found = true; if (found == false) _compiledDebugFileList.Add(instruction.File); } // Go through each operand attach to this instruction // and check for any trackers. foreach (Operand operand in instruction.Operands) { if (operand == null) continue; // Update operand based on type. switch (operand.OpType) { case OperandType.JumpTarget: operand.OpType = OperandType.InstrIndex; switch (symbol.Type) { case SymbolType.Function: operand.InstrIndex = ((FunctionSymbol)symbol).EntryPoint + operand.JumpTarget.InstrIndex; break; } break; case OperandType.SymbolIndexTracker: operand.OpType = OperandType.SymbolIndex; operand.SymbolIndex = _compiledSymbolList.IndexOf(operand.SymbolIndexTracker); break; } } _compiledInstructionList.Add(instruction); } } // Optimize this symbols instructions. (Currently somewhat error prone) //int instructionCount = _compiledInstructionList.Count; //ScriptOptimizer optimizer = new ScriptOptimizer(); //optimizer.Optimize(_compiledInstructionList, _compiledSymbolList); //_compiledInstructionList = optimizer.OptimizedInstructions; //_compiledSymbolList = optimizer.OptimizedSymbols; // int index = 0; //foreach (Instruction instr in _compiledInstructionList) //{ // System.Console.WriteLine("\t"+instr.Decompile()); // index++; //} #if !DEBUG } catch (Exception) { _errorList.Add(new CompileError(ErrorCode.InternalError, "An internal compiler error occured.", ErrorAlertLevel.FatalError, 0, 0, "")); } #endif return _errorList.Count; }
/// <summary> /// Executes a script or native function. /// </summary> /// <param name="symbol">Symbol of function to call.</param> /// <param name="ignoreThread">If set and this function is a thread spawner a new thread will not be created.</param> private void CallFunction(FunctionSymbol symbol, bool ignoreThread) { // Can't call if debugging :S. if (_debugger != null && _debugger.RunScript == false) return; // Push this function onto the call stack. _callStack.Push(symbol); _registers[(int)Register.Return].Clear(); _callingFunction = symbol; if (symbol.IsImport == true) { // Find and call native function. if (_process.VirtualMachine != null) { DataTypeValue[] parameterTypes = null; NativeFunction function = symbol.NativeFunction; if (function == null) { // Find the functions parameter types. parameterTypes = new DataTypeValue[symbol.ParameterCount]; for (int i = 0; i < symbol.ParameterCount; i++) parameterTypes[(symbol.ParameterCount - 1) - i] = ((VariableSymbol)symbol.Symbols[i]).DataType; // Find native function function = _process.VirtualMachine.FindNativeFunction(symbol.Identifier, parameterTypes); symbol.NativeFunction = function; } if (function != null) { #if !DEBUG try { #endif function.Delegate(this); #if !DEBUG } catch (Exception e) { Error(e.ToString()); } #endif } // Ok so its not a native one, lets check the script exports. else { ScriptExportFunction callFunction = (ScriptExportFunction)ScriptExportFunction.FunctionHashTable[symbol.ToString().ToLower()]; /* foreach (ScriptExportFunction exportFunction in ScriptExportFunction.FunctionList) { if (exportFunction.Symbol.Identifier.ToLower() != symbol.Identifier.ToLower()) continue; if (exportFunction.Symbol.ParameterCount != parameterTypes.Length) continue; bool paramsValid = true; for (int i = 0; i < parameterTypes.Length; i++) if (exportFunction.Symbol.CheckParameterTypeValid(i, parameterTypes[i]) == false) paramsValid = false; if (paramsValid == false) continue; callFunction = exportFunction; break; } */ if (callFunction != null) { InvokeExportFunction(callFunction.Symbol, callFunction.Thread, this); } else { Error("Attempt to call unknown function '" + symbol.ToString() + "'"); } } } // Pop of this functions parameters. for (int i = 0; i < symbol.ParameterCount; i++) { RuntimeValue stack = _runtimeStack.Pop(); if (stack.ObjectIndex != -1) SetObjectValue(stack, -1); else if (stack.MemoryIndex != -1) SetMemoryIndexValue(stack, -1); } // Pop this value off the call stack. _callStack.Pop(); } else { if (symbol.IsThreadSpawner == true && ignoreThread == false) SpawnThread(symbol); else { int oldFrameIndex = _runtimeStack.FrameIndex; // Push the return address which is the current instruction. RuntimeValue returnAddress = _runtimeStack.PushEmpty(RuntimeValueType.ReturnAddress); returnAddress.InstrIndex = _instructionPointer; // Pushs this function stack frame onto stack. _runtimeStack.PushFrame(symbol.LocalDataSize + 1); // Place the function and old stack index into value // and push it onto stack. RuntimeValue stackValue = _runtimeStack.Peek(); stackValue.ValueType = RuntimeValueType.StackFrameIndex; stackValue.Symbol = symbol; stackValue.InstrIndex = oldFrameIndex; // Jump to entry point of this function. _instructionPointer = symbol.EntryPoint; // Force this script into 'running' mode if its been stopped. _isRunning = true; } } }
/// <summary> /// Creates a new thread attached to the given function. /// </summary> /// <param name="symbol">The symbol of the function to execute from.</param> private void SpawnThread(FunctionSymbol symbol) { ScriptThread thread = new ScriptThread(_process); thread.InvokeFunction(symbol.Identifier, false, true); }
/// <summary> /// Syncronizes all the data shown on the window with that of the script. /// </summary> private void SyncronizeWindow() { // Clear everything. Text = "Script Debugger - " + _scriptThread.Process.Url; variablesPropertyListView.Clear(); callStackListView.Items.Clear(); stackTreeView.Nodes.Clear(); heapTreeView.Nodes.Clear(); objectsTreeView.Nodes.Clear(); sourceCodeScriptTextBox.Enabled = true; disassemblyScriptTextBox.Enabled = true; variablesPropertyListView.Enabled = true; callStackListView.Enabled = true; startToolStripButton.Enabled = true; stopToolStripButton.Enabled = false; stepToolStripButton.Enabled = true; stackTreeView.Enabled = true; stackPropertyGrid.Enabled = true; heapTreeView.Enabled = true; heapPropertyGrid.Enabled = true; objectsTreeView.Enabled = true; objectsPropertyGrid.Enabled = true; // If we are running then show nothing. if (_runScript == true) { startToolStripButton.Enabled = false; stopToolStripButton.Enabled = true; stepToolStripButton.Enabled = false; sourceCodeScriptTextBox.Enabled = false; disassemblyScriptTextBox.Enabled = false; variablesPropertyListView.Enabled = false; callStackListView.Enabled = false; stackTreeView.Enabled = false; stackPropertyGrid.Enabled = false; heapTreeView.Enabled = false; heapPropertyGrid.Enabled = false; objectsTreeView.Enabled = false; objectsPropertyGrid.Enabled = false; return; } // Grab the current instruction. RuntimeInstruction currentInstruction = _scriptThread.Process.Instructions[_scriptThread.InstructionPointer]; // See if we can find the source code for this instruction. if (currentInstruction.File != "") { if (File.Exists(currentInstruction.File)) { // Load in source code. if (_sourceURL == "" || _sourceURL != currentInstruction.File) { string text = File.ReadAllText(currentInstruction.File); sourceCodeScriptTextBox.Text = text; _sourceURL = currentInstruction.File; // Highlight. sourceCodeScriptTextBox.Highlight(true); } // Remove any background colors. sourceCodeScriptTextBox.RichTextBox.SelectionStart = 0; sourceCodeScriptTextBox.RichTextBox.SelectionLength = sourceCodeScriptTextBox.RichTextBox.Text.Length; sourceCodeScriptTextBox.RichTextBox.SelectionBackColor = Color.White; // Scroll to the correct line. sourceCodeScriptTextBox.Focus(); sourceCodeScriptTextBox.RichTextBox.SelectionStart = sourceCodeScriptTextBox.RichTextBox.GetFirstCharIndexFromLine(currentInstruction.Line - 1);// +currentInstruction.Offset; int nextLineIndex = sourceCodeScriptTextBox.RichTextBox.Text.IndexOf('\n', sourceCodeScriptTextBox.RichTextBox.SelectionStart); sourceCodeScriptTextBox.RichTextBox.SelectionLength = nextLineIndex == -1 ? sourceCodeScriptTextBox.Text.Length - sourceCodeScriptTextBox.RichTextBox.SelectionStart : nextLineIndex - sourceCodeScriptTextBox.RichTextBox.SelectionStart; sourceCodeScriptTextBox.RichTextBox.SelectionBackColor = Color.Red; sourceCodeScriptTextBox.RichTextBox.ScrollToCaret(); sourceCodeScriptTextBox.RichTextBox.SelectionLength = 0; } else sourceCodeScriptTextBox.Text = ""; } // Build the disassembly text. if (disassemblyScriptTextBox.Text == "") { StringBuilder builder = new StringBuilder(); foreach (RuntimeInstruction instruction in _scriptThread.Process.Instructions) builder.Append(instruction.Decompile() + "\n"); disassemblyScriptTextBox.Text = builder.ToString(); } // Remove any background colors. disassemblyScriptTextBox.RichTextBox.SelectionStart = 0; disassemblyScriptTextBox.RichTextBox.SelectionLength = disassemblyScriptTextBox.RichTextBox.Text.Length; disassemblyScriptTextBox.RichTextBox.SelectionBackColor = Color.Transparent; // Scroll to the correct line. disassemblyScriptTextBox.Focus(); disassemblyScriptTextBox.RichTextBox.SelectionStart = disassemblyScriptTextBox.RichTextBox.GetFirstCharIndexFromLine(_scriptThread.InstructionPointer); int disassemblyNextLineIndex = disassemblyScriptTextBox.RichTextBox.Text.IndexOf('\n', disassemblyScriptTextBox.RichTextBox.SelectionStart); disassemblyScriptTextBox.RichTextBox.SelectionLength = disassemblyNextLineIndex == -1 ? disassemblyScriptTextBox.Text.Length - disassemblyScriptTextBox.RichTextBox.SelectionStart : disassemblyNextLineIndex - disassemblyScriptTextBox.RichTextBox.SelectionStart; disassemblyScriptTextBox.RichTextBox.SelectionBackColor = Color.Red; disassemblyScriptTextBox.RichTextBox.ScrollToCaret(); disassemblyScriptTextBox.RichTextBox.SelectionLength = 0; // Find the last last scope we were in thats not native :P. _lastScope = null; object[] callStack = _scriptThread.CallStack.ToArray(); for (int i = 0; i < callStack.Length; i++) { callStackListView.Items.Add(new ListViewItem(new string[] { ((FunctionSymbol)callStack[i]).Identifier})); // FIX ENTRY POINT if (_lastScope == null && ((FunctionSymbol)callStack[i]).IsImport == false) { _lastScope = ((FunctionSymbol)callStack[i]); callStackListView.SelectedIndices.Add(callStackListView.Items.Count - 1); callStackListView.Items[callStackListView.Items.Count - 1].BackColor = Color.Red; } } // If we have a valid scope then starting filling the locals list :P. #region Variables _localCategory = new PropertyListViewCategory("Locals"); variablesPropertyListView.AddCategory(_localCategory); if (_lastScope != null) { foreach (Symbol symbol in _lastScope.Symbols) { if (symbol.Type == SymbolType.Variable) { VariableSymbol variable = symbol as VariableSymbol; if (variable.IsArray == true) { int arrayIndex = _scriptThread.GetArrayLocal(variable.Identifier); // Can be optimized. if (arrayIndex == -1 || _scriptThread.Process.MemoryHeap[arrayIndex - 1] == null) { _localCategory.AddProperty(new PropertyListViewItem(variable.Identifier, null, null, "", typeof(string))); continue; } int arrayLength = _scriptThread.GetArrayLength(arrayIndex); object value = ""; Type valueType = null; switch (variable.DataType.DataType) { case DataType.Bool: value = new bool[arrayLength]; for (int i = 0; i < arrayLength; i++) ((bool[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).BooleanLiteral; valueType = typeof(bool[]); break; case DataType.Byte: value = new byte[arrayLength]; for (int i = 0; i < arrayLength; i++) ((byte[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).ByteLiteral; valueType = typeof(byte[]); break; case DataType.Double: value = new double[arrayLength]; for (int i = 0; i < arrayLength; i++) ((double[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).DoubleLiteral; valueType = typeof(double[]); break; case DataType.Float: value = new float[arrayLength]; for (int i = 0; i < arrayLength; i++) ((float[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).FloatLiteral; valueType = typeof(float[]); break; case DataType.Int: value = new int[arrayLength]; for (int i = 0; i < arrayLength; i++) ((int[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).IntegerLiteral; valueType = typeof(int[]); break; case DataType.Long: value = new long[arrayLength]; for (int i = 0; i < arrayLength; i++) ((long[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).LongLiteral; valueType = typeof(long[]); break; case DataType.Object: value = new int[arrayLength]; for (int i = 0; i < arrayLength; i++) ((int[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).ObjectIndex; valueType = typeof(int[]); break; case DataType.Short: value = new short[arrayLength]; for (int i = 0; i < arrayLength; i++) ((short[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).ShortLiteral; valueType = typeof(short[]); break; case DataType.String: value = new string[arrayLength]; for (int i = 0; i < arrayLength; i++) ((string[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).StringLiteral; valueType = typeof(string[]); break; } _localCategory.AddProperty(new PropertyListViewItem(variable.Identifier, value, value, "", valueType)); } else { RuntimeValue variableValue = _scriptThread.GetRuntimeValueLocal(variable.Identifier); // Can be optimized. object value = ""; Type valueType = null; switch (variable.DataType.DataType) { case DataType.Bool: value = variableValue.BooleanLiteral; valueType = typeof(bool); break; case DataType.Byte: value = variableValue.ByteLiteral; valueType = typeof(byte); break; case DataType.Double: value = variableValue.DoubleLiteral; valueType = typeof(double); break; case DataType.Float: value = variableValue.FloatLiteral; valueType = typeof(float); break; case DataType.Int: value = variableValue.IntegerLiteral; valueType = typeof(int); break; case DataType.Long: value = variableValue.LongLiteral; valueType = typeof(long); break; case DataType.Object: value = variableValue.ObjectIndex; valueType = typeof(int); break; case DataType.Short: value = variableValue.ShortLiteral; valueType = typeof(short); break; case DataType.String: value = variableValue.StringLiteral; valueType = typeof(string); break; } _localCategory.AddProperty(new PropertyListViewItem(variable.Identifier, value,value, "", valueType)); } } } } // Global list FTW! _globalCategory = new PropertyListViewCategory("Globals"); variablesPropertyListView.AddCategory(_globalCategory); foreach (Symbol symbol in _scriptThread.Process.GlobalScope.Symbols) { if (symbol.Type == SymbolType.Variable) { VariableSymbol variable = symbol as VariableSymbol; if (variable.IsArray == true) { int arrayIndex = _scriptThread.GetArrayGlobal(variable.Identifier); // Can be optimized. if (arrayIndex == -1 || _scriptThread.Process.MemoryHeap[arrayIndex - 1] == null) { _globalCategory.AddProperty(new PropertyListViewItem(variable.Identifier, null, null, "", typeof(string))); continue; } int arrayLength = _scriptThread.GetArrayLength(arrayIndex); object value = ""; Type valueType = null; switch (variable.DataType.DataType) { case DataType.Bool: value = new bool[arrayLength]; for (int i = 0; i < arrayLength; i++) ((bool[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).BooleanLiteral; valueType = typeof(bool[]); break; case DataType.Byte: value = new byte[arrayLength]; for (int i = 0; i < arrayLength; i++) ((byte[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).ByteLiteral; valueType = typeof(byte[]); break; case DataType.Double: value = new double[arrayLength]; for (int i = 0; i < arrayLength; i++) ((double[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).DoubleLiteral; valueType = typeof(double[]); break; case DataType.Float: value = new float[arrayLength]; for (int i = 0; i < arrayLength; i++) ((float[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).FloatLiteral; valueType = typeof(float[]); break; case DataType.Int: value = new int[arrayLength]; for (int i = 0; i < arrayLength; i++) ((int[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).IntegerLiteral; valueType = typeof(int[]); break; case DataType.Long: value = new long[arrayLength]; for (int i = 0; i < arrayLength; i++) ((long[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).LongLiteral; valueType = typeof(long[]); break; case DataType.Object: value = new int[arrayLength]; for (int i = 0; i < arrayLength; i++) ((int[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).ObjectIndex; valueType = typeof(int[]); break; case DataType.Short: value = new short[arrayLength]; for (int i = 0; i < arrayLength; i++) ((short[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).ShortLiteral; valueType = typeof(short[]); break; case DataType.String: value = new string[arrayLength]; for (int i = 0; i < arrayLength; i++) ((string[])value)[i] = _scriptThread.GetRuntimeValueArrayElement(arrayIndex, i).StringLiteral; valueType = typeof(string[]); break; } _globalCategory.AddProperty(new PropertyListViewItem(variable.Identifier, value, value, "", valueType)); } else { RuntimeValue variableValue = _scriptThread.GetRuntimeValueGlobal(variable.Identifier); // Can be optimized. object value = ""; Type valueType = null; switch (variable.DataType.DataType) { case DataType.Bool: value = variableValue.BooleanLiteral; valueType = typeof(bool); break; case DataType.Byte: value = variableValue.ByteLiteral; valueType = typeof(byte); break; case DataType.Double: value = variableValue.DoubleLiteral; valueType = typeof(double); break; case DataType.Float: value = variableValue.FloatLiteral; valueType = typeof(float); break; case DataType.Int: value = variableValue.IntegerLiteral; valueType = typeof(int); break; case DataType.Long: value = variableValue.LongLiteral; valueType = typeof(long); break; case DataType.Object: value = variableValue.ObjectIndex; valueType = typeof(int); break; case DataType.Short: value = variableValue.ShortLiteral; valueType = typeof(short); break; case DataType.String: value = variableValue.StringLiteral; valueType = typeof(string); break; } _globalCategory.AddProperty(new PropertyListViewItem(variable.Identifier, value, value, "", valueType)); } } } #endregion // Fill up stack. topIndexLabel.Text = "Top Index: " + _scriptThread.Stack.TopIndex; frameIndexLabel.Text = "Frame Index: " + _scriptThread.Stack.FrameIndex; int top = _scriptThread.Stack.TopIndex > _scriptThread.Stack.FrameIndex ? _scriptThread.Stack.TopIndex : _scriptThread.Stack.FrameIndex; for (int i = 0; i < top; i++) { RuntimeValue runtimeValue = _scriptThread.Stack.RawStack[i]; string name = runtimeValue.ToString(); stackTreeView.Nodes.Add(i + ": " + name, i + ": " + name, 0); } // Fill up the object stack. int index = 0; foreach (RuntimeObject obj in _scriptThread.Process.ObjectHeap) { if (obj != null) { string name = obj.ToString(); if (name.LastIndexOf('.') > -1) name = name.Substring(name.LastIndexOf('.') + 1); objectsTreeView.Nodes.Add(index + ": " + name, index + ": " + name, 0); } index++; } // Fill up the heap. index = 0; foreach (RuntimeValue obj in _scriptThread.Process.MemoryHeap) { if (obj != null) { string name = obj.ToString(); heapTreeView.Nodes.Add(index + ": " + name, index + ": " + name, 0); } index++; } // Refresh the variables list! variablesPropertyListView.Refresh(); }
public void InvokeFunction(FunctionSymbol symbol) { InvokeFunction(symbol, false, false, false); }
/// <summary> /// Invokes a export function from a given script. /// </summary> /// <param name="symbol">Symbol of function to call.</param> /// <param name="toThread">Thread to call function.</param> /// <param name="fromThread">Thread to call function from.</param> /// <returns>Memory index of new array.</returns> public void InvokeExportFunction(FunctionSymbol symbol, ScriptThread toThread, ScriptThread fromThread) { // Can't invoke functions if debugging :S. if (_debugger != null && _debugger.AllowInvokedFunctions == false && toThread == this) return; // Find the functions parameter types. DataTypeValue[] parameterTypes = new DataTypeValue[symbol.ParameterCount]; for (int i = 0; i < symbol.ParameterCount; i++) parameterTypes[i] = ((VariableSymbol)symbol.Symbols[i]).DataType; // Push any parameters we have been given. for (int i = 0; i < parameterTypes.Length; i++) { RuntimeValue parameter = fromThread._runtimeStack[(fromThread._runtimeStack.TopIndex - parameterTypes.Length) + i]; parameter.DataType = parameterTypes[i]; if (parameterTypes[i].IsArray == true) toThread.PassParameterArray(CopyValueArrayFromThread(parameter, toThread, fromThread)); else toThread.PassParameter(CopyValueFromThread(parameter, toThread, fromThread)); } // Call the function. toThread.InvokeFunction(symbol.Identifier, true, true); // Copy the return register. fromThread._registers[(int)Register.Return].DataType = symbol.ReturnType; if (symbol.ReturnType.IsArray == true) SetMemoryIndexValue(fromThread._registers[(int)Register.Return], CopyValueArrayFromThread(toThread._registers[(int)Register.Return], fromThread, toThread)); else fromThread._registers[(int)Register.Return] = CopyValueFromThread(toThread._registers[(int)Register.Return], fromThread, toThread); }
public void InvokeFunction(FunctionSymbol functionSymbol, bool waitForReturn, bool ignoreThread, bool stackTop) { // Can't invoke functions if debugging :S. if (_debugger != null && _debugger.AllowInvokedFunctions == false) return; // Check we haven't already been called. if (stackTop == true && _callStack.Count != 0 && _callStack.Contains(functionSymbol)) return; // Check the function exists. if (functionSymbol == null || _isWaiting == true) { // Clear out the return register. _registers[(int)Register.Return].Clear(); // Pop of passed parameters. for (int i = 0; i < _passedParameterCount; i++) { RuntimeValue value = _runtimeStack.Pop(); if (value.ObjectIndex != -1) SetObjectValue(value, -1); else if (value.MemoryIndex != -1) SetMemoryIndexValue(value, -1); } _passedParameterMask.Clear(); _passedParameterCount = 0; return; } // Look through functions parameters and check the mask is correct. int parameterIndex = 0; foreach (DataTypeValue value in _passedParameterMask) if (functionSymbol.CheckParameterTypeValid(parameterIndex++, value) == false) { for (int i = 0; i < _passedParameterCount; i++) { RuntimeValue stack = _runtimeStack.Pop(); if (stack.ObjectIndex != -1) SetObjectValue(stack, -1); else if (stack.MemoryIndex != -1) SetMemoryIndexValue(stack, -1); } _passedParameterMask.Clear(); _passedParameterCount = 0; return; } _passedParameterMask.Clear(); _passedParameterCount = 0; // Call the function. _isRunning = true; CallFunction(functionSymbol, ignoreThread); // Push the stack base marker onto frame. _runtimeStack.Peek().ValueType = RuntimeValueType.StackBaseMarker; // Wait until function returns if thats what has been asked for. // Don't exit if thread is just paused. if (waitForReturn == true) { while (true) { int retVal = Run(-1); if (retVal == 2 || retVal == 3 || retVal == 4 || retVal == 5 || retVal == 6) break; } } // Collect any garbage if required. _process.CheckForGarbageCollection(); }
/// Initializes a new instance of thsi class. /// </summary> /// <param name="symbol">Function symbol describing the function to call.</param> /// <param name="thread">Script thread that function is embedded in.</param> public ScriptExportFunction(FunctionSymbol symbol, ScriptThread thread) { _thread = thread; _functionSymbol = symbol; _functionHashTable.Add(symbol.ToString().ToLower(), this); }
/// <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> /// Initializes a new instance of thsi class. /// </summary> /// <param name="symbol">Function symbol describing the function to call.</param> /// <param name="thread">Script thread that function is embedded in.</param> public ScriptConsoleCommand(FunctionSymbol symbol, ScriptThread thread) { _thread = thread; _functionSymbol = symbol; ConsoleValueType[] parameters = new ConsoleValueType[symbol.ParameterCount]; for (int i = 0; i < parameters.Length; i++) { switch (((VariableSymbol)symbol.Symbols[i]).DataType.DataType) { case DataType.Bool: parameters[i] = ConsoleValueType.Bool; break; case DataType.Float: parameters[i] = ConsoleValueType.Float; break; case DataType.Int: parameters[i] = ConsoleValueType.Int; break; case DataType.String: parameters[i] = ConsoleValueType.String; break; } } _command = new ConsoleCommand(symbol.Identifier, new CommandDelegate(InvokeCommand), parameters); Console.Console.RegisterCommand(_command); }
/// Initializes a new instance of thsi class. /// </summary> /// <param name="symbol">Function symbol describing the function to call.</param> /// <param name="thread">Script thread that function is embedded in.</param> public ScriptExportFunction(FunctionSymbol symbol, ScriptThread thread) { _thread = thread; _functionSymbol = symbol; _functionList.Add(this); }
/// <summary> /// Called when the state of this entities script is changed. /// </summary> /// <param name="process">Process that had its state changed.</param> /// <param name="sate">New state.</param> public void OnStateChange(ScriptProcess process, StateSymbol state) { _tickFunction = (state == null ? null : (state.FindSymbol("OnTick", SymbolType.Function) as FunctionSymbol)); }
/// <summary> /// /// </summary> private void ParseMemberFunctionCall(string identifier, DataTypeValue returnDataType) { // Read the opening parenthesis. ExpectToken(TokenID.CharOpenParenthesis); // Pop the object out. if (_currentPass == 1) { Instruction instruction = CreateInstruction(OpCode.POP_OBJECT, _currentScope, _currentToken); new Operand(instruction, Register.Member); } // Read in each parameter's expression. ArrayList parameterTypeList = new ArrayList(); string parameterMask = ""; while (true) { // Check for parenthesis close if (LookAheadToken().ID != TokenID.CharCloseParenthesis) { // Read in the parameters expression. DataTypeValue expressionType = ParseExpression(); parameterMask += (parameterMask != "" ? "," : "") + expressionType.ToString(); parameterTypeList.Add(expressionType); // Read in comma if we are not at the // end of the parameter list. if (LookAheadToken().ID != TokenID.CharCloseParenthesis) ExpectToken(TokenID.CharComma); } else break; } // *looks arounds shiftily* ... Ok its hack like but it works. parameterTypeList.Reverse(); // Read the closing parenthesis. ExpectToken(TokenID.CharCloseParenthesis); // Get the function symbol if in pass 2. FunctionSymbol functionSymbol = null; if (_currentPass == 1) { functionSymbol = _memberScope.FindFunctionByMask(identifier, parameterTypeList) as FunctionSymbol; if (functionSymbol == null) { // Create the function symbol. functionSymbol = new FunctionSymbol(identifier, _memberScope); functionSymbol.Identifier = identifier; functionSymbol.ReturnType = returnDataType; functionSymbol.IsMember = true; functionSymbol.ParameterCount = parameterTypeList.Count; // Create a symbol for each parameters. foreach (DataTypeValue value in parameterTypeList) { VariableSymbol variableSymbol = new VariableSymbol(functionSymbol); variableSymbol.DataType = value; variableSymbol.Identifier = ""; variableSymbol.VariableType = VariableType.Parameter; variableSymbol.IsArray = value.IsArray; } } Instruction instruction = CreateInstruction(OpCode.CALL_METHOD, _currentScope, _currentToken); new Operand(instruction, Register.Member); new Operand(instruction, functionSymbol); } }
public void InvokeFunction(FunctionSymbol symbol, bool waitForReturn, bool ignoreThread) { InvokeFunction(symbol, waitForReturn, ignoreThread, false); }
/// <summary> /// Called when the state of this entities script is changed. /// </summary> /// <param name="process">Process that had its state changed.</param> /// <param name="sate">New state.</param> public void OnStateChange(ScriptProcess process, StateSymbol state) { _renderFunction = state == null ? null : _process.Process.State.FindSymbol("OnRender", SymbolType.Function) as FunctionSymbol; // SyncCollisionEvents(); }
/// <summary> /// Invoked when a script wants to call a method of this object. /// </summary> /// <param name="thread">Script thread that invoked this function.</param> /// <param name="method">Symbol describing the method that it wants called.</param> /// <returns>True if successfull or false if not.</returns> public override bool InvokeMethod(ScriptThread thread, FunctionSymbol method) { if (_nativeObject is ScriptedEntityNode) { ScriptProcess process = ((ScriptedEntityNode)_nativeObject).ScriptProcess; if (process == null) return false; FunctionSymbol func = (FunctionSymbol)process.MemberFunctionHashTable[method.ToString().ToLower()]; if (func != null) { // Call the method. process[0].InvokeExportFunction(func, process[0], thread); return true; } /* foreach (Symbol symbol in process.GlobalScope.Symbols) { if (symbol != null && symbol.Identifier.ToLower() == method.Identifier.ToLower() && symbol.Type == SymbolType.Function && ((FunctionSymbol)symbol).ParameterCount == method.ParameterCount && ((FunctionSymbol)symbol).AccessModifier == SymbolAccessModifier.Public) { FunctionSymbol functionSymbol = symbol as FunctionSymbol; bool parametersValid = true; for (int i = 0; i < functionSymbol.ParameterCount; i++) if (((VariableSymbol)symbol.Symbols[i]).DataType != ((VariableSymbol)method.Symbols[i]).DataType) { parametersValid = false; break; } if (parametersValid == true) { // Call the method. process[0].InvokeExportFunction(functionSymbol, process[0], thread); return true; } } } */ DebugLogger.WriteLog("Unable to find method '"+method.Identifier+"'.", LogAlertLevel.Warning); } else if (_nativeObject is EntityNode) { //EntityNode entityNode = _nativeObject as EntityNode; } else if (_nativeObject is EmitterNode) { } else if (_nativeObject is TilemapSegmentNode) { } else if ((_nativeObject as SceneNode) != null) { } return false; }