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 } }