#!/bin/sh
#] 
#] *********************
#] $ bash "$d_bin"'port bash to python.sh' - Howell's semi-manual conversion
# www.BillHowell.ca  03Mar2023 initial, testDevelop with geany, then bash
# view in text editor, using constant-width font (eg courier), tabWidth = 3
# for tests, see : 
#		"$d_bin"'0_test/port bash to python test.sh' 
#		"$d_bin"'port bash to python.txt'



# neither [Python, QNial] can have empty lines in function bodies
#		this forces a "no empty lines" style, which I don't like, but there are compromises
#		eg put in [# for bash, % ; for QNial, ??? for Python]
# NOTE!!! : NOT used here - random 3-digit codes for varNames in each function
#		assumes that only library functions are called, which do have unique codes #24************************24



#24************************24
# List of operators, generated with :
# $ grep  "^#]"  "$d_bin"'port bash to python.sh' |  sed "s/^#\]/# /" 
#
#  *********************
#  $ bash "$d_bin"'port bash to python.sh' - Howell's semi-manual conversion
#  +-----+
#  Setup 
#  +-----+
#  Philosopy, overall approach 
#  objectives : As a start for me to learn the Python language... 
#  [test, development] approach : 
#     @start of development - typically I used geany txtEditor regexpr search-replace
#     subsequent: in pBash_dPy_portTo_pPython():
#  +-----+
#  format styles : 
#  +-----+
#  sedExprs - to make code easier to [read, edit] 
#  +-----+
#  code 
#  port_bash_to_python_Arx()  - backup project files (check for missing files in list!)
#  sedIt()  - str replacement function for this file, with file updates in ramdisk
#  pBash_dPy_portTo_pPython()  - does the lion's work of port (hopefully gets the simple stuff)
#  pPython_dBash_portTo_pBash()  - does the lion's work of port (hopefully gets the simple stuff)
#  manual_clean()  - manual edits will always be required (eg Python module calls)


#24************************24
#] +-----+
#] Setup 

#	source  "$d_bin""standard header.sh"		# done by fileops.sh 
	source  "$d_bin""fileops.sh"


#24************************24
#] +-----+
#] Philosopy, overall approach 

#] objectives : As a start for me to learn the Python language... 
#						how stupid is that?, eh! But it has helped (I keep telling myself)


#] context : 
#		My bash knowledge is limited, I am not advanced
#		Normally, my main programming language is QNial, but 
#			for a couple of years I have been revamping my QNial [library, symbol]s, 
#			and that may take another year or two.


#] +-----+
#] [test, development] approach : 
#]    @start of development - typically I used geany txtEditor regexpr search-replace
#			then I converted geany regular expression to bash
#]    subsequent: in pBash_dPy_portTo_pPython():
#			then [add specifics, copy-paste] variable defs and sedExpr to bash command line to check
#			copy-paste sedExpr into new 'sedIt' AFTER the 'if		[ 5 == 4 ]; then ... fi' section 
#				test pBash_dPy_portTo_pPython() on a '.sh' file
#					put all other 'active' code into 'if		[ 5 == 4 ]; then ... fi' section 
#
#]		sedExprMap:  helps me track what I am doing with very long sedExpr  (eyes get tired)
#			also bypass limit of 9 sed groups,  
#			the following example has been updated, but for illustration purposes it's fine 
#			making the short acronyms' substiutions makes it easier to [map, see, edit]
#]        for an operating example, see "$d_bin"'0_test/port bash to python test.sh'  

#] +-----+
#] format styles : 
#		forced across different languages
#			demands Python indentation (which I don't like!)
#			preserve [indentation, format]s as much as possible
#			note that I retain some tabs within the seds! '\([ \t\)'
#		retain man original bash lines, but commented out - easy to back-translate
#		symCodes : bash library(s) requirement to prevent 'cross-over' of global variables
#			symCodes are 3-digit random integers that are suffixed to all local symNames 
#			(not just funcArgNames), 
#			this carries over to other languages even though they don't require it
#			this file only 'source's others (fileops.sh) - so symCodes not used here
#		comments: are retained (important - a lot of [work, explanation] there)
#		keyWords: are first words on line [sheBang, if, while, for, etc, etc]
#			this could cause 'misses'
#		dropped bash keywords [fi, done, ???] in Python port :  
#			retained by coment-out.  doesn't hurt, easier to back-port
#		ported files end up with fNam of form "[.sh.py]*"
#			doesn't overwrite original file, as manual edits will always be required 
#				for this [simple, incomplete] port 
#		this port is extremely incomplete - might be 'easy' to add other capabilities
#		user will have to adapt code for Python [modul, def, global]s 
#		my bash programming style - heavily influences this port
#			will have errors for others' styles


