"插件IDE"jxml语言(js+xml) 类定义

    昨天介绍了我的web插件化构想.在实现中为了底层能和用户编写的代码进行方便的交互.我把面向对象里的类融合进来了.
    最初,面向开发者的编程,打算直接使用js.后来发现底层不能很方便的与开发者写的代码进行交互.
    思考2天后,我使用xml描述类结构.底层通过类的描述生成动态的js对象.这样就可以很方便的与底层C#交互了.
    最后我把这种编程方式命名为 "jrxml"

< jrxml:classes  xmlns:jrxml ="http://tmp" >
     < jrxml:method  access ="private"  name ="loadTpl"  modifier ="readonly" />
     < jrxml:method  access ="internal"  name ="render"  modifier ="fixed" >
        // <![CDATA[
        return '<div id="root">render</div>';
        //
]]>
     </ jrxml:method >
     < jrxml:method  access ="internal"  name ="domReady"  params ="htmlDoc"  modifier ="fixed" >
        // <![CDATA[
        htmlDoc.getElementById('root').innerHTML='domReady<br/>--------------<br/>---------- by jaws';
        this.onCreate.fire();
        //
]]>
     </ jrxml:method >
     < jrxml:method  access ="internal"  name ="ctor"  modifier ="fixed" ><!--构造函数-->
        this.width=100;
     </ jrxml:method >
     < jrxml:method  name ="update"  modifier ="readonly" />
     < jrxml:event  name ="onCreate" />
     < jrxml:prop  name ="width" />
     < jrxml:prop  name ="config" >
         < jrxml:setter >
            return value+100;
         </ jrxml:setter >
         < jrxml:getter >
            return value;
         </ jrxml:getter >
     </ jrxml:prop >
</ jrxml:classes >

 

上面是一个完整的类结构

xml元素:

    <classes 根节点
    <method 方法定义

    <prop 属性定义 属性可以在method节点里,this.xxxx,可以set和get

    <event 事件  事件可以在method节点力,this.xxxx.subscribe(function(){});进行订阅,和调用this.xxxx.fire();

xml节点属性:

    name="" 类成员名

    access="public|private|internal" 访问控制, 公共|私有|内部

    modifier="none|fixed|readonly" 修饰符, 无|固定|只读

    因为本身只是简单的类结构模拟,所以没有考虑结构,抽象类,继承. 所以加入fixed和readonly特性,对于标示2个特性的成员,开发者不可对此成员进行修改.


上面是对类结构的描述,接下来需要有一个编译过程.

    在C#代码中要初始化一个类的顺序为:

    验证类结构-> js运行时-> 编译 ->创建js object

    验证类结构:

    其实就是验证xml,对于classes的xml结构定义了一个xsd,验证的话直接C#用xsd验证xml结构即可.

    下面是classes_schema.xsd

 

View Code
< xs:schema  xmlns:xs ="http://www.w3.org/2001/XMLSchema"  xmlns:xs2 ="http://tmp"  targetNamespace ="http://tmp" >

     < xs:attributeGroup  name ="attr_typeb" >
         < xs:attribute  name ="access"  default ="public" >
             < xs:simpleType >
                 < xs:restriction  base ="xs:string" >
                     < xs:enumeration  value ="public" />
                     < xs:enumeration  value ="private" />
                     < xs:enumeration  value ="internal" />
                 </ xs:restriction >
             </ xs:simpleType >
         </ xs:attribute >
         < xs:attribute  name ="modifier"  default ="none" >
             < xs:simpleType >
                 < xs:restriction  base ="xs:string" >
                     < xs:enumeration  value ="none" />
                     < xs:enumeration  value ="fixed" />
                     < xs:enumeration  value ="readonly" />
                 </ xs:restriction >
             </ xs:simpleType >
         </ xs:attribute >
     </ xs:attributeGroup >

     < xs:attributeGroup  name ="attr_name" >
         < xs:attribute  name ="name"  use ="required" >
             < xs:simpleType >
                 < xs:restriction  base ="xs:string" >
                     < xs:pattern  value ="[a-zA-Z_][a-zA-Z0-9_]{0,49}"   />
                 </ xs:restriction >
             </ xs:simpleType >
         </ xs:attribute >
     </ xs:attributeGroup >

     < xs:complexType  name ="setget" >
         < xs:simpleContent >
             < xs:extension  base ="xs:string" >
                 < xs:attributeGroup  ref ="xs2:attr_typeb" />
             </ xs:extension >
         </ xs:simpleContent >
     </ xs:complexType >

     < xs:element  name ="classes" >
         < xs:complexType >
             < xs:choice  minOccurs ="0"  maxOccurs ="unbounded" >
                 < xs:element  name ="prop"  minOccurs ="0"  maxOccurs ="unbounded" >
                     < xs:complexType >
                         < xs:all >
                             < xs:element  name ="setter"  type ="xs2:setget"  minOccurs ="0"  maxOccurs ="1" />
                             < xs:element  name ="getter"  type ="xs2:setget"  minOccurs ="0"  maxOccurs ="1" />
                         </ xs:all >
                         < xs:attributeGroup  ref ="xs2:attr_name" />
                         < xs:attributeGroup  ref ="xs2:attr_typeb" />
                     </ xs:complexType >
                 </ xs:element >
                 < xs:element  name ="event"  minOccurs ="0"  maxOccurs ="unbounded" >
                     < xs:complexType >
                         < xs:attributeGroup  ref ="xs2:attr_name" />
                         < xs:attributeGroup  ref ="xs2:attr_typeb" />
                     </ xs:complexType >
                 </ xs:element >
                 < xs:element  name ="method"  minOccurs ="0"  maxOccurs ="unbounded" >
                     < xs:complexType >
                         < xs:simpleContent >
                             < xs:extension  base ="xs:string" >
                                 < xs:attributeGroup  ref ="xs2:attr_name" />
                                 < xs:attribute  name ="params" >
                                     < xs:simpleType >
                                         < xs:restriction  base ="xs:string" >
                                             < xs:pattern  value ="([a-zA-Z_][a-zA-Z0-9_]{0,45}|[a-zA-Z_][a-zA-Z0-9_]{0,45}, )+[^, ]" />
                                         </ xs:restriction >
                                     </ xs:simpleType >
                                 </ xs:attribute >
                                 < xs:attributeGroup  ref ="xs2:attr_typeb" />
                             </ xs:extension >
                         </ xs:simpleContent >
                     </ xs:complexType >
                 </ xs:element >
             </ xs:choice >
         </ xs:complexType >
     </ xs:element >
