Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/AntlrParser' into CompileFunc
Browse files Browse the repository at this point in the history
Conflicts:
	Parser/AntlrParser.cs
	Parser/ExprEval.g3.parser.cs
  • Loading branch information
RupertAvery committed May 5, 2014
2 parents 7805fee + c5ba669 commit 21a77f6
Show file tree
Hide file tree
Showing 12 changed files with 556 additions and 207 deletions.
2 changes: 2 additions & 0 deletions CompiledExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ public class CompiledExpression<TResult> : ExpressionCompiler
public CompiledExpression()
{
Parser = new AntlrParser();
Parser.ReturnType = typeof(TResult);
}

public CompiledExpression(string expression)
Expand Down Expand Up @@ -106,6 +107,7 @@ public class CompiledExpression : ExpressionCompiler
public CompiledExpression()
{
Parser = new AntlrParser();
Parser.ReturnType = typeof(object);
}

public CompiledExpression(string expression)
Expand Down
2 changes: 2 additions & 0 deletions ExpressionEvaluator.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
<Compile Include="obj\Debug\ExprEvalLexer.cs" />
<Compile Include="obj\Debug\ExprEvalParser.cs" />
<Compile Include="Parser\AntlrParser.cs" />
<Compile Include="Parser\CompilerState.cs" />
<Compile Include="Parser\ExpressionHelper.cs" />
<Compile Include="Parser\ExpressionParseException.cs" />
<Compile Include="Parser\Expressions\AccessIdentifier.cs" />
Expand All @@ -89,6 +90,7 @@
</Compile>
<Compile Include="Parser\HelperMethods.cs" />
<Compile Include="Parser\MethodResolution.cs" />
<Compile Include="Parser\ParameterList.cs" />
<Compile Include="Parser\TypeConversion.cs" />
<Compile Include="Parser\TypeExtensions.cs" />
<Compile Include="Parser\TypeVariable.cs" />
Expand Down
2 changes: 2 additions & 0 deletions Parser/AntlrParser.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
Expand Down Expand Up @@ -56,5 +57,6 @@ public Expression Parse(Expression scope, bool isCall = false)
public CompiledExpressionType ExpressionType { get; set; }

public List<ParameterExpression> ExternalParameters { get; set; }
public Type ReturnType { get; set; }
}
}
64 changes: 64 additions & 0 deletions Parser/CompilerState.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;

namespace ExpressionEvaluator.Parser
{
internal class CompilerState
{
public LabelTarget ReturnTarget { get; set; }
public Stack<LabelTarget> BreakContext { get; private set; }
public Stack<LabelTarget> ContinueContext { get; private set; }
public LabelTarget CurrentBreak { get; private set; }
public LabelTarget CurrentContinue { get; private set; }

public CompilerState()
{
BreakContext = new Stack<LabelTarget>();
ContinueContext = new Stack<LabelTarget>();
}

public LabelTarget PushContinue()
{
CurrentContinue = Expression.Label();
ContinueContext.Push(CurrentContinue);
return CurrentContinue;
}

public LabelTarget PushBreak()
{
CurrentBreak = Expression.Label();
BreakContext.Push(CurrentBreak);
return CurrentBreak;
}

public void PopBreak()
{
CurrentBreak = BreakContext.Pop();
}

public void PopContinue()
{
CurrentContinue = ContinueContext.Pop();
}

public Expression Break()
{
if (BreakContext.Count == 0)
{
throw new Exception("No enclosing loop out of which to break or continue");
}
return Expression.Break(BreakContext.Peek());
}

public Expression Continue()
{
if (ContinueContext.Count == 0)
{
throw new Exception("No enclosing loop out of which to break or continue");
}
return Expression.Continue(ContinueContext.Peek());
}

}
}
92 changes: 65 additions & 27 deletions Parser/ExprEval.g3
Original file line number Diff line number Diff line change
Expand Up @@ -509,7 +509,44 @@ public expression_list returns [List<Expression> values]
first=expression { $values.Add($first.value); } (',' succeeding=expression { $values.Add($succeeding.value); })* ;

