using System; using System.Diagnostics; using System.IO; using System.Collections.Generic; using System.Linq; using System.Text; using System.Configuration; using System.Threading; using System.Threading.Tasks; using miew.String; using miew.Enumerable; using miew.Tokenization; using miew.Concurrency; using Resources = agree.Properties.Resources; namespace agree { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public abstract class CommandToken { //static int next_id = 0; public CommandToken(ISysObj iso) { this.iso = iso; //this.id = Interlocked.Increment(ref next_id); } public ISysObj Context { get { return iso; } } readonly public ISysObj iso; //readonly public int id; protected Task t; String error_message = null; public String ErrorMessage { get { return error_message; } } public Task Task { get { return t; } protected set { t = value; } } public bool IsComplete { get { return t == null || t.IsCompleted; } } public void TransactionStatus(String fmt, params Object[] args) { SystemInstance.TransactionStatus(this, fmt, args); } public void AddTransaction(CommandToken ct) { SystemInstance.AddTransaction(this, ct); } public void Abort(params String[] args) { error_message = String.Format(args[0], args.Skip(1).ToArray()); if (args != null && args.Length > 0) SystemInstance.TransactionStatus(this, error_message); t = Tasks.CompletedTask; } public SysObj SystemInstance { get { SysObj o; ISysObj t = iso; while ((o = t as SysObj) == null) t = t.SysObjParent; return o; } } //public void Execute() //{ // if (t.Status == TaskStatus.Created) // t.Start(); //} } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public abstract class CommandToken<T> : CommandToken { public CommandToken(ISysObj so) : base(so) { } public new Task<T> Task { get { if (t == null) throw new Exception(); return t as Task<T>; } protected set { t = value; } } internal void _complete_and_post(T result) { t = Tasks.FromResult<T>(result); SystemInstance.TransactionStatus(this); } internal void _complete_and_post(String fmt, params Object[] args) { Debug.Assert(typeof(T) == typeof(String)); t = Tasks.FromResult<String>(String.Format(fmt, args)); SystemInstance.TransactionStatus(this); } public Task<CommandToken> QueueResultInteraction(String s) { return Task.ContinueWith<CommandToken>(x => { var next_cmd = new SysCommands.CmdTokInteractive((ISysObj)x.Result, s); return next_cmd.Task.Result; }, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public abstract class CommandSet { protected SysObj _so; public CommandSet(SysObj so) { this._so = so; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class SysCommands : CommandSet { public SysCommands(SysObj so) : base(so) { } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokNop : CommandToken { public CmdTokNop(ISysObj iso) : base(iso) { } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokDisplayMessage : CommandToken<String> { public CmdTokDisplayMessage(ISysObj iso, String resource_key, params Object[] args) : base(iso) { _complete_and_post(String.Format(SystemInstance.ResourceManager.GetString(resource_key), args)); } public CmdTokDisplayMessage(ISysObj iso) : base(iso) { } public void SetMessage(String fmt, params Object[] args) { _complete_and_post(String.Format(fmt, args)); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokInteractive : CommandToken<CommandToken> { public CmdTokInteractive(ISysObj iso, String s_input) : base(iso) { this.t = Tasks.FromResult<CommandToken>(CommandFromString(iso, s_input)); } CommandToken CommandFromString(ISysObj iso, String s_input) { s_input = s_input.Trim(); if (s_input.Length == 0) return new CmdTokNop(iso); if (s_input.StartsWith("/")) s_input = "/ " + s_input.Substring(1); String[] rgs = s_input.Split(default(Char[]), StringSplitOptions.RemoveEmptyEntries); if (rgs.Length == 0) return new CmdTokNop(iso); String cmd = rgs[0].ToLower(); rgs = rgs.Skip(1).ToArray(); if (cmd == ".." || cmd == iso.SysObjParent.SysObjName) return new CmdTokChangeDefaultObject(iso, iso.SysObjParent); CommandToken ct; switch (cmd) { case "version": return new CmdTokDisplayVersionInfo(SystemInstance); case "pwd": return new CmdTokDisplayCurrentPath(SystemInstance); case "cd": if (rgs.Length != 1) return new CmdTokDisplayMessage(SystemInstance, Resources.ihelpmsg_cd); return new CmdTokChangeCurrentPath(SystemInstance, rgs[0]); case "help": { CmdTokDisplayMessage xd = new CmdTokDisplayMessage(SystemInstance); ct = xd; if (rgs.Length == 0) { xd.SetMessage(Resources.ihelpmsg_help); } else { String sub_help_topic = rgs.StringJoin("_").ToLower(); String sub_help = SystemInstance.ResourceManager.GetString("ihelpmsg_" + sub_help_topic); if (sub_help != null) xd.SetMessage(sub_help); else xd.SetMessage(Resources.ihelpmsg_unknown_help_topic, sub_help_topic); } } break; case "/": case "select": if (rgs.Length == 1) return new CmdTokChangeDefaultObject(SystemInstance, rgs[0]); ct = new CmdTokDisplayMessage(SystemInstance, Resources.msg_need_target, "select"); break; case "load": { if (rgs.Length == 0 || rgs.Length > 2) { ct = new CmdTokDisplayMessage(SystemInstance, Resources.ihelpmsg_load); } else { ct = new CmdTokLoadGrammar(SystemInstance, rgs[0], rgs.Length == 2 ? rgs[1] : null); } } break; case "cls": return new CmdTokClearConsole(SystemInstance); case "unload": return new CmdTokUnloadGrammar(iso); case "save": ct = null; break; case "names": case "*": return new CmdTokQueryNamePrefix(iso, cmd); case "show": if (rgs.Length == 1) { CmdTokQueryNamePrefix qp = new CmdTokQueryNamePrefix(iso, rgs[0]); if (qp != null && qp.Task.Result.Length == 1) return new CmdTokShowItem(iso, qp.Task.Result[0]); } ct = new CmdTokDisplayMessage(SystemInstance); (ct as CmdTokDisplayMessage).SetMessage(Resources.msg_need_name, cmd); break; case "parse": return new CmdTokParse(iso, rgs.StringJoin(" ")); case "info": return new CmdTokDisplayGrammarInfo(iso); default: { CmdTokQueryNamePrefix rp = new CmdTokQueryNamePrefix(iso, cmd); if (rp != null) { if (rp.Task.Result.Length == 1) { ISysObj so_new = rp.Task.Result[0]; if (so_new.SysObjChildren.Any()) return new CmdTokChangeDefaultObject(SystemInstance, so_new); return new CmdTokShowItem(iso, so_new); } else if (rp.Task.Result.Length > 0) return rp; } } ct = new CmdTokDisplayMessage(SystemInstance); (ct as CmdTokDisplayMessage).SetMessage(Resources.errmsg_unknown_cmd, cmd, iso.SysObjName); break; } return ct; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokLoadGrammar : CommandToken<Grammar> { public CmdTokLoadGrammar(ISysObj iso, String filename, String name = null, Config config = null) : base(iso) { if (name == null) name = Path.GetFileNameWithoutExtension(filename); Grammar g = new Grammar(SystemInstance, name, config); if (!g.config.system.MultiThreading) { g.Load(this, filename); TaskCompletionSource<Grammar> tcs = new TaskCompletionSource<Grammar>(); tcs.SetResult(g); t = tcs.Task; } else { t = new Task<Grammar>(() => { try { g.Load(this, filename); } catch (Exception ex) { TransactionStatus(ex.Message); } return g; }); t.Start(); } } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokUnloadGrammar : CommandToken<bool> { public CmdTokUnloadGrammar(ISysObj target) : base(target) { this.g = target as Grammar; bool f_result = false; if (target == null) { TransactionStatus(Resources.msg_need_target, "unload"); } else { Grammar g = target as Grammar; if (g == null) TransactionStatus(Resources.ihelpmsg_cannot_unload); else f_result = true; } t = Tasks.FromResult<bool>(f_result); } public Grammar g; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokSaveGrammar : CommandToken { public CmdTokSaveGrammar(ISysObj iso, Grammar target, String filename) : base(iso) { if (target == null) { Abort(Resources.msg_need_target, "save"); t = Tasks.FromResult<bool>(false); return; } Grammar g = target as Grammar; if (g == null) { TransactionStatus(Resources.ihelpmsg_cannot_save); t = Tasks.FromResult<bool>(false); return; } else { t = Task.Factory.StartNew(() => { g.Save(this, filename); }); } } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokDisplayVersionInfo : CmdTokDisplayMessage { public CmdTokDisplayVersionInfo(ISysObj iso) : base(iso) { _complete_and_post(SystemInstance.VersionInfo()); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokDisplayCurrentPath : CmdTokDisplayMessage { public CmdTokDisplayCurrentPath(ISysObj iso) : base(iso) { _complete_and_post(Environment.CurrentDirectory); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokChangeCurrentPath : CmdTokDisplayMessage { public CmdTokChangeCurrentPath(ISysObj iso, String s) : base(iso) { s = Path.Combine(Environment.CurrentDirectory, s); s += Path.DirectorySeparatorChar; s = Path.GetFullPath(s); String msg; if (Directory.Exists(s)) { Environment.CurrentDirectory = s; msg = Environment.CurrentDirectory; } else { s = s.Trim(Path.DirectorySeparatorChar); msg = String.Format(Resources.msg_path_not_found, s); } _complete_and_post(msg); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokDisplayGrammarInfo : CmdTokDisplayMessage { public CmdTokDisplayGrammarInfo(ISysObj target) : base(target) { if (target == null) { Abort(Resources.msg_need_target, "info"); return; } Grammar g = target as Grammar; String s; if (g == null) s = Resources.ihelpmsg_no_info; else s = g.GetInfo(); _complete_and_post(s); } } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokClearConsole : CommandToken { public CmdTokClearConsole(SysObj so) : base(so) { t = Tasks.CompletedTask; } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokQueryNamePrefix : CommandToken<ISysObj[]> { public CmdTokQueryNamePrefix(ISysObj target, String s_pfx) : base(target) { if (target == null) { Abort(Resources.msg_need_target, "names"); } else { t = Tasks.FromResult<ISysObj[]>(SysObjHelper<ISysObj>.GetNamePrefixMatches(target, s_pfx).ToArray()); } } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokShowItem : CommandToken<ISysObj> { public CmdTokShowItem(ISysObj target, ISysObj obj) : base(target) { if (target == null) { Abort(Resources.msg_need_target, "show"); } else { t = Tasks.FromResult<ISysObj>(obj); } } public CmdTokShowItem(ISysObj target, IDerivation obj) : base(target) { if (target == null) { Abort(Resources.msg_need_target, "show"); } else { t = Tasks.FromResult<IDerivation>(obj); } } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokShowHighlightedItem : CommandToken { public ISysObj obj_parent; public ISysObj obj_highlight; public CmdTokShowHighlightedItem(ISysObj target, ISysObj obj_parent, ISysObj obj_highlight) : base(target) { this.obj_parent = obj_parent; this.obj_highlight = obj_highlight; if (target == null) { Abort(Resources.msg_need_target, "show"); } else { t = Tasks.CompletedTask; } } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokParse : CommandToken<ParseControl> { public CmdTokParse(ISysObj grm, String s) : base(grm) { if (grm == null) { Abort(Resources.msg_need_target, "parse"); return; } if (String.IsNullOrEmpty(s)) { Abort(Resources.msg_nothing_to_parse); return; } Grammar g = grm as Grammar; if (g == null) { Abort(Resources.msg_cannot_parse, grm.SysObjName, SysObj.GetObjectTypeName(grm)); } else { try { t = g.Parse(s); } catch (ParseException ex) { Abort(ex.Message); } catch (DebuggingTfsDisplayException ex) { var exhl = ex as DebuggingTfsDisplayExceptionWithHighlighting; if (exhl != null) AddTransaction(new CmdTokShowHighlightedItem(grm, exhl.Tfs[0], exhl.TfsHighlight)); else { foreach (var te in ex.Tfs) AddTransaction(new CmdTokShowItem(grm, te)); } Abort("parse interrupted"); } } } public CmdTokParse(ISysObj grm, TokenSet ts) : base(grm) { if (grm == null) { Abort(Resources.msg_need_target, "parse"); return; } if (ts == null || ts.Count == 0) { Abort(Resources.msg_nothing_to_parse); return; } Grammar g = grm as Grammar; if (g == null) { Abort(Resources.msg_cannot_parse, grm.SysObjName, SysObj.GetObjectTypeName(grm)); } else { try { t = g.Parse(ts); } catch (ParseException ex) { Abort(ex.Message); } catch (DebuggingTfsDisplayException ex) { var exhl = ex as DebuggingTfsDisplayExceptionWithHighlighting; if (exhl != null) AddTransaction(new CmdTokShowHighlightedItem(grm, exhl.Tfs[0], exhl.TfsHighlight)); else { foreach (var te in ex.Tfs) AddTransaction(new CmdTokShowItem(grm, te)); } Abort("parse interrupted"); } } } }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class CmdTokChangeDefaultObject : CommandToken<ISysObj> { public CmdTokChangeDefaultObject(ISysObj target, ISysObj so_new) : base(target) { Finish(target, so_new); } public CmdTokChangeDefaultObject(ISysObj target, String s_obj) : base(target) { if (target == null) { Abort(Resources.msg_need_target, "select"); return; } ISysObj so_new; if (!target.SysObjChildren.TryGetValue(s_obj, out so_new)) { Abort(Resources.errmsg_name_not_found, s_obj, target.SysObjName); return; } Finish(target, so_new); } public void Finish(ISysObj target, ISysObj so_new) { if (target == null) { Abort(Resources.msg_need_target, "select"); return; } t = Tasks.FromResult<ISysObj>(so_new); } }; }; /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// /// </summary> /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// public class GrammarCommands : SysCommands { public GrammarCommands(SysObj so) : base(so) { } }; }