#] +-----+
#] sedExprs - to make code easier to [read, edit] 

	# 10Mar2023 short acronyms: upperCase are positional args, lowerCase aren't 
	# must add double-quote when non-whiteSpce follows acronym!!
	#	I don't use unless lines are[long, complex] (these take you away from the code)
	#	apos	 `' often envelope raw sedExprs
	#	quotes `" are used when 'short acronyms' are present
	AC='\(.*\)'					# Any Character sequence (zero or more)
	bl='[{]'						# BraceLeft  - not useful? '[{]' is as short as $bl
	br='[}]'						# BraceRight - not useful? '[}]' is as short as $br
	LA='\([&]\{2\}\)'			# LogicalAnd	&&
	LAO='\([&|].*\)'			# LogicalAndOR	[&&,||] but not mixed like [|&, &|]
	LE='\(=\{2\}\)'			# LogicalEqual	== (oops - might need $LE for '<= less than equal')
	LO='\([|]\{2\}\)'			# LogicalOR		||
	sl='[[]'						# SquareBracketLeft
	sr='[]]'						# SquareBracketRight
	ST='\([ \t]*\)'			# Space-Tab (whiteSpace, zero or more)


	# sheBang: replace 1st line of bash file:  bash '#!/bin/sh' to Python '#!/usr/bin/python3'
	#		comment-out bash sources (^#b), comment-in Python imports (^#p)
	#		will probably use this for other code-swaps
	sheBang='s|^#!/bin/sh|#!/usr/bin/python3|;s|^\(source\)|#b\t\1|;s|^#p\t||'
	# +-----+
	# generate Python function def line, with a list of all function argSymNames   
	#		note that the automatic function arg type defn ': str,' may be wrong - cleanup later 
	#		empty lines within pRgx are NOT added (for now)
	#			pRgx: file that lists regular expressions for changes to function defs
	defArgs='s|^\t\([0-9A-Za-z_]*\)[(][)][ \t]*|def \1(|;s|^[{][ \t]*||;s|^[}][ \t]*||;s|^\t\([0-9A-Za-z_]*\)=\"\$[0-9]\"[ \t]*|\1: str, |'  
	# remove ', ' from end of function def line, must come AFTER defArgs
	defLastArg='s|^def \(.*\), [)]|def \1)|'
	# +-----+
	# if statements :  [elif, else] are the same in Python as bash, 
	#		assumes that if is the first statement on a line, this also captures elif
	ifRev='s|\(.*\)\(neht\)*\([ \t]*\);\([ \t]*\)[]]\(.*\)[[]\(.*\)fi\(.*\)$|  :\4\5\6fi\7|'
	#		else is simple
	ifElse='s|^\([ \t]*\)else\([ \t]*\)|\1else:\2|'  
	#		fi disappears, but retain it commented-out for easy back-conversion
	ifFi='s|^\([ \t]*\)fi\([ \t]*\)|\1# fi\2|'
	# +-----+
	# control loops
	# while loops : (almost a copy of if statements)
	#		08Mar I just excluded single-line fixes
	# assumes that [while, done] are always on their own lines 
	whiLoop='s|^\([ \t]*\)while\([ \t]*\)\(.*\);\([ \t]*\)do\(.*\)|\1while\2\3:\4|'
	# for loops : (almost a copy of if statements)
	#		assumes that [for, done] are always on their own lines
	#	format : only does start_oneInc_create_seq( 0 1 i252 )  
	forLoop='s|^\([ \t]*\)for\([ \t]*\)\(.*\);\([ \t]*\)do\(.*\)|\1for\2\3:\4\5|'
	# whiForDone (whiFor= [while, for]) done (haven't dealt with file input, eg 9>) 
	# +-----+
	# both [for, while] loops
	# done - 07Mar2023 haven't yet dealt with file input, eg 9>
	whiForDone='s|^\([ \t]*\)done\(.*\)|\1# done\2|'
	# iterations, assumes 
	#	no [ \t] between [parens, word `;] 
	whiForIter='s|^\([ \t]*\)for\([ \t]*\)[(][(]\([ \t]*\)\(.*\)=\(.*\)|\1iL = incOne_create_seq( 0 1 \4 )  \n\1for i in iL:  |'

	# dirExists
	# I need to use Howell envVars like d_[bin, myPy, temp, web, etc] 
	#		$ env  |  grep 'd_'  |  sort  >"$d_myPy"'3_Howell environmental variables.txt' 
	#		then: geany txtEditor to put in apostrophes, tab replace `=
	#		or maybe just load into python as an array of text pairs
	
	# if3Conditions - for 3 sed logical groups [&& etc] on a line, must involve pths
	#		must come after doing basic 'if' line port
	#		copy-paste from screen output for 'ALL three "if" conditionals :' of tests in : 
	#			"$d_bin"'0_test/port bash to python test.sh'
	#		run larger number conditions first, then down to one
	#		10Mar2023 $LAO was changed - need to re-test
	# minor difference between if3Conditions with[, out] 'short acronyms' (both hard to read)
	# best to use both : 
	#		raw for normal conditionals (retain your familiarity with code)
	#		'short acronyms' when it becomes difficult to follow the code
	if3Conditions="s|^$ST""if$ST[[]$ST\-\([fd]\)$ST$AC$ST$LA$LA|\1if  os.path.exists(\6) \8\9 |;s|^$AC$LA$ST\-\([fd]\)$ST$AC$ST$LA|\1\2 os.path.exists(\6) \8|;s|^$AC$LAO$AC$LAO$ST\-\([fd]\)$ST$AC$ST[]]$ST:|\1\2\3\4 os.path.exists(\8):|" 
	# if2Conditions - must come after if3Conditions
	if2Conditions='s|^\([ \t]*\)if\([ \t]*\)[[]\([ \t]*\)\-\([fd]\)\([ \t]*\)\(.*\)\([ \t]*\)\([&]\{2\}\)|\1if  os.path.exists(\6) \8 |;s|\(.*\)\([&|]*\)\([ \t]*\)\-\([fd]\)\([ \t]*\)\(.*\)\([ \t]*\)[]]\([ \t]*\):|\1os.path.exists(\6):|'
	# if1Condition  - must come after if2Conditions
	if1Condition='s|^\([ \t]*\)if\([ \t]*\)\-\([fd]\)\([ \t]*\)\(.*\)\([ \t]*\):|\1if  os.path.exists(\5):|'
	
	# whiReadArgL : read a file within a while loop, first line setup. 
	#   fID.[open, close] lines at time of 'done'
	whiReadArgL='s|^\([ \t]*\)while\([ \t]*\)read\([ \t]*\)\-u\([ \t]*\)\([0-9]\{3\}\)\([ \t]*\)\(.*\):|\1while True:\n\1\t\7 = file.readline()|'
	# whiPthOpen - terminate with file.close() at same indentation level as 'while'
	#		must also create file[open, close].  It's the wrong coding line, but move later.
	whiPthOpen='s|^\([ \t]*\)done\([ \t]*\)\([0-9]\{3\}\)\([ \t]*\)<\([ \t]*\)\([a-zA-Z0-9_"]*\)\(.*\)|\1fID = open(\7,'r') \n\1fID.close() |'
	
	# for : readarray -t lineLOld146 < <( cat "$pOld146"  ), python arrays are just lists
	readLst="s|^\(.*\)readarray\([ \t]*\)\-t\([ \t]*\)\(.*\)\([ \t]*\)<\([ \t]*\)<(\([ \t]*\)cat\([ \t]*\)\(.*\)\([ \t]*\)[)]\([ \t]*\)|\1fID = open(\9,'r')  \n\1\4 = list(fID):\n\1fID.close()|"
	
	# array (list!) references - eg "${lineLOld146[$i146]}"
	lstItm="s|\$$bl$AC$sl\$$AC$sr$br|\1[\"$\2\"]|"
	
	#		bshSimple - with NO pipes! no other unxCmd etc
	#			ToDos :	[rm, cp, find, grep, sed, mv, 'IFS', cat, ???], 
	#			done :	[echo, readarray, ]
	#		special bshCmd $( ... ) with NO pipes! no other unxCmd etc
	#			printf with no [pipes, other unxCmd, ]  
	#			idx252=$(( $idx252 + 1 ))] 
	echo='s|^\([ \t]*\)echo\([ \t]*\)\(.*\)\([ \t]*\)|\1print(\3)|'
	
	
	
	
	
	
	
	# output  = subprocess.check_output(cmd, shell=True, encoding='utf8')
	# bash executables, eg 
	#		$( "pStrP:  $pStrP384") 
	#		$(date +"%y%m%d %kh%Mm")
	#		$( printf '%s\n' "$line"  |  sed  's|\x9.*||' )
	#		$(  echo "$line295"  |  grep  -i  "$line_endd295"  )  
	bshExpr="s|\$($ST$AC$ST)|\2|"
	
	
	
	
	


