#!/usr/bin/env rexx
/******************************************************************************/
/*                                                                            */
/* elident.rex - Check that a program is equal to its Element API parsing     */
/* ======================================================================     */
/*                                                                            */
/* This program is part of the Rexx Parser package                            */
/* [See https://rexx.epbcn.com/rexx-parser/]                                  */
/*                                                                            */
/* Copyright (c) 2024-2026 Josep Maria Blasco <josep.maria.blasco@epbcn.com>  */
/*                                                                            */
/* License: Apache License 2.0 (https://www.apache.org/licenses/LICENSE-2.0)  */
/*                                                                            */
/* Version history:                                                           */
/*                                                                            */
/* Date     Version Details                                                   */
/* -------- ------- --------------------------------------------------------- */
/* 20241206    0.1  First public release                                      */
/* 20241208    0.1a c/CLASSIC_COMMENT/STANDARD_COMMENT/                       */
/* 20250328    0.2  Main dir is now rexx-parser instead of rexx[.]parser      */
/* 20251110    0.3a Change the name to elident.rex                            */
/* 20251211         Add Executor support, move to /bin                        */
/* 20251218         Add TUTOR support                                         */
/* 20251221    0.4a Add --itrace option, improve error messages               */
/* 20251226         Send error messages to .error, not .output                */
/* 20251227         Use .SysCArgs when available                              */
/* 20260103         Use compound variable parts                               */
/* 20260307    0.5  Implement experimental option                             */
/* 20260314         Use InitCLI() from CLISupport.cls                         */
/*                                                                            */
/******************************************************************************/

  Signal On Syntax

  CLIhelper    = InitCLI()
  myName       = CLIhelper~name
  myHelp       = CLIhelper~help
  args         = CLIhelper~args

  executor     = 0
  experimental = 0
  unicode      = 0
  itrace       = 0
  cms          = 0

ProcessOptions:
  If args~items == 0 Then Signal Help

  option = args[1]
  args~delete(1)

  If option[1] == "-" Then Do
    Select Case Lower(option)
      When "-h", "--help"                 Then Signal Help
      When "--executor", "-xtr"           Then executor     = 1
      When "--cms", "-cms",               -
           "--rexxvm", "-rexxvm"          Then cms          = 1
      When "-e", "-exp", "--experimental" Then experimental = 1
      When "-it", "--itrace"              Then itrace       = 1
      When "-u", "--tutor", "--unicode"   Then unicode      = 1
      Otherwise Call Error "Invalid option '"option"'."
    End
    Call ProcessOptions
  End

  If args~items > 0 Then Call Error "Invalid argument '"args[1]"'."

  file = option

  fullPath = .context~package~findProgram(file)

  If fullPath == .Nil Then Call Error "File '"file"' does not exist."

  -- Read the whole file into an array
  chunk = CharIn(fullPath,1,Chars(fullPath))
  Call Stream fullPath,"c","close"
  source = chunk~makeArray
  -- Makearray has a funny definition that ignores a possible
  -- last empty line.
  If Right(chunk,1) = "0a"X Then source~append("")

  options = .Array~new
  If executor     Then options~append(("EXECUTOR",     1))
  If cms          Then options~append(("CMS",          1))
  If unicode      Then options~append(("UNICODE",      1))
  If experimental Then options~append(("EXPERIMENTAL", 1))

  parser = .Rexx.Parser~new( file, source, options )

  currentLineNo = 1
  currentLine   = ""

  element = parser~firstElement -- Same as parser~package~prolog~body~begin
  Do Counter elements Until element == .Nil
    If element~from \== element~to Then Do
      category = element~category
      elementLine  = element~from~word(1)
      If      elementLine > currentLineNo          Then Call ChangeLine
      If      category == .EL.STANDARD_COMMENT     Then Call StandardComment
      Else If category == .EL.DOC_COMMENT          Then Call StandardComment
      Else If category == .EL.DOC_COMMENT_MARKDOWN Then Call StandardComment
      Else If category == .EL.RESOURCE_DATA        Then Call ResourceData
      Else If category == .EL.EXPOSED_COMPOUND_VARIABLE | -
              category == .EL.COMPOUND_VARIABLE    Then Call CompoundVariable
      Else    currentLine ||= element~source
    End
    element = element~next
  End

  Exit 0

Help:
  Say .Resources[Help]~makeString        -
    ~caselessChangeStr("myName", myName) -
    ~caselessChangeStr("myHelp", myHelp)
  Exit 1

CompoundVariable:
  Do part Over element~parts
    currentLine ||= part~source
  End
  Return

StandardComment:
  lastLine = element~to~word(1)
  start = element~from~word(2)
  end   = element~  to~word(2)
  If elementLine == lastLine Then Do
    currentLine ||= source[currentLineNo][ start, end-start ]
    Return
  End
  elementLine += 1
  currentLine ||= SubStr( source[currentLineNo], start )
  Call ChangeLine
  currentLineNo = lastLine
  currentLine   = source[currentLineNo][1, end - 1]
Return

ResourceData:
  lastLine = element~to~word(1)
  currentLineNo = lastLine + 1
  currentLine   = ""
Return

ChangeLine:
  Do While elementLine > currentLineNo
    If source[currentLineNo] \== currentLine Then Do
      Say( "Difference found in line number" currentLineNo":" )
      Say "Source line is '"source[currentLineNo]"',"
      Say "Parsed line is '"currentLine"'."
      Exit 1
    End
    currentLineNo += 1
    currentLine    = ""
  End
Return

--------------------------------------------------------------------------------

Error:
 .Error~Say(Arg(1))
  Exit 1

--------------------------------------------------------------------------------
-- Standard Rexx Parser error handler                                         --
--------------------------------------------------------------------------------

Syntax:
  co = condition("O")
  If co~code \== 98.900 Then Do
   .Error~Say( "Error" co~code "in" co~program", line" co~position":" )
    Raise Propagate
  End
  Exit ErrorHandler( file, source, co, itrace)

::Resource HELP
myname -- Checks that the Parser' stream of elements is identical to a FILE.

Usage: myname [OPTION]... [FILE]

If the only option is -h or --help, or if no arguments are present,
then display this help and exit.

Options:

-it, --itrace             Print internal trace on error
-u, --tutor, --unicode    Enable TUTOR-flavored Unicode
-e, -exp, --experimental  Enable Experimental features
-xtr, --executor          Activate support for Executor language extensions
-cms, --cms               Activate support for CMS (Classic Rexx) syntax (also -rexxvm, --rexxvm)

The 'myname' program is part of the Rexx Parser package,
see https://rexx.epbcn.com/rexx-parser/. It is distributed under
the Apache 2.0 License (https://www.apache.org/licenses/LICENSE-2.0).

Copyright (c) 2024-2026 Josep Maria Blasco <josep.maria.blasco@epbcn.com>.

See myHelp for details.
::END

::Requires "Rexx.Parser.cls"
::Requires "BaseClassesAndRoutines.cls"
::Requires "ErrorHandler.cls"
::Requires "CLISupport.cls"