Эх сурвалжийг харах

Introduce variables and obtain keywords via reflection

Bepsi 6 жил өмнө
parent
commit
75ce4d28e9

+ 1 - 3
NTERA.Engine/Attributes.cs

@@ -17,12 +17,10 @@ namespace NTERA.Engine
 	public class LexerKeywordAttribute : Attribute
 	{
 		public string Keyword { get; }
-		public bool IsLineKeyword { get; }
 
-		public LexerKeywordAttribute(string keyword, bool isLineKeyword = false)
+		public LexerKeywordAttribute(string keyword)
 		{
 			Keyword = keyword;
-			IsLineKeyword = isLineKeyword;
 		}
 	}
 }

+ 4 - 4
NTERA.Engine/Compiler/Parser.cs

@@ -785,15 +785,15 @@ namespace NTERA.Engine.Compiler
 				}
 				else if (token == Token.Identifer)
 				{
-					if (IsVariable(Lexer.Identifier))
+					if (FunctionDefinitions.Any(x => x.Name == Lexer.Identifier))
 					{
-						operands.Push(GetVariable(out error));
+						operands.Push(GetFunction(out error));
 						if (error != null)
 							return null;
 					}
-					else if (FunctionDefinitions.Any(x => x.Name == Lexer.Identifier))
+					else if (IsVariable(Lexer.Identifier))
 					{
-						operands.Push(GetFunction(out error));
+						operands.Push(GetVariable(out error));
 						if (error != null)
 							return null;
 					}

+ 48 - 1
NTERA.Engine/Runtime/Base/Keywords.cs

@@ -1,16 +1,63 @@
 using System;
 using System.Collections.Generic;
 using System.Linq;
+using System.Reflection;
 using System.Text;
 using System.Threading.Tasks;
+using NTERA.Engine.Compiler;
 
 namespace NTERA.Engine.Runtime.Base
 {
+	public class KeywordAttribute : Attribute
+	{
+		public string Name { get; }
+
+		public bool ImplicitString { get; }
+		public bool ImplicitFormatted { get; }
+
+		public KeywordAttribute(string name, bool implicitString = false, bool implicitFormatted = false)
+		{
+			if (implicitFormatted && !implicitString)
+				throw new ArgumentException("Keyword cannot support formatting if it does not use implicit strings");
+
+			Name = name;
+
+			ImplicitString = implicitString;
+			ImplicitFormatted = implicitFormatted;
+		}
+	}
+
 	public static class Keywords
 	{
-		public static void DrawLine(EraRuntime runtime, ExecutionSet set)
+		public static Dictionary<string, Action<EraRuntime, ExecutionSet, ExecutionNode>> StaticKeywords { get; } = _getKeywords();
+
+		private static Dictionary<string, Action<EraRuntime, ExecutionSet, ExecutionNode>> _getKeywords()
+		{
+			var output = new Dictionary<string, Action<EraRuntime, ExecutionSet, ExecutionNode>>();
+
+			foreach (MethodInfo method in typeof(Keywords).GetMethods(BindingFlags.Public | BindingFlags.Static))
+			{
+				var keyword = method.GetCustomAttribute<KeywordAttribute>();
+
+				if (keyword != null)
+					output[keyword.Name] = (runtime, set, node) => { method.Invoke(null, new object[] { runtime, set, node }); };
+			}
+
+			return output;
+		}
+
+		[Keyword("DRAWLINE")]
+		public static void DrawLine(EraRuntime runtime, ExecutionSet set, ExecutionNode node)
 		{
 			runtime.Console.PrintBar();
 		}
+
+		[Keyword("DRAWLINEFORM", true, true)]
+		public static void DrawLineForm(EraRuntime runtime, ExecutionSet set, ExecutionNode node)
+		{
+			var value = runtime.ComputeExpression(set, node.SubNodes.Single());
+
+			runtime.Console.printCustomBar(value.ToString().Trim());
+		}
 	}
 }

+ 59 - 18
NTERA.Engine/Runtime/EraRuntime.cs

@@ -39,10 +39,22 @@ namespace NTERA.Engine.Runtime
 		{
 			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
+				SelfDefinition = function,
+				GlobalVariables = globalVariables,
+				LocalVariables = localVariables
 			};
 
 			ExecutionStack.Push(executionSet);
@@ -52,28 +64,57 @@ namespace NTERA.Engine.Runtime
 			ExecutionStack.Pop();
 		}
 
-		protected void ExecuteSet(ExecutionSet set)
+		public void ExecuteSet(ExecutionSet set)
 		{
 			for (; set.Position < set.Nodes.Count; set.Position++)
 			{
 				ExecutionNode node = set.Nodes[set.Position];
 
-				switch (node.Type)
-				{
-					case "statement":
-						string statement = node.Metadata["name"];
-
-						if (statement == "DRAWLINE")
-							Base.Keywords.DrawLine(this, set);
-						else
-						{
-							throw new Exception($"Unknown statement: '{statement}'");
-						}
-
-						break;
-					default:
-						throw new Exception($"Unknown node type: '{node.Type}'");
-				}
+				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}'");
 			}
 		}
 

+ 3 - 0
NTERA.Engine/Runtime/ExecutionSet.cs

@@ -5,6 +5,9 @@ namespace NTERA.Engine.Runtime
 {
 	public class ExecutionSet
 	{
+		public VariableDictionary LocalVariables { get; set; }
+		public VariableDictionary GlobalVariables { get; set; }
+
 		public FunctionDefinition SelfDefinition { get; set; }
 
 		public IList<ExecutionNode> Nodes { get; set; }