#************
#] +-----+
#] code 


#] port_bash_to_python_Arx()  - backup project files (check for missing files in list!)
	port_bash_to_python_Arx()
{  
	date_ymdhm=$(date +"%y%m%d %kh%Mm")
	d_Arx="$d_bin"'z_Archive/'"$date_ymdhm"'/'
	mkdir "$d_Arx"
	cp -p "$d_bin"'fileops.sh'						"$d_Arx"'fileops.sh'
	cp -p "$d_bin"'fileops notes.txt'			"$d_Arx"'fileops notes.txt'
	cp -p "$d_bin"'port bash to python.sh'		"$d_Arx"'port bash to python.sh'
	cp -p "$d_bin"'port bash to python.txt'	"$d_Arx"'port bash to python.txt'
	cp -p "$d_Python"'0_python notes.txt'		"$d_Arx"'0_python notes.txt'
	cp -p "$d_SysMaint"'Linux/bash notes.txt'	"$d_Arx"'bash notes.txt'
#	cp -p "$d_bin"		"$d_Arx"
#	cp -p "$d_bin"		"$d_Arx"
}  


#] calls to Howell's bash libraries
# several standard functions of fileops.sh
# special - povr_pRgxL_cat() - lineSequence replacement using sedExprs


#] sedIt()  - str replacement function for this file, with file updates in ramdisk
	sedIt()
{  
	sed	"$1"	"$ptmp1"	>"$ptmp2"	;	mv		"$ptmp2"	"$ptmp1"  
}  


