using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using Irony.Compiler;
using ScriptNET.Runtime;
using ScriptNET.Ast;
using ScriptNET.Processing;
namespace ScriptNET
{
///
/// Compiled script
///
public class Script
{
#region Properties
///
/// Ast of the given Source Code
///
public ScriptAst Ast { get; set; }
///
/// Code of the script
///
public string SourceCode { get; set; }
///
/// Execution context
///
public IScriptContext Context { get; set; }
#endregion
#region Constructors
///
/// Default constructor
///
protected Script()
{
Context = new ScriptContext();
Runtime.RuntimeHost.InitializeScript(Context);
}
///
/// Script Constructor
///
/// Context in which script will execute
protected Script(IScriptContext context)
{
if (context == null)
throw new ArgumentNullException("context");
this.Context = context;
}
#endregion
#region Methods
///
/// Executes current script returning result
///
/// result of execution
public object Execute()
{
object rez = Ast.Execute(Context);
EventBroker.ClearAllEventsIfNeeded();
return rez;
}
///
/// Returns source code for given node
///
/// Node
/// source code
public string Code(ScriptAst node)
{
return SourceCode.Substring(node.Span.Start.Position, node.Span.Length);
}
///
/// String representing syntax tree
///
public string SyntaxTree
{
get
{
return Ast.ConcreteSyntaxTree();
}
}
#endregion
#region Service Methods
//TODO: Consider This
//scriptEngine.SetValue(”theObject.LastName”, “Malkovich”) - would set the property theObject.LastName to “Malkovich”.
//The same with methods: scriptEngine.Call(”theObject.AddPhoneNumber”, “+489983293″)
///
/// Compiles code and performs post processing
///
///
/// instance of vistor
///
public static Script Compile(string code, IEnumerable postProcessings, bool isExpression)
{
Script script = new Script();
script.SourceCode = code;
RuntimeHost.Lock();
try
{
script.Ast = (ScriptAst)Parse(code, isExpression);
if (postProcessings != null)
{
foreach (var postProcessing in postProcessings)
{
postProcessing.BeginProcessing(script);
script.Ast.AcceptVisitor(postProcessing);
postProcessing.EndProcessing(script);
}
}
}
finally
{
RuntimeHost.UnLock();
}
return script;
}
///
/// Compiles Script.NET code into AST representation
///
/// Code string
/// Compiled Script. Throws Script Exception on Syntax Errors
public static Script Compile(string code)
{
return Compile(code, new IPostProcessing[] { new FunctionDeclarationVisitor() }, false);
}
public static Script CompileExpression(string code)
{
return Compile(code, null, true);
}
///
/// Executes script code
///
///
///
public static object RunCode(string code)
{
return RunCode(code, null, false);
}
public static object RunCode(string code, bool isExpression)
{
return RunCode(code, null, isExpression);
}
public static object RunCode(string code, IScriptContext context)
{
return RunCode(code, context, false);
}
public static object RunCode(string code, IScriptContext context, bool isExpression)
{
Script script = isExpression ? CompileExpression(code) : Compile(code);
if (context != null)
script.Context = context;
return script.Execute();
}
///
/// Parses code
///
/// Script code
/// AstNode or throws:ArgumentException, ScriptSyntaxErrorException
protected internal static AstNode Parse(string code, bool isExpression)
{
if (string.IsNullOrEmpty(code)) throw new ArgumentNullException("code");
LanguageCompiler compiler = null;
if (isExpression)
compiler = ScriptdotnetGrammar.ExpressionCompiler;
else
compiler = ScriptdotnetGrammar.Compiler;
AstNode result = compiler.Parse(code);
if (result == null)
{
StringBuilder errorMessage = new StringBuilder("Parsing error:");
foreach (SyntaxError error in compiler.Context.Errors)
{
errorMessage.AppendLine(error.Message);
errorMessage.AppendLine(string.Format("at line:{0} position:{1} in code:",
error.Location.Line,
error.Location.Position));
errorMessage.AppendLine(code.Substring(error.Location.Position, Math.Min(50, code.Length - error.Location.Position)));
}
throw new ScriptSyntaxErrorException(errorMessage.ToString());
}
return result;
}
#endregion
}
}