Exemple #1
0
        /// <summary>导入某类型,导入程序集引用及命名空间引用,主要处理泛型</summary>
        /// <param name="item"></param>
        /// <param name="type"></param>
        void ImportType(TemplateItem item, Type type)
        {
            String name = null;
            try
            {
                name = type.Assembly.Location;
            }
            catch { }

            if (!String.IsNullOrEmpty(name) && !AssemblyReferences.Contains(name)) AssemblyReferences.Add(name);
            name = type.Namespace;
            if (!item.Imports.Contains(name)) item.Imports.Add(name);

            if (type.IsGenericType && !type.IsGenericTypeDefinition)
            {
                Type[] ts = type.GetGenericArguments();
                foreach (Type elm in ts)
                {
                    if (!elm.IsGenericParameter) ImportType(item, elm);
                }
            }
        }
Exemple #2
0
        private static String ConstructGeneratorCode(TemplateItem item, Boolean lineNumbers, String namespaceName, CodeDomProvider provider)
        {
            // 准备类名和命名空间
            CodeNamespace codeNamespace = new CodeNamespace(namespaceName);

            // 加入引用的命名空间
            foreach (String str in item.Imports)
            {
                if (!String.IsNullOrEmpty(str)) codeNamespace.Imports.Add(new CodeNamespaceImport(str));
            }
            CodeTypeDeclaration typeDec = new CodeTypeDeclaration(item.ClassName);
            typeDec.IsClass = true;
            codeNamespace.Types.Add(typeDec);

            // 基类
            if (!String.IsNullOrEmpty(item.BaseClassName))
                typeDec.BaseTypes.Add(new CodeTypeReference(item.BaseClassName));
            else if (!String.IsNullOrEmpty(BaseClassName))
                typeDec.BaseTypes.Add(new CodeTypeReference(BaseClassName));
            else
                typeDec.BaseTypes.Add(new CodeTypeReference(typeof(TemplateBase)));

            if (!String.IsNullOrEmpty(item.Name)) typeDec.LinePragma = new CodeLinePragma(item.Name, 1);

            // Render方法
            CreateRenderMethod(item.Blocks, lineNumbers, typeDec);

            // 代码生成选项
            CodeGeneratorOptions options = new CodeGeneratorOptions();
            options.VerbatimOrder = true;
            options.BlankLinesBetweenMembers = false;
            options.BracingStyle = "C";

            // 其它类成员代码块
            Boolean firstMemberFound = false;
            foreach (Block block in item.Blocks)
            {
                firstMemberFound = GenerateMemberForBlock(block, typeDec, lineNumbers, provider, options, firstMemberFound);
            }

            // 模版变量
            if (item.Vars != null && item.Vars.Count > 0)
            {
                // 构建静态构造函数,初始化静态属性Vars
                CreateCctorMethod(typeDec, item.Vars);

                //public Int32 VarName
                //{
                //    get { return (Int32)GetData("VarName"); }
                //    set { Data["VarName"] = value; }
                //}
                foreach (String v in item.Vars.Keys)
                {
                    TypeX vtype = TypeX.Create(item.Vars[v]);
                    String codeName = vtype.FullName;

                    StringBuilder sb = new StringBuilder();
                    sb.AppendLine();
                    sb.AppendFormat("public {0} {1}", codeName, v);
                    sb.AppendLine("{");
                    sb.AppendFormat("    get {{ return GetData<{0}>(\"{1}\"); }}", codeName, v);
                    sb.AppendLine();
                    sb.AppendFormat("    set {{ Data[\"{0}\"] = value; }}", v);
                    sb.AppendLine();
                    sb.AppendLine("}");

                    CodeSnippetTypeMember member = new CodeSnippetTypeMember(sb.ToString());
                    typeDec.Members.Add(member);
                }
            }

            // 输出
            using (StringWriter writer = new StringWriter())
            {
                provider.GenerateCodeFromNamespace(codeNamespace, new IndentedTextWriter(writer), options);
                return writer.ToString();
            }
        }
