Explorar o código

Initial rework of interpreter

Bepis %!s(int64=6) %!d(string=hai) anos
pai
achega
208e595984

+ 3 - 1
NTERA.Core/IConsole.cs

@@ -5,7 +5,9 @@ namespace NTERA.Core
 {
 	public interface IConsole
 	{
-		InputRequest CurrentRequest { get; }
+        string LastInput { get; }
+
+        InputRequest CurrentRequest { get; }
 		void GiveInput(string input);
 
 		void PrintError(string message);

+ 30 - 0
NTERA.Interpreter/Attributes.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace NTERA.Interpreter
+{
+    [AttributeUsage(AttributeTargets.Method)]
+    public class TargetKeywordAttribute : Attribute
+    {
+        public Token Token { get; }
+
+        public TargetKeywordAttribute(Token token)
+        {
+            Token = token;
+        }
+    }
+
+    [AttributeUsage(AttributeTargets.Method)]
+    public class BuiltInFunctionAttribute : Attribute
+    {
+        public string Name { get; }
+
+        public BuiltInFunctionAttribute(string name)
+        {
+            Name = name;
+        }
+    }
+}

+ 15 - 3
NTERA.Interpreter/Engine.cs

@@ -1,4 +1,5 @@
 using System;
+using System.IO;
 using NTERA.Core;
 using NTERA.EmuEra.Game.EraEmu.Content;
 
@@ -6,14 +7,25 @@ namespace NTERA.Interpreter
 {
 	public class Engine : IScriptEngine
 	{
+        public IConsole Console { get; protected set; }
+
+        public string EntrypointPath { get; protected set; }
+
+        public Interpreter Interpreter { get; protected set; }
+
 		public bool Initialize(IConsole console)
 		{
-			throw new NotImplementedException();
-		}
+            Console = console;
+
+            EntrypointPath = @"M:\era\eraSemifullTest\erb\SYSTEM_TITLE.ERB";
+            Interpreter = new Interpreter(console, File.ReadAllText(EntrypointPath));
+
+            return true;
+        }
 
 		public void Start()
 		{
-			throw new NotImplementedException();
+            Interpreter.Exec();
 		}
 
 		public void InputString(string input)

+ 0 - 66
NTERA.Interpreter/Functions/BuiltInFunctions.cs

@@ -1,66 +0,0 @@
-using System;
-using System.Collections.Generic;
-
-namespace NTERA.Interpreter.Functions
-{
-    class BuiltInFunctions
-    {
-        public static void InstallAll(Interpreter interpreter)
-        {
-            interpreter.AddFunction("str", Str);
-            interpreter.AddFunction("num", Num);
-            interpreter.AddFunction("abs", Abs);
-            interpreter.AddFunction("min", Min);
-            interpreter.AddFunction("max", Max);
-            interpreter.AddFunction("not", Not);
-        }
-
-        public static Value Str(Interpreter interpreter, List<Value> args)
-        {
-            if (args.Count < 1)
-                throw new ArgumentException();
-
-            return args[0].Convert(ValueType.String);
-        }
-
-        public static Value Num(Interpreter interpreter, List<Value> args)
-        {
-            if (args.Count < 1)
-                throw new ArgumentException();
-
-            return args[0].Convert(ValueType.Real);
-        }
-
-        public static Value Abs(Interpreter interpreter, List<Value> args)
-        {
-            if (args.Count < 1)
-                throw new ArgumentException();
-
-            return new Value(Math.Abs(args[0].Real));
-        }
-
-        public static Value Min(Interpreter interpreter, List<Value> args)
-        {
-            if (args.Count < 2)
-                throw new ArgumentException();
-
-            return new Value(Math.Min(args[0].Real, args[1].Real));
-        }
-
-        public static Value Max(Interpreter interpreter, List<Value> args)
-        {
-            if (args.Count < 1)
-                throw new ArgumentException();
-
-            return new Value(Math.Max(args[0].Real, args[1].Real));
-        }
-
-        public static Value Not(Interpreter interpreter, List<Value> args)
-        {
-            if (args.Count < 1)
-                throw new ArgumentException();
-
-            return new Value(args[0].Real == 0 ? 1 : 0);
-        }
-    }
-}

+ 315 - 45
NTERA.Interpreter/Interpreter.cs

@@ -1,14 +1,13 @@
 using System;
 using System.Collections.Generic;
-using NTERA.Interpreter.Functions;
+using System.Linq;
+using System.Reflection;
+using NTERA.Core;
 
 namespace NTERA.Interpreter
 {
     public partial class Interpreter
     {
-        public bool HasPrint { get; set; } = true;
-        public bool HasInput { get; set; } = true;
-
         private Lexer lex;
         private Token prevToken;
         private Token lastToken;
@@ -16,8 +15,9 @@ namespace NTERA.Interpreter
         private Dictionary<string, Value> vars;
         private Dictionary<string, Marker> loops;
 
-        public delegate Value BasicFunction(Interpreter interpreter, List<Value> args);
-        private Dictionary<string, BasicFunction> funcs;
+        public delegate Value BasicFunction(List<Value> args);
+
+        private readonly IConsole console;
 
         private int ifcounter;
 
@@ -25,14 +25,16 @@ namespace NTERA.Interpreter
 
         private bool exit;
 
-        public Interpreter(string input)
+        public Interpreter(IConsole console, string input)
         {
+            this.console = console;
             lex = new Lexer(input);
             vars = new Dictionary<string, Value>();
             loops = new Dictionary<string, Marker>();
-            funcs = new Dictionary<string, BasicFunction>();
             ifcounter = 0;
-            BuiltInFunctions.InstallAll(this);
+
+            GenerateKeywordDictionary();
+            GenerateFunctionDictionary();
         }
 
         public Value GetVar(string name)
@@ -48,12 +50,6 @@ namespace NTERA.Interpreter
             else vars[name] = val;
         }
 
-        public void AddFunction(string name, BasicFunction function)
-        {
-            if (!funcs.ContainsKey(name)) funcs.Add(name, function);
-            else funcs[name] = function;
-        }
-
         void Error(string text)
         {
             throw new Exception(text + " at line: " + lineMarker.Line);
@@ -104,28 +100,35 @@ namespace NTERA.Interpreter
         {
             Token keyword = lastToken;
             GetNextToken();
-            switch (keyword)
+
+            if (KeywordMethods.ContainsKey(keyword))
+                KeywordMethods[keyword]();
+            else
             {
-                case Token.Print: Print(); break;
-                case Token.Input: Input(); break;
-                case Token.If: If(); break;
-                case Token.Else: Else(); break;
-                case Token.EndIf: break;
-                case Token.For: For(); break;
-                case Token.Next: Next(); break;
-                case Token.Let: Let(); break;
-                case Token.End: End(); break;
-                case Token.Identifer:
-                    if (lastToken == Token.Equal) Let();
-                    else goto default;
-                    break;
-                case Token.EOF:
-                    exit = true;
-                    break;
-                default:
-                    Error("Expect keyword got " + keyword);
-                    break;
+                switch (keyword)
+                {
+                    case Token.Input: Input(); break;
+
+                    case Token.Function:
+                    case Token.Global:
+                    case Token.Dim:
+                    case Token.Const:
+                        while (GetNextToken() != Token.NewLine) { }
+                        break;
+
+                    case Token.Identifer:
+                        if (lastToken == Token.Equal) Let();
+                        else goto default;
+                        break;
+                    case Token.EOF:
+                        exit = true;
+                        break;
+                    default:
+                        Error("Expect keyword got " + keyword);
+                        break;
+                }
             }
+
             if (lastToken == Token.Colon)
             {
                 GetNextToken();
@@ -133,26 +136,293 @@ namespace NTERA.Interpreter
             }
         }
 
+        #region Functions
+        
+        private Dictionary<string, BasicFunction> FunctionDictionary { get; set; }
+
+        private void GenerateFunctionDictionary()
+        {
+            FunctionDictionary = new Dictionary<string, BasicFunction>(StringComparer.InvariantCultureIgnoreCase);
+
+            foreach (var method in typeof(Interpreter).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
+            {
+                var attribute = method.GetCustomAttributes(typeof(BuiltInFunctionAttribute), true).FirstOrDefault() as BuiltInFunctionAttribute;
+
+                if (attribute == null)
+                    continue;
+
+                FunctionDictionary[attribute.Name] = args => (Value)method.Invoke(this, new object[] { args });
+            }
+        }
+
+
+        [BuiltInFunction("str")]
+        private Value Str(List<Value> args)
+        {
+            if (args.Count < 1)
+                throw new ArgumentException();
+
+            return args[0].Convert(ValueType.String);
+        }
+
+        [BuiltInFunction("num")]
+        private Value Num(List<Value> args)
+        {
+            if (args.Count < 1)
+                throw new ArgumentException();
+
+            return args[0].Convert(ValueType.Real);
+        }
+
+        [BuiltInFunction("abs")]
+        private Value Abs(List<Value> args)
+        {
+            if (args.Count < 1)
+                throw new ArgumentException();
+
+            return new Value(Math.Abs(args[0].Real));
+        }
+
+        [BuiltInFunction("min")]
+        private Value Min(List<Value> args)
+        {
+            if (args.Count < 2)
+                throw new ArgumentException();
+
+            return new Value(Math.Min(args[0].Real, args[1].Real));
+        }
+
+        [BuiltInFunction("max")]
+        private Value Max(List<Value> args)
+        {
+            if (args.Count < 2)
+                throw new ArgumentException();
+
+            return new Value(Math.Max(args[0].Real, args[1].Real));
+        }
+
+        [BuiltInFunction("not")]
+        private Value Not(List<Value> args)
+        {
+            if (args.Count < 1)
+                throw new ArgumentException();
+
+            return new Value(args[0].Real == 0 ? 1 : 0);
+        }
+
+        private readonly Random random = new Random();
+
+        [BuiltInFunction("rand")]
+        private Value Rand(List<Value> args)
+        {
+            if (args.Count < 2)
+                throw new ArgumentException();
+
+            return new Value(random.Next((int)args[0].Real, (int)args[1].Real - 1));
+        }
+
+        #endregion
+
+        #region Keywords
+
+        private Dictionary<Token, Action> KeywordMethods { get; set; }
+
+        private void GenerateKeywordDictionary()
+        {
+            KeywordMethods = new Dictionary<Token, Action>();
+
+            foreach (var method in typeof(Interpreter).GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance))
+            {
+                var attribute = method.GetCustomAttributes(typeof(TargetKeywordAttribute), true).FirstOrDefault() as TargetKeywordAttribute;
+
+                if (attribute == null)
+                    continue;
+
+                KeywordMethods[attribute.Token] = () => method.Invoke(this, null);
+            }
+        }
+
+
+        [TargetKeyword(Token.Print)]
         void Print()
         {
-            if (!HasPrint)
-                Error("Print command not allowed");
+            console.Write(Expr().ToString());
+        }
 
-            Console.WriteLine(Expr().ToString());
+        [TargetKeyword(Token.PrintL)]
+        void PrintL()
+        {
+            console.PrintSingleLine(Expr().ToString());
         }
 
-        void Input()
+        [TargetKeyword(Token.DrawLine)]
+        void DrawLine()
         {
-            if (!HasInput)
-                Error("Input command not allowed");
+            console.PrintBar();
+        }
 
+        [TargetKeyword(Token.DrawLineForm)]
+        void DrawLineForm()
+        {
+            console.printCustomBar(Expr().ToString());
+        }
+
+        [TargetKeyword(Token.If)]
+        private void If()
+        {
+            bool result = Expr().BinOp(new Value(0), Token.Equal).Real == 1;
+
+            Match(Token.Then);
+            GetNextToken();
+
+            if (result)
+            {
+                int i = ifcounter;
+                while (true)
+                {
+                    if (lastToken == Token.If)
+                    {
+                        i++;
+                    }
+                    else if (lastToken == Token.Else)
+                    {
+                        if (i == ifcounter)
+                        {
+                            GetNextToken();
+                            return;
+                        }
+                    }
+                    else if (lastToken == Token.EndIf)
+                    {
+                        if (i == ifcounter)
+                        {
+                            GetNextToken();
+                            return;
+                        }
+                        i--;
+                    }
+                    GetNextToken();
+                }
+            }
+        }
+
+        [TargetKeyword(Token.Else)]
+        private void Else()
+        {
+            int i = ifcounter;
+            while (true)
+            {
+                if (lastToken == Token.If)
+                {
+                    i++;
+                }
+                else if (lastToken == Token.EndIf)
+                {
+                    if (i == ifcounter)
+                    {
+                        GetNextToken();
+                        return;
+                    }
+                    i--;
+                }
+                GetNextToken();
+            }
+        }
+
+        [TargetKeyword(Token.EndIf)]
+        private void EndIf()
+        {
+
+        }
+
+        [TargetKeyword(Token.End)]
+        private void End()
+        {
+            exit = true;
+        }
+
+        [TargetKeyword(Token.Let)]
+        private void Let()
+        {
+            if (lastToken != Token.Equal)
+            {
+                Match(Token.Identifer);
+                GetNextToken();
+                Match(Token.Equal);
+            }
+
+            string id = lex.Identifer;
+
+            GetNextToken();
+
+            SetVar(id, Expr());
+        }
+
+        [TargetKeyword(Token.For)]
+        private void For()
+        {
+            Match(Token.Identifer);
+            string var = lex.Identifer;
+
+            GetNextToken();
+            Match(Token.Equal);
+
+            GetNextToken();
+            Value v = Expr();
+
+            if (loops.ContainsKey(var))
+            {
+                loops[var] = lineMarker;
+            }
+            else
+            {
+                SetVar(var, v);
+                loops.Add(var, lineMarker);
+            }
+
+            Match(Token.To);
+
+            GetNextToken();
+            v = Expr();
+
+            if (vars[var].BinOp(v, Token.More).Real == 1)
+            {
+                while (true)
+                {
+                    while (!(GetNextToken() == Token.Identifer && prevToken == Token.Next)) ;
+                    if (lex.Identifer == var)
+                    {
+                        loops.Remove(var);
+                        GetNextToken();
+                        Match(Token.NewLine);
+                        break;
+                    }
+                }
+            }
+        }
+
+        [TargetKeyword(Token.Next)]
+        private void Next()
+        {
+            Match(Token.Identifer);
+            string var = lex.Identifer;
+            vars[var] = vars[var].BinOp(new Value(1), Token.Plus);
+            lex.GoTo(new Marker(loops[var].Pointer - 1, loops[var].Line, loops[var].Column - 1));
+            lastToken = Token.NewLine;
+        }
+
+        #endregion
+
+        void Input()
+        {
             while (true)
             {
                 Match(Token.Identifer);
                
                 if (!vars.ContainsKey(lex.Identifer)) vars.Add(lex.Identifer, new Value());
-                
-                string input = Console.ReadLine();
+
+                console.WaitInput(new Core.Interop.InputRequest() { InputType = Core.Interop.InputType.StrValue });
+                string input = console.LastInput;
                 double d;
                 if (double.TryParse(input, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out d))
                     vars[lex.Identifer] = new Value(d);
@@ -193,7 +463,7 @@ namespace NTERA.Interpreter
                     {
                         stack.Push(vars[lex.Identifer]);
                     }
-                    else if (funcs.ContainsKey(lex.Identifer))
+                    else if (FunctionDictionary.ContainsKey(lex.Identifer))
                     {
                         string name = lex.Identifer;
                         List<Value> args = new List<Value>();
@@ -208,7 +478,7 @@ namespace NTERA.Interpreter
                                 goto start;
                         }
 
-                        stack.Push(funcs[name](null, args));
+                        stack.Push(FunctionDictionary[name](args));
                     }
                     else
                     {

+ 0 - 137
NTERA.Interpreter/Keywords/Control.cs

@@ -1,137 +0,0 @@
-namespace NTERA.Interpreter
-{
-	public partial class Interpreter
-	{
-		private void If() 
-        {
-            bool result = Expr().BinOp(new Value(0), Token.Equal).Real == 1;
-
-            Match(Token.Then);
-            GetNextToken();
-
-            if (result)
-            {
-                int i = ifcounter;
-                while (true)
-                {
-                    if (lastToken == Token.If)
-                    {
-                        i++;
-                    }
-                    else if (lastToken == Token.Else)
-                    {
-                        if (i == ifcounter)
-                        {
-                            GetNextToken();
-                            return;
-                        }
-                    }
-                    else if (lastToken == Token.EndIf)
-                    {
-                        if(i == ifcounter)
-                        {
-                            GetNextToken();
-                            return;
-                        }
-                        i--;
-                    }
-                    GetNextToken();
-                }
-            }
-        }
-
-		private void Else()
-		{
-			int i = ifcounter;
-			while (true)
-            {
-                if (lastToken == Token.If)
-                {
-                    i++;
-                }
-                else if (lastToken == Token.EndIf)
-                {
-                    if(i == ifcounter)
-                    {
-                        GetNextToken();
-                        return;
-                    }
-                    i--;
-                }
-				GetNextToken ();
-			}
-		}
-
-		private void End()
-        {
-            exit = true;
-        }
-
-		private void Let()
-        {
-            if (lastToken != Token.Equal)
-            {
-                Match(Token.Identifer);
-                GetNextToken();
-                Match(Token.Equal);
-            }
-
-            string id = lex.Identifer;
-
-            GetNextToken();
-            
-            SetVar(id, Expr());
-        }
-
-		private void For()
-        {
-            Match(Token.Identifer);
-            string var = lex.Identifer;
-
-            GetNextToken();
-            Match(Token.Equal);
-
-            GetNextToken();
-            Value v  = Expr();
-
-            if (loops.ContainsKey(var))
-            {
-                loops[var] = lineMarker;
-            }
-            else
-            {
-                SetVar(var, v);
-                loops.Add(var, lineMarker);
-            }
-
-            Match(Token.To);
-
-            GetNextToken();
-            v = Expr();
-            
-            if (vars[var].BinOp(v, Token.More).Real == 1)
-            {
-                while (true)
-                {
-                    while (!(GetNextToken() == Token.Identifer && prevToken == Token.Next)) ;
-                    if (lex.Identifer == var)
-                    {
-                        loops.Remove(var);
-                        GetNextToken();
-                        Match(Token.NewLine);
-                        break;
-                    }
-                }
-            }
-        }
-
-		private void Next()
-        {
-            Match(Token.Identifer);
-            string var = lex.Identifer;
-            vars[var] = vars[var].BinOp(new Value(1), Token.Plus);
-            lex.GoTo(new Marker(loops[var].Pointer - 1, loops[var].Line, loops[var].Column - 1));
-            lastToken = Token.NewLine;
-        }
-	}
-}

+ 7 - 0
NTERA.Interpreter/Lexer.cs

@@ -56,6 +56,11 @@ namespace NTERA.Interpreter
                 switch (Identifer.ToUpper())
                 {
                     case "PRINT": return Token.Print;
+                    case "PRINTL": return Token.PrintL;
+                    case "DRAWLINE": return Token.DrawLine;
+                    case "DRAWLINEFORM": return Token.DrawLineForm;
+                    case "DIM": return Token.Dim;
+                    case "CONST": return Token.Const;
                     case "IF": return Token.If;
                     case "ENDIF": return Token.EndIf;
                     case "THEN": return Token.Then;
@@ -95,6 +100,8 @@ namespace NTERA.Interpreter
             switch (lastChar)
             {
                 case '\n': tok = Token.NewLine; break;
+                case '@': tok = Token.Function; break;
+                case '#': tok = Token.Global; break;
                 case ':': tok = Token.Colon; break;
                 case ';': tok = Token.Semicolon; break;
                 case ',': tok = Token.Comma; break;

+ 1 - 2
NTERA.Interpreter/NTERA.Interpreter.csproj

@@ -40,10 +40,9 @@
     <Reference Include="System.Xml" />
   </ItemGroup>
   <ItemGroup>
+    <Compile Include="Attributes.cs" />
     <Compile Include="Engine.cs" />
-    <Compile Include="Functions\BuiltInFunctions.cs" />
     <Compile Include="Interpreter.cs" />
-    <Compile Include="Keywords\Control.cs" />
     <Compile Include="Lexer.cs" />
     <Compile Include="Marker.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />

+ 11 - 1
NTERA.Interpreter/Token.cs

@@ -5,11 +5,21 @@ namespace NTERA.Interpreter
     {
         Unkown,
 
+        Global,
+        Function,
+
         Identifer,
         Value,
 
-        //Keywords
+        Dim,
+        Const,
+
+        DrawLine,
+        DrawLineForm,
         Print,
+        PrintL,
+
+        //Keywords
         If,
 		EndIf,
         Then,

+ 11 - 7
NTERA/Console/EraConsoleInstance.cs

@@ -30,11 +30,13 @@ namespace NTERA.Console
 			else
 				Renderer.WriteItem(item);
 		}
-
+        
 
 		public bool IsRunning { get; set; } = true;
 		public bool Enabled { get; set; } = true;
 
+        public string LastInput { get; protected set; }
+
 
 
 		public EraConsoleInstance(ConsoleRenderer renderer, IScriptEngine scriptEngine)
@@ -47,7 +49,9 @@ namespace NTERA.Console
 
 		public void GiveInput(string input)
 		{
-			PrintSingleLine(input);
+            LastInput = input;
+
+            PrintSingleLine(input);
 			InputResetEvent.Set();
 		}
 
@@ -198,22 +202,22 @@ namespace NTERA.Console
 
 		public void PrintButton(string something, long something1)
 		{
-			Write(something);
+		    Write(something);
 		}
 
 		public void PrintButton(string something, string something1)
 		{
-			Write(something);
+		    Write(something);
 		}
 
 		public void PrintButtonC(string something, long something1, bool something2)
 		{
-			Write(something);
+		    Write(something);
 		}
 
 		public void PrintButtonC(string something, string something1, bool something2)
 		{
-			Write(something);
+		    Write(something);
 		}
 
 		public void PrintPlain(string message)
@@ -249,7 +253,7 @@ namespace NTERA.Console
 		{
 			AddText(shape);
 		}
-
+        
 		public void DebugPrint(string message)
 		{
 			AddText(message);

+ 4 - 0
NTERA/NTERA.csproj

@@ -105,6 +105,10 @@
       <Project>{8cdf43e9-301c-42aa-b752-ff42fa10dd6f}</Project>
       <Name>NTERA.EmuEra</Name>
     </ProjectReference>
+    <ProjectReference Include="..\NTERA.Interpreter\NTERA.Interpreter.csproj">
+      <Project>{F3B58EF3-E3FF-4B76-92B8-2AB87663FC4D}</Project>
+      <Name>NTERA.Interpreter</Name>
+    </ProjectReference>
   </ItemGroup>
   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
 </Project>

+ 4 - 2
NTERA/formMain.cs

@@ -3,6 +3,7 @@ using System.Windows.Forms;
 using NTERA.Console;
 using NTERA.Core;
 using NTERA.EmuEra;
+using NTERA.Interpreter;
 
 namespace NTERA
 {
@@ -14,9 +15,10 @@ namespace NTERA
 		{
 			InitializeComponent();
 
-			var scriptEngine = new EmuEraGameInstance();
+            //var scriptEngine = new EmuEraGameInstance();
+            var scriptEngine = new Engine();
 
-			Task.Factory.StartNew(() => instance.Run(new EraConsoleInstance(consoleControl1.Renderer, scriptEngine), scriptEngine));
+            Task.Factory.StartNew(() => instance.Run(new EraConsoleInstance(consoleControl1.Renderer, scriptEngine), scriptEngine));
 		}
 
 		private void txtInput_KeyDown(object sender, KeyEventArgs e)