A few fixes and renames

--HG--
branch : dev
This commit is contained in:
Renaud Paquay
2010-11-27 17:36:55 -08:00
parent ca1d1987bf
commit 334726e08a
8 changed files with 104 additions and 69 deletions

View File

@@ -135,6 +135,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="CodeGeneration\Commands\CodeGenerationCommandsTests.cs" /> <Compile Include="CodeGeneration\Commands\CodeGenerationCommandsTests.cs" />
<Compile Include="SimpleScriptingTests\ExpressionEvaluatorTests.cs" />
<Compile Include="SimpleScriptingTests\ExpressionParserTests.cs" /> <Compile Include="SimpleScriptingTests\ExpressionParserTests.cs" />
<Compile Include="SimpleScriptingTests\ExpressionLexerTests.cs" /> <Compile Include="SimpleScriptingTests\ExpressionLexerTests.cs" />
<Compile Include="SimpleScriptingTests\SimpleScriptingTests.cs" /> <Compile Include="SimpleScriptingTests\SimpleScriptingTests.cs" />

View File

@@ -0,0 +1,13 @@
using NUnit.Framework;
using Orchard.Widgets.SimpleScripting;
namespace Orchard.Tests.Modules.SimpleScriptingTests {
[TestFixture]
public class ExpressionEvaluatorTests {
[Test]
public void EvaluateSimpleConstant() {
var tree = new ExpressionParser("1*2+3").Parse();
}
}
}

View File

