Help language development. Donate to The Perl Foundation

Gnome::Gtk3 cpan:MARTIMM last updated on 2023-02-06

Design-docs/Rouge-higlighter/raku.rb
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

module Rouge
  module Lexers
    class Raku < RegexLexer
      title "Raku"
      desc "The Raku scripting language (raku.org)"

      tag 'raku'
      aliases 'rk'

      filenames '*.pl6', '*.pm6', '*.t', '*.t6', '*.raku', '*.rakumod', '*.rakutest'

      mimetypes 'text/x-raku', 'application/x-raku'

      def self.detect?(text)
        return true if text.shebang? 'raku'
      end

      keywords = %w(
#        case continue do else elsif for foreach if last my next our
#        redo reset then unless until while use print new BEGIN CHECK
#        INIT END return
      )

      builtins = %w(
#        abs accept alarm atan2 bind binmode bless caller chdir chmod
#        chomp chop chown chr chroot close closedir connect continue cos
#        crypt dbmclose dbmopen defined delete die dump each endgrent
#        endhostent endnetent endprotoent endpwent endservent eof eval
#        exec exists exit exp fcntl fileno flock fork format formline getc
#        getgrent getgrgid getgrnam gethostbyaddr gethostbyname gethostent
#        getlogin getnetbyaddr getnetbyname getnetent getpeername
#        getpgrp getppid getpriority getprotobyname getprotobynumber
#        getprotoent getpwent getpwnam getpwuid getservbyname getservbyport
#        getservent getsockname getsockopt glob gmtime goto grep hex
#        import index int ioctl join keys kill last lc lcfirst length
#        link listen local localtime log lstat map mkdir msgctl msgget
#        msgrcv msgsnd my next no oct open opendir ord our pack package
#        pipe pop pos printf prototype push quotemeta rand read readdir
#        readline readlink readpipe recv redo ref rename require reverse
#        rewinddir rindex rmdir scalar seek seekdir select semctl semget
#        semop send setgrent sethostent setnetent setpgrp setpriority
#        setprotoent setpwent setservent setsockopt shift shmctl shmget
#        shmread shmwrite shutdown sin sleep socket socketpair sort splice
#        split sprintf sqrt srand stat study substr symlink syscall sysopen
#        sysread sysseek system syswrite tell telldir tie tied time times
#        tr truncate uc ucfirst umask undef unlink unpack unshift untie
#        utime values vec wait waitpid wantarray warn write
      )

      re_tok = Str::Regex

      state :balanced_regex do
#        rule %r(/(\\[\\/]|[^/])*/[egimosx]*)m, re_tok, :pop!
#        rule %r(!(\\[\\!]|[^!])*![egimosx]*)m, re_tok, :pop!
#        rule %r(\\(\\\\|[^\\])*\\[egimosx]*)m, re_tok, :pop!
#        rule %r({(\\[\\}]|[^}])*}[egimosx]*), re_tok, :pop!
#        rule %r(<(\\[\\>]|[^>])*>[egimosx]*), re_tok, :pop!
#        rule %r(\[(\\[\\\]]|[^\]])*\][egimosx]*), re_tok, :pop!
#        rule %r[\((\\[\\\)]|[^\)])*\)[egimosx]*], re_tok, :pop!
#        rule %r(@(\\[\\@]|[^@])*@[egimosx]*), re_tok, :pop!
#        rule %r(%(\\[\\%]|[^%])*%[egimosx]*), re_tok, :pop!
#        rule %r(\$(\\[\\\$]|[^\$])*\$[egimosx]*), re_tok, :pop!
      end

      state :root do
#        rule %r/#.*?$/, Comment::Single
#        rule %r/^=[a-zA-Z0-9]+\s+.*?\n=cut/m, Comment::Multiline
#        rule %r/(?:#{keywords.join('|')})\b/, Keyword

#        rule %r/(format)(\s+)([a-zA-Z0-9_]+)(\s*)(=)(\s*\n)/ do
#          groups Keyword, Text, Name, Text, Punctuation, Text

#          push :format
#        end

#        rule %r/(?:eq|lt|gt|le|ge|ne|not|and|or|cmp)\b/, Operator::Word

        # substitution/transliteration: balanced delimiters
#        rule %r((?:s|tr|y){(\\\\|\\}|[^}])*}\s*), re_tok, :balanced_regex
#        rule %r((?:s|tr|y)<(\\\\|\\>|[^>])*>\s*), re_tok, :balanced_regex
#        rule %r((?:s|tr|y)\[(\\\\|\\\]|[^\]])*\]\s*), re_tok, :balanced_regex
#        rule %r[(?:s|tr|y)\((\\\\|\\\)|[^\)])*\)\s*], re_tok, :balanced_regex

        # substitution/transliteration: arbitrary non-whitespace delimiters
#        rule %r((?:s|tr|y)\s*([^\w\s])((\\\\|\\\1)|[^\1])*?\1((\\\\|\\\1)|[^\1])*?\1[msixpodualngcr]*)m, re_tok
#        rule %r((?:s|tr|y)\s+(\w)((\\\\|\\\1)|[^\1])*?\1((\\\\|\\\1)|[^\1])*?\1[msixpodualngcr]*)m, re_tok

        # matches: common case, m-optional
#        rule %r(m?/(\\\\|\\/|[^/\n])*/[msixpodualngc]*), re_tok
#        rule %r(m(?=[/!\\{<\[\(@%\$])), re_tok, :balanced_regex

        # arbitrary non-whitespace delimiters
#        rule %r(m\s*([^\w\s])((\\\\|\\\1)|[^\1])*?\1[msixpodualngc]*)m, re_tok
#        rule %r(m\s+(\w)((\\\\|\\\1)|[^\1])*?\1[msixpodualngc]*)m, re_tok

