public void Execute() { AbstractMachineState state = new AbstractMachineState(new AMFactory()); ArrayList prog = new ArrayList(); prog.Add(new PutConstantInstruction()); prog.Add(new HaltInstruction()); state.Initialize(prog); AMProgram program = (AMProgram)state.Program; ProgramClause clause = new ProgramClause("male", 2); program.AddLabel("male/2", clause); ExecuteInstruction i = new ExecuteInstruction(); object[] args = { "male", "2" }; i.Process(args); i.Execute(state); Assert.AreEqual("execute", i.Name()); Assert.AreEqual(2, i.NumberOfArguments()); Assert.AreSame(clause, program.P); }
/// <summary> /// Loads the file name specified, with a relative path from the /// <see cref="NameSpace.Directory"/> property. Use a forward slash /// to represent files in sub folders. /// </summary> /// <param name="fileName"> /// The fileName to load in this <see cref="NameSpace.Directory"/>, or sub /// folder path and filename from this NameSpace directory. /// </param> /// <param name="overwrite"> /// If the file is already loaded in this NameSpace, do we overwrite the existing /// loaded file and its objects? If false, and Exception will be thrown if this file /// is already loaded. /// </param> /// <returns>Returns true if the file exists and loaded successfully, false otherwise</returns> public async Task <bool> LoadFile( string fileName, bool overwrite = false, Scope scope = null, ExecuteInstruction instruction = ExecuteInstruction.Skip) { // Make sure this isnt loaded already... if (!overwrite && Files.ContainsKey(fileName)) { throw new Exception($"{fileName} has already been loaded into this namespace!"); } // Get full file path string corrected = fileName.Replace('/', Path.DirectorySeparatorChar); string filePath = Path.Combine(Directory, corrected); // Skip not found files if (!File.Exists(filePath)) { return(false); } // Create variables Scope fileScope = scope ?? CreateScope(); ConFile cFile; // Try-Catch this beast try { // Create sub scope for this file, and load it cFile = await ScriptEngine.LoadFileAsync(filePath, fileScope, instruction); // For dev purposes, will be removed later Interlocked.Increment(ref TotalFilesLoaded); Interlocked.Add(ref TotalObjectsLoaded, cFile.Scope.GetObjects().Count()); // Add item Files[fileName] = cFile; return(true); } catch { // Pass the exception up throw; } }
/// <summary> /// Loads the file name specified, with a relative path from the /// <see cref="NameSpace.Directory"/> property. Use a forward slash /// to represent files in sub folders. /// </summary> /// <param name="fileName"> /// The fileName to load in this <see cref="NameSpace.Directory"/>, or sub /// folder path and filename from this NameSpace directory. /// </param> /// <param name="overwrite"> /// If the file is already loaded in this NameSpace, do we overwrite the existing /// loaded file and its objects? If false, and Exception will be thrown if this file /// is already loaded. /// </param> /// <returns>Returns true if the file exists and loaded successfully, false otherwise</returns> public async Task<bool> LoadFile( string fileName, bool overwrite = false, Scope scope = null, ExecuteInstruction instruction = ExecuteInstruction.Skip) { // Make sure this isnt loaded already... if (!overwrite && Files.ContainsKey(fileName)) throw new Exception($"{fileName} has already been loaded into this namespace!"); // Get full file path string corrected = fileName.Replace('/', Path.DirectorySeparatorChar); string filePath = Path.Combine(Directory, corrected); // Skip not found files if (!File.Exists(filePath)) return false; // Create variables Scope fileScope = scope ?? CreateScope(); ConFile cFile; // Try-Catch this beast try { // Create sub scope for this file, and load it cFile = await ScriptEngine.LoadFileAsync(filePath, fileScope, instruction); // For dev purposes, will be removed later Interlocked.Increment(ref TotalFilesLoaded); Interlocked.Add(ref TotalObjectsLoaded, cFile.Scope.GetObjects().Count()); // Add item Files[fileName] = cFile; return true; } catch { // Pass the exception up throw; } }
public AMInstructionSet() { _instructions["allocate"] = new AllocateInstruction(); _instructions["bcall"] = new BCallInstruction(); _instructions["call"] = new CallInstruction(); _instructions["cut"] = new CutInstruction(); _instructions["deallocate"] = new DeallocateInstruction(); _instructions["execute"] = new ExecuteInstruction(); _instructions["fcall"] = new FCallInstruction(); _instructions["fail"] = new FailInstruction(); _instructions["get_constant"] = new GetConstantInstruction(); _instructions["get_list"] = new GetListInstruction(); _instructions["get_structure"] = new GetStructureInstruction(); _instructions["get_value"] = new GetValueInstruction(); _instructions["get_variable"] = new GetVariableInstruction(); _instructions["halt"] = new HaltInstruction(); _instructions["nop"] = new NopInstruction(); _instructions["proceed"] = new ProceedInstruction(); _instructions["put_constant"] = new PutConstantInstruction(); _instructions["put_list"] = new PutListInstruction(); _instructions["put_structure"] = new PutStructureInstruction(); _instructions["put_unsafe_value"] = new PutUnsafeValueInstruction(); _instructions["put_variable"] = new PutVariableInstruction(); _instructions["put_value"] = new PutValueInstruction(); _instructions["retry_me_else"] = new RetryMeElseInstruction(); _instructions["set_constant"] = new SetConstantInstruction(); _instructions["set_local_value"] = new SetLocalValueInstruction(); _instructions["set_value"] = new SetValueInstruction(); _instructions["set_variable"] = new SetVariableInstruction(); _instructions["set_void"] = new SetVoidInstruction(); _instructions["trust_me"] = new TrustMeInstruction(); _instructions["try_me_else"] = new TryMeElseInstruction(); _instructions["unify_constant"] = new UnifyConstantInstruction(); _instructions["unify_local_value"] = new UnifyLocalValueInstruction(); _instructions["unify_variable"] = new UnifyVariableInstruction(); _instructions["unify_value"] = new UnifyValueInstruction(); _instructions["unify_void"] = new UnifyVoidInstruction(); _instructions["procedure"] = new ProcedureInstruction(); }
/// <summary> /// Loads a .con or .ai file, and converts the script objects into C# objects /// </summary> /// <param name="filePath">The path to the .con / .ai file</param> /// <param name="scope"> /// Sets the scope in which the objects from this <see cref="ConFile"/> /// will be loaded into. /// </param> /// <param name="runInstruction"> /// Defines how the script engine should handle nested file includes /// </param> /// <exception cref="Exception"> /// Thrown if there is a problem loading the script file in any way. /// </exception> /// <returns>Returns the parsed bf2 script file.</returns> public static async Task <ConFile> LoadFileAsync(string filePath, Scope scope = null, ExecuteInstruction runInstruction = ExecuteInstruction.Skip) { // Create new ConFile contents ConFile cFile = new ConFile(filePath, scope); Dictionary <int, string> fileContents = new Dictionary <int, string>(); int lineNum = 1; // Create Log Logger.Info("Loading file: " + filePath); // Open the confile, and read its contents using (FileStream fStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) using (StreamReader reader = new StreamReader(fStream)) { // While we can keep reading while (!reader.EndOfStream) { string line = await reader.ReadLineAsync(); fileContents.Add(lineNum++, line); } } // Parse the contents of the Con / Ai file try { await ParseFileLines(fileContents, cFile, runInstruction); } catch { // Pass the exception up throw; } // Return the file return(cFile); }
/// <summary> /// Loads a .con or .ai file, and converts the script objects into C# objects /// </summary> /// <param name="filePath">The path to the .con / .ai file</param> /// <param name="scope"> /// Sets the scope in which the objects from this <see cref="ConFile"/> /// will be loaded into. /// </param> /// <param name="runInstruction"> /// Defines how the script engine should handle nested file includes /// </param> /// <exception cref="Exception"> /// Thrown if there is a problem loading the script file in any way. /// </exception> /// <returns>Returns the parsed bf2 script file.</returns> public static async Task<ConFile> LoadFileAsync(string filePath, Scope scope = null, ExecuteInstruction runInstruction = ExecuteInstruction.Skip) { // Create new ConFile contents ConFile cFile = new ConFile(filePath, scope); Dictionary<int, string> fileContents = new Dictionary<int, string>(); int lineNum = 1; // Create Log Logger.Info("Loading file: " + filePath); // Open the confile, and read its contents using (FileStream fStream = new FileStream(filePath, FileMode.Open, FileAccess.Read)) using (StreamReader reader = new StreamReader(fStream)) { // While we can keep reading while (!reader.EndOfStream) { string line = await reader.ReadLineAsync(); fileContents.Add(lineNum++, line); } } // Parse the contents of the Con / Ai file try { await ParseFileLines(fileContents, cFile, runInstruction); } catch { // Pass the exception up throw; } // Return the file return cFile; }
// Reset CPU control section and instruction decoder internal state private void ResetCPUControlState() { // Z80CPU.cs internal state tStateCounter = 0; machineCycleCounter = 0; instructionCounter = 0; instructionOrigin = null; currentInstruction = null; executeInstruction = null; halfTStateIndex = 0; machineCycleIndex = 0; machineCycleCountAfterInstruction = 0; currentMachineCycle = null; executeMachineCycle = null; // Z80CPU_Instruction_Decoder.cs internal state opcodeTableIndex = 0; // Z80CPU_ExternalControl.cs internal state busRequestPending = false; maskableInterruptPending = false; nonMaskableInterruptPending = false; }
private void EndInstruction() { instructionOrigin = null; currentInstruction = null; executeInstruction = null; }
/// <summary> /// Parses the contents of a .con or .ai file, and converts the contents into C# objects /// </summary> /// <param name="fileContents">A dictionary of file contents [LineNumber => LineContents]</param> /// <param name="workingFile">A reference to the ConFile that contains the contents</param> internal static async Task ParseFileLines( Dictionary<int, string> fileContents, ConFile workingFile, ExecuteInstruction run) { // ============ // First we convert our confile lines into parsed tokens // ============ Token[] fileTokens = Tokenizer.Tokenize(workingFile, ref fileContents); TokenArgs tokenArgs; Scope currentScope = workingFile.Scope; // ============ // Now we create an object reference of all objects in the Confile // before parsing the object properties, which **can** reference an object // in the same file before its defined // NOTE: Do not create object references for .Active and .safeActive // ============ foreach (Token token in fileTokens.Where(x => x.Kind == TokenType.ObjectStart).OrderBy(x => x.Position)) { // Create the object var Method = token.TokenArgs.ReferenceType.GetMethod(token.TokenArgs.PropertyName); ConFileObject template = Method.Invoke(token); // Finally, register the object with the ObjectManager currentScope.AddObject(template, token); Logger.Info($"Created {token.TokenArgs.ReferenceType} \"{template.Name}\"", workingFile, token.Position); } // ============ // Finally, we load all of the object properties, and assign them to their // respective objects // ============ // Create our needed objects RemComment comment = null; ConFileObject currentObj = null; ReferenceType type; var builder = new StringBuilder(); // We use a for loop here so we can skip rem blocks and statements for (int i = 0; i < fileTokens.Length; i++) { // Grab token value Token token = fileTokens[i]; try { switch (token.Kind) { case TokenType.ObjectStart: case TokenType.ActiveSwitch: // NOTE: the object was created before this loop! currentObj = currentScope.GetObject(token); currentScope.SetActiveObject(currentObj); // === Objects are already added to the working file before hand === // // Add object reference to file workingFile.AddEntry(currentObj, token); // Reset comment comment = null; // Log Logger.Info($"Loading object properties for \"{currentObj.Name}\"", workingFile, token.Position ); break; case TokenType.ObjectProperty: // Convert args to an object tokenArgs = token.TokenArgs; // Get the last used object type = tokenArgs.ReferenceType; currentObj = currentScope.GetActiveObject(type); // Make sure we have an object to work with and the object // reference matches our current working object if (currentObj == null) { // If we are here, we have an issue... string error = $"Failed to set property \"{token.TokenArgs.ReferenceType.Name}.\"" + $"{token.TokenArgs.PropertyName}. No object reference set!"; throw new ParseException(error, token); } // Let the object parse its own lines... try { currentObj.Parse(token); // Ensure comment is null comment = null; } catch (Exception e) { Logger.Error(e.Message, workingFile, token.Position, e); throw; } break; case TokenType.RemComment: // Create a new comment if we need to if (comment == null) { comment = new RemComment(token); } // Add comment to the current string comment.AppendLine(token.Value); break; case TokenType.BeginRem: RemComment rem = new RemComment(token); rem.IsRemBlock = true; // Skip every line until we get to the endRem builder.AppendLine(token.Value); i = ScopeUntil(TokenType.EndRem, fileTokens, i, builder); // Set rem value rem.Value = builder.ToString().TrimEnd(); workingFile.AddEntry(rem, rem.Token); // Clear the string builder builder.Clear(); break; case TokenType.IfStart: Statement statement = new Statement(token); if (token.Kind == TokenType.IfStart) { // Skip every line until we get to the endIf builder.AppendLine(token.Value); i = ScopeUntil(TokenType.EndIf, fileTokens, i, builder); // Clear the string builder statement.Token.Value = builder.ToString().TrimEnd(); builder.Clear(); } // Add entry workingFile.AddEntry(statement, statement.Token); break; case TokenType.Run: case TokenType.Include: // Just add to as a string RunStatement stmt = new RunStatement(token); workingFile.AddEntry(stmt, stmt.Token); // Do we execute the statement? if (run == ExecuteInstruction.Skip) continue; // Create new scope for execution Scope runScope = currentScope; // Are we executing in a new scope? if (run == ExecuteInstruction.ExecuteInNewScope) { // For now, we just inherit the parent scope type runScope = new Scope(currentScope, currentScope.ScopeType); runScope.MissingObjectHandling = MissingObjectHandling.CheckParent; } // Get the filepath string filePath = Path.GetDirectoryName(workingFile.FilePath); string fileName = Path.Combine(filePath, stmt.FileName); // Define file arguments runScope.SetArguments(stmt.Arguments); // Load the file try { ConFile include = await LoadFileAsync(fileName, runScope, run); workingFile.ExecutedIncludes.Add(include); } catch (FileNotFoundException) // Only acceptable exception { fileName = Path.GetFileName(fileName); Logger.Warning($"Failed to run file \"{fileName}\". File Not Found", workingFile, token.Position); } break; case TokenType.Constant: case TokenType.Variable: // Set the new expression reference in Scope Expression exp = new Expression(token); currentScope.Expressions[exp.Name] = exp; // Add expression to the confile as well workingFile.AddEntry(exp, exp.Token); break; case TokenType.None: // Dont attach comment to a property if we have an empty line here if (comment != null) { workingFile.AddEntry(comment, comment.Token); comment = null; } // Throw error if the line is not empty if (!String.IsNullOrWhiteSpace(token.Value)) { string message = $"Unable to parse file entry \"{token.Value}\" on line {token.Position}"; throw new ParseException(message, token); } break; } } catch (Exception e) { Logger.Error(e.Message, token.File, token.Position, e); throw; } } // Finalize this confile workingFile.Finish(); }
/// <summary> /// Parses the contents of a .con or .ai file, and converts the contents into C# objects /// </summary> /// <param name="fileContents">A dictionary of file contents [LineNumber => LineContents]</param> /// <param name="workingFile">A reference to the ConFile that contains the contents</param> internal static async Task ParseFileLines( Dictionary <int, string> fileContents, ConFile workingFile, ExecuteInstruction run) { // ============ // First we convert our confile lines into parsed tokens // ============ Token[] fileTokens = Tokenizer.Tokenize(workingFile, ref fileContents); TokenArgs tokenArgs; Scope currentScope = workingFile.Scope; // ============ // Now we create an object reference of all objects in the Confile // before parsing the object properties, which **can** reference an object // in the same file before its defined // NOTE: Do not create object references for .Active and .safeActive // ============ foreach (Token token in fileTokens.Where(x => x.Kind == TokenType.ObjectStart).OrderBy(x => x.Position)) { // Create the object var Method = token.TokenArgs.ReferenceType.GetMethod(token.TokenArgs.PropertyName); ConFileObject template = Method.Invoke(token); // Finally, register the object with the ObjectManager currentScope.AddObject(template, token); Logger.Info($"Created {token.TokenArgs.ReferenceType} \"{template.Name}\"", workingFile, token.Position); } // ============ // Finally, we load all of the object properties, and assign them to their // respective objects // ============ // Create our needed objects RemComment comment = null; ConFileObject currentObj = null; ReferenceType type; var builder = new StringBuilder(); // We use a for loop here so we can skip rem blocks and statements for (int i = 0; i < fileTokens.Length; i++) { // Grab token value Token token = fileTokens[i]; try { switch (token.Kind) { case TokenType.ObjectStart: case TokenType.ActiveSwitch: // NOTE: the object was created before this loop! currentObj = currentScope.GetObject(token); currentScope.SetActiveObject(currentObj); // === Objects are already added to the working file before hand === // // Add object reference to file workingFile.AddEntry(currentObj, token); // Reset comment comment = null; // Log Logger.Info($"Loading object properties for \"{currentObj.Name}\"", workingFile, token.Position ); break; case TokenType.ObjectProperty: // Convert args to an object tokenArgs = token.TokenArgs; // Get the last used object type = tokenArgs.ReferenceType; currentObj = currentScope.GetActiveObject(type); // Make sure we have an object to work with and the object // reference matches our current working object if (currentObj == null) { // If we are here, we have an issue... string error = $"Failed to set property \"{token.TokenArgs.ReferenceType.Name}.\"" + $"{token.TokenArgs.PropertyName}. No object reference set!"; throw new ParseException(error, token); } // Let the object parse its own lines... try { currentObj.Parse(token); // Ensure comment is null comment = null; } catch (Exception e) { Logger.Error(e.Message, workingFile, token.Position, e); throw; } break; case TokenType.RemComment: // Create a new comment if we need to if (comment == null) { comment = new RemComment(token); } // Add comment to the current string comment.AppendLine(token.Value); break; case TokenType.BeginRem: RemComment rem = new RemComment(token); rem.IsRemBlock = true; // Skip every line until we get to the endRem builder.AppendLine(token.Value); i = ScopeUntil(TokenType.EndRem, fileTokens, i, builder); // Set rem value rem.Value = builder.ToString().TrimEnd(); workingFile.AddEntry(rem, rem.Token); // Clear the string builder builder.Clear(); break; case TokenType.IfStart: Statement statement = new Statement(token); if (token.Kind == TokenType.IfStart) { // Skip every line until we get to the endIf builder.AppendLine(token.Value); i = ScopeUntil(TokenType.EndIf, fileTokens, i, builder); // Clear the string builder statement.Token.Value = builder.ToString().TrimEnd(); builder.Clear(); } // Add entry workingFile.AddEntry(statement, statement.Token); break; case TokenType.Run: case TokenType.Include: // Just add to as a string RunStatement stmt = new RunStatement(token); workingFile.AddEntry(stmt, stmt.Token); // Do we execute the statement? if (run == ExecuteInstruction.Skip) { continue; } // Create new scope for execution Scope runScope = currentScope; // Are we executing in a new scope? if (run == ExecuteInstruction.ExecuteInNewScope) { // For now, we just inherit the parent scope type runScope = new Scope(currentScope, currentScope.ScopeType); runScope.MissingObjectHandling = MissingObjectHandling.CheckParent; } // Get the filepath string filePath = Path.GetDirectoryName(workingFile.FilePath); string fileName = Path.Combine(filePath, stmt.FileName); // Define file arguments runScope.SetArguments(stmt.Arguments); // Load the file try { ConFile include = await LoadFileAsync(fileName, runScope, run); workingFile.ExecutedIncludes.Add(include); } catch (FileNotFoundException) // Only acceptable exception { fileName = Path.GetFileName(fileName); Logger.Warning($"Failed to run file \"{fileName}\". File Not Found", workingFile, token.Position); } break; case TokenType.Constant: case TokenType.Variable: // Set the new expression reference in Scope Expression exp = new Expression(token); currentScope.Expressions[exp.Name] = exp; // Add expression to the confile as well workingFile.AddEntry(exp, exp.Token); break; case TokenType.None: // Dont attach comment to a property if we have an empty line here if (comment != null) { workingFile.AddEntry(comment, comment.Token); comment = null; } // Throw error if the line is not empty if (!String.IsNullOrWhiteSpace(token.Value)) { string message = $"Unable to parse file entry \"{token.Value}\" on line {token.Position}"; throw new ParseException(message, token); } break; } } catch (Exception e) { Logger.Error(e.Message, token.File, token.Position, e); throw; } } // Finalize this confile workingFile.Finish(); }