lucenenet-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From synhers...@apache.org
Subject [5/5] lucenenet git commit: Adding Expressions with some failing tests
Date Sat, 31 Jan 2015 20:03:53 GMT
Adding Expressions with some failing tests

Thanks to work by @hakeemsm

Closes #64


Project: http://git-wip-us.apache.org/repos/asf/lucenenet/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucenenet/commit/b6c1b5d2
Tree: http://git-wip-us.apache.org/repos/asf/lucenenet/tree/b6c1b5d2
Diff: http://git-wip-us.apache.org/repos/asf/lucenenet/diff/b6c1b5d2

Branch: refs/heads/master
Commit: b6c1b5d2e29185e167f37f6f86c711913fe6f0b5
Parents: 69f2911
Author: Itamar Syn-Hershko <itamar@code972.com>
Authored: Sat Jan 31 22:03:24 2015 +0200
Committer: Itamar Syn-Hershko <itamar@code972.com>
Committed: Sat Jan 31 22:03:24 2015 +0200

----------------------------------------------------------------------
 Lucene.Net.sln                                  |   26 +-
 src/Lucene.Net.Expressions/Bindings.cs          |   38 +
 src/Lucene.Net.Expressions/Expression.cs        |   98 +
 .../ExpressionComparator.cs                     |   94 +
 .../ExpressionFunctionValues.cs                 |   48 +
 .../ExpressionRescorer.cs                       |  120 +
 .../ExpressionSortField.cs                      |   86 +
 .../ExpressionValueSource.cs                    |  169 ++
 .../JS/JavascriptCompiler.cs                    |  749 ++++++
 .../JS/JavascriptLexer.cs                       | 2177 ++++++++++++++++++
 .../JS/JavascriptParser.cs                      | 1879 +++++++++++++++
 .../Lucene.Net.Expressions.csproj               |   92 +
 .../Properties/AssemblyInfo.cs                  |   36 +
 .../Properties/Settings.Designer.cs             |  323 +++
 .../Properties/Settings.settings                |   81 +
 .../ScoreFunctionValues.cs                      |   34 +
 src/Lucene.Net.Expressions/ScoreValueSource.cs  |   59 +
 src/Lucene.Net.Expressions/SimpleBindings.cs    |  130 ++
 src/Lucene.Net.Expressions/app.config           |   94 +
 src/Lucene.Net.Expressions/packages.config      |    4 +
 .../JS/TestCustomFunctions.cs                   |  262 +++
 .../JS/TestJavascriptCompiler.cs                |  187 ++
 .../JS/TestJavascriptFunction.cs                |  309 +++
 .../JS/TestJavascriptOperations.cs              |  373 +++
 .../Lucene.Net.Tests.Expressions.csproj         |   84 +
 .../Properties/AssemblyInfo.cs                  |   36 +
 .../TestDemoExpressions.cs                      |  202 ++
 .../TestExpressionRescorer.cs                   |   92 +
 .../TestExpressionSortField.cs                  |   92 +
 .../TestExpressionSorts.cs                      |  151 ++
 .../TestExpressionValidation.cs                 |  151 ++
 .../TestExpressionValueSource.cs                |  157 ++
 32 files changed, 8432 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucenenet/blob/b6c1b5d2/Lucene.Net.sln
----------------------------------------------------------------------
diff --git a/Lucene.Net.sln b/Lucene.Net.sln
index 02dee4a..8fe7746 100644
--- a/Lucene.Net.sln
+++ b/Lucene.Net.sln
@@ -1,7 +1,7 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
 # Visual Studio 2013
-VisualStudioVersion = 12.0.30110.0
+VisualStudioVersion = 12.0.30501.0
 MinimumVisualStudioVersion = 10.0.40219.1
 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net", "src\Lucene.Net.Core\Lucene.Net.csproj", "{5D4AD9BE-1FFB-41AB-9943-25737971BF57}"
 EndProject
@@ -28,6 +28,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Classifica
 		{69D7956C-C2CC-4708-B399-A188FEC384C4} = {69D7956C-C2CC-4708-B399-A188FEC384C4}
 	EndProjectSection
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Expressions", "src\Lucene.Net.Expressions\Lucene.Net.Expressions.csproj", "{DC83004C-183A-4E1A-ABEA-4FE95B4BC079}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lucene.Net.Tests.Expressions", "src\Lucene.Net.Tests.Expressions\Lucene.Net.Tests.Expressions.csproj", "{F4873D95-4300-4E83-AFFA-EF796495D0F0}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Any CPU = Debug|Any CPU
@@ -119,6 +123,26 @@ Global
 		{866723F4-E3A4-47C5-A49F-9A68ADD4CFAE}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
 		{866723F4-E3A4-47C5-A49F-9A68ADD4CFAE}.Release|Mixed Platforms.Build.0 = Release|Any CPU
 		{866723F4-E3A4-47C5-A49F-9A68ADD4CFAE}.Release|x86.ActiveCfg = Release|Any CPU
