瀏覽代碼

Performance optimizations and monitoring

Xanathar 11 年之前
父節點
當前提交
458fc0bc2e
共有 29 個文件被更改,包括 1030 次插入300 次删除
  1. 27 3
      src/MoonSharp.Interpreter.Tests/EndToEnd/SimpleTests.cs
  2. 1 1
      src/MoonSharp.Interpreter.Tests/EndToEnd/UserDataPropertiesTests.cs
  3. 1 1
      src/MoonSharp.Interpreter.Tests/TestMore/231-metatable.t
  4. 1 1
      src/MoonSharp.Interpreter/DataTypes/DynValue.cs
  5. 14 5
      src/MoonSharp.Interpreter/Diagnostics/AstDump.cs
  6. 0 33
      src/MoonSharp.Interpreter/Diagnostics/CodeChrono.cs
  7. 18 0
      src/MoonSharp.Interpreter/Diagnostics/PerformanceCounter.cs
  8. 13 0
      src/MoonSharp.Interpreter/Diagnostics/PerformanceCounterType.cs
  9. 65 0
      src/MoonSharp.Interpreter/Diagnostics/PerformanceCounters/GlobalPerformanceStopwatch.cs
  10. 13 0
      src/MoonSharp.Interpreter/Diagnostics/PerformanceCounters/IPerformanceStopwatch.cs
  11. 61 0
      src/MoonSharp.Interpreter/Diagnostics/PerformanceCounters/PerformanceStopwatch.cs
  12. 66 0
      src/MoonSharp.Interpreter/Diagnostics/PerformanceResult.cs
  13. 70 0
      src/MoonSharp.Interpreter/Diagnostics/PerformanceStatistics.cs
  14. 5 0
      src/MoonSharp.Interpreter/Execution/VM/Processor/Processor.cs
  15. 50 114
      src/MoonSharp.Interpreter/Grammar/Lua.g4
  16. 32 28
      src/MoonSharp.Interpreter/Interop/UserDataMethodDescriptor.cs
  17. 43 36
      src/MoonSharp.Interpreter/Interop/UserDataPropertyDescriptor.cs
  18. 11 2
      src/MoonSharp.Interpreter/MoonSharp.Interpreter.csproj
  19. 2 2
      src/MoonSharp.Interpreter/Properties/AssemblyInfo.cs
  20. 17 2
      src/MoonSharp.Interpreter/Script.cs
  21. 328 0
      src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs
  22. 11 4
      src/MoonSharp.Interpreter/Tree/Expressions/OperatorExpression.cs
  23. 30 0
      src/MoonSharp.Interpreter/Tree/Expressions/PowerOperatorExpression.cs
  24. 50 0
      src/MoonSharp.Interpreter/Tree/Expressions/UnaryOperatorExpression.cs
  25. 29 23
      src/MoonSharp.Interpreter/Tree/Loader_Antlr.cs
  26. 64 39
      src/MoonSharp.Interpreter/Tree/NodeFactory.cs
  27. 0 1
      src/MoonSharp.Interpreter/Tree/Statements/ChunkStatement.cs
  28. 8 2
      src/PerformanceComparison/HugeFile.cs
  29. 0 3
      src/moonsharp.sln

+ 27 - 3
src/MoonSharp.Interpreter.Tests/EndToEnd/SimpleTests.cs

@@ -463,12 +463,24 @@ namespace MoonSharp.Interpreter.Tests
 			Assert.AreEqual(120.0, res.Number);
 		}
 
+		[Test]
+		public void VeryBasic()
+		{
+			string script = @"return 7";
+
+			DynValue res = Script.RunString(script);
+
+			Assert.AreEqual(DataType.Number, res.Type);
+			Assert.AreEqual(7, res.Number);
+		}
+
 		[Test]
 		public void OperatorPrecedence1()
 		{
 			string script = @"return 1+2*3";
 
-			DynValue res = Script.RunString(script);
+			Script s = new Script(CoreModules.None);
+			DynValue res = s.DoString(script);
 
 			Assert.AreEqual(DataType.Number, res.Type);
 			Assert.AreEqual(7, res.Number);
@@ -519,6 +531,17 @@ namespace MoonSharp.Interpreter.Tests
 			Assert.AreEqual(2, res.Number);
 		}
 
+		[Test]
+		public void OperatorPrecedence5()
+		{
+			string script = @"return 3 * -1 + 5 * 3";
+			Script S = new Script(CoreModules.None);
+
+			DynValue res = S.DoString(script);
+
+			Assert.AreEqual(DataType.Number, res.Type);
+			Assert.AreEqual(12, res.Number);
+		}
 
 
 
@@ -615,7 +638,8 @@ namespace MoonSharp.Interpreter.Tests
     
 				return fact(5)";
 
-			DynValue res = Script.RunString(script);
+			Script s = new Script(CoreModules.None);
+			DynValue res = s.DoString(script);
 
 			Assert.AreEqual(DataType.Number, res.Type);
 			Assert.AreEqual(120.0, res.Number);
@@ -831,7 +855,7 @@ namespace MoonSharp.Interpreter.Tests
 					do return x(); end
 								";
 
-			DynValue res = Script.RunString(script);
+			DynValue res = (new Script(CoreModules.None)).DoString(script);
 
 			Assert.AreEqual(DataType.Number, res.Type);
 			Assert.AreEqual(1, res.Number);

+ 1 - 1
src/MoonSharp.Interpreter.Tests/EndToEnd/UserDataPropertiesTests.cs

@@ -429,7 +429,7 @@ namespace MoonSharp.Interpreter.Tests.EndToEnd
 			Script s = new Script();
 			long big = long.MaxValue;
 			var v = DynValue.FromObject(s, big);
-			int a = 3;
+			Assert.IsNotNull(v);
 		}
 
 	}

+ 1 - 1
src/MoonSharp.Interpreter.Tests/TestMore/231-metatable.t

@@ -103,7 +103,7 @@ mt = {
   end,
 }
 setmetatable(t, mt)
-is(t .. t .. t .. 4 ..'end', "t|t|t|4end", "__concat")
+is(t .. t .. t .. 4 ..'end', "t|t|t|4end", "__concatx")
 
 
 --[[ Cplx ]]

+ 1 - 1
src/MoonSharp.Interpreter/DataTypes/DynValue.cs

@@ -138,7 +138,7 @@ namespace MoonSharp.Interpreter
 		/// Creates a new writable value initialized to the specified coroutine.
 		/// Internal use only, for external use, see Script.CoroutineCreate
 		/// </summary>