@@ -35,9 +35,9 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
public void LexerShouldProcessReservedWords() { public void LexerShouldProcessReservedWords() {
TestReservedWord("true", true, TokenKind.True); TestReservedWord("true", true, TokenKind.True);
TestReservedWord("false", false, TokenKind.False); TestReservedWord("false", false, TokenKind.False);
TestReservedWord("not", "not", TokenKind.Not); TestReservedWord("not", null, TokenKind.Not);
TestReservedWord("and", "and", TokenKind.And); TestReservedWord("and", null, TokenKind.And);
TestReservedWord("or", "or", TokenKind.Or); TestReservedWord("or", null, TokenKind.Or);
} }
private void TestReservedWord(string expression, object value, TokenKind expectedTokenKind) { private void TestReservedWord(string expression, object value, TokenKind expectedTokenKind) {
@@ -58,7 +58,7 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
[Test] [Test]
public void LexerShouldProcesSequenceOfTokens2() { public void LexerShouldProcesSequenceOfTokens2() {
CheckTokenSequence("1+2*3", TokenKind.NumberLiteral, TokenKind.Plus, TokenKind.NumberLiteral, TokenKind.Mul, TokenKind.NumberLiteral); CheckTokenSequence("1+2*3", TokenKind.Integer, TokenKind.Plus, TokenKind.Integer, TokenKind.Mul, TokenKind.Integer);
} }

View File

@@ -10,7 +10,7 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
public void ParserShouldUnderstandConstantExpressions() { public void ParserShouldUnderstandConstantExpressions() {
var tree = new ExpressionParser("true").Parse(); var tree = new ExpressionParser("true").Parse();
CheckTree(tree, new object[] { CheckTree(tree, new object[] {
typeof(ExpressionTree.ContantExpression), true, "const", true,
}); });
} }
@@ -18,9 +18,9 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
public void ParserShouldUnderstandBinaryExpressions() { public void ParserShouldUnderstandBinaryExpressions() {
var tree = new ExpressionParser("true+true").Parse(); var tree = new ExpressionParser("true+true").Parse();
CheckTree(tree, new object[] { CheckTree(tree, new object[] {
typeof(ExpressionTree.BinaryExpression), TokenKind.Plus, "binop", TokenKind.Plus,
typeof(ExpressionTree.ContantExpression), true, "const", true,
typeof(ExpressionTree.ContantExpression), true, "const", true,
}); });
} }
@@ -28,11 +28,11 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
public void ParserShouldUnderstandOperatorPrecedence() { public void ParserShouldUnderstandOperatorPrecedence() {
var tree = new ExpressionParser("1+2*3").Parse(); var tree = new ExpressionParser("1+2*3").Parse();
CheckTree(tree, new object[] { CheckTree(tree, new object[] {
typeof(ExpressionTree.BinaryExpression), TokenKind.Plus, "binop", TokenKind.Plus,
typeof(ExpressionTree.ContantExpression), 1, "const", 1,
typeof(ExpressionTree.BinaryExpression), TokenKind.Mul, "binop", TokenKind.Mul,
typeof(ExpressionTree.ContantExpression), 2, "const", 2,
typeof(ExpressionTree.ContantExpression), 3, "const", 3,
}); });
} }
@@ -40,11 +40,11 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
public void ParserShouldUnderstandOperatorPrecedence2() { public void ParserShouldUnderstandOperatorPrecedence2() {
var tree = new ExpressionParser("1*2+3").Parse(); var tree = new ExpressionParser("1*2+3").Parse();
CheckTree(tree, new object[] { CheckTree(tree, new object[] {
typeof(ExpressionTree.BinaryExpression), TokenKind.Plus, "binop", TokenKind.Plus,
typeof(ExpressionTree.BinaryExpression), TokenKind.Mul, "binop", TokenKind.Mul,
typeof(ExpressionTree.ContantExpression), 1, "const", 1,
typeof(ExpressionTree.ContantExpression), 2, "const", 2,
typeof(ExpressionTree.ContantExpression), 3, "const", 3,
}); });
} }
@@ -52,10 +52,10 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
public void ParserShouldUnderstandOperatorPrecedence3() { public void ParserShouldUnderstandOperatorPrecedence3() {
var tree = new ExpressionParser("not true or true").Parse(); var tree = new ExpressionParser("not true or true").Parse();
CheckTree(tree, new object[] { CheckTree(tree, new object[] {
typeof(ExpressionTree.BinaryExpression), TokenKind.Or, "binop", TokenKind.Or,
typeof(ExpressionTree.UnaryExpression), TokenKind.Not, "unop", TokenKind.Not,
typeof(ExpressionTree.ContantExpression), true, "const", true,
typeof(ExpressionTree.ContantExpression), true, "const", true,
}); });
} }
@@ -63,10 +63,10 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
public void ParserShouldUnderstandOperatorPrecedence4() { public void ParserShouldUnderstandOperatorPrecedence4() {
var tree = new ExpressionParser("not (true or true)").Parse(); var tree = new ExpressionParser("not (true or true)").Parse();
CheckTree(tree, new object[] { CheckTree(tree, new object[] {
typeof(ExpressionTree.UnaryExpression), TokenKind.Not, "unop", TokenKind.Not,
typeof(ExpressionTree.BinaryExpression), TokenKind.Or, "binop", TokenKind.Or,
typeof(ExpressionTree.ContantExpression), true, "const", true,
typeof(ExpressionTree.ContantExpression), true, "const", true,
}); });
} }
@@ -74,11 +74,11 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
public void ParserShouldUnderstandParenthesis() { public void ParserShouldUnderstandParenthesis() {
var tree = new ExpressionParser("1*(2+3)").Parse(); var tree = new ExpressionParser("1*(2+3)").Parse();
CheckTree(tree, new object[] { CheckTree(tree, new object[] {
typeof(ExpressionTree.BinaryExpression), TokenKind.Mul, "binop", TokenKind.Mul,
typeof(ExpressionTree.ContantExpression), 1, "const", 1,
typeof(ExpressionTree.BinaryExpression), TokenKind.Plus, "binop", TokenKind.Plus,
typeof(ExpressionTree.ContantExpression), 2, "const", 2,
typeof(ExpressionTree.ContantExpression), 3, "const", 3,
}); });
} }
@@ -86,16 +86,16 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
public void ParserShouldUnderstandComplexExpressions() { public void ParserShouldUnderstandComplexExpressions() {
var tree = new ExpressionParser("not 1 * (2 / 4 * 6 + (3))").Parse(); var tree = new ExpressionParser("not 1 * (2 / 4 * 6 + (3))").Parse();
CheckTree(tree, new object[] { CheckTree(tree, new object[] {
typeof(ExpressionTree.UnaryExpression), TokenKind.Not, "unop", TokenKind.Not,
typeof(ExpressionTree.BinaryExpression), TokenKind.Mul, "binop", TokenKind.Mul,
typeof(ExpressionTree.ContantExpression), 1, "const", 1,
typeof(ExpressionTree.BinaryExpression), TokenKind.Plus, "binop", TokenKind.Plus,
typeof(ExpressionTree.BinaryExpression), TokenKind.Div, "binop", TokenKind.Div,
typeof(ExpressionTree.ContantExpression), 2, "const", 2,
typeof(ExpressionTree.BinaryExpression), TokenKind.Mul, "binop", TokenKind.Mul,
typeof(ExpressionTree.ContantExpression), 4, "const", 4,
typeof(ExpressionTree.ContantExpression), 6, "const", 6,
typeof(ExpressionTree.ContantExpression), 3, "const", 3,
}); });
} }
@@ -103,9 +103,9 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
public void ParserShouldContainErrorExpressions() { public void ParserShouldContainErrorExpressions() {
var tree = new ExpressionParser("1 + not 3").Parse(); var tree = new ExpressionParser("1 + not 3").Parse();
CheckTree(tree, new object[] { CheckTree(tree, new object[] {
typeof(ExpressionTree.BinaryExpression), TokenKind.Plus, "binop", TokenKind.Plus,
typeof(ExpressionTree.ContantExpression), 1, "const", 1,
typeof(ExpressionTree.ErrorExpression), "error",
}); });
} }
@@ -119,19 +119,34 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
} }
private void CheckExpression(ExpressionTree.Expression expression, int indent, object[] objects, ref int index) { private void CheckExpression(ExpressionTree.Expression expression, int indent, object[] objects, ref int index) {
var type = (Type)objects[index++]; var exprName = (string)objects[index++];
Type type = null;
switch(exprName) {
case "const":
type = typeof(ExpressionTree.ConstantExpression);
break;
case "binop":
type = typeof(ExpressionTree.BinaryExpression);
break;
case "unop":
type = typeof(ExpressionTree.UnaryExpression);
break;
case "error":
type = typeof(ExpressionTree.ErrorExpression);
break;
}
Trace.WriteLine(string.Format("{0}: {1}{2} (Current: {3})", indent, new string(' ', indent * 2), type.Name, expression)); Trace.WriteLine(string.Format("{0}: {1}{2} (Current: {3})", indent, new string(' ', indent * 2), type.Name, expression));
Assert.That(expression.GetType(), Is.EqualTo(type)); Assert.That(expression.GetType(), Is.EqualTo(type));
if (type == typeof(ExpressionTree.ContantExpression)) { if (exprName == "const") {
Assert.That((expression as ExpressionTree.ContantExpression).Value, Is.EqualTo(objects[index++])); Assert.That((expression as ExpressionTree.ConstantExpression).Value, Is.EqualTo(objects[index++]));
} }
else if (type == typeof(ExpressionTree.BinaryExpression)) { else if (exprName == "binop") {
Assert.That((expression as ExpressionTree.BinaryExpression).Operator.Kind, Is.EqualTo(objects[index++])); Assert.That((expression as ExpressionTree.BinaryExpression).Operator.Kind, Is.EqualTo(objects[index++]));
} }
else if (type == typeof(ExpressionTree.UnaryExpression)) { else if (exprName == "unop") {
Assert.That((expression as ExpressionTree.UnaryExpression).Operator.Kind, Is.EqualTo(objects[index++])); Assert.That((expression as ExpressionTree.UnaryExpression).Operator.Kind, Is.EqualTo(objects[index++]));
} }

View File

@@ -109,17 +109,25 @@ namespace Orchard.Widgets.SimpleScripting {
case TokenKind.False: case TokenKind.False:
case TokenKind.SingleQuotedStringLiteral: case TokenKind.SingleQuotedStringLiteral:
case TokenKind.StringLiteral: case TokenKind.StringLiteral:
case TokenKind.NumberLiteral: case TokenKind.Integer:
_lexer.NextToken(); return ProduceConstant(token);
return new ExpressionTree.ContantExpression(token);
case TokenKind.OpenParen: case TokenKind.OpenParen:
return ParseParenthesizedExpression(); return ParseParenthesizedExpression();
default: default:
return ProduceError(token);
}
}
private ExpressionTree.Expression ProduceConstant(ExpressionTokenizer.Token token) {
_lexer.NextToken();
return new ExpressionTree.ConstantExpression(token);
}
private ExpressionTree.Expression ProduceError(ExpressionTokenizer.Token token) {
_lexer.NextToken(); _lexer.NextToken();
return new ExpressionTree.ErrorExpression(token, return new ExpressionTree.ErrorExpression(token,
string.Format("Unexptected token in primary expression ({0})", token)); string.Format("Unexptected token in primary expression ({0})", token));
} }
}
private ExpressionTree.Expression ParseParenthesizedExpression() { private ExpressionTree.Expression ParseParenthesizedExpression() {
Match(TokenKind.OpenParen); Match(TokenKind.OpenParen);

View File

@@ -6,6 +6,7 @@ namespace Orchard.Widgets.SimpleScripting {
private readonly string _expression; private readonly string _expression;
private readonly StringBuilder _stringBuilder; private readonly StringBuilder _stringBuilder;
private int _index; private int _index;
private int _startTokenIndex;
public ExpressionTokenizer(string expression) { public ExpressionTokenizer(string expression) {
_expression = expression; _expression = expression;
@@ -17,6 +18,7 @@ namespace Orchard.Widgets.SimpleScripting {
return CreateToken(TokenKind.Eof); return CreateToken(TokenKind.Eof);
LexAgain: LexAgain:
_startTokenIndex = _index;
char ch = Character(); char ch = Character();
switch (ch) { switch (ch) {
case '(': case '(':
@@ -84,7 +86,7 @@ namespace Orchard.Widgets.SimpleScripting {
_stringBuilder.Append(Character()); _stringBuilder.Append(Character());
} }
else { else {
return CreateToken(TokenKind.NumberLiteral, Int32.Parse(_stringBuilder.ToString())); return CreateToken(TokenKind.Integer, Int32.Parse(_stringBuilder.ToString()));
} }
} }
} }
@@ -96,11 +98,11 @@ namespace Orchard.Widgets.SimpleScripting {
case "false": case "false":
return CreateToken(TokenKind.False, false); return CreateToken(TokenKind.False, false);
case "or": case "or":
return CreateToken(TokenKind.Or, identifier); return CreateToken(TokenKind.Or, null);
case "and": case "and":
return CreateToken(TokenKind.And, identifier); return CreateToken(TokenKind.And, null);
case "not": case "not":
return CreateToken(TokenKind.Not, identifier); return CreateToken(TokenKind.Not, null);
default: default:
return CreateToken(TokenKind.Identifier, identifier); return CreateToken(TokenKind.Identifier, identifier);
} }
@@ -201,7 +203,7 @@ namespace Orchard.Widgets.SimpleScripting {
private Token CreateToken(TokenKind kind, object value = null) { private Token CreateToken(TokenKind kind, object value = null) {
return new Token { return new Token {
Kind = kind, Kind = kind,
Position = _index, Position = _startTokenIndex,
Value = value Value = value
}; };
} }
@@ -216,7 +218,7 @@ namespace Orchard.Widgets.SimpleScripting {
public object Value { get; set; } public object Value { get; set; }
public override string ToString() { public override string ToString() {
return string.Format("{0} at position {1}", Value ?? Kind, Position); return string.Format("{0} ({1}) at position {2}", Kind, Value ?? "<noval>", Position);
} }
} }
} }