#] pBash_dPy_portTo_pPython()  - does the lion's work of port (hopefully gets the simple stuff)
	pBash_dPy_portTo_pPython()  
{  
	pBash="$1"
	dPy="$2"  
											# 
	pRegx="$d_bin"'port bash-to-python funcDecln via regexpr.txt' 
	ptmp1="$d_temp"'pBash_portTo_pPython temp1.txt'  
	ptmp2="$d_temp"'pBash_portTo_pPython temp2.txt'  
	ptmp3="$d_temp"'pBash_portTo_pPython temp3.txt'  
	pDiff12="$d_temp"'pPython_portTo_pBash diff12.txt'
	pDiff23="$d_temp"'pPython_portTo_pBash diff23.txt'
											# 
	#---------------------------------- #
	# take already-dones out-of-the-loop, after testing on .sh file
	if		[ 5 == 4 ]; then 
		echo 'oops - loop to take already-dones out-of-the-loop'
			# keep this line to prevent bash error if empty 'if', ensure bash runs'
			# copy specific lines to 'active' area below for testing
		
		cp  "$pBash"  "$ptmp1"
												# 
		sedIt  "$sheBang"					# 1st line of file: bash '#!', python '#!/usr/bin/python3' 
		sedIt  "$defArgs"					# function declaration: bash line -> python def
		povr_pRgxL_cat  0		"$ptmp1"  "$pRegx"  ')  '  # catenate function declaration line
		sedIt  "$defLastArg"			
		cat	 "$ptmp1"  |  rev  |  sed  "$ifRev"  |  rev  >"$ptmp2"  
																	mv		"$ptmp2"	"$ptmp1"  
		sedIt  "$ifElse"					# 
		sedIt  "$ifFi"						# 
		sedIt  "$whiLoop"					# 
		sedIt  "$forLoop"					# 
		sedIt  "$whiForDone"				# 
		sedIt  "$whiForIter"				# 
	fi  
		# the ordering of some items is important, 
		#		but generally these can be re-ordered as independent

	#---------------------------------- #
	# current files in-the-loop, ready for testing on .sh file
		
		sedIt  "$if3Conditions"			# after doing basic 'if'
		sedIt  "$if2Conditions"			# must come after ifThrePthDirExists
		sedIt  "$if1Conditions"			# must come after ifTwoPthDirExists
		sedIt  "$whiReadArgL"			# whiReadArgL : read while loop, first line setup
		sedIt  "$whiPthOpen"				# read file, terminate with file.close()
		sedIt  "$readLst"					# list : readarray -t lineLOld146 < <( cat "$pOld146"  )
		sedIt  "$lstItm"					# array (list!) references - eg "${lineLOld146[$i146]}"
		sedIt  "$whiReadArgL"			# read a file within a while loop, first line setup
		sedIt  "$whiPthOpen"				# terminate with file.close() same indentation as 'while'
		sedIt  "$unxCmd"					# unix eg : $(  sed  's|\x9.*||' "$pinn" ), AFTER lstItm
		sedIt  "$echo"						# echo -> print()
		
		
		
		
		
		
		
		
		# $ bash  "$d_bin"'port bash to python.sh'  
		
	#---------------------------------- #
	# keep ToDos out-of-the-loop, waiting before testing on .sh file
	if		[ 5 == 4 ]; then 
		echo 'oops - take already-dones out-of-the-loop (for now)'
			# keep this line to prevent bash error if empty 'if', ensure bash runs'
			# copy specific lines to 'active' area below for testing
		
		
		
		# +-----+
		# ToDos : 
		#
		#		partly done : [while, for, ] loops [read, ]
		#		bshSimple - with NO pipes! no other unxCmd etc
		#			ToDos :	[rm, cp, find, grep, sed, mv, 'IFS', cat, ???], 
		#			done :	[echo, readarray, ]
		#		special bshCmd $( ... ) with NO pipes! no other unxCmd etc
		#			printf with no [pipes, other unxCmd, ]  
		#			idx252=$(( $idx252 + 1 ))] 
		#			date +"%y%m%d %kh%Mm"
		#		pBashCmdL - leave as-is for now [unxCmd, ]
		#		$(( ... )) forms
		#		leave for now as typically in pipeExpr [find, grep, sed, read, sort, etc] 
		#		pHowellBashFuncL - build for all my functions [pth_get_fnmNoExt, etc]
		#
		
		# re-arrange line [sequence, placement] * [pthOpen, imports, etc]
		
		# fix indentation (especially commentBlankLines)
		
		# [strm sum] catenates - Python is nearly the same as bash? insert spaces, sometimes `+
		#		relys on consistent usage of ["']!!!
		#		how toDo to make back-port easy? - pSymLPythonToBash?
		# geany
		# search:	([0-9A-Za-z_]*)[ \t]*=[ \t]*["]\$([0-9A-Za-z_]*)["][']([0-9A-Za-z_/]*)['"]
		# replace:	\1 = "$\2" + '\3'
		# check:	([0-9A-Za-z_]*) = ["]\$([0-9A-Za-z_]*)["] + [']([0-9A-Za-z_/]*)[']
		# 
		# remove `+ in str catenations :
		# search:	(["'])[ \t]\+[ \t](["'])
		# replace:	\1\2
		# mv  "$ptmp2"  "$ptmp1"  
		#
		# what is this?
		#	[concat, separate] stringL into [symbol, string]s
		#		from : p2tmp521="$d_temp""webSite_fixes_noChrBads empty.txt"
		#		to:	 p2tmp521=  d_temp 'webSite_fixes_noChrBads empty.txt'
		#	ptmp1='/media/bill/ramdisk/pBash_portTo_pPython temp1.txt'
		
		
		#	introduce variable symbols as required in Python
		#	
		
	fi  
		
		
		
												# 
	# final cp to Python semi-translated file for manual work 
	#		this program may never be good enough to rely on, but U hope it's a good start?
	#		it should save some text editing and frustration
	# pPy="$dPy"$( pth_get_fname  "$pBash" )'.py'  
	# pinn_backupDatedTo_zArchive  "$pPy"
	# mv  "$ptmp1"  "$pPython"  
}  


