Skip to content

Commit

Permalink
Merge pull request #771 from ztone/code-segments
Browse files Browse the repository at this point in the history
Mono engine using code segments to better parse scripts
  • Loading branch information
adamralph committed Jan 26, 2015
2 parents c085872 + 2931ec3 commit 483e284
Show file tree
Hide file tree
Showing 23 changed files with 1,174 additions and 321 deletions.
40 changes: 7 additions & 33 deletions src/ScriptCs.Engine.Mono/MonoScriptEngine.cs
Expand Up @@ -8,7 +8,7 @@
using Mono.Collections.Generic;
using MonoCSharp::Mono.CSharp;
using ScriptCs.Contracts;
using ScriptCs.Engine.Mono.Parser;
using ScriptCs.Engine.Mono.Segmenter;

namespace ScriptCs.Engine.Mono
{
Expand Down Expand Up @@ -126,39 +126,15 @@ protected virtual ScriptResult Execute(string code, Evaluator session)

try
{
var parser = new SyntaxParser();
var parseResult = parser.Parse(code);

if (parseResult.TypeDeclarations != null && parseResult.TypeDeclarations.Any())
{
foreach (var @class in parseResult.TypeDeclarations)
{
session.Compile(@class);
}
}

if (parseResult.MethodExpressions != null && parseResult.MethodExpressions.Any())
object scriptResult = null;
var segmenter = new ScriptSegmenter();
foreach (var segment in segmenter.Segment(code))
{
foreach (var prototype in parseResult.MethodPrototypes)
{
session.Run(prototype);
}

foreach (var method in parseResult.MethodExpressions)
{
session.Run(method);
}
}

if (!string.IsNullOrWhiteSpace(parseResult.Evaluations))
{
object scriptResult;
bool resultSet;

session.Evaluate(parseResult.Evaluations, out scriptResult, out resultSet);

return new ScriptResult(scriptResult);
session.Evaluate(segment.Code, out scriptResult, out resultSet);
}

return new ScriptResult(returnValue: scriptResult);
}
catch (AggregateException ex)
{
Expand All @@ -168,8 +144,6 @@ protected virtual ScriptResult Execute(string code, Evaluator session)
{
return new ScriptResult(executionException: ex);
}

return ScriptResult.Empty;
}

private void ImportNamespaces(IEnumerable<string> namespaces, SessionState<Evaluator> sessionState)
Expand Down
12 changes: 0 additions & 12 deletions src/ScriptCs.Engine.Mono/Parser/ParseResult.cs

This file was deleted.

121 changes: 0 additions & 121 deletions src/ScriptCs.Engine.Mono/Parser/SyntaxParser.cs

This file was deleted.

18 changes: 13 additions & 5 deletions src/ScriptCs.Engine.Mono/ScriptCs.Engine.Mono.csproj
Expand Up @@ -85,11 +85,19 @@
<Compile Include="MonoScriptEngine.cs" />
<Compile Include="MonoHost.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Parser\Visitors\ClassTypeVisitor.cs" />
<Compile Include="Parser\Visitors\MethodVisitor.cs" />
<Compile Include="Parser\ParseResult.cs" />
<Compile Include="Parser\SyntaxParser.cs" />
<Compile Include="Parser\Visitors\MethodVisitorResult.cs" />
<Compile Include="Segmenter\Lexer\Token.cs" />
<Compile Include="Segmenter\Lexer\LexerResult.cs" />
<Compile Include="Segmenter\Lexer\ScriptLexer.cs" />
<Compile Include="Segmenter\Analyser\MethodResult.cs" />
<Compile Include="Segmenter\SegmentResult.cs" />
<Compile Include="Segmenter\SegmentType.cs" />
<Compile Include="Segmenter\ScriptSegmenter.cs" />
<Compile Include="Segmenter\Parser\RegionParser.cs" />
<Compile Include="Segmenter\Parser\RegionResult.cs" />
<Compile Include="Segmenter\Analyser\Visitors\ClassTypeVisitor.cs" />
<Compile Include="Segmenter\Analyser\Visitors\MethodVisitor.cs" />
<Compile Include="Segmenter\Analyser\Visitors\MethodVisitorResult.cs" />
<Compile Include="Segmenter\Analyser\CodeAnalyzer.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
Expand Down
66 changes: 66 additions & 0 deletions src/ScriptCs.Engine.Mono/Segmenter/Analyser/CodeAnalyzer.cs
@@ -0,0 +1,66 @@
using System;
using System.Linq;

using ScriptCs.Engine.Mono.Segmenter.Analyser.Visitors;

using ICSharpCode.NRefactory.CSharp;

namespace ScriptCs.Engine.Mono.Segmenter.Analyser
{
public class CodeAnalyzer
{
public bool IsClass(string code)
{
var visitor = new ClassTypeVisitor();
var parser = new CSharpParser();
var syntaxTree = parser.Parse(code);
syntaxTree.AcceptVisitor(visitor);
syntaxTree.Freeze();

return visitor.GetClassDeclarations().Any();
}

public bool IsMethod(string code)
{
var @class = "class A { " + code + " } ";
var visitor = new MethodVisitor();
var parser = new CSharpParser();
var syntaxTree = parser.Parse(@class);
syntaxTree.AcceptVisitor(visitor);
syntaxTree.Freeze();

return visitor.GetMethodDeclarations().Any() && code.TrimEnd().EndsWith("}");
}

public MethodResult ExtractPrototypeAndMethod(string code)
{
var @class = "class A { " + code + " } ";
var visitor = new MethodVisitor();
var parser = new CSharpParser();
var syntaxTree = parser.Parse(@class);
syntaxTree.AcceptVisitor(visitor);
syntaxTree.Freeze();

var result = visitor.GetMethodDeclarations().FirstOrDefault();

// find newlines in method signature to maintain linenumbers
var newLines = code.Substring(0, code.IndexOf("{", StringComparison.Ordinal) - 1)
.Where(x => x.Equals('\n'))
.Aggregate(string.Empty, (a, c) => a + c);

// use code methodblock to maintain linenumbers
var codeBlock = code.Substring(code.IndexOf("{", StringComparison.Ordinal), code.LastIndexOf("}", StringComparison.Ordinal) - code.IndexOf("{", StringComparison.Ordinal) + 1);
var method = result.MethodExpression.GetText();
var blockStart = method.IndexOf("{", StringComparison.Ordinal);
var blockEnd = method.LastIndexOf("}", StringComparison.Ordinal);
method = method.Remove(blockStart, blockEnd - blockStart + 1);
method = method.Insert(blockStart, codeBlock);

return new MethodResult
{
ProtoType = result.MethodPrototype.GetText().Trim() + newLines,
MethodExpression = newLines + method.Trim()
};
}
}
}
9 changes: 9 additions & 0 deletions src/ScriptCs.Engine.Mono/Segmenter/Analyser/MethodResult.cs
@@ -0,0 +1,9 @@
namespace ScriptCs.Engine.Mono.Segmenter.Analyser
{
public class MethodResult
{
public string ProtoType { get; set; }

public string MethodExpression { get; set; }
}
}
@@ -1,9 +1,9 @@
namespace ScriptCs.Engine.Mono.Parser.Visitors
{
using System.Collections.Generic;
using System.Collections.Generic;

using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp;

namespace ScriptCs.Engine.Mono.Segmenter.Analyser.Visitors
{
internal class ClassTypeVisitor : DepthFirstAstVisitor
{
private readonly List<TypeDeclaration> _classes;
Expand Down
@@ -1,11 +1,11 @@
namespace ScriptCs.Engine.Mono.Parser.Visitors
{
using System;
using System.Collections.Generic;
using System.Linq;
using System;
using System.Collections.Generic;
using System.Linq;

using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp;

namespace ScriptCs.Engine.Mono.Segmenter.Analyser.Visitors
{
internal class MethodVisitor : DepthFirstAstVisitor
{
private readonly List<MethodVisitorResult> _methods;
Expand Down Expand Up @@ -58,7 +58,8 @@ public override void VisitMethodDeclaration(MethodDeclaration methodDeclaration)
.FirstOrDefault();
if (methodBody == null)
{
throw new NullReferenceException(string.Format("Method '{0}' has no method body", methodName));
// method has no method body
return;
}
methodBody = (BlockStatement)methodBody.Clone();

Expand Down
@@ -1,11 +1,13 @@
namespace ScriptCs.Engine.Mono.Parser.Visitors
{
using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.CSharp;

namespace ScriptCs.Engine.Mono.Segmenter.Analyser.Visitors
{
public class MethodVisitorResult
{
public MethodDeclaration MethodDefinition { get; set; }

public VariableDeclarationStatement MethodPrototype { get; set; }

public ExpressionStatement MethodExpression { get; set; }
}
}
10 changes: 10 additions & 0 deletions src/ScriptCs.Engine.Mono/Segmenter/Lexer/LexerResult.cs
@@ -0,0 +1,10 @@
namespace ScriptCs.Engine.Mono.Segmenter.Lexer
{
public class LexerResult
{
public int Token { get; set; }
public string TokenValue { get; set; }
public int Start { get; set; }
public int End { get; set; }
}
}

0 comments on commit 483e284

Please sign in to comment.