# -*- coding: utf-8 -*- #
# frozen_string_literal: true

# See http://www.cs.cmu.edu/afs/andrew/course/15/411/ghc/share/doc/ghc/ext-core/core.pdf for a description of the syntax
# of the language and https://www.aosabook.org/en/ghc.html for a high level overview.
module Rouge
  module Lexers
    class GHCCore < RegexLexer
      title "GHC Core"
      desc "Intermediate representation of the GHC Haskell compiler."
      tag 'ghc-core'

      filenames '*.dump-simpl', '*.dump-cse', '*.dump-ds', '*.dump-spec'

      state :root do
        # sections
        rule %r/^=====.*=====$/, Generic::Heading
        # timestamps
        rule %r/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+ UTC$/, Comment::Single
        rule %r/^Result size of .+\s*.*}/, Comment::Multiline
        rule %r/--.*$/, Comment::Single

        rule %r/\[/, Comment::Special, :annotation

        mixin :recursive_binding
        mixin :ghc_rule
        mixin :function

        # rest is Text
        # TODO: this is really inefficient
        rule %r/\s/m, Text
        rule %r/./, Text
      end

      state :expression do
        rule %r/[\n]+/, Text
        rule %r/(?=^\S)/ do
          pop!
        end

        rule %r/\s+/, Text, :expression_line
      end

      state :expression_line do
        rule %r/ /, Text

        mixin :common

        rule %r/\n/, Text, :pop!
      end

      state :annotation do
        rule %r/\]/, Comment::Special, :pop!
        rule %r/\[/, Comment::Special, :annotation
        rule %r/[^\[\]]+/, Comment::Special
      end

      state :common do
        # array, e.g. '[]' or '[Char]'
        rule %r/\[[^=]*\]/, Keyword::Type

        rule %r/\[/, Comment::Special, :annotation

        mixin :literal
        mixin :constants
        mixin :punctuation
        mixin :operator
        mixin :name
      end

      state :literal do
        rule %r/\d+\.\d+\#{0,2}/, Literal::Number::Float
        rule %r/\d+\#{0,2}/, Literal::Number::Integer
        rule %r/".*"#/, Literal::String
        rule %r/'.'#/, Literal::String::Char
      end

      state :constants do
        rule %r/__DEFAULT/, Name::Constant
      end

      state :name do
        rule %r/^([A-Z]\w*)(\.)/ do |m|
          token Name::Namespace, m[0]
          token Punctuation, m[1]
        end

        rule %r/[A-Z][^\s.,(){}]*/, Keyword::Type

        # packages, e.g. 'ghc-prim-0.5.3:'
        rule %r/(^[a-z].*?\d+\.\d+\.\d+)(:)(?=\S)/ do |m|
          token Name::Namespace, m[1]
          token Punctuation, m[2]
        end

        rule %r/\S*\(,\)\S*/, Name::Variable # '(,)' is a name, not punctuation
        rule %r/\S[^\s.,(){}]*/, Name::Variable
      end

      state :punctuation do
        rule %r/[.,(){};]/, Punctuation
      end

      state :operator do
        rule %r/=>/, Operator
        rule %r/->/, Operator
        rule %r/::/, Operator
        rule %r/=/, Operator
        rule %r/forall/, Keyword
        rule %r/case/, Keyword
        rule %r/of/, Keyword
        rule %r/letrec/, Keyword
        rule %r/let/, Keyword
        rule %r/join/, Keyword
        rule %r/@/, Operator
        rule %r/\\/, Operator
      end

      state :recursive_binding do
        rule %r/(Rec)(\s*)({)/ do |m|
          token Keyword, m[1]
          token Text, m[2]
          token Punctuation, m[3]
        end

        rule %r/^(end)(\s*)(Rec)(\s*)(})/ do |m|
          token Keyword, m[1]
          token Text, m[2]
          token Keyword, m[3]
          token Text, m[4]
          token Punctuation, m[5]
        end
      end

      state :ghc_rule do
        rule %r/^(".*?")/m do |m|
          token Name::Label, m[0]

          push :expression
        end
      end

      state :function do
        rule %r/^(\S+)(?=.*?(=|::))/m do |m|
          token Name::Function, m[0]

          push :expression
        end
      end
    end
  end
end