View File

@@ -24,11 +24,7 @@ namespace Orchard.Widgets.SimpleScripting {
var ewt = (this as IExpressionWithToken); var ewt = (this as IExpressionWithToken);
if (ewt != null) { if (ewt != null) {
sb.Append(" - "); sb.Append(" - ");
sb.Append(ewt.Token.Kind); sb.Append(ewt.Token);
if (ewt.Token.Value != null) {
sb.Append(" - ");
sb.Append(ewt.Token.Value);
}
} }
return sb.ToString(); return sb.ToString();
} }
@@ -57,10 +53,10 @@ namespace Orchard.Widgets.SimpleScripting {
} }
public class ContantExpression : Expression, IExpressionWithToken { public class ConstantExpression : Expression, IExpressionWithToken {
private readonly ExpressionTokenizer.Token _token; private readonly ExpressionTokenizer.Token _token;
public ContantExpression(ExpressionTokenizer.Token token) { public ConstantExpression(ExpressionTokenizer.Token token) {
_token = token; _token = token;
} }

View File

@@ -5,7 +5,7 @@
CloseParen, CloseParen,
StringLiteral, StringLiteral,
SingleQuotedStringLiteral, SingleQuotedStringLiteral,
NumberLiteral, Integer,
Plus, Plus,
Minus, Minus,
Mul, Mul,