#] pPython_dBash_portTo_pBash()  - does the lion's work of port (hopefully gets the simple stuff)
	pPython_dBash_portTo_pBash()  
{  
	pBash="$1"
	dPy="$2"  
											# 
	pRegx="$d_bin"'port python-to-bash funcDecln via regexpr.txt' 
	ptmp1="$d_temp"'pBash_portTo_pPython temp1.txt'  
	ptmp2="$d_temp"'pBash_portTo_pPython temp2.txt'  
	ptmp3="$d_temp"'pBash_portTo_pPython temp3.txt'  
	pDiff12="$d_temp"'pPython_portTo_pBash diff12.txt'
	pDiff23="$d_temp"'pPython_portTo_pBash diff23.txt'
	
	#---------------------------------- #
	# loop to take already-dones out-of-the-loop
	if		[ 5 == 4 ]; then 
		echo 'oops - loop to take already-dones out-of-the-loop shouldn"t echo!!?'
	fi  
		# the ordering of some items is important, 
		#		but generally these can be re-ordered as independent
		
		# +-----+
		# pPython_portTo_pBash() - convert python file back to bash, diff with original
		# 
		# pBackwards="$d_temp"'pPython_portTo_pBash backwards.txt'
		# pDiff="$d_temp"'pPython_portTo_pBash diff.txt'
		# pPython_portTo_pBash  "$ptmp1"  "$pBackwards"  
		# echo 'diff "$ptmp1"  "$pBackwards"  --suppress-common-lines'  >"$pDiff"  
		# diff "$ptmp1"  "$pBackwards"  --suppress-common-lines  |  grep "<"  |  sed 's/< //'  >>"$pDiff"  
		# echo '' >>"$pDiff"  
		# echo '' >>"$pDiff"  
		# echo '*****************************' >>"$pDiff"  
		# echo 'diff "$pBackwards"  "$ptmp1"  --suppress-common-lines'  >"$pDiff"  
		# diff "$pBackwards"  "$ptmp1"  --suppress-common-lines  |  grep "<"  |  sed 's/< //'  >>"$pDiff"  
											# 
}  



