' Gambas module file

Private Const IDENT_CAR As String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$"
Private Const DIGIT_CAR As String = "0123456789.+-eE"

Private $cKeyword As New Collection
Private $cOperator As New Collection
Private $aKeywords As String[]

Public Sub _init()
  
  Dim sStr As String
  
  $aKeywords = New String[]
  
  For Each sStr In ["break", "case", "catch", "const", "continue", "debugger", "default", "delete", "do", "else", "finally", "for",
    "function", "if", "in", "instanceof", "new", "return", "switch", "throw", "try", "typeof", "var", "void", "while", "with"]
    $cKeyword[sStr] = 0
    $aKeywords.Add(sStr)
  Next

  For Each sStr In ["false", "null", "this", "true", "undefined"]
    $cKeyword[sStr] = 1
    $aKeywords.Add(sStr)
  Next

  For Each sStr In ["{", "}", ".", ">=", "+", "<<", "!", "=", ">>=", ";", "==", "-", ">>", "~", "+=", ">>>=", "(", ",", "!=", "*", ">>>", "&&", "-=", "&=", ")", "<", "===", "%", "&", "||", "*=", "|=", "[", ">", "!==", "++", "|", "?", "%=", "^=",
    "--", "^", ":", "<<=", "]", "<=", "/", "/="]
    $cOperator[sStr] = True
  Next
  
End

Public Sub GetKeywords() As String[]
  
  Return $aKeywords
  
End