-		/// <param name="coroutineHandle">The coroutine handle.</param>
+		/// <param name="coroutine">The coroutine object.</param>
 		/// <returns></returns>
 		public static DynValue NewCoroutine(Coroutine coroutine)
 		{

+ 14 - 5
src/MoonSharp.Interpreter/Diagnostics/AstDump.cs

@@ -13,19 +13,28 @@ namespace MoonSharp.Interpreter.Diagnostics
 
 		public void DumpTree(IParseTree tree, string filename)
 		{
-			DumpTree(tree, 0);
+			DumpTree(true, tree, 0);
 			File.WriteAllText(filename, m_TreeDump.ToString());
 		}
 
-		private void DumpTree(IParseTree tree, int depth = 0)
+		public void WalkTreeForWaste(IParseTree tree)
 		{
-			string tabs = new string(' ', depth * 4);
+			DumpTree(false, tree, 0);
+		}
+
+		private void DumpTree(bool dooutput, IParseTree tree, int depth = 0)
+		{
+			string tabs;
 
-			m_TreeDump.AppendFormat("{0}{1} : {2}\n", tabs, Purify(tree.GetType()), tree.GetText());
+			if (dooutput)
+			{
+				tabs = new string(' ', depth * 4);
+				m_TreeDump.AppendFormat("{0}{1} : {2}\n", tabs, Purify(tree.GetType()), tree.GetText());
+			}
 
 			for (int i = 0; i < tree.ChildCount; i++)
 			{
-				DumpTree(tree.GetChild(i), depth + 1);
+				DumpTree(dooutput, tree.GetChild(i), depth + 1);
 			}
 		}
 

+ 0 - 33
src/MoonSharp.Interpreter/Diagnostics/CodeChrono.cs

@@ -1,33 +0,0 @@
-using System;
-using System.Collections.Generic;
-using MoonSharp.Interpreter.Diagnostics;
-using System.Linq;
-using System.Text;
-using System.Diagnostics;
-
-namespace MoonSharp.Interpreter.Diagnostics
-{
-	class CodeChrono : IDisposable
-	{
-		[System.Diagnostics.Conditional("DEBUG")]
-		public static void WriteLine(string source, string msg, params object[] args)
-		{
-			System.Diagnostics.Debug.WriteLine(string.Format(msg, args));
-		}
-
-		string m_Desc;
-		Stopwatch m_Stopwatch;
-
-		public CodeChrono(string descFormat, params object[] args)
-		{
-			m_Desc = string.Format(descFormat, args);
-			m_Stopwatch = Stopwatch.StartNew();
-		}
-
-		public void Dispose()
-		{
-			m_Stopwatch.Stop();
-			WriteLine("CodeChrono", "Activity {0} took {1}ms", m_Desc, m_Stopwatch.ElapsedMilliseconds);
-		}
-	}
-}

+ 18 - 0
src/MoonSharp.Interpreter/Diagnostics/PerformanceCounter.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Diagnostics
+{
+	public enum PerformanceCounter
+	{
+		Parsing,
+		AstCreation,
+		Compilation,
+		Execution,
+		AdaptersCompilation,
+
+		LastValue
+	}
+}

+ 13 - 0
src/MoonSharp.Interpreter/Diagnostics/PerformanceCounterType.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Diagnostics
+{
+	public enum PerformanceCounterType
+	{
+		MemoryBytes,
+		TimeMilliseconds,
+	}
+}

+ 65 - 0
src/MoonSharp.Interpreter/Diagnostics/PerformanceCounters/GlobalPerformanceStopwatch.cs

@@ -0,0 +1,65 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Diagnostics.PerformanceCounters
+{
+	/// <summary>
+	/// This class is not *really* IDisposable.. it's just use to have a RAII like pattern.
+	/// You are free to reuse this instance after calling Dispose.
+	/// </summary>
+	internal class GlobalPerformanceStopwatch : IPerformanceStopwatch
+	{
+		private class GlobalPerformanceStopwatch_StopwatchObject : IDisposable
+		{
+			Stopwatch m_Stopwatch;
+			GlobalPerformanceStopwatch m_Parent;
+
+			public GlobalPerformanceStopwatch_StopwatchObject(GlobalPerformanceStopwatch parent)
+			{
+				m_Parent = parent;
+				m_Stopwatch = Stopwatch.StartNew();
+			}
+
+			public void Dispose()
+			{
+				m_Stopwatch.Stop();
+				m_Parent.SignalStopwatchTerminated(m_Stopwatch);
+			}
+		}
+
+		int m_Count = 0;
+		long m_Elapsed = 0;
+		PerformanceCounter m_Counter;
+
+		public GlobalPerformanceStopwatch(PerformanceCounter perfcounter)
+		{
+			m_Counter = perfcounter;
+		}
+
+		private void SignalStopwatchTerminated(Stopwatch sw)
+		{
+			m_Elapsed += sw.ElapsedMilliseconds;
+			m_Count += 1;
+		}
+
+		public IDisposable Start()
+		{
+			return new GlobalPerformanceStopwatch_StopwatchObject(this);
+		}
+
+		public PerformanceResult GetResult()
+		{
+			return new PerformanceResult()
+			{
+				Type = PerformanceCounterType.TimeMilliseconds,
+				Global = false,
+				Name = m_Counter.ToString(),
+				Instances = m_Count,
+				Counter = m_Elapsed
+			};
+		}
+	}
+}

+ 13 - 0
src/MoonSharp.Interpreter/Diagnostics/PerformanceCounters/IPerformanceStopwatch.cs

@@ -0,0 +1,13 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Diagnostics.PerformanceCounters
+{
+	public interface IPerformanceStopwatch
+	{
+		IDisposable Start();
+		PerformanceResult GetResult();
+	}
+}

+ 61 - 0
src/MoonSharp.Interpreter/Diagnostics/PerformanceCounters/PerformanceStopwatch.cs

@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Diagnostics.PerformanceCounters
+{
+	/// <summary>
+	/// This class is not *really* IDisposable.. it's just use to have a RAII like pattern.
+	/// You are free to reuse this instance after calling Dispose.
+	/// </summary>
+	internal class PerformanceStopwatch : IDisposable, IPerformanceStopwatch
+	{
+		Stopwatch m_Stopwatch = new Stopwatch();
+		int m_Count = 0;
+		int m_Reentrant = 0;
+		PerformanceCounter m_Counter;
+
+		public PerformanceStopwatch(PerformanceCounter perfcounter)
+		{
+			m_Counter = perfcounter;
+		}
+
+
+		public IDisposable Start()
+		{
+			if (m_Reentrant == 0)
+			{
+				m_Count += 1;
+				m_Stopwatch.Start();
+			}
+
+			m_Reentrant += 1;
+
+			return this;
+		}
+
+		public void Dispose()
+		{
+			m_Reentrant -= 1;
+
+			if (m_Reentrant == 0)
+			{
+				m_Stopwatch.Stop();
+			}
+		}
+
+		public PerformanceResult GetResult()
+		{
+			return new PerformanceResult()
+			{
+				Type = PerformanceCounterType.TimeMilliseconds,
+				Global = false,
+				Name = m_Counter.ToString(),
+				Instances = m_Count,
+				Counter = m_Stopwatch.ElapsedMilliseconds
+			};
+		}
+	}
+}

+ 66 - 0
src/MoonSharp.Interpreter/Diagnostics/PerformanceResult.cs

@@ -0,0 +1,66 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+
+namespace MoonSharp.Interpreter.Diagnostics
+{
+	/// <summary>
+	/// The result of a performance counter
+	/// </summary>
+	public class PerformanceResult
+	{
+		/// <summary>
+		/// Gets the name of the performance counter which generated this result.
+		/// </summary>
+		public string Name { get; internal set; }
+		/// <summary>
+		/// Gets the quantity monitored - see Type to understand what this field contains
+		/// </summary>
+		public long Counter { get; internal set; }
+		/// <summary>
+		/// Gets the number of instances which led to the specified counter being incremented - e.g. the times a specific
+		/// code is executed, or object instanced
+		/// </summary>
+		public int Instances { get; internal set; }
+		/// <summary>
+		/// Gets a value indicating whether this <see cref="PerformanceResult"/> is global or relative to the resource
+		/// for which it's called.
+		/// </summary>
+		public bool Global { get; internal set; }
+		/// <summary>
+		/// Gets the unit of measure of the Counter field.
+		/// </summary>
+		public PerformanceCounterType Type { get; internal set; }
+
+		/// <summary>
+		/// Returns a <see cref="System.String" /> that represents this instance.
+		/// </summary>
+		public override string ToString()
+		{
+			return string.Format("{0}{1} : {2} times / {3} {4}",
+				Name,
+				Global ? "(g)" : "",
+				Instances,
+				Counter,
+				PerformanceCounterTypeToString(Type));
+		}
+
+		/// <summary>
+		/// Converts a PerformanceCounterType to a string.
+		/// </summary>
+		/// <param name="Type">The type.</param>
+		public static string PerformanceCounterTypeToString(PerformanceCounterType Type)
+		{
+			switch (Type)
+			{
+				case PerformanceCounterType.MemoryBytes:
+					return "bytes";
+				case PerformanceCounterType.TimeMilliseconds:
+					return "ms";
+				default:
+					throw new InvalidOperationException("PerformanceCounterType has invalid value " + Type.ToString());
+			}
+		}
+	}
+}

+ 70 - 0
src/MoonSharp.Interpreter/Diagnostics/PerformanceStatistics.cs

@@ -0,0 +1,70 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using MoonSharp.Interpreter.Diagnostics.PerformanceCounters;
+
+namespace MoonSharp.Interpreter.Diagnostics
+{
+	/// <summary>
+	/// A single object of this type exists for every script and gives access to performance statistics.
+	/// </summary>
+	public class PerformanceStatistics
+	{
+		IPerformanceStopwatch[] m_Stopwatches = new IPerformanceStopwatch[(int)PerformanceCounter.LastValue];
+		static IPerformanceStopwatch[] m_GlobalStopwatches = new IPerformanceStopwatch[(int)PerformanceCounter.LastValue];
+
+		static PerformanceStatistics()
+		{
+			m_GlobalStopwatches[(int)PerformanceCounter.AdaptersCompilation] = new GlobalPerformanceStopwatch(PerformanceCounter.AdaptersCompilation);
+		}
+
+		internal PerformanceStatistics()
+		{
+			for (int i = 0; i < (int)PerformanceCounter.LastValue; i++)
+				m_Stopwatches[i] = m_GlobalStopwatches[i] ?? new PerformanceStopwatch((PerformanceCounter)i);
+		}
+
+		/// <summary>
+		/// Gets the result of the specified performance counter .
+		/// </summary>
+		/// <param name="pc">The PerformanceCounter.</param>
+		/// <returns></returns>
+		public PerformanceResult GetPerformanceCounterResult(PerformanceCounter pc)
+		{
+			return m_Stopwatches[(int)pc].GetResult();
+		}
+
+		/// <summary>
+		/// Starts a stopwatch.
+		/// </summary>
+		/// <returns></returns>
+		internal IDisposable StartStopwatch(PerformanceCounter pc)
+		{
+			return m_Stopwatches[(int)pc].Start();
+		}
+
+		/// <summary>
+		/// Starts a stopwatch.
+		/// </summary>
+		/// <returns></returns>
+		internal static IDisposable StartGlobalStopwatch(PerformanceCounter pc)
+		{
+			return m_GlobalStopwatches[(int)pc].Start();
+		}
+
+		/// <summary>
+		/// Gets a string with a complete performance log.
+		/// </summary>
+		/// <returns></returns>
+		public string GetPerformanceLog()
+		{
+			StringBuilder sb = new StringBuilder();
+
+			for (int i = 0; i < (int)PerformanceCounter.LastValue; i++)
+				sb.AppendLine(this.GetPerformanceCounterResult((PerformanceCounter)i).ToString());
+
+			return sb.ToString();
+		}
+	}
+}

+ 5 - 0
src/MoonSharp.Interpreter/Execution/VM/Processor/Processor.cs

@@ -45,6 +45,8 @@ namespace MoonSharp.Interpreter.Execution.VM
 
 		public DynValue Call(DynValue function, DynValue[] args)
 		{
+			var stopwatch = this.m_Script.PerformanceStats.StartStopwatch(Diagnostics.PerformanceCounter.Execution);
+
 			m_CanYield = false;
 
 			try
@@ -55,6 +57,9 @@ namespace MoonSharp.Interpreter.Execution.VM
 			finally
 			{
 				m_CanYield = true;
+
+				if (stopwatch != null)
+					stopwatch.Dispose();
 			}
 		}
 

+ 50 - 114
src/MoonSharp.Interpreter/Grammar/Lua.g4

@@ -1,55 +1,10 @@
-/*
-BSD License
-
-Copyright (c) 2014, Marco Mastropaolo
-Copyright (c) 2013, Kazunori Sakamoto
-
-
-All rights reserved.   
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions
-are met:
- 
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-3. Neither the NAME of Rainer Schuster nor the NAMEs of its contributors
-   may be used to endorse or promote products derived from this software
-   without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-This grammar file derived from:
-
-    Lua 5.2 Reference Manual
-    http://www.lua.org/manual/5.2/manual.html
-
-    Lua 5.1 grammar written by Nicolai Mainiero
-    http://www.antlr3.org/grammar/1178608849736/Lua.g
-
-I tested my grammar with Test suite for Lua 5.2 (http://www.lua.org/tests/5.2/)
-*/
-
-grammar Lua; 
+grammar Lua;
 
 chunk
     : block EOF
     ;
 
-block 
+block
     : stat* retstat?
     ;
 
@@ -81,7 +36,7 @@ label
     ;
 
 // this is an addition
-funcnametableaccessor 
+funcnametableaccessor
 	: ('.' NAME);
 
 funcname
@@ -94,54 +49,27 @@ varlist
 
 namelist
     : NAME (',' NAME)*
-    ;
+    ; 
 
 explist
     : exp (',' exp)*
     ;
 
-expterm 
-	: 'nil' | 'false' | 'true' | number | string		
-	| vararg
-	| anonfunctiondef								
-    | prefixexp										 
-	| tableconstructor
-	;
-	
-powerExp 
-	: expterm 													#exp_powerfallback
-	| expterm operatorPower powerExp							#exp_power
-	;
-unaryExp 
-	: powerExp 													#exp_unaryfallback
-	| operatorUnary unaryExp									#exp_unary
-	;
-muldivExp 
-	: unaryExp 													#exp_muldivfallback
-	| unaryExp operatorMulDivMod muldivExp						#exp_muldiv
-	;
-addsubExp 
-	: muldivExp 												#exp_addsubfallback
-	| muldivExp operatorAddSub addsubExp						#exp_addsub
-	;
-strcatExp 	
-	: addsubExp 												#exp_strcastfallback
-	| addsubExp operatorStrcat strcatExp						#exp_strcat
-	;
-compareExp 
-	: strcatExp 												#exp_comparefallback
-	| strcatExp operatorComparison compareExp                   #exp_compare
-	;
-logicAndExp 
-	: compareExp 												#exp_logicAndfallback
-	| compareExp operatorAnd logicAndExp                        #exp_logicAnd
-	;
-exp 
-	: logicAndExp 												#exp_logicOrfallback
-	| logicAndExp operatorOr exp								#exp_logicOr
+exp
+    : NIL												#exp_nil
+	| FALSE												#exp_false
+	| TRUE												#exp_true
+	| number											#exp_number
+	| string											#exp_string
+	| vararg											#exp_varargs
+	| FUNCTION funcbody									#exp_anonfunc
+    | prefixexp											#exp_prefixexp
+	| tableconstructor									#exp_tabctor
+	| <assoc=right> exp '^' exp							#exp_power
+	| operatorunary exp									#exp_unary
+	| exp operatorbinary exp							#exp_binary
 	;
 
-
 var
     : (NAME | '(' exp ')' varSuffix) varSuffix*
     ;
@@ -150,11 +78,12 @@ prefixexp
     : varOrExp nameAndArgs*
     ;
 
-// 
+//
 varOrExp
     : var | '(' exp ')'
     ;
 
+
 nameAndArgs
     : (':' NAME)? args
     ;
@@ -184,7 +113,7 @@ anonfunctiondef
 //	: '[' parlist ':' 'do' block 'end' ']'
 //	;
 
-// A func body from the parlist to end. 
+// A func body from the parlist to end.
 funcbody
     : '(' parlist? ')' block 'end'
     ;
@@ -218,29 +147,6 @@ fieldsep
     : ',' | ';'
     ;
 
-operatorOr 
-	: 'or';
-
-operatorAnd 
-	: 'and';
-
-operatorComparison 
-	: '<' | '>' | '<=' | '>=' | '~=' | '==';
-
-operatorStrcat
-	: '..';
-
-operatorAddSub
-	: '+' | '-';
-
-operatorMulDivMod
-	: '*' | '/' | '%';
-
-operatorUnary
-    : 'not' | '#' | '-';
-
-operatorPower
-    : '^';
 
 number
     : INT | HEX | FLOAT | HEX_FLOAT
@@ -255,6 +161,36 @@ vararg
 	;
 
 // LEXER
+AND : 'and';
+BREAK : 'break';
+DO : 'do';
+ELSE : 'else';
+ELSEIF : 'elseif';
+END : 'end';
+FALSE : 'false';
+FOR : 'for';
+FUNCTION : 'function';
+GOTO : 'goto';
+IF : 'if';
+IN : 'in';
+LOCAL : 'local';
+NIL : 'nil';
+NOT : 'not';
+OR : 'or';
+REPEAT : 'repeat';
+RETURN : 'return';
+THEN : 'then';
+TRUE : 'true';
+UNTIL : 'until';
+WHILE : 'while';
+
+
+operatorbinary 
+	: OR | AND | '<' | '>' | '<=' | '>=' | '~=' | '==' | '..' | '+' | '-' | '*' | '/' | '%' ;
+
+operatorunary
+    : NOT | '#' | '-';
+
 
 NAME
     : [a-zA-Z_][a-zA-Z_0-9]*

+ 32 - 28
src/MoonSharp.Interpreter/Interop/UserDataMethodDescriptor.cs

@@ -5,6 +5,7 @@ using System.Linq.Expressions;
 using System.Reflection;
 using System.Text;
 using System.Threading;
+using MoonSharp.Interpreter.Diagnostics;
 using MoonSharp.Interpreter.Execution;
 
 namespace MoonSharp.Interpreter.Interop
@@ -80,40 +81,43 @@ namespace MoonSharp.Interpreter.Interop
 
 		internal void Optimize()
 		{
-			var ep = Expression.Parameter(typeof(object[]), "pars");
-			var objinst = Expression.Parameter(typeof(object), "instance");
-			var inst = Expression.Convert(objinst, MethodInfo.DeclaringType);
+			using (PerformanceStatistics.StartGlobalStopwatch(PerformanceCounter.AdaptersCompilation))
+			{
+				var ep = Expression.Parameter(typeof(object[]), "pars");
+				var objinst = Expression.Parameter(typeof(object), "instance");
+				var inst = Expression.Convert(objinst, MethodInfo.DeclaringType);
 
-			Expression[] args = new Expression[m_Arguments.Length];
+				Expression[] args = new Expression[m_Arguments.Length];
 
-			for (int i = 0; i < m_Arguments.Length; i++)
-			{
-				var x = Expression.ArrayIndex(ep, Expression.Constant(i));
-				args[i] = Expression.Convert(x, m_Arguments[i]);
-			}
+				for (int i = 0; i < m_Arguments.Length; i++)
+				{
+					var x = Expression.ArrayIndex(ep, Expression.Constant(i));
+					args[i] = Expression.Convert(x, m_Arguments[i]);
+				}
 
-			Expression fn;
+				Expression fn;
 
-			if (IsStatic)
-			{
-				fn = Expression.Call(MethodInfo, args);
-			}
-			else
-			{
-				fn = Expression.Call(inst, MethodInfo, args);
-			}
+				if (IsStatic)
+				{
+					fn = Expression.Call(MethodInfo, args);
+				}
+				else
+				{
+					fn = Expression.Call(inst, MethodInfo, args);
+				}
 
 
-			if (MethodInfo.ReturnType == typeof(void))
-			{
-				var lambda = Expression.Lambda<Action<object, object[]>>(fn, objinst, ep);
-				Interlocked.Exchange(ref m_OptimizedAction, lambda.Compile());
-			}
-			else
-			{
-				var fnc = Expression.Convert(fn, typeof(object));
-				var lambda = Expression.Lambda<Func<object, object[], object>>(fnc, objinst, ep);
-				Interlocked.Exchange(ref m_OptimizedFunc, lambda.Compile());
+				if (MethodInfo.ReturnType == typeof(void))
+				{
+					var lambda = Expression.Lambda<Action<object, object[]>>(fn, objinst, ep);
+					Interlocked.Exchange(ref m_OptimizedAction, lambda.Compile());
+				}
+				else
+				{
+					var fnc = Expression.Convert(fn, typeof(object));
+					var lambda = Expression.Lambda<Func<object, object[], object>>(fnc, objinst, ep);
+					Interlocked.Exchange(ref m_OptimizedFunc, lambda.Compile());
+				}
 			}
 		}
 	}

+ 43 - 36
src/MoonSharp.Interpreter/Interop/UserDataPropertyDescriptor.cs

@@ -5,6 +5,7 @@ using System.Linq.Expressions;
 using System.Reflection;
 using System.Text;
 using System.Threading;
+using MoonSharp.Interpreter.Diagnostics;
 
 namespace MoonSharp.Interpreter.Interop
 {
@@ -47,52 +48,58 @@ namespace MoonSharp.Interpreter.Interop
 
 		internal void OptimizeGetter()
 		{
-			if (PropertyInfo.CanRead)
+			using (PerformanceStatistics.StartGlobalStopwatch(PerformanceCounter.AdaptersCompilation))
 			{
-				if (IsStatic)
+				if (PropertyInfo.CanRead)
 				{
-					var paramExp = Expression.Parameter(typeof(object), "dummy");
-					var propAccess = Expression.Property(null, PropertyInfo);
-					var castPropAccess = Expression.Convert(propAccess, typeof(object));
-					var lambda = Expression.Lambda<Func<object, object>>(castPropAccess, paramExp);
-					Interlocked.Exchange(ref m_OptimizedGetter, lambda.Compile());
-				}
-				else
-				{
-					var paramExp = Expression.Parameter(typeof(object), "obj");
-					var castParamExp = Expression.Convert(paramExp, this.PropertyInfo.DeclaringType);
-					var propAccess = Expression.Property(castParamExp, PropertyInfo);
-					var castPropAccess = Expression.Convert(propAccess, typeof(object));
-					var lambda = Expression.Lambda<Func<object, object>>(castPropAccess, paramExp);
-					Interlocked.Exchange(ref m_OptimizedGetter, lambda.Compile());
+					if (IsStatic)
+					{
+						var paramExp = Expression.Parameter(typeof(object), "dummy");
+						var propAccess = Expression.Property(null, PropertyInfo);
+						var castPropAccess = Expression.Convert(propAccess, typeof(object));
+						var lambda = Expression.Lambda<Func<object, object>>(castPropAccess, paramExp);
+						Interlocked.Exchange(ref m_OptimizedGetter, lambda.Compile());
+					}
+					else
+					{
+						var paramExp = Expression.Parameter(typeof(object), "obj");
+						var castParamExp = Expression.Convert(paramExp, this.PropertyInfo.DeclaringType);
+						var propAccess = Expression.Property(castParamExp, PropertyInfo);
+						var castPropAccess = Expression.Convert(propAccess, typeof(object));
+						var lambda = Expression.Lambda<Func<object, object>>(castPropAccess, paramExp);
+						Interlocked.Exchange(ref m_OptimizedGetter, lambda.Compile());
+					}
 				}
 			}
 		}
 
 		internal void OptimizeSetter()
 		{
-			if (PropertyInfo.CanWrite)
+			using (PerformanceStatistics.StartGlobalStopwatch(PerformanceCounter.AdaptersCompilation))
 			{
-				MethodInfo setterMethod = PropertyInfo.GetSetMethod();
-
-				if (IsStatic)
+				if (PropertyInfo.CanWrite)
 				{
-					var paramExp = Expression.Parameter(typeof(object), "dummy");
-					var paramValExp = Expression.Parameter(typeof(object), "val");
-					var castParamValExp = Expression.Convert(paramValExp, this.PropertyInfo.PropertyType);
-					var callExpression = Expression.Call(setterMethod, castParamValExp);
-					var lambda = Expression.Lambda<Action<object, object>>(callExpression, paramExp, paramValExp);
-					Interlocked.Exchange(ref m_OptimizedSetter, lambda.Compile());
-				}
-				else
-				{
-					var paramExp = Expression.Parameter(typeof(object), "obj");
-					var paramValExp = Expression.Parameter(typeof(object), "val");
-					var castParamExp = Expression.Convert(paramExp, this.PropertyInfo.DeclaringType);
-					var castParamValExp = Expression.Convert(paramValExp, this.PropertyInfo.PropertyType);
-					var callExpression = Expression.Call(castParamExp, setterMethod, castParamValExp);
-					var lambda = Expression.Lambda<Action<object, object>>(callExpression, paramExp, paramValExp);
-					Interlocked.Exchange(ref m_OptimizedSetter, lambda.Compile());
+					MethodInfo setterMethod = PropertyInfo.GetSetMethod();
+
+					if (IsStatic)
+					{
+						var paramExp = Expression.Parameter(typeof(object), "dummy");
+						var paramValExp = Expression.Parameter(typeof(object), "val");
+						var castParamValExp = Expression.Convert(paramValExp, this.PropertyInfo.PropertyType);
+						var callExpression = Expression.Call(setterMethod, castParamValExp);
+						var lambda = Expression.Lambda<Action<object, object>>(callExpression, paramExp, paramValExp);
+						Interlocked.Exchange(ref m_OptimizedSetter, lambda.Compile());
+					}
+					else
+					{
+						var paramExp = Expression.Parameter(typeof(object), "obj");
+						var paramValExp = Expression.Parameter(typeof(object), "val");
+						var castParamExp = Expression.Convert(paramExp, this.PropertyInfo.DeclaringType);
+						var castParamValExp = Expression.Convert(paramValExp, this.PropertyInfo.PropertyType);
+						var callExpression = Expression.Call(castParamExp, setterMethod, castParamValExp);
+						var lambda = Expression.Lambda<Action<object, object>>(callExpression, paramExp, paramValExp);
+						Interlocked.Exchange(ref m_OptimizedSetter, lambda.Compile());
+					}
 				}
 			}
 		}

+ 11 - 2
src/MoonSharp.Interpreter/MoonSharp.Interpreter.csproj

@@ -117,13 +117,19 @@
     <Compile Include="Debugging\SourceRef.cs" />
     <Compile Include="Debugging\WatchItem.cs" />
     <Compile Include="Debugging\WatchType.cs" />
+    <Compile Include="Diagnostics\PerformanceCounters\IPerformanceStopwatch.cs" />
+    <Compile Include="Diagnostics\PerformanceCounter.cs" />
+    <Compile Include="Diagnostics\PerformanceCounters\GlobalPerformanceStopwatch.cs" />
+    <Compile Include="Diagnostics\PerformanceCounterType.cs" />
+    <Compile Include="Diagnostics\PerformanceStatistics.cs" />
+    <Compile Include="Diagnostics\PerformanceResult.cs" />
+    <Compile Include="Diagnostics\PerformanceCounters\PerformanceStopwatch.cs" />
     <Compile Include="Errors\ScriptRuntimeException.cs">
       <SubType>Code</SubType>
     </Compile>
     <Compile Include="Errors\StackTraceItem.cs" />
     <Compile Include="Errors\InternalErrorException.cs" />
     <Compile Include="Diagnostics\AstDump.cs" />
-    <Compile Include="Diagnostics\CodeChrono.cs" />
     <Compile Include="Errors\InterpreterException.cs" />
     <Compile Include="Errors\SyntaxErrorException.cs" />
     <Compile Include="DataTypes\CallbackArguments.cs" />
@@ -203,6 +209,9 @@
       <SubType>Code</SubType>
     </Compile>
     <Compile Include="Tree\Expressions\AdjustmentExpression.cs" />
+    <Compile Include="Tree\Expressions\BinaryOperatorExpression.cs" />
+    <Compile Include="Tree\Expressions\PowerOperatorExpression.cs" />
+    <Compile Include="Tree\Expressions\UnaryOperatorExpression.cs" />
     <Compile Include="Tree\IVariable.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Tree\Expressions\ExprListExpression.cs" />
@@ -214,7 +223,7 @@
     <Compile Include="Tree\Expression.cs" />
     <Compile Include="Tree\Expressions\OperatorExpression.cs" />
     <Compile Include="Tree\Expressions\SymbolRefExpression.cs" />
-    <Compile Include="Tree\Loader.cs" />
+    <Compile Include="Tree\Loader_Antlr.cs" />
     <Compile Include="Tree\Loop.cs" />
     <Compile Include="Tree\NodeBase.cs" />
     <Compile Include="Tree\NodeFactory.cs" />

+ 2 - 2
src/MoonSharp.Interpreter/Properties/AssemblyInfo.cs

@@ -10,7 +10,7 @@ using System.Runtime.InteropServices;
 [assembly: AssemblyConfiguration("")]
 [assembly: AssemblyCompany("http://www.moonsharp.org")]
 [assembly: AssemblyProduct("MoonSharp.Interpreter")]
-[assembly: AssemblyCopyright("Copyright ©  2014, Marco Mastropaolo")]
+[assembly: AssemblyCopyright("Copyright © 2014, Marco Mastropaolo")]
 [assembly: AssemblyTrademark("")]
 [assembly: AssemblyCulture("")]
 
@@ -32,5 +32,5 @@ using System.Runtime.InteropServices;
 // You can specify all the values or you can default the Build and Revision Numbers 
 // by using the '*' as shown below:
 // [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("0.5.4.0")]
+[assembly: AssemblyVersion("0.5.5.0")]
 [assembly: AssemblyFileVersion("1.0.0.0")]

+ 17 - 2
src/MoonSharp.Interpreter/Script.cs

@@ -29,6 +29,7 @@ namespace MoonSharp.Interpreter
 		IScriptLoader m_ScriptLoader = DefaultScriptLoader;
 		Table[] m_TypeMetatables = new Table[(int)LuaTypeExtensions.MaxMetaTypes];
 
+	
 		static Script()
 		{
 			DefaultScriptLoader = new ClassicLuaScriptLoader();
@@ -49,6 +50,8 @@ namespace MoonSharp.Interpreter
 		/// <param name="coreModules">The core modules to be pre-registered in the default global table.</param>
 		public Script(CoreModules coreModules)
 		{
+			PerformanceStats = new PerformanceStatistics();
+
 			DebugPrint = s => { Console.WriteLine(s); };
 			m_ByteCode = new ByteCode();
 			m_GlobalTable = new Table(this).RegisterCoreModules(coreModules);
@@ -76,6 +79,11 @@ namespace MoonSharp.Interpreter
 		/// </summary>
 		public static IScriptLoader DefaultScriptLoader { get; set; }
 
+		/// <summary>
+		/// Gets access to performance statistics.
+		/// </summary>
+		public PerformanceStatistics PerformanceStats { get; private set; }
+
 		/// <summary>
 		/// Gets the default global table for this script. Unless a different table is intentionally passed (or setfenv has been used)
 		/// execution uses this table.
@@ -102,7 +110,8 @@ namespace MoonSharp.Interpreter
 
 			m_Sources.Add(source);
 
-			int address = Loader.LoadFunctionFromICharStream(new AntlrInputStream(code),
+			int address = Loader_Antlr.LoadFunction(this, 
+				code,
 				m_ByteCode,
 				funcFriendlyName ?? chunkName,
 				m_Sources.Count - 1,
@@ -133,7 +142,8 @@ namespace MoonSharp.Interpreter
 
 			m_Sources.Add(source);
 
-			int address = Loader.LoadChunkFromICharStream(new AntlrInputStream(code),
+			int address = Loader_Antlr.LoadChunk(this,
+				code,
 				m_ByteCode,
 				codeFriendlyName ?? chunkName,
 				m_Sources.Count - 1,
@@ -441,5 +451,10 @@ namespace MoonSharp.Interpreter
 			Script s = new Script(CoreModules.Basic);
 			s.LoadString("return 1;");
 		}
+
+
+
+
+
 	}
 }

+ 328 - 0
src/MoonSharp.Interpreter/Tree/Expressions/BinaryOperatorExpression.cs

@@ -0,0 +1,328 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Antlr4.Runtime.Tree;
+using MoonSharp.Interpreter.Execution;
+using MoonSharp.Interpreter.Execution.VM;
+using MoonSharp.Interpreter.Grammar;
+
+namespace MoonSharp.Interpreter.Tree.Expressions
+{
+	/// <summary>
+	/// 
+	/// </summary>
+	class BinaryOperatorExpression : Expression
+	{
+		[Flags]
+		private enum Operator
+		{
+			NotAnOperator = 0, 
+			
+			Or = 0x1, 
+			And = 0x2,
+			Less = 0x4,
+			Greater = 0x8,
+			LessOrEqual = 0x10,
+
+			GreaterOrEqual = 0x20,
+			NotEqual = 0x40,
+			Equal = 0x80,
+			StrConcat = 0x100,
+			Add = 0x200,
+			Sub = 0x400,
+			Mul = 0x1000,
+			Div = 0x2000,
+			Mod = 0x4000,
+		}
+
+
+		class Node
+		{
+			public Expression Expr;
+			public Operator Op;
+			public Node Prev;
+			public Node Next;
+		}
+
+		class LinkedList
+		{
+			public Node Nodes;
+			public Node Last;
+		}
+
+		private static Operator CreateLinkedList(LinkedList list, IParseTree root, ScriptLoadingContext lcontext)
+		{
+			Operator opfound = 0;
+
+			foreach (IParseTree tt in root.EnumChilds())
+			{
+				Node n = null;
+
+				if (tt is LuaParser.OperatorbinaryContext)
+				{
+					Operator op = ParseBinaryOperator(tt);
+					opfound |= op;
+					n = new Node() { Op = op };
+				}
+				else
+				{
+					if (tt is LuaParser.Exp_binaryContext)
+					{
+						Operator op = CreateLinkedList(list, tt, lcontext);
+						opfound |= op;
+					}
+					else
+					{
+						n = new Node() { Expr = NodeFactory.CreateExpression(tt, lcontext) };
+					}
+				}
+
+				if (n != null)
+				{
+					if (list.Nodes == null)
+					{
+						list.Nodes = list.Last = n;
+					}
+					else
+					{
+						list.Last.Next = n;
+						n.Prev = list.Last;
+						list.Last = n;
+					}
+				}
+			}
+
+			return opfound;
+		}
+
+
+		/// <summary>
+		/// Creates a sub tree of binary expressions
+		/// </summary>
+		public static Expression CreateSubTree(IParseTree tree, ScriptLoadingContext lcontext)
+		{
+			const Operator MUL_DIV_MOD = Operator.Mul | Operator.Div | Operator.Mod;
+			const Operator ADD_SUB = Operator.Add | Operator.Sub;
+			const Operator STRCAT = Operator.StrConcat;
+			const Operator COMPARES = Operator.Less | Operator.Greater | Operator.GreaterOrEqual | Operator.LessOrEqual | Operator.Equal | Operator.NotEqual;
+			const Operator LOGIC_AND = Operator.And;
+			const Operator LOGIC_OR = Operator.Or;
+
+			LinkedList list = new LinkedList();
+
+			Operator opfound = CreateLinkedList(list, tree, lcontext);
+
+			Node nodes = list.Nodes;
+
+			if ((opfound & MUL_DIV_MOD) != 0)
+				nodes = PrioritizeLeftAssociative(tree, nodes, lcontext, MUL_DIV_MOD);
+
+			if ((opfound & ADD_SUB) != 0)
+				nodes = PrioritizeLeftAssociative(tree, nodes, lcontext, ADD_SUB);
+
+			if ((opfound & STRCAT) != 0)
+				nodes = PrioritizeRightAssociative(tree, nodes, lcontext, STRCAT);
+
+			if ((opfound & COMPARES) != 0)
+				nodes = PrioritizeLeftAssociative(tree, nodes, lcontext, COMPARES);
+
+			if ((opfound & LOGIC_AND) != 0)
+				nodes = PrioritizeLeftAssociative(tree, nodes, lcontext, LOGIC_AND);
+
+			if ((opfound & LOGIC_OR) != 0)
+				nodes = PrioritizeLeftAssociative(tree, nodes, lcontext, LOGIC_OR);
+
+
+			if (nodes.Next != null || nodes.Prev != null)
+				throw new InternalErrorException("Expression reduction didn't work! - 1");
+			if (nodes.Expr == null)
+				throw new InternalErrorException("Expression reduction didn't work! - 2");
+			
+			return nodes.Expr;
+		}
+
+		private static Node PrioritizeLeftAssociative(IParseTree tree, Node nodes, ScriptLoadingContext lcontext, Operator operatorsToFind)
+		{
+			for (Node N = nodes; N != null; N = N.Next)
+			{
+				Operator o = N.Op;
+
+				if ((o & operatorsToFind) != 0)
+				{
+					N.Op = Operator.NotAnOperator;
+					N.Expr = new BinaryOperatorExpression(tree, N.Prev.Expr, N.Next.Expr, o, lcontext);
+					N.Prev = N.Prev.Prev;
+					N.Next = N.Next.Next;
+
+					if (N.Next != null)
+						N.Next.Prev = N;
+
+					if (N.Prev != null)
+						N.Prev.Next = N;
+					else
+						nodes = N;
+				}
+			}
+
+			return nodes;
+		}
+
+		private static Node PrioritizeRightAssociative(IParseTree tree, Node nodes, ScriptLoadingContext lcontext, Operator operatorsToFind)
+		{
+			Node last;
+			for (last = nodes; last.Next != null; last = last.Next) ;
+
+			for (Node N = last; N != null; N = N.Prev)
+			{
+				Operator o = N.Op;
+
+				if ((o & operatorsToFind) != 0)
+				{
+					N.Op = Operator.NotAnOperator;
+					N.Expr = new BinaryOperatorExpression(tree, N.Prev.Expr, N.Next.Expr, o, lcontext);
+					N.Prev = N.Prev.Prev;
+					N.Next = N.Next.Next;
+
+					if (N.Next != null)
+						N.Next.Prev = N;
+
+					if (N.Prev != null)
+						N.Prev.Next = N;
+					else
+						nodes = N;
+				}
+			}
+
+			return nodes;
+		}
+
+
+
+
+		private static Operator ParseBinaryOperator(IParseTree parseTree)
+		{
+			string txt = parseTree.GetText();
+
+			switch (txt)
+			{
+				case "or":
+					return Operator.Or;
+				case "and":
+					return Operator.And;
+				case "<":
+					return Operator.Less;
+				case ">":
+					return Operator.Greater;
+				case "<=":
+					return Operator.LessOrEqual;
+				case ">=":
+					return Operator.GreaterOrEqual;
+				case "~=":
+					return Operator.NotEqual;
+				case "==":
+					return Operator.Equal;
+				case "..":
+					return Operator.StrConcat;
+				case "+":
+					return Operator.Add;
+				case "-":
+					return Operator.Sub;
+				case "*":
+					return Operator.Mul;
+				case "/":
+					return Operator.Div;
+				case "%":
+					return Operator.Mod;
+				default:
+					throw new InternalErrorException("Unexpected binary operator '{0}'", txt);
+			}
+		}
+
+
+
+
+		Expression m_Exp1, m_Exp2;
+		Operator m_Operator;
+
+
+
+		private BinaryOperatorExpression(IParseTree tree, Expression exp1, Expression exp2, Operator op, ScriptLoadingContext lcontext)
+			: base (tree, lcontext)
+		{
+			m_Exp1 = exp1;
+			m_Exp2 = exp2;
+			m_Operator = op;
+		}
+
+		private static bool ShouldInvertBoolean(Operator op)
+		{
+			return (op == Operator.NotEqual)
+				|| (op == Operator.GreaterOrEqual)
+				|| (op == Operator.Greater);
+		}
+
+		private static OpCode OperatorToOpCode(Operator op)
+		{
+			switch (op)
+			{
+				case Operator.Less:
+				case Operator.GreaterOrEqual:
+					return OpCode.Less;
+				case Operator.LessOrEqual:
+				case Operator.Greater:
+					return OpCode.LessEq;
+				case Operator.Equal:
+				case Operator.NotEqual:
+					return OpCode.Eq;
+				case Operator.StrConcat:
+					return OpCode.Concat;
+				case Operator.Add:
+					return OpCode.Add;
+				case Operator.Sub:
+					return OpCode.Sub;
+				case Operator.Mul:
+					return OpCode.Mul;
+				case Operator.Div:
+					return OpCode.Div;
+				case Operator.Mod:
+					return OpCode.Mod;
+				default:
+					throw new InternalErrorException("Unsupported operator {0}", op);
+			}
+		}
+
+
+		public override void Compile(Execution.VM.ByteCode bc)
+		{
+			m_Exp1.Compile(bc);
+
+			if (m_Operator == Operator.Or)
+			{
+				Instruction i = bc.Emit_Jump(OpCode.JtOrPop, -1);
+				m_Exp2.Compile(bc);
+				i.NumVal = bc.GetJumpPointForNextInstruction();
+				return;
+			}
+
+			if (m_Operator == Operator.And)
+			{
+				Instruction i = bc.Emit_Jump(OpCode.JfOrPop, -1);
+				m_Exp2.Compile(bc);
+				i.NumVal = bc.GetJumpPointForNextInstruction();
+				return;
+			}
+
+
+			if (m_Exp2 != null)
+			{
+				m_Exp2.Compile(bc);
+			}
+
+			bc.Emit_Operator(OperatorToOpCode(m_Operator));
+
+			if (ShouldInvertBoolean(m_Operator))
+				bc.Emit_Operator(OpCode.Not);
+		}
+	}
+}

+ 11 - 4
src/MoonSharp.Interpreter/Tree/Expressions/OperatorExpression.cs

@@ -1,4 +1,6 @@
-using System;
+#if false
+
+using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
@@ -221,7 +223,7 @@ namespace MoonSharp.Interpreter.Tree.Expressions
 
 
 
-		private bool ShouldInvertBoolean(Operator op)
+		private static bool ShouldInvertBoolean(Operator op)
 		{
 			return (op == Operator.NotEqual)
 				|| (op == Operator.GreaterOrEqual)
@@ -229,7 +231,7 @@ namespace MoonSharp.Interpreter.Tree.Expressions
 		}
 
 
-		private OpCode OperatorToOpCode(Operator op)
+		private static OpCode OperatorToOpCode(Operator op)
 		{
 			switch (op)
 			{
@@ -263,8 +265,13 @@ namespace MoonSharp.Interpreter.Tree.Expressions
 				case Operator.Power:
 					return OpCode.Power;
 				default:
-					throw new InternalErrorException("Unsupported operator {0}", m_Operator);
+					throw new InternalErrorException("Unsupported operator {0}", op);
 			}
 		}
 	}
 }
+
+
+
+
+#endif

+ 30 - 0
src/MoonSharp.Interpreter/Tree/Expressions/PowerOperatorExpression.cs

@@ -0,0 +1,30 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Antlr4.Runtime.Tree;
+using MoonSharp.Interpreter.Execution;
+using MoonSharp.Interpreter.Execution.VM;
+using MoonSharp.Interpreter.Grammar;
+
+namespace MoonSharp.Interpreter.Tree.Expressions
+{
+	class PowerOperatorExpression : Expression
+	{
+		Expression m_Exp1, m_Exp2;
+
+		public PowerOperatorExpression(IParseTree tree, ScriptLoadingContext lcontext)
+			: base(tree, lcontext)
+		{
+			m_Exp1 = NodeFactory.CreateExpression(tree.GetChild(0), lcontext);
+			m_Exp2 = NodeFactory.CreateExpression(tree.GetChild(2), lcontext);
+		}
+
+		public override void Compile(ByteCode bc)
+		{
+			m_Exp1.Compile(bc);
+			m_Exp2.Compile(bc);
+			bc.Emit_Operator(OpCode.Power);
+		}
+	}
+}

+ 50 - 0
src/MoonSharp.Interpreter/Tree/Expressions/UnaryOperatorExpression.cs

@@ -0,0 +1,50 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using Antlr4.Runtime.Tree;
+using MoonSharp.Interpreter.Execution;
+using MoonSharp.Interpreter.Execution.VM;
+using MoonSharp.Interpreter.Grammar;
+
+namespace MoonSharp.Interpreter.Tree.Expressions
+{
+	class UnaryOperatorExpression : Expression
+	{
+		Expression m_Exp;
+		string m_OpText;
+
+		public UnaryOperatorExpression(IParseTree tree, ScriptLoadingContext lcontext)
+			: base(tree, lcontext)
+		{
+			var child0 = tree.GetChild(0);
+
+			m_OpText = child0.GetText();
+
+			m_Exp = NodeFactory.CreateExpression(tree.GetChild(1), lcontext);
+		}
+
+
+		public override void Compile(ByteCode bc)
+		{
+			m_Exp.Compile(bc);
+
+			switch (m_OpText)
+			{
+				case "not":
+					bc.Emit_Operator(OpCode.Not);
+					break;
+				case "#":
+					bc.Emit_Operator(OpCode.Len);
+					break;
+				case "-":
+					bc.Emit_Operator(OpCode.Neg);
+					break;
+				default:
+					throw new InternalErrorException("Unexpected unary operator '{0}'", m_OpText);
+			}
+
+
+		}
+	}
+}

+ 29 - 23
src/MoonSharp.Interpreter/Tree/Loader.cs → src/MoonSharp.Interpreter/Tree/Loader_Antlr.cs

@@ -18,29 +18,32 @@ using MoonSharp.Interpreter.Tree.Statements;
 
 namespace MoonSharp.Interpreter.Tree
 {
-	internal static class Loader
+	internal static class Loader_Antlr
 	{
-		internal static int LoadChunkFromICharStream(ICharStream charStream, ByteCode bytecode, string sourceName, int sourceIdx, Table globalContext)
+		internal static int LoadChunk(Script script, string code, ByteCode bytecode, string sourceName, int sourceIdx, Table globalContext)
 		{
 			try
 			{
-				LuaParser parser = CreateParser(charStream, sourceIdx, p => p.chunk());
+				LuaParser parser = CreateParser(script, new AntlrInputStream(code), sourceIdx, p => p.chunk());
 
 				ScriptLoadingContext lcontext = CreateLoadingContext(sourceName, sourceIdx);
-				ChunkStatement stat = new ChunkStatement(parser.chunk(), lcontext, globalContext);
+				ChunkStatement stat;
+
+				using (script.PerformanceStats.StartStopwatch(Diagnostics.PerformanceCounter.AstCreation))
+					stat = new ChunkStatement(parser.chunk(), lcontext, globalContext);
 
 				int beginIp = -1;
 
-				//using (var _ = new CodeChrono("ChunkStatement.LoadFromICharStream/Compile"))
+				using (script.PerformanceStats.StartStopwatch(Diagnostics.PerformanceCounter.Compilation))
 				{
 					bytecode.Emit_Nop(string.Format("Begin chunk {0}", sourceName));
 					beginIp = bytecode.GetJumpPointForLastInstruction();
 					stat.Compile(bytecode);
 					bytecode.Emit_Nop(string.Format("End chunk {0}", sourceName));
-
-					Debug_DumpByteCode(bytecode, sourceIdx);
 				}
 
+				Debug_DumpByteCode(bytecode, sourceIdx);
+
 				return beginIp;
 			}
 			catch (ParseCanceledException ex)
@@ -50,18 +53,21 @@ namespace MoonSharp.Interpreter.Tree
 			}
 		}
 
-		internal static int LoadFunctionFromICharStream(ICharStream charStream, ByteCode bytecode, string sourceName, int sourceIdx, Table globalContext)
+		internal static int LoadFunction(Script script, string code, ByteCode bytecode, string sourceName, int sourceIdx, Table globalContext)
 		{
 			try
 			{
-				LuaParser parser = CreateParser(charStream, sourceIdx, p => p.anonfunctiondef());
+				LuaParser parser = CreateParser(script, new AntlrInputStream(code), sourceIdx, p => p.anonfunctiondef());
 
 				ScriptLoadingContext lcontext = CreateLoadingContext(sourceName, sourceIdx);
-				FunctionDefinitionExpression fndef = new FunctionDefinitionExpression(parser.anonfunctiondef(), lcontext, false, globalContext);
+				FunctionDefinitionExpression fndef;
+
+				using (script.PerformanceStats.StartStopwatch(Diagnostics.PerformanceCounter.AstCreation))
+					fndef = new FunctionDefinitionExpression(parser.anonfunctiondef(), lcontext, false, globalContext);
 
 				int beginIp = -1;
 
-				//using (var _ = new CodeChrono("ChunkStatement.LoadFromICharStream/Compile"))
+				using (script.PerformanceStats.StartStopwatch(Diagnostics.PerformanceCounter.Compilation))
 				{
 					bytecode.Emit_Nop(string.Format("Begin function {0}", sourceName));
 					beginIp = fndef.CompileBody(bytecode, sourceName);
@@ -91,16 +97,17 @@ namespace MoonSharp.Interpreter.Tree
 			//bytecode.Dump(string.Format(@"c:\temp\codedump_{0}.txt", sourceIdx));
 		}
 
-		[Conditional("DEBUG_COMPILER")]
+		//[Conditional("DEBUG_COMPILER")]
 		private static void Debug_DumpAst(LuaParser parser, int sourceIdx, Func<LuaParser, IParseTree> dumper)
 		{
-			//try
-			//{
-			//	AstDump astDump = new AstDump();
-			//	astDump.DumpTree(dumper(parser), string.Format(@"c:\temp\treedump_{0:000}.txt", sourceIdx));
-			//}
-			//catch { }
-			//parser.Reset();
+			try
+			{
+				AstDump astDump = new AstDump();
+				// astDump.DumpTree(dumper(parser), string.Format(@"c:\temp\treedump_{0:000}.txt", sourceIdx));
+				astDump.WalkTreeForWaste(dumper(parser));
+			}
+			catch { }
+			parser.Reset();
 		}
 
 
@@ -114,12 +121,12 @@ namespace MoonSharp.Interpreter.Tree
 			};
 		}
 
-		private static LuaParser CreateParser(ICharStream charStream, int sourceIdx, Func<LuaParser, IParseTree> dumper)
+		private static LuaParser CreateParser(Script script, ICharStream charStream, int sourceIdx, Func<LuaParser, IParseTree> dumper)
 		{
 			LuaLexer lexer;
 			LuaParser parser;
 
-			//using (var _ = new CodeChrono("ChunkStatement.LoadFromICharStream/Parsing"))
+			using (script.PerformanceStats.StartStopwatch(Diagnostics.PerformanceCounter.Parsing))
 			{
 				lexer = new LuaLexer(charStream);
 				parser = new LuaParser(new CommonTokenStream(lexer))
@@ -128,10 +135,9 @@ namespace MoonSharp.Interpreter.Tree
 				};
 
 				parser.Interpreter.PredictionMode = PredictionMode.Sll;
+				Debug_DumpAst(parser, sourceIdx, dumper);
 			}
 
-			//Debug_DumpAst(parser, sourceIdx, dumper);
-
 
 			return parser;
 		}

+ 64 - 39
src/MoonSharp.Interpreter/Tree/NodeFactory.cs

@@ -16,8 +16,8 @@ namespace MoonSharp.Interpreter.Tree
 		public static Statement CreateStatement(IParseTree tree, ScriptLoadingContext lcontext)
 		{
 			if (tree is Antlr4.Runtime.Tree.TerminalNodeImpl)
-			{ } 
-			
+			{ }
+
 			if (tree is LuaParser.BlockContext)
 				return new CompositeStatement((LuaParser.BlockContext)tree, lcontext);
 
@@ -77,54 +77,79 @@ namespace MoonSharp.Interpreter.Tree
 
 		public static Expression CreateExpression(IParseTree tree, ScriptLoadingContext lcontext)
 		{
-			// flatten tree for operators precedence 
-			if (tree is LuaParser.Exp_logicOrfallbackContext) tree = ((LuaParser.Exp_logicOrfallbackContext)tree).logicAndExp();
-			if (tree is LuaParser.Exp_logicAndfallbackContext) tree = ((LuaParser.Exp_logicAndfallbackContext)tree).compareExp();
-			if (tree is LuaParser.Exp_comparefallbackContext) tree = ((LuaParser.Exp_comparefallbackContext)tree).strcatExp();
-			if (tree is LuaParser.Exp_strcastfallbackContext) tree = ((LuaParser.Exp_strcastfallbackContext)tree).addsubExp();
-			if (tree is LuaParser.Exp_addsubfallbackContext) tree = ((LuaParser.Exp_addsubfallbackContext)tree).muldivExp();
-			if (tree is LuaParser.Exp_muldivfallbackContext) tree = ((LuaParser.Exp_muldivfallbackContext)tree).unaryExp();
-			if (tree is LuaParser.Exp_unaryfallbackContext) tree = ((LuaParser.Exp_unaryfallbackContext)tree).powerExp();
-			if (tree is LuaParser.Exp_powerfallbackContext) tree = ((LuaParser.Exp_powerfallbackContext)tree).expterm();
-			if (tree is LuaParser.ExptermContext) tree = tree.GetChild(0);
-
-			if (tree is LuaParser.Exp_addsubContext ||
-				tree is LuaParser.Exp_compareContext ||
-				tree is LuaParser.Exp_logicAndContext ||
-				tree is LuaParser.Exp_logicOrContext ||
-				tree is LuaParser.Exp_muldivContext ||
-				tree is LuaParser.Exp_powerContext ||
-				tree is LuaParser.Exp_strcatContext ||
-				tree is LuaParser.Exp_unaryContext)
-			{
-				return new OperatorExpression(tree, lcontext);
-			}
+			IParseTree originalTree = tree;
 
-
-			if (tree is LuaParser.VarOrExpContext)
+			// prune dummy tree nodes 
+			while (true)
 			{
-				// this whole rubbish just to detect adjustments to 1 arg of tuples
-				if ((tree.ChildCount > 0))
+				//if (tree is LuaParser.Exp_logicOrfallbackContext) tree = ((LuaParser.Exp_logicOrfallbackContext)tree).logicAndExp();
+				//else if (tree is LuaParser.Exp_logicAndfallbackContext) tree = ((LuaParser.Exp_logicAndfallbackContext)tree).compareExp();
+				//else if (tree is LuaParser.Exp_comparefallbackContext) tree = ((LuaParser.Exp_comparefallbackContext)tree).strcatExp();
+				//else if (tree is LuaParser.Exp_strcastfallbackContext) tree = ((LuaParser.Exp_strcastfallbackContext)tree).addsubExp();
+				//else if (tree is LuaParser.Exp_addsubfallbackContext) tree = ((LuaParser.Exp_addsubfallbackContext)tree).muldivExp();
+				//else if (tree is LuaParser.Exp_muldivfallbackContext) tree = ((LuaParser.Exp_muldivfallbackContext)tree).unaryExp();
+				//else if (tree is LuaParser.Exp_unaryfallbackContext) tree = ((LuaParser.Exp_unaryfallbackContext)tree).powerExp();
+				//else if (tree is LuaParser.Exp_powerfallbackContext) tree = ((LuaParser.Exp_powerfallbackContext)tree).expterm();
+				//else if (tree is LuaParser.ExptermContext) tree = tree.GetChild(0);
+				//else 
+				if (tree is LuaParser.VarOrExpContext)
 				{
-					Antlr4.Runtime.Tree.TerminalNodeImpl token = tree.GetChild(0) as Antlr4.Runtime.Tree.TerminalNodeImpl;
-
-					if (token != null && token.GetText() == "(")
+					// this whole rubbish just to detect adjustments to 1 arg of tuples
+					if ((tree.ChildCount > 0))
 					{
-						var subTree = tree.EnumChilds().Single(t => !(t is Antlr4.Runtime.Tree.TerminalNodeImpl));
-						return new AdjustmentExpression(tree, lcontext, subTree);
+						Antlr4.Runtime.Tree.TerminalNodeImpl token = tree.GetChild(0) as Antlr4.Runtime.Tree.TerminalNodeImpl;
+
+						if (token != null && token.GetText() == "(")
+						{
+							var subTree = tree.EnumChilds().Single(t => !(t is Antlr4.Runtime.Tree.TerminalNodeImpl));
+							return new AdjustmentExpression(tree, lcontext, subTree);
+						}
 					}
-				}
 
-				tree = tree.EnumChilds().Single(t => !(t is Antlr4.Runtime.Tree.TerminalNodeImpl));
+					tree = tree.EnumChilds().Single(t => !(t is Antlr4.Runtime.Tree.TerminalNodeImpl));
+				}
+				else break;
 			}
 
+			//if (tree is LuaParser.ParenthesizedExpressionContext)
+			//{
+			//	return new AdjustmentExpression(tree, lcontext, ((LuaParser.ParenthesizedExpressionContext)tree).exp());
+			//}
+
+			//if (tree is LuaParser.Exp_addsubContext ||
+			//	tree is LuaParser.Exp_compareContext ||
+			//	tree is LuaParser.Exp_logicAndContext ||
+			//	tree is LuaParser.Exp_logicOrContext ||
+			//	tree is LuaParser.Exp_muldivContext ||
+			//	tree is LuaParser.Exp_powerContext ||
+			//	tree is LuaParser.Exp_strcatContext ||
+			//	tree is LuaParser.Exp_unaryContext)
+			//{
+			//	return new OperatorExpression(tree, lcontext);
+			//}
+
+			if (tree is LuaParser.Exp_nilContext) return new LiteralExpression(tree, lcontext, DynValue.Nil);
+			if (tree is LuaParser.Exp_trueContext) return new LiteralExpression(tree, lcontext, DynValue.True);
+			if (tree is LuaParser.Exp_falseContext) return new LiteralExpression(tree, lcontext, DynValue.False);
+
+			if (tree is LuaParser.Exp_numberContext) tree = ((LuaParser.Exp_numberContext)tree).number();
+			if (tree is LuaParser.Exp_stringContext) tree = ((LuaParser.Exp_stringContext)tree).@string();
+			if (tree is LuaParser.Exp_varargsContext) tree = ((LuaParser.Exp_varargsContext)tree).vararg();
+
+			if (tree is LuaParser.Exp_anonfuncContext) return new FunctionDefinitionExpression(((LuaParser.Exp_anonfuncContext)tree).funcbody(), lcontext);
+			if (tree is LuaParser.Exp_prefixexpContext) tree = ((LuaParser.Exp_prefixexpContext)tree).prefixexp();
+			if (tree is LuaParser.Exp_tabctorContext) tree = ((LuaParser.Exp_tabctorContext)tree).tableconstructor();
+			if (tree is LuaParser.Exp_powerContext) return new PowerOperatorExpression(tree, lcontext);
+			if (tree is LuaParser.Exp_unaryContext) return new UnaryOperatorExpression(tree, lcontext);
+			if (tree is LuaParser.Exp_binaryContext) return BinaryOperatorExpression.CreateSubTree(tree, lcontext);
+
 			if (tree is Antlr4.Runtime.Tree.TerminalNodeImpl)
 			{
 				string txt = tree.GetText();
 				if (txt == null) return null;
-				else if (txt == "nil") return new LiteralExpression(tree, lcontext, DynValue.Nil);
-				else if (txt == "false") return new LiteralExpression(tree, lcontext, DynValue.False);
-				else if (txt == "true") return new LiteralExpression(tree, lcontext, DynValue.True);
+				//else if (txt == "nil") return new LiteralExpression(tree, lcontext, DynValue.Nil);
+				//else if (txt == "false") return new LiteralExpression(tree, lcontext, DynValue.False);
+				//else if (txt == "true") return new LiteralExpression(tree, lcontext, DynValue.True);
 				else return null;
 			}
 
@@ -181,7 +206,7 @@ namespace MoonSharp.Interpreter.Tree
 				var exp = suffix.exp();
 				var suff_NAME = suffix.NAME();
 				Expression indexExp;
-				if (exp != null) 
+				if (exp != null)
 					indexExp = CreateExpression(exp, lcontext);
 				else
 					indexExp = new LiteralExpression(suff_NAME, lcontext, DynValue.NewString(suff_NAME.GetText()));

+ 0 - 1
src/MoonSharp.Interpreter/Tree/Statements/ChunkStatement.cs

@@ -41,7 +41,6 @@ namespace MoonSharp.Interpreter.Tree.Statements
 
 			m_Block.Compile(bc);
 			bc.Emit_Ret(0);
-			//bc.Leave(m_StackFrame);
 		}
 
 		public SymbolRef CreateUpvalue(BuildTimeScope scope, SymbolRef symbol)

+ 8 - 2
src/PerformanceComparison/HugeFile.cs

@@ -14,19 +14,25 @@ namespace PerformanceComparison
 		{
 			Console.WriteLine("Started...");
 			Script.WarmUp();
+			Console.WriteLine("Warmed-up...");
 
 			Script s = new Script(CoreModules.None);
-			s.LoadFile(@"C:\gr\tsg\mod_assets\scripts\alcoves.lua");
+			// s.LoadFile(@"C:\gr\tsg\mod_assets\scripts\alcoves.lua");
 			//s.LoadFile(@"C:\temp\test3.lua");
 
 			Stopwatch sw = Stopwatch.StartNew();
 
 			//for (int i = 0; i < 10; i++)
-			s.LoadFile(@"C:\temp\test3.lua");
+			var v = s.LoadFile(@"C:\temp\test3.lua");
 
+			for(int i = 0; i < 1000; i++)
+				s.Call(v);
 
 			sw.Stop();
+
 			Console.WriteLine("Ended : {0} ms", sw.ElapsedMilliseconds);
+
+			Console.WriteLine(s.PerformanceStats.GetPerformanceLog());
 			Console.ReadLine();
 		}
 

+ 0 - 3
src/moonsharp.sln

@@ -86,7 +86,4 @@ Global
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
 	EndGlobalSection
-	GlobalSection(Performance) = preSolution
-		HasPerformanceSessions = true
-	EndGlobalSection
 EndGlobal