Exemple #3
0
        private TemplateItem ProcessDirective(Directive directive, TemplateItem item)
        {
            #region 包含include
            if (String.Equals(directive.Name, "include", StringComparison.OrdinalIgnoreCase))
            {
                String name = directive.GetParameter("name");
                // 可能采用了相对路径
                if (!File.Exists(name)) name = Path.Combine(Path.GetDirectoryName(item.Name), name);

                String content = null;
                TemplateItem ti = FindTemplateItem(name);
                if (ti != null)
                {
                    ti.Included = true;
                    content = ti.Content;
                }
                else
                {
                    // 尝试读取文件
                    if (File.Exists(name))
                    {
                        ti = new TemplateItem();
                        ti.Name = name;
                        ti.Content = File.ReadAllText(name);
                        Templates.Add(ti);

                        ti.Included = true;
                        content = ti.Content;
                    }
                }
                // 允许内容为空
                //if (String.IsNullOrEmpty(content)) throw new TemplateException(directive.Block, String.Format("加载模版[{0}]失败!", name));

                return ti;
            }
            #endregion

            if (String.Equals(directive.Name, "assembly", StringComparison.OrdinalIgnoreCase))
            {
                String name = directive.GetParameter("name");
                if (!AssemblyReferences.Contains(name)) AssemblyReferences.Add(name);
            }
            else if (String.Equals(directive.Name, "import", StringComparison.OrdinalIgnoreCase))
            {
                item.Imports.Add(directive.GetParameter("namespace"));
            }
            else if (String.Equals(directive.Name, "template", StringComparison.OrdinalIgnoreCase))
            {
                if (!item.Processed)
                {
                    // 由模版指令指定类名
                    String name = directive.GetParameter("name");
                    if (!String.IsNullOrEmpty(name)) item.ClassName = name;

                    //item.BaseClassName = directive.GetParameter("inherits");
                    if (directive.TryGetParameter("inherits", out name)) item.BaseClassName = name;
                    item.Processed = true;
                }
                else
                    throw new TemplateException(directive.Block, "多个模版指令!");
            }
            else if (String.Equals(directive.Name, "var", StringComparison.OrdinalIgnoreCase))
            {
                String name = directive.GetParameter("name");
                String type = directive.GetParameter("type");

                if (item.Vars.ContainsKey(name)) throw new TemplateException(directive.Block, "模版变量" + name + "已存在!");

                Type ptype = TypeX.GetType(type, true);
                if (ptype == null) throw new TemplateException(directive.Block, "无法找到模版变量类型" + type + "!");

                // 因为TypeX.GetType的强大,模版可能没有引用程序集和命名空间,甚至type位于未装载的程序集中它也会自动装载,所以这里需要加上
                ImportType(item, ptype);
                item.Vars.Add(name, ptype);
            }
            return null;
        }
Exemple #4
0
        /// <summary>处理指令</summary>
        /// <param name="item"></param>
        /// <returns>返回指令集合</returns>
        private void ProcessDirectives(TemplateItem item)
        {
            // 使用包含堆栈处理包含,检测循环包含
            Stack<String> includeStack = new Stack<String>();
            includeStack.Push(item.Name);

            String[] directives = new String[] { "template", "assembly", "import", "include", "var" };

            for (Int32 i = 0; i < item.Blocks.Count; i++)
            {
                Block block = item.Blocks[i];
                if (block.Type != BlockType.Directive) continue;

                // 弹出当前块的模版名
                while (includeStack.Count > 0 && !String.Equals(includeStack.Peek(), block.Name, StringComparison.OrdinalIgnoreCase))
                {
                    includeStack.Pop();
                }
                Directive directive = TemplateParser.ParseDirectiveBlock(block);
                if (directive == null || Array.IndexOf(directives, directive.Name.ToLower()) < 0)
                    throw new TemplateException(block, String.Format("无法识别的指令:{0}!", block.Text));

                // 包含指令时,返回多个代码块
                //List<Block> list = ProcessDirective(directive, item);
                TemplateItem ti = ProcessDirective(directive, item);
                if (ti == null) continue;
                //List<Block> list = TemplateParser.Parse(ti.Name, ti.Content);
                // 拆分成块
                if (ti.Blocks == null || ti.Blocks.Count < 1) ti.Blocks = TemplateParser.Parse(ti.Name, ti.Content);
                if (ti.Blocks == null || ti.Blocks.Count < 1) continue;

                List<Block> list = ti.Blocks;
                String name = ti.Name;
                if (includeStack.Contains(name)) throw new TemplateException(block, String.Format("循环包含名为[{0}]的模版!", name));

                includeStack.Push(name);

                // 包含模版并入当前模版
                item.Blocks.InsertRange(i + 1, list);
            }
        }
