Menu

FunctionList: Ruby parser

2013-12-01
2015-03-03
  • Menno Vogels

    Menno Vogels - 2013-12-01

    My take on the Ruby parser:

      <parser
          id="ruby_function"
          displayName="Ruby"
          commentExpr="(?s:#.*?[\r\n]|(?-i:(?&lt;=^|[\r\n])=begin).*?(?-i:[\r\n]=end(?=[\r\n]|$)))" >
        <function
            mainExpr="(?s:\b(?-i:def)[\t ]+(?!(?-i:alias|and|BEGIN|begin|break|case|class|def|defined\?|do|else|elsif|END|end|ensure|false|for|if|in|module|next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield|__FILE__|__LINE__))(?:[A-Za-z_]\w*[?!=]?(?:[\t ]*\([^)]*\))?|(?::{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?)[\t ]*\([^)]*\)).+?(?-i:end))"
            displayMode="$functionName" >
          <functionName>
            <nameExpr expr="(?s:\b(?-i:def)[\t ]+(?:[A-Za-z_]\w*[?!=]?(?:[\t ]*\()?|(?::{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?)[\t ]*\())" />
            <nameExpr expr="(?m:\b(?-i:def)[\t ]+(?:[A-Za-z_]\w*[?!=]?|(?::{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?))(?=(?:\b|[\t ]*\()|.*$))" />
            <nameExpr expr="[\t ]+(?:[A-Za-z_]\w*[?!=]?|(?::{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?))" />
            <nameExpr expr="(?:[A-Za-z_]\w*[?!=]?|(?::{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?))" />
          </functionName>
        </function>
      </parser>
    

    TODO:

    1. add 'class' support.
    2. add 'alias' support.

    The parser test file:

    # I am a comment. Just ignore me.
    
    # You can comment multiple lines as follows:
    
    # This is a comment.
    # This is a comment, too.
    # This is a comment, too.
    # I said that already.
    
    # Here is another form. This block comment conceals several lines from the
    # interpreter with =begin/=end:
    
    =begin
        __FILE__  and    def       end     in      or      self   unless
        alias  class
    This is a comment.
    This is a comment, too.
    This is a comment, too.
    Not again.
    =end
    
    # The syntax of a Ruby method is as follows:
    def MethodName1( arg1, arg2, arg3, ... )
    #  .. ruby code ..
       return value
    end
    
    def  MethodName2( arg1, arg2, arg3, ... )
    #  .. ruby code ..
       return value
    end
    
    def MethodName3 ( arg1, arg2, arg3, ... )
    #  .. ruby code ..
       return value
    end
    
    def         MethodName4 ( arg1, arg2, arg3, ... )
    #  .. ruby code ..
       return value
    end
    
    def multiply(val1, val2 )
         result = val1 * val2
         return result
    end
    
    alias docalc multiply # line comment
    
    class ClassName
       def ClassMethodName
            @@classVariable = 0.2               # class variable
       end
       def GetterMethodName                     # getter method
            @instanceVariable = "12345"         # instance variable
       end
       def SetterMethodName=( value )           # setter method
            @instanceVariable = value
       end
       def initialize ()
       end
       def InstanceMethodName ( argument )      # instance method
           puts argument * classVariable
       end
       def InstanceMethodName_NoArgs            # method
            puts "The class is working"
            puts instanceVariable
       end
    end
    
    class SubClassName < SuperClassName         # class inheritance
       def SetterMethodName
            @instanceVariable
       end
       def GetterMethodName=( value )
            @instanceVariable = value
       end
    end
    
    # Declares code to be called at the end of the program.
    END {
       puts "Terminating Ruby Program"
    }
    # Declares code to be called before the program is run.
    BEGIN {
       puts "Initializing Ruby Program"
    }
    
    # { name }
    # " text " text "
    
       # { name }
       # " text " text "
    
    class Person
      attr_reader :name, :age
      def initialize(name, age)
        @name, @age = name, age
      end
      # "the comparison "operator for sorting"
      def <=>(person)
        age <=> person.age
      end
      def <=>(person) # "the comparison "operator for sorting"
        age <=> person.age
      end
      def to_s
        # the next line should not be interpreted as comment!
        "#{name} (#{age})"
      end
    end
    
    # should match
    def ::( arg )
        # statements
    end
    def []( arg )
        # statements
    end
    def []=( arg )
        # statements
    end
    def **( arg )
        # statements
    end
    def !( arg )
        # statements
    end
    def ~( arg )
        # statements
    end
    def +( arg )
        # statements
    end
    def -( arg )
        # statements
    end
    def *( arg )
        # statements
    end
    def /( arg )
        # statements
    end
    def % ( arg )
        # statements
    end
    def >>( arg )
        # statements
    end
    def <<( arg )
        # statements
    end
    def &( arg )
        # statements
    end
    def ^( arg )
        # statements
    end
    def |( arg )
        # statements
    end
    def <=( arg )
        # statements
    end
    def <( arg )
        # statements
    end
    def >( arg )
        # statements
    end
    def >=( arg )
        # statements
    end
    def <=>( arg )
        # statements
    end
    def ==( arg )
        # statements
    end
    def ===( arg )
        # statements
    end
    def !=( arg )
        # statements
    end
    def =~( arg )
        # statements
    end
    def !~( arg )
        # statements
    end
    
    # should NOT match
    def =<( arg )
        # statements
    end
    def =>( arg )
        # statements
    end
    def >>>( arg )
        # statements
    end
    def <>( arg )
        # statements
    end
    def <<>( arg )
        # statements
    end
    
    =begin
    
    The following words are reserved in Ruby:
    
        __FILE__  and    def       end     in      or      self   unless
        __LINE__  begin  defined?  ensure  module  redo    super  until
        BEGIN     break  do        false   next    rescue  then   when
        END       case   else      for     nil     retry   true   while
        alias     class  elsif     if      not     return  undef  yield
    
    =end
    

    Regards, Menno

     
    • JoMazM

      JoMazM - 2015-02-13

      hi,

      I modified my functionlist.xml as you described, somehow I am still not able to get it working.

      I have attached my functionlist.xml

      Notepad++ Je suis Charile edition

       
  • Menno Vogels

    Menno Vogels - 2015-02-13

    The latest edition (tested with Notepad++ 6.7.3):

      <parser
          id         ="ruby_syntax" 
          displayName="Ruby"
          commentExpr="(?'SLC'(?m-s)#[^{].*$)|(?'MLC'(?s-m)(?:^|(?&lt;=[\r\n]))(?-i:=begin\b)(?:[\t ][^\r\n]+)?\r?\n(?:[^\r\n]*\r?\n)*?(?-i:=end\b))" 
          version    ="1.0.2.0"
        >
        <classRange
            mainExpr="[\t ]*(?-i:\bclass\b)[\t ]+\b(?'clid'(?:\b(?!(?-i:alias|and|BEGIN|begin|break|case|class|def|defined\?|do|else|elsif|END|end|ensure|false|for|if|in|module|next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield|__FILE__|__LINE__))\b)[A-Za-z_]\w*)\b[^\r\n]*\r?\n(?:(?'sl'[\t ]*#[^\r\n]*\r?\n)|(?'ml'(?-i:=begin\b)(?:[\t ][^\r\n]+)?\r?\n(?:[^\r\n]*\r?\n)*?(?-i:=end\b))|(?'bl'[\t ]*\r?\n)|(?'vl'[\t ]*\b(?'vid'\$(?:(?:\b(?!(?-i:alias|and|BEGIN|begin|break|case|class|def|defined\?|do|else|elsif|END|end|ensure|false|for|if|in|module|next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield|__FILE__|__LINE__))\b)[A-Za-z_]\w*|-.|.)|@{0,2}(?:\b(?!(?-i:alias|and|BEGIN|begin|break|case|class|def|defined\?|do|else|elsif|END|end|ensure|false|for|if|in|module|next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield|__FILE__|__LINE__))\b)[A-Za-z_]\w*)\b[^\r\n]*\r?\n)|(?'mt'[\t ]*(?-i:\bdef\b)[\t ]+(?'mtid'(?:\b(?!(?-i:alias|and|BEGIN|begin|break|case|class|def|defined\?|do|else|elsif|END|end|ensure|false|for|if|in|module|next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield|__FILE__|__LINE__))\b)[A-Za-z_]\w*[?!=]?|:{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?)[^\r\n]*\r?\n(?:[^\r\n]*\r?\n)*?[\t ]*(?-i:\bend\b)[^\r\n]*\r?\n))*?[\t ]*(?-i:\bend\b)[^\r\n]*(?:\r?\n|$)"
          >
          <className>
            <nameExpr expr="(?-i:\bclass\b)[\t ]+[A-Za-z_]\w*\b" />
            <nameExpr expr="[\t ]+[A-Za-z_]\w*" />
            <nameExpr expr="[A-Za-z_]\w*" />
          </className>
          <function
              mainExpr="(?-i:\bdef\b)[\t ]+(?:[A-Za-z_]\w*[?!=]?|:{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?)[^\r\n]*\r?\n(?:[^\r\n]*\r?\n)*?[\t ]*(?-i:\bend\b)[^\r\n]*\r?\n"
            >
            <functionName>
              <funcNameExpr expr="(?&lt;=def)[\t ]+(?:[A-Za-z_]\w*[?!=]?(?:[\t ]*\()?|(?::{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?)[\t ]*\()" />
              <!-- comment out the following node to display the method with parameters -->
              <funcNameExpr expr="(?:[A-Za-z_]\w*[?!=]?|(?::{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?))" />
            </functionName>
          </function>
        </classRange>
        <function mainExpr="[\t ]*(?-i:\balias\b)(?:[\t ]+(?:(?:\b(?!(?-i:alias|and|BEGIN|begin|break|case|class|def|defined\?|do|else|elsif|END|end|ensure|false|for|if|in|module|next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield|__FILE__|__LINE__))\b)[A-Za-z_]\w*)){2}[^\r\n]*(?:\r?\n|$)|[\t ]*(?-i:\bdef\b)[\t ]+(?:(?:\b(?!(?-i:alias|and|BEGIN|begin|break|case|class|def|defined\?|do|else|elsif|END|end|ensure|false|for|if|in|module|next|nil|not|or|redo|rescue|retry|return|self|super|then|true|undef|unless|until|when|while|yield|__FILE__|__LINE__))\b)[A-Za-z_]\w*[?!=]?(?:[\t ]*\([^)]*\))?|(?::{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?)[\t ]*\([^)]*\))(?:[^\r\n]*\r?\n)+?[\t ]*(?-i:\bend\b)[^\r\n]*(?:\r?\n|$)" >
          <functionName>
            <nameExpr expr="(?-i:\balias\b)(?:[\t ]+(?:[A-Za-z_]\w*)){2}|(?-i:\bdef\b)[\t ]+(?:[A-Za-z_]\w*[?!=]?(?:[\t ]*\()?|(?::{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?)[\t ]*\()" />
            <nameExpr expr="(?&lt;=alias)[\t ]+[A-Za-z_]\w*|(?&lt;=def)[\t ]+(?:[A-Za-z_]\w*[?!=]?|(?::{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?))" />
            <nameExpr expr="(?:[A-Za-z_]\w*[?!=]?|(?::{2}|\*{1,2}|![=~]?|=(?:~|={1,2})?|[~+\-/%&amp;|\^]|&lt;(?:&lt;|=&gt;?)?|&gt;[&gt;=]?|\[]=?))" />
          </functionName>
        </function>
      </parser>
    
     
  • JoMazM

    JoMazM - 2015-03-02

    Great,

    Thanks for the update. I tested on Notepad 6.7.3 and It works fine, however testing with Notepad 6.7.4 just shows nothing.

    Any clue what do I need to change to make it work on 6.7.4?

    Thanks

     
  • JoMazM

    JoMazM - 2015-03-03

    Hi,

    I verified on 6.7.4. Since I patched SciLexer.cpp in order to Fold multiline comments, somehow this change makes FunctionList regular expression to fail.

    Here additional information:

    https://sourceforge.net/p/notepad-plus/feature-requests/2032/?limit=25#7071

    Thans for your support