</ xs:schema >

 

     js运行时: 服务端js引擎使用开源的Jurassic

    这里挺曲折的,最早我用的IronJS引擎.据说效率很好,用了之后发现效率真的很烂.开始怀疑是我使用方式错了.
    最后时用官方的例子来跑,结果一样慢.我把.net几个开源的js引擎做了个简单对比就改用Jurassic了.

 

            var jsEngine= new js.ScriptEngine(); 

    编译:

    读取xml类结构,根据不同的节点,生成相应的对象.  下面贴出相应的代码片段   

 

View Code
        pe.result_rt CompileMethod(pe.jtype type)
        {
             var ret =  new pe.result_rt { succ =  true };
             var method = (pe.jmethod)type;
             try
            {
                 var ls =  new List< string>();
                 foreach ( var item  in method.param_list)
                {
                    ls.Add(item);
                }
                ls.Add(method.body);
                 var fun = Engine.Function.Construct(ls.ToArray());

                 if (_methodDic.ContainsKey(method.name))
                {
                    DefineProperty(method.name,  new PropertyDescriptor(_methodDic[method.name], PropertyAttributes.Enumerable),  true);
                }
                 else  if (method.access_type != pe.jaccess_type.jinternal)
                {
                    DefineProperty(method.name,  new PropertyDescriptor(fun, PropertyAttributes.Enumerable),  true);
                }
                 else
                {
                    _methodDic.Add(method.name, fun);
                }
            }
             catch (Exception ex)
            {
                ret.succ =  false;
                 #region code mark
                ret.markline_list.Add( new pe.result_rt_markline
                {
                    line = method.line -  1,
                    type =  " err ",
                    msg = ex.Message
                });
                 #endregion
            }
             return ret;
        }

        pe.result_rt CompileEvent(pe.jtype type)
        {
             var ret =  new pe.result_rt { succ =  true };
             var evt = (pe.jevent)type;
            DefineProperty(evt.name,  new PropertyDescriptor( new ClassesEvent( this, evt.name, Engine), PropertyAttributes.Enumerable),  true);
             return ret;
        }

        pe.result_rt CompileSetterGetter( string name, pe.jsgtter sgtter)
        {
             var ret =  new pe.result_rt { succ =  true };
             if (sgtter !=  null && sgtter.body !=  "")
            {
                 try
                {
                     var fun = Engine.Function.Construct( " value ", sgtter.body);
                    _propSGDic.Add(name, fun);
                }
                 catch (Exception ex)
                {
                    ret.succ =  false;
                     #region code mark
                    ret.markline_list.Add( new pe.result_rt_markline
                    {
                        line = sgtter.line -  1,
                        type =  " err ",
                        msg = ex.Message
                    });
                     #endregion
                }
            }
             return ret;
        }

        pe.result_rt CompileProp(pe.jtype type)
        {
             var ret =  new pe.result_rt { succ =  true };
             var prop = (pe.jprop)type;
             var pName = prop.name;
            ret = CompileSetterGetter( " set " + pName, prop.setter);
             if (!ret.succ)
            {
                 return ret;
            }
            ret = CompileSetterGetter( " get " + pName, prop.getter);
             if (!ret.succ)
            {
                 return ret;
            }

             var c = prop.access_type == pe.jaccess_type.jpublic ?  1 :  0;
            c += prop.setter ==  null || prop.setter.access_type == pe.jaccess_type.jpublic ?  1 :  0;
            c += prop.getter ==  null || prop.getter.access_type == pe.jaccess_type.jpublic ?  1 :  0;
             if (c ==  3)
            {
                _publicPropNameIdDic.Add(pName, type.id);
            }

            _propValueDic.Add(pName, Null.Value);


             var setter =  new ClrFunction(Engine.Function.InstancePrototype,  new Action< object>(value =>
            {
                SetPropValue(pName, value);
            }));

             var getter =  new ClrFunction(Engine.Function.InstancePrototype,  new Func< object>(() =>
            {
                 return GetPropValue(pName);
            }));

            DefineProperty(prop.name,  new PropertyDescriptor(getter, setter, js.lib.PropertyAttributes.Enumerable),  true);

             return ret;
        }

 

 

 

    思路很简单,只是一个简单的实现.希望能给一些朋友带来帮助.

 

你可能感兴趣的:(xml)