public assignment returns [Expression value]:
unary_expression assignment_operator expression { $value = ExpressionHelper.Assign($unary_expression.value, $expression.value); } ;
unary_expression assignment_operator expression {
switch($assignment_operator.text) {
case "=":
$value = ExpressionHelper.Assign($unary_expression.value, $expression.value);
break;
case "+=":
$value = ExpressionHelper.BinaryOperator($unary_expression.value, $expression.value, ExpressionType.AddAssign);
break;
case "-=":
$value = ExpressionHelper.BinaryOperator($unary_expression.value, $expression.value, ExpressionType.SubtractAssign);
break;
case "*=":
$value = ExpressionHelper.BinaryOperator($unary_expression.value, $expression.value, ExpressionType.MultiplyAssign);
break;
case "/=":
$value = ExpressionHelper.BinaryOperator($unary_expression.value, $expression.value, ExpressionType.DivideAssign);
break;
// Note: StringTemplate requires escaping the percent symbol
case "\%=":
$value = ExpressionHelper.BinaryOperator($unary_expression.value, $expression.value, ExpressionType.ModuloAssign);
break;
case "&=":
$value = ExpressionHelper.BinaryOperator($unary_expression.value, $expression.value, ExpressionType.AndAssign);
break;
case "|=":
$value = ExpressionHelper.BinaryOperator($unary_expression.value, $expression.value, ExpressionType.OrAssign);
break;
case "^=":
$value = ExpressionHelper.BinaryOperator($unary_expression.value, $expression.value, ExpressionType.PowerAssign);
break;
case "<<=":
$value = ExpressionHelper.BinaryOperator($unary_expression.value, $expression.value, ExpressionType.LeftShiftAssign);
break;
case ">>=":
$value = ExpressionHelper.BinaryOperator($unary_expression.value, $expression.value, ExpressionType.RightShiftAssign);
break;
}
} ;
public unary_expression returns [Expression value]:
//('(' arguments ')' ('[' | '.' | '(')) => primary_or_array_creation_expression
(cast_expression) => cast_expression { $value = $cast_expression.value; }
Expand All @@ -525,8 +562,8 @@ public unary_expression returns [Expression value]:
;
public cast_expression returns [Expression value]:
'(' type ')' unary_expression { $value = Expression.Convert($unary_expression.value, GetType($type.text)); } ;
public assignment_operator returns [Expression value]:
'=' | '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>' '>=' ;
public assignment_operator:
'=' | '+=' | '-=' | '*=' | '/=' | '%=' | '&=' | '|=' | '^=' | '<<=' | '>>=' ;
public pre_increment_expression returns [Expression value]:
'++' unary_expression ;
public pre_decrement_expression returns [Expression value]:
Expand Down Expand Up @@ -1259,20 +1296,11 @@ public if_statement returns [Expression value]:
public else_statement returns [Expression value]:
'else' embedded_statement { $value = $embedded_statement.value; };

public switch_statement returns [Expression value]:
public switch_statement returns [Expression value]
@init{ var breakTarget = compilerState.PushBreak(); }
@after{ compilerState.PopBreak(); }:
'switch' '(' expression ')' switch_block {
// TODO: Better switch handling???
var defaultCase = $switch_block.value.SingleOrDefault(x=>x.TestValues[0].Type == typeof(void));
var cases = $switch_block.value.Where(x=>x.TestValues[0].Type != typeof(void)).ToArray();

if(defaultCase == null)
{
$value = Expression.Switch($expression.value, cases);
}
else
{
$value = Expression.Switch($expression.value, defaultCase.Body, cases);
}
$value = ExpressionHelper.Switch(breakTarget, $expression.value, $switch_block.value);
};

public switch_block returns [List<SwitchCase> value]:
Expand Down Expand Up @@ -1304,26 +1332,26 @@ public iteration_statement returns [Expression value]:
| foreach_statement { $value = $foreach_statement.value; };

public while_statement returns [Expression value]
@init{ var breakTarget = Expression.Label(); var continueTarget = Expression.Label(); _breakContext.Push(breakTarget); _continueContext.Push(continueTarget); }
@after{ _continueContext.Pop(); _breakContext.Pop(); }:
@init{ var breakTarget = compilerState.PushBreak(); var continueTarget = compilerState.PushContinue(); }
@after{ compilerState.PopContinue(); compilerState.PopBreak(); }:
'while' '(' boolean_expression ')' embedded_statement
{ $value = ExpressionHelper.While(breakTarget, continueTarget, null, $boolean_expression.value, $embedded_statement.value); };

public do_statement returns [Expression value]
@init{ var breakTarget = Expression.Label(); var continueTarget = Expression.Label(); _breakContext.Push(breakTarget); _continueContext.Push(continueTarget); }
@after{ _continueContext.Pop(); _breakContext.Pop(); }:
@init{ var breakTarget = compilerState.PushBreak(); var continueTarget = compilerState.PushContinue(); }
@after{ compilerState.PopContinue(); compilerState.PopBreak(); }:
'do' embedded_statement 'while' '(' boolean_expression ')' ';'
{ $value = ExpressionHelper.DoWhile(breakTarget, continueTarget, $embedded_statement.value, $boolean_expression.value); };

public for_statement returns [Expression value]
@init{ var breakTarget = Expression.Label(); var continueTarget = Expression.Label(); _breakContext.Push(breakTarget); _continueContext.Push(continueTarget); }
@after{ _continueContext.Pop(); _breakContext.Pop(); }:
@init{ var breakTarget = compilerState.PushBreak(); var continueTarget = compilerState.PushContinue(); }
@after{ compilerState.PopContinue(); compilerState.PopBreak(); }:
'for' '(' for_initializer? ';' for_condition? ';' for_iterator? ')' embedded_statement
{ $value = ExpressionHelper.For(breakTarget, continueTarget, $for_initializer.value, $for_condition.value, $for_iterator.value, $embedded_statement.value); };