Public Sub Run()
  
  Dim iState As Integer
  Dim iTag As Integer
  Dim sText As String
  Dim iLenText As Integer
  Dim iPos As Integer
  Dim sCar As String
  Dim bSingleLineComment As Boolean
  Dim bSingleQuoteString As Boolean
  Dim sIdent As String
  Dim bTestShowLimit As Boolean
  Dim bLastExpr As Boolean
  
  iState = Highlight.State
  iTag = Highlight.Tag
  sText = Highlight.Text
  iLenText = String.Len(sText)
  bLastExpr = True
  If iState = Highlight.Operator Then bLastExpr = False
  
  For iPos = 1 To iLenText

    sCar = String.Mid$(sText, iPos, 1)
    
    If HighlightHTML.AllowCode And If sCar = "<" And String.Mid$(sText, iPos, 2) = "<%" Then
      HighlightHTML.MeetCodeAt = iPos
      Highlight.State = iState
      Highlight.Tag = iTag
      Return
    Endif
  
    If iState = Highlight.Normal Then
    
      If sCar = "/" Then
        sCar = String.Mid$(sText, iPos + 1, 1)
        If sCar = "/" Then
          iState = Highlight.Comment
          bSingleLineComment = True
        Else If sCar = "*" Then
          sCar = String.Mid$(sText, iPos + 2, 1)
          If sCar = "*" Then
            iState = Highlight.Help
          Else
            iState = Highlight.Comment
          Endif
          bSingleLineComment = False
        Else If Not bLastExpr And If String.Mid$(sText, iPos + 1, 1) <> " " Then ' Regular expression
        
          sIdent = sCar
          
          While iPos < iLenText
            Inc iPos
            sCar = String.Mid$(sText, iPos, 1)
            If sCar = "\\" Then
              Inc iPos
              sIdent &= sCar & String.Mid$(sText, iPos, 1)
              Continue
            Endif
            sIdent &= sCar
            If sCar = "/" Then
              Break
            Endif
          Wend
          
          While iPos < iLenText
            Inc iPos
            sCar = String.Mid$(sText, iPos, 1)
            If Not IsLetter(sCar) Then 
              Dec iPos
              Break
            Endif
            sIdent &= sCar
          Wend
          
          Highlight.Add(Highlight.DataType, String.Len(sIdent))
          iState = Highlight.Normal
          Continue
        Else
          Highlight.Add(Highlight.Operator)
          Continue
        Endif
        
      Else If sCar = "\"" Then
        iState = Highlight.String
        bSingleQuoteString = False
      Else If sCar = "'" Then
        iState = Highlight.String
        bSingleQuoteString = True
      Else If Asc(sCar) <= 32 Then 
      
      Else If IsDigit(sCar) Then
      
        sIdent = sCar
        sCar = String.Mid$(sText, iPos + 1, 1)
        If sCar = "x" Or If sCar = "X" Then
          sIdent &= sCar
          Inc iPos
          While iPos < iLenText
            Inc iPos
            sCar = String.Mid$(sText, iPos, 1)
            If Not IsHexa(sCar) Then
              Dec iPos
              Break
            Endif
            sIdent &= sCar
          Wend
        Else
          While iPos < iLenText
            Inc iPos
            sCar = String.Mid$(sText, iPos, 1)
            If InStr(DIGIT_CAR, sCar) = 0 Then
              Dec iPos
              Break
            Endif
            sIdent &= sCar
          Wend
        Endif
      
        Highlight.Add(Highlight.Number, String.Len(sIdent))
        iState = Highlight.Normal
        bLastExpr = True
        Continue
        
      Else If Len(sCar) >= 2 Or If InStr(IDENT_CAR, sCar) Then
        
        sIdent = sCar
        
        While iPos < iLenText
          Inc iPos
          sCar = String.Mid$(sText, iPos, 1)
          If Len(sCar) = 1 And If Not IsDigit(sCar) And If InStr(IDENT_CAR, sCar) = 0 Then
            Dec iPos
            Break
          Endif
          sIdent &= sCar
        Wend
        
        If $cKeyword.Exist(sIdent) Then
          iState = Highlight.Keyword
          If sIdent = "function" Then bTestShowLimit = True
          If $cKeyword[sIdent] = 1 Then bLastExpr = True
        Else
          iState = Highlight.Symbol
          bLastExpr = True
        Endif
        
        Highlight.Add(iState, String.Len(sIdent))
        iState = Highlight.Normal
        Continue
      
      Else
      
        sIdent = sCar
        
        While iPos < iLenText
          If $cOperator.Exist(sIdent) Then Break
          Inc iPos
          sCar = String.Mid$(sText, iPos, 1)
          If IsLetter(sCar) Or If IsDigit(sCar) Or If IsBlank(sCar) Then
            Dec iPos
            Break
          Endif
          sIdent &= sCar
        Wend
        
        bLastExpr = False

        If $cOperator.Exist(sIdent) Then
          iState = Highlight.Operator
          If sIdent = ")" Or If sIdent = "]" Then bLastExpr = True
        Else
          iState = Highlight.Error
        Endif
        
        Highlight.Add(iState, String.Len(sIdent))
        iState = Highlight.Normal
        
        'Dec iPos
        Continue
      
      Endif
      
    Else If iState = Highlight.Comment Or If iState = Highlight.Help Then
    
      If Not bSingleLineComment Then
        sCar = String.Mid$(sText, iPos, 2)
        If sCar = "*/" Then
          Highlight.Add(iState, 2)
          Inc iPos
          iState = Highlight.Normal
          Continue
        Endif
      Endif
      
    Else If iState = Highlight.String Then
    
      If sCar = "\\" Then
        sCar = String.Mid$(sText, iPos + 1, 1)
        If sCar = "x" Then
          Highlight.Add(iState, 3)
          iPos += 2
          Continue
        Else If sCar = "u" Then
          Highlight.Add(iState, 5)
          iPos += 4
          Continue
        Else
          Highlight.Add(iState, 2)
          Inc iPos
          Continue
        Endif
      Else If sCar = "\"" And If Not bSingleQuoteString Then
        Highlight.Add(iState)
        iState = Highlight.Normal
        bLastExpr = True
        Continue
      Else If sCar = "'" And If bSingleQuoteString Then
        Highlight.Add(iState)
        iState = Highlight.Normal
        bLastExpr = True
        Continue
      Endif
      
    Endif
    
    Highlight.Add(iState)
    
  Next
  
  If iState = Highlight.Comment And If bSingleLineComment Then
    iState = Highlight.Normal
  Endif
  
  If iState <> Highlight.Comment And If iState <> Highlight.Help Then
    iState = Highlight.Normal
  Endif
  
  If bTestShowLimit Then
    Highlight.ShowLimit = LTrim(sText) Begins "function "
  Endif
  
  Highlight.State = iState
  Highlight.Tag = iTag
  
End