+		{DC83004C-183A-4E1A-ABEA-4FE95B4BC079}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{DC83004C-183A-4E1A-ABEA-4FE95B4BC079}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{DC83004C-183A-4E1A-ABEA-4FE95B4BC079}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{DC83004C-183A-4E1A-ABEA-4FE95B4BC079}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{DC83004C-183A-4E1A-ABEA-4FE95B4BC079}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{DC83004C-183A-4E1A-ABEA-4FE95B4BC079}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{DC83004C-183A-4E1A-ABEA-4FE95B4BC079}.Release|Any CPU.Build.0 = Release|Any CPU
+		{DC83004C-183A-4E1A-ABEA-4FE95B4BC079}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{DC83004C-183A-4E1A-ABEA-4FE95B4BC079}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{DC83004C-183A-4E1A-ABEA-4FE95B4BC079}.Release|x86.ActiveCfg = Release|Any CPU
+		{F4873D95-4300-4E83-AFFA-EF796495D0F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F4873D95-4300-4E83-AFFA-EF796495D0F0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F4873D95-4300-4E83-AFFA-EF796495D0F0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+		{F4873D95-4300-4E83-AFFA-EF796495D0F0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+		{F4873D95-4300-4E83-AFFA-EF796495D0F0}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{F4873D95-4300-4E83-AFFA-EF796495D0F0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F4873D95-4300-4E83-AFFA-EF796495D0F0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F4873D95-4300-4E83-AFFA-EF796495D0F0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+		{F4873D95-4300-4E83-AFFA-EF796495D0F0}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+		{F4873D95-4300-4E83-AFFA-EF796495D0F0}.Release|x86.ActiveCfg = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/b6c1b5d2/src/Lucene.Net.Expressions/Bindings.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Expressions/Bindings.cs b/src/Lucene.Net.Expressions/Bindings.cs
new file mode 100644
index 0000000..c299f15
--- /dev/null
+++ b/src/Lucene.Net.Expressions/Bindings.cs
@@ -0,0 +1,38 @@
+using Lucene.Net.Queries.Function;
+
+namespace Lucene.Net.Expressions
+{
+	/// <summary>Binds variable names in expressions to actual data.</summary>
+	/// <remarks>
+	/// Binds variable names in expressions to actual data.
+	/// <p>
+	/// These are typically DocValues fields/FieldCache, the document's
+	/// relevance score, or other ValueSources.
+	/// </remarks>
+	/// <lucene.experimental></lucene.experimental>
+	public abstract class Bindings
+	{
+		/// <summary>Sole constructor.</summary>
+		/// <remarks>
+		/// Sole constructor. (For invocation by subclass
+		/// constructors, typically implicit.)
+		/// </remarks>
+		public Bindings()
+		{
+		}
+
+		/// <summary>Returns a ValueSource bound to the variable name.</summary>
+		
+		public abstract ValueSource GetValueSource(string name);
+
+		/// <summary>
+		/// Returns a
+		/// <code>ValueSource</code>
+		/// over relevance scores
+		/// </summary>
+		protected internal ValueSource GetScoreValueSource()
+		{
+			return new ScoreValueSource();
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/b6c1b5d2/src/Lucene.Net.Expressions/Expression.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Expressions/Expression.cs b/src/Lucene.Net.Expressions/Expression.cs
new file mode 100644
index 0000000..cd33d92
--- /dev/null
+++ b/src/Lucene.Net.Expressions/Expression.cs
@@ -0,0 +1,98 @@
+using Lucene.Net.Queries.Function;
+using Lucene.Net.Search;
+
+namespace Lucene.Net.Expressions
+{
+	/// <summary>Base class that computes the value of an expression for a document.</summary>
+	/// <remarks>
+	/// Base class that computes the value of an expression for a document.
+	/// <p>
+	/// Example usage:
+	/// <pre class="prettyprint">
+	/// // compile an expression:
+	/// Expression expr = JavascriptCompiler.compile("sqrt(_score) + ln(popularity)");
+	/// // SimpleBindings just maps variables to SortField instances
+	/// SimpleBindings bindings = new SimpleBindings();
+	/// bindings.add(new SortField("_score", SortField.Type.SCORE));
+	/// bindings.add(new SortField("popularity", SortField.Type.INT));
+	/// // create a sort field and sort by it (reverse order)
+	/// Sort sort = new Sort(expr.getSortField(bindings, true));
+	/// Query query = new TermQuery(new Term("body", "contents"));
+	/// searcher.search(query, null, 10, sort);
+	/// </pre>
+	/// </remarks>
+	/// <seealso cref="Lucene.Net.Expressions.JS.JavascriptCompiler.Compile(string)">Lucene.Net.Expressions.JS.JavascriptCompiler.Compile(string)</seealso>
+	/// <lucene.experimental></lucene.experimental>
+	public abstract class Expression
+	{
+		/// <summary>The original source text</summary>
+		public readonly string sourceText;
+
+		/// <summary>Named variables referred to by this expression</summary>
+		public readonly string[] variables;
+
+		/// <summary>
+		/// Creates a new
+		/// <code>Expression</code>
+		/// .
+		/// </summary>
+		/// <param name="sourceText">
+		/// Source text for the expression: e.g.
+		/// <code>ln(popularity)</code>
+		/// </param>
+		/// <param name="variables">
+		/// Names of external variables referred to by the expression
+		/// </param>
+		public Expression(string sourceText, string[] variables)
+		{
+			// javadocs
+			this.sourceText = sourceText;
+			this.variables = variables;
+		}
+
+		/// <summary>Evaluates the expression for the given document.</summary>
+		/// <remarks>Evaluates the expression for the given document.</remarks>
+		/// <param name="document"><code>docId</code> of the document to compute a value for</param>
+		/// <param name="functionValues">
+		/// 
+		/// <see cref="Lucene.Net.Queries.Function.FunctionValues">Lucene.Net.Queries.Function.FunctionValues
+		/// 	</see>
+		/// for each element of
+		/// <see cref="variables">variables</see>
+		/// .
+		/// </param>
+		/// <returns>The computed value of the expression for the given document.</returns>
+		public abstract double Evaluate(int document, FunctionValues[] functionValues);
+
+		/// <summary>Get a value source which can compute the value of this expression in the context of the given bindings.
+		/// 	</summary>
+		/// <remarks>Get a value source which can compute the value of this expression in the context of the given bindings.
+		/// 	</remarks>
+		/// <param name="bindings">Bindings to use for external values in this expression</param>
+		/// <returns>A value source which will evaluate this expression when used</returns>
+		public virtual ValueSource GetValueSource(Bindings bindings)
+		{
+			return new ExpressionValueSource(bindings, this);
+		}
+
+		/// <summary>Get a sort field which can be used to rank documents by this expression.
+		/// 	</summary>
+		/// <remarks>Get a sort field which can be used to rank documents by this expression.
+		/// 	</remarks>
+		public virtual SortField GetSortField(Bindings bindings, bool reverse)
+		{
+			return GetValueSource(bindings).GetSortField(reverse);
+		}
+
+		/// <summary>
+		/// Get a
+		/// <see cref="Lucene.Net.Search.Rescorer">Lucene.Net.Search.Rescorer</see>
+		/// , to rescore first-pass hits
+		/// using this expression.
+		/// </summary>
+		public virtual Rescorer GetRescorer(Bindings bindings)
+		{
+			return new ExpressionRescorer(this, bindings);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/b6c1b5d2/src/Lucene.Net.Expressions/ExpressionComparator.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Expressions/ExpressionComparator.cs b/src/Lucene.Net.Expressions/ExpressionComparator.cs
new file mode 100644
index 0000000..2f67621
--- /dev/null
+++ b/src/Lucene.Net.Expressions/ExpressionComparator.cs
@@ -0,0 +1,94 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using Lucene.Net.Index;
+using Lucene.Net.Queries.Function;
+using Lucene.Net.Search;
+using Lucene.Net.Support;
+
+namespace Lucene.Net.Expressions
+{
+    /// <summary>A custom comparator for sorting documents by an expression</summary>
+    internal class ExpressionComparator : FieldComparator<double>
+    {
+        private readonly double[] values;
+
+        private double bottom;
+
+        private double topValue;
+
+        private ValueSource source;
+
+        private FunctionValues scores;
+
+        private AtomicReaderContext readerContext;
+
+        public ExpressionComparator(ValueSource source, int numHits)
+        {
+            values = new double[numHits];
+            this.source = source;
+        }
+
+        // TODO: change FieldComparator.setScorer to throw IOException and remove this try-catch
+        public override Scorer Scorer
+        {
+            set
+            {
+                base.Scorer = value;
+                // TODO: might be cleaner to lazy-init 'source' and set scorer after?
+
+                Debug.Assert(readerContext != null);
+                var context = new Dictionary<string, object>();
+                Debug.Assert(value != null);
+                context["scorer"] = value;
+                scores = source.GetValues(context, readerContext);
+            }
+        }
+
+        public override int Compare(int slot1, int slot2)
+        {
+            return values[slot1].CompareTo(values[slot2]);
+        }
+
+        public override int Bottom
+        {
+            set { bottom = values[value]; }
+        }
+
+        public override object TopValue
+        {
+            set { topValue = (double)value; }
+        }
+
+
+        public override int CompareBottom(int doc)
+        {
+            return bottom.CompareTo(scores.DoubleVal(doc));
+        }
+
+
+        public override void Copy(int slot, int doc)
+        {
+            values[slot] = scores.DoubleVal(doc);
+        }
+
+
+        public override FieldComparator SetNextReader(AtomicReaderContext context)
+        {
+            this.readerContext = context;
+            return this;
+        }
+
+        public override IComparable Value(int slot)
+        {
+            return (values[slot]);
+        }
+
+
+        public override int CompareTop(int doc)
+        {
+            return topValue.CompareTo(scores.DoubleVal(doc));
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/b6c1b5d2/src/Lucene.Net.Expressions/ExpressionFunctionValues.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Expressions/ExpressionFunctionValues.cs b/src/Lucene.Net.Expressions/ExpressionFunctionValues.cs
new file mode 100644
index 0000000..63b8f67
--- /dev/null
+++ b/src/Lucene.Net.Expressions/ExpressionFunctionValues.cs
@@ -0,0 +1,48 @@
+using System;
+using Lucene.Net.Queries.Function;
+using Lucene.Net.Queries.Function.DocValues;
+
+namespace Lucene.Net.Expressions
+{
+	/// <summary>
+	/// A
+	/// <see cref="Lucene.Net.Queries.Function.FunctionValues">Lucene.Net.Queries.Function.FunctionValues
+	/// 	</see>
+	/// which evaluates an expression
+	/// </summary>
+	internal class ExpressionFunctionValues : DoubleDocValues
+	{
+		internal readonly Expression expression;
+
+		internal readonly FunctionValues[] functionValues;
+
+		internal int currentDocument = -1;
+
+		internal double currentValue;
+
+		internal ExpressionFunctionValues(ValueSource parent, Expression expression, FunctionValues
+			[] functionValues) : base(parent)
+		{
+			if (expression == null)
+			{
+				throw new ArgumentNullException();
+			}
+			if (functionValues == null)
+			{
+				throw new ArgumentNullException();
+			}
+			this.expression = expression;
+			this.functionValues = functionValues;
+		}
+
+		public override double DoubleVal(int document)
+		{
+			if (currentDocument != document)
+			{
+				currentDocument = document;
+				currentValue = expression.Evaluate(document, functionValues);
+			}
+			return currentValue;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/b6c1b5d2/src/Lucene.Net.Expressions/ExpressionRescorer.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Expressions/ExpressionRescorer.cs b/src/Lucene.Net.Expressions/ExpressionRescorer.cs
new file mode 100644
index 0000000..8d0fd7e
--- /dev/null
+++ b/src/Lucene.Net.Expressions/ExpressionRescorer.cs
@@ -0,0 +1,120 @@
+using System;
+using System.Collections.Generic;
+using Lucene.Net.Index;
+using Lucene.Net.Search;
+
+namespace Lucene.Net.Expressions
+{
+    /// <summary>
+    /// A
+    /// <see cref="Lucene.Net.Search.Rescorer">Lucene.Net.Search.Rescorer</see>
+    /// that uses an expression to re-score
+    /// first pass hits.  Functionally this is the same as
+    /// <see cref="Lucene.Net.Search.SortRescorer">Lucene.Net.Search.SortRescorer
+    /// 	</see>
+    /// (if you build the
+    /// <see cref="Lucene.Net.Search.Sort">Lucene.Net.Search.Sort</see>
+    /// using
+    /// <see cref="Expression.GetSortField(Bindings, bool)">Expression.GetSortField(Bindings, bool)
+    /// 	</see>
+    /// ), except for the explain method
+    /// which gives more detail by showing the value of each
+    /// variable.
+    /// </summary>
+    /// <lucene.experimental></lucene.experimental>
+    internal class ExpressionRescorer : SortRescorer
+    {
+        private readonly Expression expression;
+
+        private readonly Bindings bindings;
+
+        /// <summary>
+        /// Uses the provided
+        /// <see cref="Lucene.Net.Queries.Function.ValueSource">Lucene.Net.Queries.Function.ValueSource
+        /// 	</see>
+        /// to assign second
+        /// pass scores.
+        /// </summary>
+        public ExpressionRescorer(Expression expression, Bindings bindings)
+            : base(new Sort
+                (expression.GetSortField(bindings, true)))
+        {
+            this.expression = expression;
+            this.bindings = bindings;
+        }
+
+        private class FakeScorer : Scorer
+        {
+            internal float score;
+
+            internal int doc = -1;
+
+            internal int freq = 1;
+
+            public FakeScorer()
+                : base(null)
+            {
+            }
+
+            public override int Advance(int target)
+            {
+                throw new NotSupportedException("FakeScorer doesn't support advance(int)");
+            }
+
+            public override int DocID()
+            {
+                return doc;
+            }
+
+            public override int Freq()
+            {
+                return freq;
+            }
+
+            public override int NextDoc()
+            {
+                throw new NotSupportedException("FakeScorer doesn't support nextDoc()");
+            }
+
+            public override float Score()
+            {
+                return score;
+            }
+
+            public override long Cost()
+            {
+                return 1;
+            }
+
+            public override Weight Weight
+            {
+                get { throw new NotSupportedException(); }
+            }
+
+            public override ICollection<Scorer.ChildScorer> Children
+            {
+                get { throw new NotSupportedException(); }
+            }
+        }
+
+
+        public override Explanation Explain(IndexSearcher searcher, Explanation firstPassExplanation, int docID)
+        {
+            Explanation result = base.Explain(searcher, firstPassExplanation, docID);
+            IList<AtomicReaderContext> leaves = searcher.IndexReader.Leaves;
+            int subReader = ReaderUtil.SubIndex(docID, leaves);
+            AtomicReaderContext readerContext = leaves[subReader];
+            int docIDInSegment = docID - readerContext.DocBase;
+            var context = new Dictionary<string, object>();
+            var fakeScorer = new FakeScorer { score = firstPassExplanation.Value, doc = docIDInSegment };
+            context["scorer"] = fakeScorer;
+            foreach (string variable in expression.variables)
+            {
+                result.AddDetail(new Explanation((float)bindings.GetValueSource(variable).GetValues
+                    (context, readerContext).DoubleVal(docIDInSegment), "variable \"" + variable + "\""
+                    ));
+            }
+            return result;
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/b6c1b5d2/src/Lucene.Net.Expressions/ExpressionSortField.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Expressions/ExpressionSortField.cs b/src/Lucene.Net.Expressions/ExpressionSortField.cs
new file mode 100644
index 0000000..e7ca2ea
--- /dev/null
+++ b/src/Lucene.Net.Expressions/ExpressionSortField.cs
@@ -0,0 +1,86 @@
+using System.Text;
+using Lucene.Net.Search;
+
+namespace Lucene.Net.Expressions
+{
+	/// <summary>
+	/// A
+	/// <see cref="Lucene.Net.Search.SortField">Lucene.Net.Search.SortField
+	/// 	</see>
+	/// which sorts documents by the evaluated value of an expression for each document
+	/// </summary>
+	internal class ExpressionSortField : SortField
+	{
+		private readonly ExpressionValueSource source;
+
+		internal ExpressionSortField(string name, ExpressionValueSource source, bool reverse
+			) : base(name, Type_e.CUSTOM, reverse)
+		{
+			this.source = source;
+		}
+
+		
+		public override FieldComparator GetComparator(int numHits, int sortPos)
+		{
+			return new ExpressionComparator(source, numHits);
+		}
+
+		public override int GetHashCode()
+		{
+			int prime = 31;
+			int result = base.GetHashCode();
+			result = prime * result + ((source == null) ? 0 : source.GetHashCode());
+			return result;
+		}
+
+		public override bool Equals(object obj)
+		{
+			if (this == obj)
+			{
+				return true;
+			}
+			if (!base.Equals(obj))
+			{
+				return false;
+			}
+			if (GetType() != obj.GetType())
+			{
+				return false;
+			}
+			ExpressionSortField other = (ExpressionSortField)obj;
+			if (source == null)
+			{
+				if (other.source != null)
+				{
+					return false;
+				}
+			}
+			else
+			{
+				if (!source.Equals(other.source))
+				{
+					return false;
+				}
+			}
+			return true;
+		}
+
+		public override string ToString()
+		{
+			StringBuilder buffer = new StringBuilder();
+			buffer.Append("<expr \"");
+			buffer.Append(Field);
+			buffer.Append("\">");
+			if (Reverse)
+			{
+				buffer.Append('!');
+			}
+			return buffer.ToString();
+		}
+
+		public override bool NeedsScores()
+		{
+			return source.NeedsScores();
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/b6c1b5d2/src/Lucene.Net.Expressions/ExpressionValueSource.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Expressions/ExpressionValueSource.cs b/src/Lucene.Net.Expressions/ExpressionValueSource.cs
new file mode 100644
index 0000000..e4501a9
--- /dev/null
+++ b/src/Lucene.Net.Expressions/ExpressionValueSource.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using Lucene.Net.Index;
+using Lucene.Net.Queries.Function;
+using Lucene.Net.Search;
+using Lucene.Net.Support;
+
+namespace Lucene.Net.Expressions
+{
+	/// <summary>
+	/// A
+	/// <see cref="Lucene.Net.Queries.Function.ValueSource">Lucene.Net.Queries.Function.ValueSource
+	/// 	</see>
+	/// which evaluates a
+	/// <see cref="Expression">Expression</see>
+	/// given the context of an
+	/// <see cref="Bindings">Bindings</see>
+	/// .
+	/// </summary>
+	internal sealed class ExpressionValueSource : ValueSource
+	{
+		internal readonly ValueSource[] variables;
+
+		internal readonly Expression expression;
+
+		internal readonly bool needsScores;
+
+		internal ExpressionValueSource(Bindings bindings, Expression expression)
+		{
+			if (bindings == null)
+			{
+				throw new ArgumentNullException();
+			}
+			if (expression == null)
+			{
+				throw new ArgumentNullException();
+			}
+			this.expression = expression;
+			variables = new ValueSource[expression.variables.Length];
+			bool needsScores = false;
+			for (int i = 0; i < variables.Length; i++)
+			{
+				ValueSource source = bindings.GetValueSource(expression.variables[i]);
+				if (source is ScoreValueSource)
+				{
+					needsScores = true;
+				}
+				else
+				{
+				    var valueSource = source as ExpressionValueSource;
+				    if (valueSource != null)
+					{
+						if (valueSource.NeedsScores())
+						{
+							needsScores = true;
+						}
+					}
+					else
+					{
+						if (source == null)
+						{
+							throw new SystemException("Internal error. Variable (" + expression.variables[i]
+								 + ") does not exist.");
+						}
+					}
+				}
+			    variables[i] = source;
+			}
+			this.needsScores = needsScores;
+		}
+
+		
+		public override FunctionValues GetValues(IDictionary context, AtomicReaderContext
+			 readerContext)
+		{
+			IDictionary<string, FunctionValues> valuesCache = (IDictionary<string, FunctionValues>)context["valuesCache"];
+			if (valuesCache == null)
+			{
+				valuesCache = new Dictionary<string, FunctionValues>();
+				context = new Hashtable(context);
+				context["valuesCache"] = valuesCache;
+			}
+			FunctionValues[] externalValues = new FunctionValues[expression.variables.Length];
+			for (int i = 0; i < variables.Length; ++i)
+			{
+				string externalName = expression.variables[i];
+				FunctionValues values;
+				if (!valuesCache.TryGetValue(externalName,out values))
+				{
+					values = variables[i].GetValues(context, readerContext);
+					if (values == null)
+					{
+						throw new SystemException("Internal error. External (" + externalName + ") does not exist.");
+					}
+					valuesCache[externalName] = values;
+				}
+				externalValues[i] = values;
+			}
+			return new ExpressionFunctionValues(this, expression, externalValues);
+		}
+
+		public override SortField GetSortField(bool reverse)
+		{
+			return new ExpressionSortField(expression.sourceText, this, reverse);
+		}
+
+		public override string Description
+		{
+		    get { return "expr(" + expression.sourceText + ")"; }
+		}
+
+		public override int GetHashCode()
+		{
+			int prime = 31;
+			int result = 1;
+			result = prime * result + ((expression == null) ? 0 : expression.GetHashCode());
+			result = prime * result + (needsScores ? 1231 : 1237);
+			result = prime * result + Arrays.GetHashCode(variables);
+			return result;
+		}
+
+		public override bool Equals(object obj)
+		{
+			if (this == obj)
+			{
+				return true;
+			}
+			if (obj == null)
+			{
+				return false;
+			}
+			if (GetType() != obj.GetType())
+			{
+				return false;
+			}
+			Lucene.Net.Expressions.ExpressionValueSource other = (Lucene.Net.Expressions.ExpressionValueSource
+				)obj;
+			if (expression == null)
+			{
+				if (other.expression != null)
+				{
+					return false;
+				}
+			}
+			else
+			{
+				if (!expression.Equals(other.expression))
+				{
+					return false;
+				}
+			}
+			if (needsScores != other.needsScores)
+			{
+				return false;
+			}
+			if (!Arrays.Equals(variables, other.variables))
+			{
+				return false;
+			}
+			return true;
+		}
+
+		internal bool NeedsScores()
+		{
+			return needsScores;
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/lucenenet/blob/b6c1b5d2/src/Lucene.Net.Expressions/JS/JavascriptCompiler.cs
----------------------------------------------------------------------
diff --git a/src/Lucene.Net.Expressions/JS/JavascriptCompiler.cs b/src/Lucene.Net.Expressions/JS/JavascriptCompiler.cs
new file mode 100644
index 0000000..cda3042
--- /dev/null
+++ b/src/Lucene.Net.Expressions/JS/JavascriptCompiler.cs
@@ -0,0 +1,749 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Configuration;
+using System.Diagnostics;
+using System.Diagnostics.SymbolStore;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+using System.Security.AccessControl;
+using Antlr.Runtime;
+using Antlr.Runtime.Tree;
+using Lucene.Net.Queries.Function;
+using Lucene.Net.Support;
+
+namespace Lucene.Net.Expressions.JS
+{
+    /// <summary>An expression compiler for javascript expressions.</summary>
+    /// <remarks>
+    /// An expression compiler for javascript expressions.
+    /// <p>
+    /// Example:
+    /// <pre class="prettyprint">
+    /// Expression foo = JavascriptCompiler.compile("((0.3*popularity)/10.0)+(0.7*score)");
+    /// </pre>
+    /// <p>
+    /// See the
+    /// <see cref="Lucene.Net.Expressions.JS">package documentation</see>
+    /// for
+    /// the supported syntax and default functions.
+    /// <p>
+    /// You can compile with an alternate set of functions via
+    /// <see cref="Compile(string, System.Collections.Generic.IDictionary{K, V})
+    /// 	">Compile(string, System.Collections.Generic.IDictionary&lt;K, V&gt;)
+    /// 	</see>
+    /// .
+    /// For example:
+    /// <pre class="prettyprint">
+    /// Map&lt;String,Method&gt; functions = new HashMap&lt;String,Method&gt;();
+    /// // add all the default functions
+    /// functions.putAll(JavascriptCompiler.DEFAULT_FUNCTIONS);
+    /// // add cbrt()
+    /// functions.put("cbrt", Math.class.getMethod("cbrt", double.class));
+    /// // call compile with customized function map
+    /// Expression foo = JavascriptCompiler.compile("cbrt(score)+ln(popularity)",
+    /// functions,
+    /// getClass().getClassLoader());
+    /// </pre>
+    /// </remarks>
+    /// <lucene.experimental></lucene.experimental>
+    public class JavascriptCompiler
+    {
+
+        private static readonly string COMPILED_EXPRESSION_CLASS = typeof(Expression).Namespace + ".CompiledExpression";
+
+        private static readonly string COMPILED_EXPRESSION_INTERNAL = COMPILED_EXPRESSION_CLASS.Replace('.', '/');
+
+        private static readonly Type EXPRESSION_TYPE = Type.GetType(typeof(Expression).FullName);
+
+        private static readonly Type FUNCTION_VALUES_TYPE = typeof(FunctionValues);
+
+        private static readonly ConstructorInfo EXPRESSION_CTOR = typeof(Expression).
+            GetConstructor(new Type[] { typeof(String), typeof(String[]) });
+
+        private static readonly MethodInfo EVALUATE_METHOD = GetMethod(EXPRESSION_TYPE, "Evaluate",
+            new[] { typeof(int), typeof(FunctionValues[]) });
+
+        private static readonly MethodInfo DOUBLE_VAL_METHOD = GetMethod(FUNCTION_VALUES_TYPE, "DoubleVal",
+            new[] { typeof(int) });
+
+
+        // We use the same class name for all generated classes as they all have their own class loader.
+        // The source code is displayed as "source file name" in stack trace.
+        // to work around import clash:
+        private static MethodInfo GetMethod(Type type, string method, Type[] parms)
+        {
+            return type.GetMethod(method, parms);
+        }
+
+        private const int MAX_SOURCE_LENGTH = 16384;
+
+        private readonly string sourceText;
+
+        private readonly IDictionary<string, int> externalsMap = new HashMap<string, int>();
+
+
+
+        private TypeBuilder dynamicType;
+
+        private readonly IDictionary<string, MethodInfo> functions;
+
+        /// <summary>The default set of functions available to expressions.</summary>
+        /// <remarks>
+        /// The default set of functions available to expressions.
+        /// <p>
+        /// See the
+        /// <see cref="Lucene.Net.Expressions.JS">package documentation</see>
+        /// for a list.
+        /// </remarks>
+        public static readonly IDictionary<string, MethodInfo> DEFAULT_FUNCTIONS;
+
+        private ILGenerator gen;
+        private AssemblyBuilder asmBuilder;
+        private string fileName;
+        private ISymbolDocumentWriter debugDoc;
+        private int lineNum = 1;
+        private StreamWriter file;
+        private MethodBuilder evalMethod;
+        private bool negate;
+
+        // This maximum length is theoretically 65535 bytes, but as its CESU-8 encoded we dont know how large it is in bytes, so be safe
+        // rcmuir: "If your ranking function is that large you need to check yourself into a mental institution!"
+        /// <summary>Compiles the given expression.</summary>
+        /// <remarks>Compiles the given expression.</remarks>
+        /// <param name="sourceText">The expression to compile</param>
+        /// <returns>A new compiled expression</returns>
+
+        public static Expression Compile(string sourceText)
+        {
+            return new JavascriptCompiler(sourceText).CompileExpression();
+        }
+
+        /// <summary>Compiles the given expression with the supplied custom functions.</summary>
+        /// <remarks>
+        /// Compiles the given expression with the supplied custom functions.
+        /// <p>
+        /// Functions must be
+        /// <code>public static</code>
+        /// , return
+        /// <code>double</code>
+        /// and
+        /// can take from zero to 256
+        /// <code>double</code>
+        /// parameters.
+        /// </remarks>
+        /// <param name="sourceText">The expression to compile</param>
+        /// <param name="functions">map of String names to functions</param>
+        /// <param name="parent">
+        /// a
+        /// <code>ClassLoader</code>
+        /// that should be used as the parent of the loaded class.
+        /// It must contain all classes referred to by the given
+        /// <code>functions</code>
+        /// .
+        /// </param>
+        /// <returns>A new compiled expression</returns>
+
+        public static Expression Compile(string sourceText, IDictionary<string, MethodInfo> functions)
+        {
+
+            foreach (MethodInfo m in functions.Values)
+            {
+                CheckFunction(m);
+            }
+            return new JavascriptCompiler(sourceText, functions).CompileExpression();
+        }
+
+        /// <summary>This method is unused, it is just here to make sure that the function signatures don't change.
+        /// 	</summary>
+        /// <remarks>
+        /// This method is unused, it is just here to make sure that the function signatures don't change.
+        /// If this method fails to compile, you also have to change the byte code generator to correctly
+        /// use the FunctionValues class.
+        /// </remarks>
+        private static void UnusedTestCompile()
+        {
+            FunctionValues f = null;
+            double ret = f.DoubleVal(2);
+        }
+
+        /// <summary>Constructs a compiler for expressions.</summary>
+
+        /// <param name="sourceText">The expression to compile</param>
+        private JavascriptCompiler(string sourceText)
+            : this(sourceText, DEFAULT_FUNCTIONS
+                )
+        {
+        }
+
+        /// <summary>Constructs a compiler for expressions with specific set of functions</summary>
+        /// <param name="sourceText">The expression to compile</param>
+        private JavascriptCompiler(string sourceText, IDictionary<string, MethodInfo> functions
+            )
+        {
+            if (sourceText == null)
+            {
+                throw new ArgumentNullException();
+            }
+            this.sourceText = sourceText;
+            this.functions = functions;
+        }
+
+        /// <summary>Compiles the given expression with the specified parent classloader</summary>
+        /// <returns>A new compiled expression</returns>
+
+        private Expression CompileExpression()
+        {
+            try
+            {
+
+                ITree antlrTree = GetAntlrComputedExpressionTree();
+                BeginCompile();
+                RecursiveCompile(antlrTree, typeof(double));
+                EndCompile();
+                return
+                    (Expression)
+                        Activator.CreateInstance(dynamicType.CreateType(), sourceText, externalsMap.Keys.ToArray());
+
+            }
+
+            catch (MemberAccessException exception)
+            {
+                throw new InvalidOperationException("An internal error occurred attempting to compile the expression ("
+                                                    + sourceText + ").", exception);
+            }
+            catch (TargetInvocationException exception)
+            {
+                throw new InvalidOperationException("An internal error occurred attempting to compile the expression ("
+                                                    + sourceText + ").", exception);
+            }
+        }
+
+        private void BeginCompile()
+        {
+            var assemblyName = new AssemblyName("Lucene.Net.Expressions.Dynamic" + new Random().Next());
+            asmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect);
+
+            ModuleBuilder modBuilder = asmBuilder.DefineDynamicModule(assemblyName.Name + ".dll");
+            dynamicType = modBuilder.DefineType(COMPILED_EXPRESSION_CLASS,
+                TypeAttributes.AnsiClass | TypeAttributes.AutoClass | TypeAttributes.Public | TypeAttributes.Class |
+                TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout, EXPRESSION_TYPE);
+
+
+            ConstructorBuilder constructorBuilder = dynamicType.DefineConstructor(MethodAttributes.Public,
+                CallingConventions.HasThis,
+                new[] { typeof(string), typeof(string[]) });
+
+            ILGenerator ctorGen = constructorBuilder.GetILGenerator();
+            ctorGen.Emit(OpCodes.Ldarg_0);
+            ctorGen.Emit(OpCodes.Ldarg_1);
+            ctorGen.Emit(OpCodes.Ldarg_2);
+            ctorGen.Emit(OpCodes.Call, EXPRESSION_CTOR);
+            ctorGen.Emit(OpCodes.Nop);
+            ctorGen.Emit(OpCodes.Nop);
+            ctorGen.Emit(OpCodes.Ret);
+
+            evalMethod = dynamicType.DefineMethod("Evaluate", MethodAttributes.Public | MethodAttributes.Virtual,
+                typeof(double), new[] { typeof(int), typeof(FunctionValues[]) });
+            gen = evalMethod.GetILGenerator();
+        }
+
+        private void RecursiveCompile(ITree current, Type expected)
+        {
+            int type = current.Type;
+            string text = current.Text;
+
+
+            switch (type)
+            {
+                case JavascriptParser.AT_CALL:
+                    {
+                        ITree identifier = current.GetChild(0);
+                        string call = identifier.Text;
+                        int arguments = current.ChildCount - 1;
+                        MethodInfo method = functions[call];
+                        if (method == null)
+                        {
+                            throw new ArgumentException("Unrecognized method call (" + call + ").");
+                        }
+                        int arity = method.GetParameters().Length;
+                        if (arguments != arity)
+                        {
+                            throw new ArgumentException("Expected (" + arity + ") arguments for method call ("
+                                                        + call + "), but found (" + arguments + ").");
+                        }
+                        for (int argument = 1; argument <= arguments; ++argument)
+                        {
+                            RecursiveCompile(current.GetChild(argument), typeof(double));
+                        }
+                        gen.Emit(OpCodes.Call, method);
+
+
+
+                        break;
+                    }
+
+                case JavascriptParser.NAMESPACE_ID:
+                    {
+                        int index;
+                        if (externalsMap.ContainsKey(text))
+                        {
+                            index = externalsMap[text];
+                        }
+                        else
+                        {
+                            index = externalsMap.Count;
+                            externalsMap[text] = index;
+                        }
+                        gen.Emit(OpCodes.Nop);
+
+                        gen.Emit(OpCodes.Ldarg_2);
+                        gen.Emit(OpCodes.Ldc_I4, index);
+
+                        gen.Emit(OpCodes.Ldelem_Ref);
+                        gen.Emit(OpCodes.Ldarg_1);
+                        gen.Emit(OpCodes.Callvirt, DOUBLE_VAL_METHOD);
+
+
+                        break;
+                    }
+
+                case JavascriptParser.HEX:
+                    {
+                        PushLong(expected, Convert.ToInt64(text.Substring(2), 16));
+                        break;
+                    }
+
+                case JavascriptParser.OCTAL:
+                    {
+                        PushLong(expected, Convert.ToInt64(text.Substring(2), 8));
+                        break;
+                    }
+
+                case JavascriptParser.DECIMAL:
+                    {
+                        gen.Emit(OpCodes.Ldc_R8, double.Parse(text));
+                        if (negate)
+                        {
+                            gen.Emit(OpCodes.Neg);
+                            negate = false;
+                        }
+                        break;
+                    }
+
+                case JavascriptParser.AT_NEGATE:
+                    {
+                        negate = true;
+                        RecursiveCompile(current.GetChild(0), typeof(double));
+
+                        break;
+                    }
+
+                case JavascriptParser.AT_ADD:
+                    {
+                        PushArith(OpCodes.Add, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_SUBTRACT:
+                    {
+                        PushArith(OpCodes.Sub, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_MULTIPLY:
+                    {
+                        PushArith(OpCodes.Mul, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_DIVIDE:
+                    {
+                        PushArith(OpCodes.Div, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_MODULO:
+                    {
+                        PushArith(OpCodes.Rem, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_BIT_SHL:
+                    {
+                        PushShift(OpCodes.Shl, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_BIT_SHR:
+                    {
+                        PushShift(OpCodes.Shr, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_BIT_SHU:
+                    {
+                        PushShift(OpCodes.Shr_Un, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_BIT_AND:
+                    {
+                        PushBitwise(OpCodes.And, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_BIT_OR:
+                    {
+                        PushBitwise(OpCodes.Or, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_BIT_XOR:
+                    {
+                        PushBitwise(OpCodes.Xor, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_BIT_NOT:
+                    {
+                        RecursiveCompile(current.GetChild(0), typeof(long));
+                        gen.Emit(OpCodes.Ldc_I4_M1);
+                        //dynamicType.Push(-1L);
+                        //dynamicType.VisitInsn(Opcodes.LXOR);
+                        //dynamicType.Cast(typeof(long), expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_COMP_EQ:
+                    {
+                        PushCond(OpCodes.Ceq, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_COMP_NEQ:
+                    {
+                        //PushCond(OpCodes, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_COMP_LT:
+                    {
+                        PushCond(OpCodes.Clt, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_COMP_GT:
+                    {
+                        PushCond(OpCodes.Cgt, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_COMP_LTE:
+                    {
+                        //PushCond(OpCodes.Clt | OpCodes.Ceq, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_COMP_GTE:
+                    {
+                        //PushCond(GeneratorAdapter.GE, current, expected);
+                        break;
+                    }
+
+                case JavascriptParser.AT_BOOL_NOT:
+                    {
+                        /*Label labelNotTrue = new Label();
+					Label labelNotReturn = new Label();
+					RecursiveCompile(current.GetChild(0), Type.INT_TYPE);
+					dynamicType.VisitJumpInsn(Opcodes.IFEQ, labelNotTrue);
+					PushBoolean(expected, false);
+					dynamicType.GoTo(labelNotReturn);
+					dynamicType.VisitLabel(labelNotTrue);
+					PushBoolean(expected, true);
+					dynamicType.VisitLabel(labelNotReturn);*/
+                        break;
+                    }
+
+                case JavascriptParser.AT_BOOL_AND:
+                    {
+                        /*Label andFalse = new Label();
+					Label andEnd = new Label();
+					RecursiveCompile(current.GetChild(0), Type.INT_TYPE);
+					dynamicType.VisitJumpInsn(Opcodes.IFEQ, andFalse);
+					RecursiveCompile(current.GetChild(1), Type.INT_TYPE);
+					dynamicType.VisitJumpInsn(Opcodes.IFEQ, andFalse);
+					PushBoolean(expected, true);
+					dynamicType.GoTo(andEnd);
+					dynamicType.VisitLabel(andFalse);
+					PushBoolean(expected, false);
+					dynamicType.VisitLabel(andEnd);*/
+                        break;
+                    }
+
+                case JavascriptParser.AT_BOOL_OR:
+                    {
+                        Label orTrue = new Label();
+                        Label orEnd = new Label();
+                        /*RecursiveCompile(current.GetChild(0), Type.INT_TYPE);
+					dynamicType.VisitJumpInsn(Opcodes.IFNE, orTrue);
+					RecursiveCompile(current.GetChild(1), Type.INT_TYPE);
+					dynamicType.VisitJumpInsn(Opcodes.IFNE, orTrue);
+					PushBoolean(expected, false);
+					dynamicType.GoTo(orEnd);
+					dynamicType.VisitLabel(orTrue);
+					PushBoolean(expected, true);
+					dynamicType.VisitLabel(orEnd);*/
+                        break;
+                    }
+
+                case JavascriptParser.AT_COND_QUE:
+                    {
+                        /*Label condFalse = new Label();
+					Label condEnd = new Label();
+					RecursiveCompile(current.GetChild(0), Type.INT_TYPE);
+					dynamicType.VisitJumpInsn(Opcodes.IFEQ, condFalse);
+					RecursiveCompile(current.GetChild(1), expected);
+					dynamicType.GoTo(condEnd);
+					dynamicType.VisitLabel(condFalse);
+					RecursiveCompile(current.GetChild(2), expected);
+					dynamicType.VisitLabel(condEnd);*/
+                        break;
+                    }
+
+                default:
+                    {
+                        throw new InvalidOperationException("Unknown operation specified: (" + current.Text + ").");
+                    }
+            }
+
+        }
+
+        private void PushArith(OpCode op, ITree current, Type expected)
+        {
+            PushBinaryOp(op, current, expected, typeof(double), typeof(double), typeof(double));
+        }
+
+        private void PushShift(OpCode op, ITree current, Type expected)
+        {
+            PushBinaryOp(op, current, expected, typeof(long), typeof(int), typeof(long));
+        }
+
+        private void PushBitwise(OpCode op, ITree current, Type expected)
+        {
+            PushBinaryOp(op, current, expected, typeof(long), typeof(long), typeof(long));
+        }
+
+        private void PushBinaryOp(OpCode op, ITree current, Type expected, Type arg1, Type arg2, Type returnType)
+        {
+            gen.Emit(OpCodes.Nop);
+            RecursiveCompile(current.GetChild(0), arg1);
+            RecursiveCompile(current.GetChild(1), arg2);
+            /* gen.Emit(OpCodes.Add, debugDoc, file, lineNum++);
+             gen.Emit(OpCodes.Stloc_0, debugDoc, file, lineNum++);
+             gen.Emit(OpCodes.Br_S, debugDoc, file, lineNum++);
+             gen.Emit(OpCodes.Ldloc_0, debugDoc, file, lineNum++);*/
+            gen.Emit(op);
+            /*dynamicType.VisitInsn(op);
+			dynamicType.Cast(returnType, expected);*/
+        }
+
+        private void PushCond(OpCode @operator, ITree current, Type expected)
+        {
+            Label labelTrue = new Label();
+            Label labelReturn = new Label();
+            RecursiveCompile(current.GetChild(0), typeof(double));
+            RecursiveCompile(current.GetChild(1), typeof(double));
+            /*dynamicType.IfCmp(typeof(double), @operator, labelTrue);
+			PushBoolean(expected, false);
+			dynamicType.GoTo(labelReturn);
+			dynamicType.VisitLabel(labelTrue);
+			PushBoolean(expected, true);
+			dynamicType.VisitLabel(labelReturn);*/
+        }
+
+        /*
+                private void PushBoolean(Type expected, bool truth)
+                {
+                    switch (expected.GetSort())
+                    {
+                        case Type.INT:
+                        {
+                            dynamicType.Push(truth);
+                            break;
+                        }
+
+                        case Type.LONG:
+                        {
+                            dynamicType.Push(truth ? 1L : 0L);
+                            break;
+                        }
+
+                        case Type.DOUBLE:
+                        {
+                            dynamicType.Push(truth ? 1. : 0.);
+                            break;
+                        }
+
+                        default:
+                        {
+                            throw new InvalidOperationException("Invalid expected type: " + expected);
+                        }
+                    }
+                }
+        */
+
+        private void PushLong(Type expected, long i)
+        {
+            /*switch (expected.GetSort())
+			{
+				case Type.INT:
+				{
+					dynamicType.Push((int)i);
+					break;
+				}
+
+				case Type.LONG:
+				{
+					dynamicType.Push(i);
+					break;
+				}
+
+				case Type.DOUBLE:
+				{
+					dynamicType.Push((double)i);
+					break;
+				}
+
+				default:
+				{
+					throw new InvalidOperationException("Invalid expected type: " + expected);
+				}
+			}*/
+            gen.Emit(OpCodes.Ldarg_0);
+        }
+
+        private void EndCompile()
+        {
+            gen.Emit(OpCodes.Ret);
+            dynamicType.DefineMethodOverride(evalMethod, EVALUATE_METHOD);
+        }
+
+
+
+        private ITree GetAntlrComputedExpressionTree()
+        {
+            ICharStream input = new ANTLRStringStream(sourceText);
+            JavascriptLexer lexer = new JavascriptLexer(input);
+            CommonTokenStream tokens = new CommonTokenStream(lexer);
+            JavascriptParser parser = new JavascriptParser(tokens);
+            try
+            {
+                return parser.Expression().Tree;
+            }
+            catch (RecognitionException re)
+            {
+                throw new ArgumentException(re.Message, re);
+            }
+            catch (SystemException exception)
+            {
+                //TODO: Uncomment after implementing ParseException in QueryParsers
+                //if (exception.InnerException is ParseException)
+                //{
+                //    throw (ParseException)exception.InnerException;
+                //}
+                throw;
+            }
+        }
+
+
+
+        static JavascriptCompiler()
+        {
+            IDictionary<string, MethodInfo> map = new Dictionary<string, MethodInfo>();
+            try
+            {
+                var props = Properties.Settings.Default;
+                foreach (SettingsProperty property in props.Properties)
+                {
+                    string[] vals = props[property.Name].ToString().Split(',');
+                    if (vals.Length != 3)
+                    {
+                        throw new Exception("Error reading Javascript functions from settings");
+                    }
+                    string typeName = vals[0];
+                    if (vals[0].Contains("Lucene.Net"))
+                    {
+                        typeName = vals[0] + ",Lucene.Net";
+                    }
+                    Type clazz = Type.GetType(typeName, true);
+                    string methodName = vals[1].Trim();
+                    int arity = int.Parse(vals[2]);
+                    Type[] args = new Type[arity];
+                    Arrays.Fill(args, typeof(double));
+                    MethodInfo method = clazz.GetMethod(methodName, args);
+                    CheckFunction(method);
+                    map[property.Name] = method;
+                }
+
+
+            }
+            catch (Exception e)
+            {
+                throw new Exception("Cannot resolve function", e);
+            }
+            DEFAULT_FUNCTIONS = map;
+        }
+
+        private static void CheckFunction(MethodInfo method)
+        {
+
+            // do some checks if the signature is "compatible":
+            if (!(method.IsStatic))
+            {
+                throw new ArgumentException(method + " is not static.");
+            }
+            if (!(method.IsPublic))
+            {
+                throw new ArgumentException(method + " is not public.");
+            }
+            if (!method.DeclaringType.IsPublic)
+            {
+                //.NET Port. Inner class is being returned as not public even when declared public
+                if (method.DeclaringType.IsNestedAssembly)
+                {
+                    throw new ArgumentException(method.DeclaringType.FullName + " is not public.");
+                }
+            }
+            if (method.GetParameters().Any(parmType => parmType.ParameterType != (typeof(double))))
+            {
+                throw new ArgumentException(method + " must take only double parameters");
+            }
+            if (method.ReturnType != typeof(double))
+            {
+                throw new ArgumentException(method + " does not return a double.");
+            }
+        }
+    }
+
+    
+}


Mime
View raw message