using System; using System.Collections.Generic; using System.Linq; using NTERA.Core; using NTERA.EmuEra.Game.EraEmu.Content; using NTERA.Engine.Compiler; namespace NTERA.Engine.Runtime { public class EraRuntime : IScriptEngine { public IExecutionProvider ExecutionProvider { get; } public IConsole Console { get; protected set; } public Stack ExecutionStack { get; } = new Stack(); public EraRuntime(IExecutionProvider executionProvider) { ExecutionProvider = executionProvider; } public bool Initialize(IConsole console) { Console = console; return true; } public void Start() { Console.PrintSystemLine("EraJIT x64 0.0.0.0"); Console.PrintSystemLine(""); try { Call(ExecutionProvider.DefinedProcedures.First(x => x.Name == "SYSTEM_TITLE")); } catch (Exception ex) { Console.PrintSystemLine($"Unhandled exception: {ex.Message}"); Console.PrintSystemLine("Stack trace:"); foreach (var stackMember in ExecutionStack) Console.PrintSystemLine($" - @{stackMember.SelfDefinition.Name} ({stackMember.SelfDefinition.Position} > {stackMember.SelfDefinition.Filename})"); throw; } System.Threading.Thread.Sleep(-1); } public void Call(FunctionDefinition function) { var executionContents = ExecutionProvider.GetExecutionNodes(function); var localVariables = new VariableDictionary(); foreach (var variable in function.Variables) localVariables[variable.Name] = variable.CalculatedValue; var globalVariables = new VariableDictionary(); foreach (var variable in BaseDefinitions.DefaultGlobalVariables) globalVariables[variable.Name] = variable.CalculatedValue; var executionSet = new ExecutionSet { Nodes = executionContents.ToList(), SelfDefinition = function, GlobalVariables = globalVariables, LocalVariables = localVariables }; ExecutionStack.Push(executionSet); ExecuteSet(executionSet); ExecutionStack.Pop(); } public void ExecuteSet(ExecutionSet set) { for (; set.Position < set.Nodes.Count; set.Position++) { ExecutionNode node = set.Nodes[set.Position]; ExecuteNode(set, node); } } public void ExecuteNode(ExecutionSet set, ExecutionNode node) { switch (node.Type) { case "statement": string statement = node.Metadata["name"]; if (!Base.Keywords.StaticKeywords.TryGetValue(statement, out var keywordAction)) throw new Exception($"Unknown statement: '{statement}'"); keywordAction(this, set, node); break; case "assignment": string variableName = node["variable"].Metadata["name"]; if (set.LocalVariables.ContainsKey(variableName)) set.LocalVariables[variableName] = ComputeExpression(set, node["value"].SubNodes.Single()); else if (set.GlobalVariables.ContainsKey(variableName)) set.GlobalVariables[variableName] = ComputeExpression(set, node["value"].SubNodes.Single()); else throw new Exception($"Unknown variable: '{variableName}'"); break; default: throw new Exception($"Unknown node type: '{node.Type}'"); } } public Value ComputeExpression(ExecutionSet set, ExecutionNode expressionNode) { switch (expressionNode.Type) { case "constant": ValueType type = (ValueType)Enum.Parse(typeof(ValueType), expressionNode.Metadata["type"]); string strValue = expressionNode.Metadata["value"]; return type == ValueType.String ? (Value)strValue : (Value)double.Parse(strValue); default: throw new Exception($"Unknown expression type: '{expressionNode.Type}'"); } } public void InputString(string input) { throw new NotImplementedException(); } public void InputInteger(long input) { throw new NotImplementedException(); } public void InputSystemInteger(long input) { throw new NotImplementedException(); } public CroppedImage GetImage(string name) { throw new NotImplementedException(); } } }