#] manual_clean()  - manual edits will always be required (eg Python module calls)
# Python module calls
# incomplement ToDos (see list in pBash_dPy_portTo_pPython())




# +-----+
# comments - leave the same as in the "original" compLang it was developed in
# 	some special comments as required for "adpator" languages


#************
# tests 
#	pBash="$d_bin"'fileops.sh'
#	cp  "$d_bin"'fileops.sh'  "$d_temp"'pBash_portTo_pPython temp1.txt' 
#	pFuncArgSymL="$d_temp"'port bash to python- funcArgNames.txt'
#	grep  '^[ 	]\([a-zA-Z0-9_]*\)=["]$[0-9]["]'  "$pBash"  |  sed  's|	\(.*\)=.*|\1|'  |  sort -u  >"$pFuncArgSymL" 
#	pBash_pSymL_dPy_stripQuotes_pPython  0  "$d_bin"'fileops.sh'  "$d_temp"'port bash to python- funcArgNames.txt'  "$d_myPy"  
#	05Mar2023 tests 
#	pNamPy="$d_myPy"$( pth_get_fname  "$d_bin"'fileops.sh' )'.py'  
#	echo "$pNamPy"
#


#************
# run - first [, un]-comment parts of pBash_dPy_portTo_pPython

#	port_bash_to_python_Arx
	pBash_dPy_portTo_pPython  "$d_bin"'fileops.sh'  "$d_myPy"






# $ bash  "$d_bin"'port bash to python.sh'  

# enddoc