Exemple #5
0
        /// <summary>处理指定模版</summary>
        /// <param name="item">模版项</param>
        private void Process(TemplateItem item)
        {
            // 拆分成块
            item.Blocks = TemplateParser.Parse(item.Name, item.Content);

            // 处理指令
            ProcessDirectives(item);
            //TemplateParser.StripExtraNewlines(item.Blocks);

            if (Imports != null) item.Imports.AddRange(Imports);
            //if (References != null) context.References.AddRange(References);

            // 生成代码
            item.Source = ConstructGeneratorCode(item, Debug, NameSpace, Provider);
        }
Exemple #6
0
        /// <summary>
        /// 添加模版项,实际上是添加到Templates集合中。
        /// 未指定模版名称时,使用模版的散列作为模版名称
        /// </summary>
        /// <param name="name"></param>
        /// <param name="content"></param>
        public void AddTemplateItem(String name, String content)
        {
            if (String.IsNullOrEmpty(name) && String.IsNullOrEmpty(content))
                throw new ArgumentNullException("content", "名称和模版内容不能同时为空!");

            if (Status >= TemplateStatus.Process) throw new InvalidOperationException("模版已分析处理,不能再添加模版!");

            // 未指定模版名称时,使用模版的散列作为模版名称
            if (String.IsNullOrEmpty(name)) name = Hash(content);

            TemplateItem item = FindTemplateItem(name);
            if (item == null)
            {
                item = new TemplateItem();
                Templates.Add(item);
            }
            item.Name = name;
            item.Content = content;

            // 设置类名
            var cname = Path.GetFileNameWithoutExtension(name);
            // 如果无扩展的名称跟前面的名称不同,并且无扩展名称跟编码后的类名相同,则设置类型为无扩展名称
            if (cname != name && cname == GetClassName(cname))
            {
                // 如果没有别的模版项用这个类名,这里使用
                if (!Templates.Any(t => t.ClassName == cname)) item.ClassName = cname;
            }

            // 设置程序集名,采用最后一级目录名
            if (String.IsNullOrEmpty(AssemblyName))
            {
                var dname = Path.GetDirectoryName(name);
                if (!String.IsNullOrEmpty(dname))
                {
                    dname = Path.GetFileName(dname);
                    if (!String.IsNullOrEmpty(dname)) AssemblyName = dname;
                }
            }
        }
Exemple #7
0
        static String FindBlockCodeInItem(String name, Int32 lineNumber, TemplateItem item)
        {
            var nocmpName = String.IsNullOrEmpty(name);
            for (var i = 0; i < item.Blocks.Count; i++)
            {
                var line = item.Blocks[i].StartLine;
                if (line >= lineNumber && (nocmpName || item.Blocks[i].Name == name))
                {
                    // 错误所在段
                    var n = i;
                    if (line > lineNumber)
                    {
                        n--;
                        line = item.Blocks[n].StartLine;
                    }

                    var code = item.Blocks[n].Text;
                    var codeLines = code.Split(new String[] { Environment.NewLine }, StringSplitOptions.None);

                    var sb = new StringBuilder();
                    // 错误行在第一行,需要上一段的最后一行
                    if (n > 0 && line == lineNumber)
                    {
                        var code2 = item.Blocks[n - 1].Text;
                        var codeLines2 = code2.Split(new String[] { Environment.NewLine }, StringSplitOptions.None);
                        sb.AppendLine((lineNumber - 1) + ":" + codeLines2[codeLines2.Length - 1]);
                    }
                    // 错误行代码段
                    {
                        // 错误行不在第一行,需要上一行
                        if (line < lineNumber) sb.AppendLine((lineNumber - 1) + ":" + codeLines[lineNumber - line - 1]);
                        // 错误行
                        sb.AppendLine(lineNumber + ":" + codeLines[lineNumber - line]);
                        // 错误行不在最后一行,需要下一行
                        if (line + codeLines.Length > lineNumber) sb.AppendLine((lineNumber + 1) + ":" + codeLines[lineNumber - line + 1]);
                    }
                    // 错误行在最后一行以后的,需要下一段的第一行
                    if (n < item.Blocks.Count - 1 && line + codeLines.Length <= lineNumber)
                    {
                        var code2 = item.Blocks[n + 1].Text;
                        var codeLines2 = code2.Split(new String[] { Environment.NewLine }, StringSplitOptions.None);
                        sb.AppendLine((lineNumber + 1) + ":" + codeLines2[0]);
                    }
                    return sb.ToString();
                }
            }
            return null;
        }