#        rule %r(((?<==~)|(?<=\())\s*/(\\\\|\\/|[^/])*/[msixpodualngc]*), re_tok, :balanced_regex

#        rule %r/\s+/, Text
#        rule %r/(?:#{builtins.join('|')})\b/, Name::Builtin
#        rule %r/((__(DIE|WARN)__)|(DATA|STD(IN|OUT|ERR)))\b/,
#          Name::Builtin::Pseudo

#        rule %r/<<([\'"]?)([a-zA-Z_][a-zA-Z0-9_]*)\1;?\n.*?\n\2\n/m, Str

#        rule %r/(__(END|DATA)__)\b/, Comment::Preproc, :end_part
#        rule %r/\$\^[ADEFHILMOPSTWX]/, Name::Variable::Global
#        rule %r/\$[\\"'\[\]&`+*.,;=%[email protected]$!<>(^\|\/-](?!\w)/, Name::Variable::Global
#        rule %r/[-+\/*%=<>&^\|!\\~]=?/, Operator
#        rule %r/[[email protected]%#]+/, Name::Variable, :varname

        rule %r/0_?[0-7]+(_[0-7]+)*/, Num::Oct
        rule %r/0x[0-9A-Fa-f]+(_[0-9A-Fa-f]+)*/, Num::Hex
        rule %r/0b[01]+(_[01]+)*/, Num::Bin
        rule %r/(\d*(_\d*)*\.\d+(_\d*)*|\d+(_\d*)*\.\d+(_\d*)*)(e[+-]?\d+)?/i,
          Num::Float
        rule %r/\d+(_\d*)*e[+-]?\d+(_\d*)*/i, Num::Float
        rule %r/\d+(_\d+)*/, Num::Integer

        rule %r/'/, Punctuation, :sq
        rule %r/"/, Punctuation, :dq
        rule %r/`/, Punctuation, :bq
        rule %r/<([^\s>]+)>/, re_tok
        rule %r/(q|qq|qw|qr|qx)\{/, Str::Other, :cb_string
        rule %r/(q|qq|qw|qr|qx)\(/, Str::Other, :rb_string
        rule %r/(q|qq|qw|qr|qx)\[/, Str::Other, :sb_string
        rule %r/(q|qq|qw|qr|qx)</, Str::Other, :lt_string
        rule %r/(q|qq|qw|qr|qx)(\W)(.|\n)*?\2/, Str::Other

        rule %r/package\s+/, Keyword, :modulename
        rule %r/sub\s+/, Keyword, :funcname
        rule %r/\[\]|\*\*|::|<<|>>|>=|<=|<=>|={3}|!=|=~|!~|&&?|\|\||\.{1,3}/,
          Operator
        rule %r/[()\[\]:;,<>\/?{}]/, Punctuation
        rule(/(?=\w)/) { push :name }
      end

      state :format do
        rule %r/\.\n/, Str::Interpol, :pop!
        rule %r/.*?\n/, Str::Interpol
      end

      state :name_common do
        rule %r/\w+::/, Name::Namespace
        rule %r/[\w:]+/, Name::Variable, :pop!
      end

      state :varname do
        rule %r/\s+/, Text
        rule %r/\{/, Punctuation, :pop! # hash syntax
        rule %r/\)|,/, Punctuation, :pop! # arg specifier
        mixin :name_common
      end

      state :name do
        mixin :name_common
        rule %r/[A-Z_]+(?=[^a-zA-Z0-9_])/, Name::Constant, :pop!
        rule(/(?=\W)/) { pop! }
      end

      state :modulename do
        rule %r/[a-z_]\w*/i, Name::Namespace, :pop!
      end

      state :funcname do
        rule %r/[a-zA-Z_]\w*[!?]?/, Name::Function
        rule %r/\s+/, Text

        # argument declaration
        rule %r/(\([[email protected]%]*\))(\s*)/ do
          groups Punctuation, Text
        end

        rule %r/.*?{/, Punctuation, :pop!
        rule %r/;/, Punctuation, :pop!
      end

      state :sq do
        rule %r/\\[']/, Str::Escape
        rule %r/[^\\']+/, Str::Single
        rule %r/'/, Punctuation, :pop!
      end

      state :dq do
        mixin :string_intp
        rule %r/\\[\\tnr"]/, Str::Escape
        rule %r/[^\\"]+?/, Str::Double
        rule %r/"/, Punctuation, :pop!
      end

      state :bq do
        mixin :string_intp
        rule %r/\\[\\tnr`]/, Str::Escape
        rule %r/[^\\`]+?/, Str::Backtick
        rule %r/`/, Punctuation, :pop!
      end

      [[:cb, '\{', '\}'],
       [:rb, '\(', '\)'],
       [:sb, '\[', '\]'],
       [:lt, '<',  '>']].each do |name, open, close|
        tok = Str::Other
        state :"#{name}_string" do
          rule %r/\\[#{open}#{close}\\]/, tok
          rule %r/\\/, tok
          rule(/#{open}/) { token tok; push }
          rule %r/#{close}/, tok, :pop!
          rule %r/[^#{open}#{close}\\]+/, tok
        end
      end

      state :in_interp do
        rule %r/}/, Str::Interpol, :pop!
        rule %r/\s+/, Text
        rule %r/[a-z_]\w*/i, Str::Interpol
      end

      state :string_intp do
        rule %r/[[email protected]][{]/, Str::Interpol, :in_interp
        rule %r/[[email protected]][a-z_]\w*/i, Str::Interpol
      end

      state :end_part do
        # eat the rest of the stream
        rule %r/.+/m, Comment::Preproc, :pop!
      end
    end
  end
end