public foreach_statement returns [Expression value]
@init{ ParameterExpression parameter = null; var breakTarget = Expression.Label(); var continueTarget = Expression.Label(); _breakContext.Push(breakTarget); _continueContext.Push(continueTarget); }
@after{ _continueContext.Pop(); _breakContext.Pop(); }:
@init{ ParameterExpression parameter = null; var breakTarget = compilerState.PushBreak(); var continueTarget = compilerState.PushContinue(); }
@after{ compilerState.PopContinue(); compilerState.PopBreak(); }:
'foreach' '(' local_variable_type identifier 'in' expression ')'
{
var typeName = $local_variable_type.value.Identifier;
Expand Down Expand Up @@ -1384,18 +1412,28 @@ public jump_statement returns [Expression value]:
| throw_statement ;

public break_statement returns [Expression value]:
'break' ';' { $value = Expression.Break(_breakContext.Peek()); };
'break' ';' { $value = compilerState.Break(); };

public continue_statement returns [Expression value]:
'continue' ';' { $value = Expression.Continue(_continueContext.Peek()); };
'continue' ';' { $value = compilerState.Continue(); };

public goto_statement:
'goto' ( identifier
| 'case' constant_expression
| 'default') ';' ;

public return_statement returns [Expression value]:
'return' expression? ';' ;
'return' expression? {
HasReturn = true;
if($expression.value == null)
{
$value = Expression.Return(ReturnTarget);
}
else
{
$value = Expression.Return(ReturnTarget, $expression.value, ReturnTarget.Type);
}
} ';' ;

public throw_statement:
'throw' expression? ';' ;
Expand Down
69 changes: 16 additions & 53 deletions Parser/ExprEval.g3.parser.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using System.Linq.Expressions;
using Antlr.Runtime;
using ExpressionEvaluator;
Expand All @@ -9,16 +9,27 @@ namespace ExpressionEvaluator.Parser
{
public partial class ExprEvalParser
{
private Stack<LabelTarget> _breakContext = new Stack<LabelTarget>();
private Stack<LabelTarget> _continueContext = new Stack<LabelTarget>();
private CompilerState compilerState = new CompilerState();

public Expression Scope { get; set; }
public bool IsCall { get; set; }

public LabelTarget ReturnTarget { get; set; }
public bool HasReturn { get; private set; }
public TypeRegistry TypeRegistry { get; set; }

public List<ParameterExpression> ExternalParameters { get; set; }

//partial void EnterRule(string ruleName, int ruleIndex)
//{
// base.TraceIn(ruleName, ruleIndex);
// Debug.WriteLine("In: {0} {1}", ruleName, ruleIndex);
//}

//partial void LeaveRule(string ruleName, int ruleIndex)
//{
// Debug.WriteLine("Out: {0} {1}", ruleName, ruleIndex);
//}

public override void ReportError(RecognitionException e)
{
base.ReportError(e);
Expand All @@ -30,7 +41,7 @@ public override void ReportError(RecognitionException e)
}
else
{
message = string.Format("Error parsing token '{0}", e.Token.Text);
message = string.Format("Error parsing token '{0}'", e.Token.Text);
}

throw new ExpressionParseException(message, input);
Expand Down Expand Up @@ -73,52 +84,4 @@ public Type GetType(string type)
private ParameterList ParameterList = new ParameterList();

}

public class ParameterList
{
private readonly List<ParameterExpression> _parameters = new List<ParameterExpression>();

public void Add(ParameterExpression parameter)
{
ParameterExpression p;
if (!ParameterLookup.TryGetValue(parameter.Name, out p))
{
_parameters.Add(parameter);
}
else
{
throw new Exception(string.Format("Parameter \"{0}\" conflicts with an existing parameter", parameter.Name));
}

}

public void Add(List<ParameterExpression> list)
{
foreach (var parameterExpression in list)
{
Add(parameterExpression);
}
}

private Dictionary<string, ParameterExpression> ParameterLookup { get { return _parameters.ToDictionary(expression => expression.Name); } }

public bool TryGetValue(string name, out ParameterExpression parameter)
{
return ParameterLookup.TryGetValue(name, out parameter);
}

public void Remove(List<ParameterExpression> list)
{
foreach (var parameterExpression in list)
{
ParameterExpression p;

if (ParameterLookup.TryGetValue(parameterExpression.Name, out p))
{
_parameters.Remove(parameterExpression);
}
}
}

}
}
Loading

0 comments on commit 21a77f6

Please sign in to comment.