mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Implement parsing of method calls
Parsing methods calls of the form: <identifier> '(' arg [, arg, ...] ')' <identifier> arg [, arg, ...] --HG-- branch : dev
This commit is contained in:
@@ -1,10 +1,8 @@
|
|||||||
using System;
|
using System.Diagnostics;
|
||||||
using System.Diagnostics;
|
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Orchard.Widgets.SimpleScripting;
|
|
||||||
using Orchard.Widgets.SimpleScripting.Compiler;
|
using Orchard.Widgets.SimpleScripting.Compiler;
|
||||||
|
|
||||||
namespace Orchard.Tests.Modules.SimpleScriptingTests {
|
namespace Orchard.Tests.Modules.SimpleScripting {
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class EvaluatorTests {
|
public class EvaluatorTests {
|
||||||
[Test]
|
[Test]
|
||||||
|
@@ -1,11 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Orchard.Widgets.SimpleScripting;
|
|
||||||
using Orchard.Widgets.SimpleScripting.Ast;
|
using Orchard.Widgets.SimpleScripting.Ast;
|
||||||
using Orchard.Widgets.SimpleScripting.Compiler;
|
using Orchard.Widgets.SimpleScripting.Compiler;
|
||||||
|
|
||||||
namespace Orchard.Tests.Modules.SimpleScriptingTests {
|
namespace Orchard.Tests.Modules.SimpleScripting {
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class ParserTests {
|
public class ParserTests {
|
||||||
[Test]
|
[Test]
|
||||||
@@ -26,6 +25,37 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParserShouldUnderstandCommandExpressions() {
|
||||||
|
var tree = new Parser("print 'foo', 'bar'").Parse();
|
||||||
|
CheckTree(tree, new object[] {
|
||||||
|
"call", TokenKind.Identifier, "print",
|
||||||
|
"const", "foo",
|
||||||
|
"const", "bar",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParserShouldUnderstandCallExpressions() {
|
||||||
|
var tree = new Parser("print('foo', 'bar')").Parse();
|
||||||
|
CheckTree(tree, new object[] {
|
||||||
|
"call", TokenKind.Identifier, "print",
|
||||||
|
"const", "foo",
|
||||||
|
"const", "bar",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ParserShouldUnderstandCallExpressions2() {
|
||||||
|
var tree = new Parser("print 1+2").Parse();
|
||||||
|
CheckTree(tree, new object[] {
|
||||||
|
"call", TokenKind.Identifier, "print",
|
||||||
|
"binop", TokenKind.Plus,
|
||||||
|
"const", 1,
|
||||||
|
"const", 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void ParserShouldUnderstandOperatorPrecedence() {
|
public void ParserShouldUnderstandOperatorPrecedence() {
|
||||||
var tree = new Parser("1+2*3").Parse();
|
var tree = new Parser("1+2*3").Parse();
|
||||||
@@ -133,6 +163,9 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
|
|||||||
case "unop":
|
case "unop":
|
||||||
type = typeof(UnaryAstNode);
|
type = typeof(UnaryAstNode);
|
||||||
break;
|
break;
|
||||||
|
case "call":
|
||||||
|
type = typeof(MethodCallAstNode);
|
||||||
|
break;
|
||||||
case "error":
|
case "error":
|
||||||
type = typeof(ErrorAstNode);
|
type = typeof(ErrorAstNode);
|
||||||
break;
|
break;
|
||||||
@@ -151,6 +184,10 @@ namespace Orchard.Tests.Modules.SimpleScriptingTests {
|
|||||||
else if (exprName == "unop") {
|
else if (exprName == "unop") {
|
||||||
Assert.That((astNode as UnaryAstNode).Operator.Kind, Is.EqualTo(objects[index++]));
|
Assert.That((astNode as UnaryAstNode).Operator.Kind, Is.EqualTo(objects[index++]));
|
||||||
}
|
}
|
||||||
|
else if (exprName == "call") {
|
||||||
|
Assert.That((astNode as MethodCallAstNode).Token.Kind, Is.EqualTo(objects[index++]));
|
||||||
|
Assert.That((astNode as MethodCallAstNode).Token.Value, Is.EqualTo(objects[index++]));
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var child in astNode.Children) {
|
foreach (var child in astNode.Children) {
|
||||||
CheckExpression(child, indent + 1, objects, ref index);
|
CheckExpression(child, indent + 1, objects, ref index);
|
||||||
|
@@ -1,8 +1,7 @@
|
|||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
using Orchard.Widgets.SimpleScripting;
|
|
||||||
using Orchard.Widgets.SimpleScripting.Compiler;
|
using Orchard.Widgets.SimpleScripting.Compiler;
|
||||||
|
|
||||||
namespace Orchard.Tests.Modules.SimpleScriptingTests {
|
namespace Orchard.Tests.Modules.SimpleScripting {
|
||||||
[TestFixture]
|
[TestFixture]
|
||||||
public class TokenizerTests {
|
public class TokenizerTests {
|
||||||
|
|
||||||
|
@@ -80,6 +80,7 @@
|
|||||||
<Compile Include="SimpleScripting\Ast\ConstantAstNode.cs" />
|
<Compile Include="SimpleScripting\Ast\ConstantAstNode.cs" />
|
||||||
<Compile Include="SimpleScripting\Ast\AstVisitor.cs" />
|
<Compile Include="SimpleScripting\Ast\AstVisitor.cs" />
|
||||||
<Compile Include="SimpleScripting\Ast\ErrorAstNode.cs" />
|
<Compile Include="SimpleScripting\Ast\ErrorAstNode.cs" />
|
||||||
|
<Compile Include="SimpleScripting\Ast\MethodCallAstNode.cs" />
|
||||||
<Compile Include="SimpleScripting\Compiler\Interpreter.cs" />
|
<Compile Include="SimpleScripting\Compiler\Interpreter.cs" />
|
||||||
<Compile Include="SimpleScripting\Compiler\InterpreterVisitor.cs" />
|
<Compile Include="SimpleScripting\Compiler\InterpreterVisitor.cs" />
|
||||||
<Compile Include="SimpleScripting\Compiler\Lexer.cs" />
|
<Compile Include="SimpleScripting\Compiler\Lexer.cs" />
|
||||||
|
@@ -1,7 +1,4 @@
|
|||||||
using System;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Orchard.Widgets.SimpleScripting.Ast {
|
namespace Orchard.Widgets.SimpleScripting.Ast {
|
||||||
public class AstVisitor {
|
public class AstVisitor {
|
||||||
@@ -28,5 +25,9 @@ namespace Orchard.Widgets.SimpleScripting.Ast {
|
|||||||
public virtual object VisitUnary(UnaryAstNode node) {
|
public virtual object VisitUnary(UnaryAstNode node) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual object VisitMethodCall(MethodCallAstNode node) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@@ -0,0 +1,24 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Orchard.Widgets.SimpleScripting.Compiler;
|
||||||
|
|
||||||
|
namespace Orchard.Widgets.SimpleScripting.Ast {
|
||||||
|
public class MethodCallAstNode : AstNode, IAstNodeWithToken {
|
||||||
|
private readonly Token _token;
|
||||||
|
private readonly IList<AstNode> _arguments;
|
||||||
|
|
||||||
|
public MethodCallAstNode(Token token, IList<AstNode> arguments) {
|
||||||
|
_token = token;
|
||||||
|
_arguments = arguments;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Token Token { get { return _token; } }
|
||||||
|
|
||||||
|
public override IEnumerable<AstNode> Children {
|
||||||
|
get { return _arguments; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override object Accept(AstVisitor visitor) {
|
||||||
|
return visitor.VisitMethodCall(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -1,4 +1,5 @@
|
|||||||
using System.Collections.Generic;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using Orchard.Widgets.SimpleScripting.Ast;
|
using Orchard.Widgets.SimpleScripting.Ast;
|
||||||
|
|
||||||
namespace Orchard.Widgets.SimpleScripting.Compiler {
|
namespace Orchard.Widgets.SimpleScripting.Compiler {
|
||||||
@@ -29,8 +30,7 @@ namespace Orchard.Widgets.SimpleScripting.Compiler {
|
|||||||
var expr = ParseKeywordAndExpression();
|
var expr = ParseKeywordAndExpression();
|
||||||
|
|
||||||
var token = IsMatch(TokenKind.Or);
|
var token = IsMatch(TokenKind.Or);
|
||||||
if (token != null)
|
if (token != null) {
|
||||||
{
|
|
||||||
var right = ParseKeywordOrExpression();
|
var right = ParseKeywordOrExpression();
|
||||||
|
|
||||||
expr = new BinaryAstNode(expr, token, right);
|
expr = new BinaryAstNode(expr, token, right);
|
||||||
@@ -66,8 +66,6 @@ namespace Orchard.Widgets.SimpleScripting.Compiler {
|
|||||||
private AstNode ParseRelationalExpression() {
|
private AstNode ParseRelationalExpression() {
|
||||||
var expr = ParseAdditiveExpression();
|
var expr = ParseAdditiveExpression();
|
||||||
//TODO
|
//TODO
|
||||||
//var Token = IsMatch(TokenKind.Not);
|
|
||||||
//if (Token != null) {
|
|
||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,11 +111,41 @@ namespace Orchard.Widgets.SimpleScripting.Compiler {
|
|||||||
return ProduceConstant(token);
|
return ProduceConstant(token);
|
||||||
case TokenKind.OpenParen:
|
case TokenKind.OpenParen:
|
||||||
return ParseParenthesizedExpression();
|
return ParseParenthesizedExpression();
|
||||||
|
case TokenKind.Identifier:
|
||||||
|
return ParseMethodCallExpression();
|
||||||
default:
|
default:
|
||||||
return ProduceError(token);
|
return ProduceError(token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private AstNode ParseParenthesizedExpression() {
|
||||||
|
Match(TokenKind.OpenParen);
|
||||||
|
var expr = ParseExpression();
|
||||||
|
Match(TokenKind.CloseParen);
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AstNode ParseMethodCallExpression() {
|
||||||
|
var target = _lexer.Token();
|
||||||
|
_lexer.NextToken();
|
||||||
|
|
||||||
|
bool hasParenthesis = (IsMatch(TokenKind.OpenParen) != null);
|
||||||
|
|
||||||
|
var arguments = new List<AstNode>();
|
||||||
|
while (true) {
|
||||||
|
var argument = ParseExpression();
|
||||||
|
arguments.Add(argument);
|
||||||
|
|
||||||
|
if (IsMatch(TokenKind.Comma) == null)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasParenthesis)
|
||||||
|
Match(TokenKind.CloseParen);
|
||||||
|
|
||||||
|
return new MethodCallAstNode(target, arguments);
|
||||||
|
}
|
||||||
|
|
||||||
private AstNode ProduceConstant(Token token) {
|
private AstNode ProduceConstant(Token token) {
|
||||||
_lexer.NextToken();
|
_lexer.NextToken();
|
||||||
return new ConstantAstNode(token);
|
return new ConstantAstNode(token);
|
||||||
@@ -125,15 +153,7 @@ namespace Orchard.Widgets.SimpleScripting.Compiler {
|
|||||||
|
|
||||||
private AstNode ProduceError(Token token) {
|
private AstNode ProduceError(Token token) {
|
||||||
_lexer.NextToken();
|
_lexer.NextToken();
|
||||||
return new ErrorAstNode(token,
|
return new ErrorAstNode(token, string.Format("Unexptected Token in primary expression ({0})", token));
|
||||||
string.Format("Unexptected Token in primary expression ({0})", token));
|
|
||||||
}
|
|
||||||
|
|
||||||
private AstNode ParseParenthesizedExpression() {
|
|
||||||
Match(TokenKind.OpenParen);
|
|
||||||
var expr = ParseExpression();
|
|
||||||
Match(TokenKind.CloseParen);
|
|
||||||
return expr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Match(TokenKind kind) {
|
private void Match(TokenKind kind) {
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
StringLiteral,
|
StringLiteral,
|
||||||
SingleQuotedStringLiteral,
|
SingleQuotedStringLiteral,
|
||||||
Integer,
|
Integer,
|
||||||
|
Comma,
|
||||||
Plus,
|
Plus,
|
||||||
Minus,
|
Minus,
|
||||||
Mul,
|
Mul,
|
||||||
|
@@ -27,6 +27,9 @@ namespace Orchard.Widgets.SimpleScripting.Compiler {
|
|||||||
case ')':
|
case ')':
|
||||||
NextCharacter();
|
NextCharacter();
|
||||||
return CreateToken(TokenKind.CloseParen);
|
return CreateToken(TokenKind.CloseParen);
|
||||||
|
case ',':
|
||||||
|
NextCharacter();
|
||||||
|
return CreateToken(TokenKind.Comma);
|
||||||
case '+':
|
case '+':
|
||||||
NextCharacter();
|
NextCharacter();
|
||||||
return CreateToken(TokenKind.Plus);
|
return CreateToken(TokenKind.Plus);
|
||||||
|
Reference in New Issue
Block a user