/*
//----------------------------------------------------------------
// JAVA version: creates JAVA project from a compiled AL4 program
// written in AL4, should be compiled by a compiled compiler
//----------------------------------------------------------------
// (C) by Vladimir Kladov, 2016-2018
//------------------------------------------------------------

CLASS {Generator|_of_Java_Android_project},
	RECURSIVE, UNTESTED, STOPPING, BITWISE :

IMPORT: {Compiler}, {Type}, {Text_file}, {Variable}, {Function},
        {Statement}, {Assignment}, {For}, {Case}, {Expression}, 
        {Limit}, {Local}, {String_functions}, {System_functions}, {Console},
        {File_path}, {Parser}, {Text_parser}, {Mathematics},
        {Localize_str}, {Date_time}, {Statistics} , {Testing} .


FUN TARGET_LANG|UAGE(
{Compiler} C|ompiler_dummy) ==> STR := "Java" .

CONST BOOL:
	ALLOW_EXIT_IN_NATIVE|_FUNCTIONS_BEFORE_NATIVE_CODE = TRUE .

CONST BOOL:
	SUPPORTS_NATIONAL_NAMES|_FOR_VARS_FUNCTIONS_TYPES = FALSE .
	
METHOD Need_compile(
{Type} C|lass_to_check) ==> BOOL : RESULT = TRUE .

METHOD Output_path_class|_compiled(
{Type} C|lass_to_path) ==> STR
    :
    STR path|_output = C.Final_name ".java" 
    RESULT = Comp.Destination.Trailing_slash "" path.Extract_file_name .
        
METHOD Output_test_path_class|_compiled(
{Type} C|lass_to_path) ==> STR
    :
	CASE "TEST$" IN Comp.Destination ? RESULT = Output_path_class(C) ==> ;
    STR path|_output = C.Final_name ".java"
     
    RESULT = Comp.Destination.Trailing_slash "TEST$".Trailing_slash 
    	"" path.Extract_file_name .	
        
{Compiler} Comp|iler
STR o|out_source[]
STR spaces|_prefix

BOOL trace_fun|ctions
STR  trace_lines|_in_function

FUN Tests_available ==> BOOL := FALSE .
	

FUN Allow_optimizations(
{Compiler} C|ompiler_with_its_options,
STR Optimizations|_found) ==> STR
    :
	CASE "$TEST" IN C.Defined_name[] ? ==> ;
    RESULT = Optimizations .	
	

FUN Additional_classes|_maybe_add_Console_app(
{Compiler} C|ompiler_obj)
	:
	CASE "$CONSOLE" IN C.Defined_name[] ?
		 FOR t IN C.All_classes[] :
		     CASE t.Names[*] == "{Console_app}" ?
		          C.Error("The {Console_app} class is already in source paths "
		          "so the option $CONSOLE is ambiguous"._EConsoleAmbig)
		          BREAK t ;
		 ;
	
	     {Type} class1|_to_call_main = C.All_classes[0]
	     STR path|_console_app
	     path = C.Defined_value[C.Defined_name[].Find("$CONSOLE")]
	     CASE path == "" ?
	          path = "%AL4%\AL4\Library\Visual\_Android\Console_app" ;
	     CASE path.Starting("%AL4%") ?
	          path = Decode_env(path) ;
	     STR path2|_location_to_copy_Console_app_modified = C.Destination
	     path2 = path2.Trailing_slash "Console_app"
	     path2.Create_dir
	     
	     ------------------------------ 'copy modified Console_app.al4'
	     STR source|_of_console_app[]
	     
	     {Text_file} tf|ile_TEMP = {Text_file}(Path = path.Trailing_slash
	     	"Console_app.al4", Encoding = 'UTF8')
	     	
	     BOOL ok_loaded = tf.Load(source[])
	     CASE !ok_loaded ?
	          C.Error("Can not load Console_app.al4 from [" path "]") ;
	     FOR s IN source[* DOWNTO 0] :
	         CASE s.Trim == "//$IMPORT" ?
	              source[s.Index] = "IMPORT: " class1.Names[*] " ." ;
	         CASE s.Trim == "//$CALL_MAIN" && "$TEST" !IN C.Defined_name[] ?
	              source[s.Index] = #TAB#TAB class1.Names[*] ".Main"
	         ;
	     ;
	     tf.Path = path2.Trailing_slash "Console_app.al4"
	     NONE = tf.Save(source[])
	     
	     -------------------------- 'insert {Console_app} class to the start'
	     C.Source_paths[].Insert(0, path2)
	     {Type} c|lass_Console_app = C.Create_class("Console_app.al4")
	     C.All_classes[].Remove(c)
	     C.All_classes[].Insert(0, c)
	     //DEBUG: Console_color('GREEN')
	     //
	     //		<< "class " c.Whole_name " inserted as the first" #NL
	     //		   "path=" path #NL
	     //		   "path2=" path2 #NL
	     //		   
	     //		Console_color('SILVER') ;
	; .

------------------------------ 'Android options'
BOOL Android|_build

FUN Is_allowed_identifier(STR S|tring_to_check) ==> BOOL :
	FOR i IN [0 TO S.Len-1] :
	    CASE S.[i] !IN "abcdefghijklmnopqrstuvwxyz0123456789" ? ==> ;
	;
	RESULT = TRUE .
	

FUNCTION Prepare_project_generator(
	{Compiler} C|ompiler_obj) ==> {Generator}, NEW
	:
	g|enerator_temp = {Generator}(Comp = C)
	RESULT = g .
	
//BOOL Any_class_from_ccc

FUNCTION Create_project(
	{Generator} G|enerator, {Compiler} C|ompiler_obj) ==> BOOL
	:
	{Generator} g|enerator_passed = G	
	------------------------- 'Android/Java specific:'
	C.SYSFUN_EnumInt.Set_final_name("")
    ------------------------------------- 'Compiler: there is no current class'
    C.Current_class = NONE
    //DEBUG:
    //<< "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$"#NL
    //;
    ------------------------------------------- 'create generator'
    STR ps|eparator_of_path = Path_separator
    ----------------------------- 'build directory'
    STR build_dir|ectory = C.Destination.Trailing_slash
    STR dest|ination_for_java_files = build_dir

    g.Android = "$ANDROID" IN C.Defined_name[] 
     		 || "$Android" IN C.Defined_name[]
     		 || "$android" IN C.Defined_name[]
     		 
    CASE "$COMPANY" IN C.Defined_name[] ?
         g.Company = C.Defined_value[C.Defined_name[].Find(
          	   "$COMPANY")].Lower
         
         CASE !g.Company.Is_allowed_identifier ?
              C.Error("$COMPANY value must be an identifier containing "
              "only Latin letters and digits, but value specified is "
              "[" g.Company "]")
         ;
    ELSE g.Company = "al4" ;
    
    CASE "$SOFT_INPUT_MODE" IN C.Defined_name[] ?
         g.windowSoftInputMode = C.Defined_value[C.Defined_name[].Find(
             "$SOFT_INPUT_MODE")] ;

    CASE g.Android ?
         dest = dest.Trailing_slash "src" ps "com" ps g.Company ps C.Project ;
    
    ----------------------------- 'remove .java files in the destination folder'
    CASE TRUE ?
         STR text|_store[] << "del " dest.Trailing_slash "*.java /q" 
         text[] << "del " dest.Trailing_slash "*.class /q"
         file|_temp = {Text_file}(Path = build_dir "deljava.cmd")
         NONE = file.Save_strings(text[])
         CASE C.Verbose ?
              << "will now delete java files in"._Mwill2 
              " " C.Destination #NL
         ;
         NONE = Execute_program(file.Path, "", 0) 
         CASE C.Verbose ?
              << "just executed"._Mjust ": " file.Path #NL
         ;
    ;
    ------------------------------------- 'trace options'
    CASE C.Defined_name[].Find("$TRACE") >= 0 ? 
         CASE C.Verbose ? << "tracing functions is ON"._Mtrac #NL 
         ;
         g.trace_fun = TRUE ;
    INT i|_trace_lines INDEXING STR = C.Defined_name[].Find("$TRACE")
    CASE i >= 0 && C.Defined_value[i] != "" ? 
         CASE C.Verbose ? << "tracing function"._Mtrac2 
                             ": " C.Defined_value[i] #NL
         ;
         g.trace_lines = C.Defined_value[i] ;
    ------------------------------------------- 'generate project'
    PUSH C.Destination = dest :
    	 RESULT = g.do_generate ;
    C.Executable = build_dir C.Project ".apk"
    //DEBUG:
    //  << "------------------------------- "
    // 	 "Generating finished, RESULT"._Mgen ":" RESULT.Str #NL
    // 	 " C.Executable=" C.Executable #NL
    //;
    //CASE !RESULT || "test" IN Start_dir.Lower ? ==> ;
    CASE !RESULT ? ==> ;
    ------------------------------------------- 'count tests'
    FOR c IN C.All_classes[] :
        INT total_tests += c.Test[].Count ;
    CASE total_tests == 0 && C.TEST_value ?
         C.Warning("There are no tests in entire project"._Wthere )
         RESULT = TRUE ==> ;
    ------------------------------------------- 'compile tests project'
    << "Start compiling tests or project"._Mstart #NL
    STR out_class|_path = build_dir C.All_classes[0].Final_name ".class"
    Delete_file(out_class)
    CASE out_class.Exists ?
         C.Error("Can not delete"._Ecannot " " out_class)
         RESULT = FALSE ==> ;
    Set_working_dir(build_dir)
    -------------------------------------------- 'path to java.exe'
    STR java|_exepath = Get_environment_var("JAVABIN").Trailing_slash "java.exe"
    java = #QU java #QU
    -------------------- 'check JAVABIN variable set and points to jdk\bin'
    STR javac|_program = "javac.exe"
    STR javabin|_environment = Get_environment_var("JAVABIN")
    CASE javabin != "" ? javac = javabin.Trailing_slash "javac.exe" ;
    javac = #QU javac #QU
    //DEBUG:
    //    <<  "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" #NL
    //        "javac = [" javac "]" #NL //>> STR in_javac
    //;
    ------------------------ 'prepare params to call javac compiler'
    STR v|erbose_flag = ""
    CASE C.Verbose ? 
         << "will now run javac in"._Mwill " " build_dir #NL //>> STR in1|_dummy
         << "current dir"._Mcurr ": " Get_working_dir #NL
         v = "-verbose " ;
    text[].Clear
    STR param|eters_javac 
    CASE C.Verbose ? param = _ "-verbose "
    ELSE param = _ "-Xmaxerrs 10 " ;
    CASE C.Defined_name[].Find("$CP") >= 0 ?
         STR class_p|ath = C.Defined_value[C.Defined_name[].Find("$CP")]
         CASE class_p == "" ? 
              STR home|_java = Get_environment_var("JAVA_HOME") ;
         CASE class_p != "" ?
              param = _ "-cp " #QU class_p #QU " " ;
         CASE home != "" ?
              param = _ "-cp " #QU home "\Lib" #QU " " ;
    ;
    param = _ C.All_classes[0].Final_name
    << "parameters for javac"._Mparam ": " param ".java" #NL
    //CASE C.Verbose ? >> in ;
    STR bat|_file[]
    STR mes|sages
    -------------------------- 'start compiling with javac'
    CASE !g.Android ?
		 C.Error("Only ANDROID is supported") ==> ;
    ------------------------------- 'ANDROID'
	STR need_subfolders[] << "bin" << "obj" << "res" << "src"
	FOR folder IN need_subfolders[] :
	 	create_subfolder(C.Destination, folder) ;
	-------------------------------- 'icon'
	CASE "$ICON" IN C.Defined_name[] ?
	     INT icon_pos INDEXING STR = C.Defined_name[].Find("$ICON")
	     STR icon_file = C.Defined_value[icon_pos]
	     C.Defined_value[icon_pos] = icon_file.Change_ext("")
	     CASE !icon_file.Exists 
	      	  && (C.Source_paths[0].Trailing_slash icon_file).Exists
	      	  ?
	      	  icon_file = C.Source_paths[0].Trailing_slash icon_file ; 
	     CASE !icon_file.Exists ?
	          C.Error("Icon file did not find"._EIconFile ": " icon_file)
	          
	     ELSE STR idest|ination_for_icon = C.Destination.Trailing_slash
	      	  "res".Trailing_slash "mipmap".Trailing_slash
	      	  "" icon_file.Extract_file_name
	     ;
	     CASE idest != "" && !idest.Extract_path.Dir_exists ?
	          idest.Extract_path.Create_dir ;
	     CASE icon_file.Exists && idest.Extract_path.Directory_exists ?
	          Copy_file(icon_file, idest) ;
	;
	------------------------------- 'AndroidManifest.xml'
	STR manifest|_AdnroidManifest_xml[]
	INT start|_manifest = DATA[].Find("--AndroidManifest.xml")
	g.prepare_android_manifest(start, manifest[])
	Text_save(build_dir "AndroidManifest.xml", manifest[])
	-------------------------------- 'src/com/<g.Company>/<C.Project>'
	STR src|_path = build_dir "src" 
	create_subfolder(src, "com")
	create_subfolder(src ps "com", g.Company)
	create_subfolder(src ps "com" ps g.Company, C.Project)
	-------------------------------- 'class MainActivity.java'
	STR main_a|ctivity_java[]
	start = DATA[].Find("--MainActivity.java")
	g.prepare_main_activity(start, main_a[])
	
	Text_save(src ps "com" ps g.Company ps C.Project ps 
	    "MainActivity.java", main_a[])
	-------------------------------- 'check environment variables'
	STR java_home = Get_environment_var("JAVA_HOME")
	CASE java_home == "" || !java_home.Directory_exists ?
	     C.Error("Environment variable JAVA_HOME is not set or does "
	     "not specify JDK installation directory"._EEnvironment)
	;
	STR android_home = Get_environment_var("ANDROID_HOME")
	CASE android_home == "" || !android_home.Directory_exists ?
	     C.Error("Environment variable ANDROID_HOME is not set or does"
	     " not specify Android SDK installation directory"._EEnvAnd)
	;
	STR build_tools_ver|sion = Get_environment_var("ANDROID_TOOLS_VER")
	CASE build_tools_ver == "" 
	 	 || !(android_home.Trailing_slash 
	 	 "build-tools" ps build_tools_ver).Directory_exists
	 	 ?
	     C.Error("Environment variable ANDROID_TOOLS_VER is not set or"
	     " resulting path " android_home.Trailing_slash "build-tools"
	     "" ps "?" build_tools_ver "? does not exist"._EEnvTools)
	;
	STR android_platform = Get_environment_var("ANDROID_PLATFORM")
	CASE android_platform == "" || !(android_home.Trailing_slash
	 	 "platforms" ps android_platform).Directory_exists
	 	 ?
	     C.Error("Environment variable ANDROID_PLATFORM is not set or "
	     "resulting path " android_home.Trailing_slash
	 	 "platforms" ps android_platform " does not "
	 	 "exist"._EEnvPlatform) ;
	-------------------------------- 'bat file'
	bat[] << "set AAPT_PATH=" android_home.Trailing_slash 
	    "build-tools" ps build_tools_ver ps "aapt.exe"
	    
	bat[] << "set DX_PATH=" android_home.Trailing_slash
	   "build-tools" ps build_tools_ver ps "dx.bat"
	   
	bat[] << "set ANDROID_JAR=" android_home.Trailing_slash
	    "platforms" ps android_platform ps "android.jar"
	-------------------------------- 'project paths'
	bat[] << "set HOME=" C.Destination
	bat[] << "set PACKAGE_PATH=com" ps g.Company ps C.Project
	bat[] << "set PACKAGE=com." g.Company "." C.Project
	bat[] << "set MAIN_CLASS=MainActivity"
	----------------------------------------- 'delete old apk'
	bat[] << "if exist "#QU"%HOME%\" C.Project ".apk"#QU" ("
	bat[] << "	  del /q "#QU"%HOME%\" C.Project ".apk"#QU
	bat[] << ")"
	bat[] << "if exist "#QU"%HOME%\bin\" C.Project ".unsigned.apk"#QU" ("
	bat[] << "	  del /q "#QU"%HOME%\bin\" C.Project ".unsigned.apk"#QU
	bat[] << ")"
	-------------------------------- 'create resources (is any?)'
	bat[] << "call "#QU"%AAPT_PATH%"#QU" package -f -m -S "
	    "%HOME%\res -J "
	    "%HOME%\src -M %HOME%/AndroidManifest.xml -I %ANDROID_JAR%"
	//bat[] << "pause" << ""
	-------------------------------- 'call javac (Android project)'
	bat[] << "" << "call "#QU"%JAVA_HOME%\bin\javac"#QU" "
	    "-Xmaxerrs 10 "
	    "-d %HOME%\obj -cp "
	    "%ANDROID_JAR% -sourcepath %HOME%\src "
	    "%HOME%\src\%PACKAGE_PATH%\*.java"
	//bat[] << "pause" << ""
	-------------------------------- 'call dex-converter'
	bat[] << "call "#QU"%DX_PATH%"#QU" --dex "
	    "--output=%HOME%\bin\classes.dex"
	    " %HOME%\obj"
	//bat[] << "pause" << ""
	-------------------------------- 'classes.dex --> apk'
	bat[] << "call "#QU"%AAPT_PATH%"#QU" package -f -M "
	    "%HOME%\AndroidManifest.xml -S %HOME%\res -I %ANDROID_JAR%"
	    " -F %HOME%\bin\" C.Project ".unsigned.apk %HOME%\bin"
	    
	bat[] << "if not exist %HOME%\bin\" C.Project ".unsigned.apk ("
	bat[] << "   echo Something is wrong -- apk was not created"
	bat[] << "	  REM pause" << "    exit"
	bat[] << ")"
	//bat[] << "pause" << ""
	-------------------------------- 'create keystore'
	bat[] << "if not exist %HOME%\" C.Project ".keystore ("
	
	bat[] << "		call "#QU"%JAVA_HOME%\bin\keytool"#QU" "
	    "-genkey -validity "
	    ''10000 -dname "CN=AndroidDebug, O=Android, C=US" ''
	 	"-keystore %HOME%\" C.Project ".keystore -storepass android "
	 	"-keypass android -alias androiddebugkey -keyalg RSA -v "
	 	"-keysize 2048"
	 	
	bat[] << ")"
	-------------------------- 'insigned.apk + key --> signed apk'
	bat[] << "call "#QU"%JAVA_HOME%\bin\jarsigner"#QU" "
	    "-sigalg SHA1withRSA "
	    "-digestalg SHA1 -keystore %HOME%\" C.Project ".keystore "
	    "-storepass android -keypass android -signedjar "
	    "%HOME%\" C.Project ".apk %HOME%\bin\" C.Project
	    ".unsigned.apk androiddebugkey"
	    
	bat[] << "if not exist %HOME%\" C.Project ".apk ("
	bat[] << "	  echo Something is wrong -- apk was not signed"
	bat[] << "	  REM pause" << "	exit"
	bat[] << ")"
	-------------------------- 'run created bat file'
	m|essages_save_temp = {Text_file}(Path = build_dir "_comp.bat")
    NONE = m.Save_strings(bat[])
    -------------------------- 'prepare also cmd to upload (ADB)'
    bat[].Clear
    
	bat[] << "set ADB=" android_home.Trailing_slash
	 		   "platform-tools" ps "adb.exe" <<
	 	   "set PACKAGE=com." g.Company "." C.Project <<
	 	   "set HOME=" C.Destination <<
	 	   "set MAIN_CLASS=MainActivity"
	 	   
	bat[] << "call "#QU"%ADB%"#QU" uninstall %PACKAGE%" <<
	 		 "call "#QU"%ADB%"#QU" install %HOME%\" 
	 		 "" C.Project ".apk" <<
	 		 "call "#QU"%ADB%"#QU" shell am start "
	 		 "%PACKAGE%/%PACKAGE%.%MAIN_CLASS%"
	 		 
	bat[] << "pause" << "echo x>finished.txt" << "exit"
	m = {Text_file}(Path = build_dir "_adb.bat")
    NONE = m.Save_strings(bat[])
    --------------------------------- 'if there were errors ?'
	CASE C.Errors_count > 0 ? ==> ;
	//DEBUG:
	//      	  << ";;;;;;;;;;;;;;;;;;; adb=" m.Path #NL 
	//      	     "build_dir=" build_dir #NL ;
    --------------------------------- 'run and wait until finished'
    Set_working_dir(build_dir)
    //DEBUG: << "work dir set to " build_dir #NL ;
	//CASE C.Verbose ?
    //     << "launching"._Mlaunch ": " m.Path #NL ;
    //Delete_file(build_dir "finished.txt")
    //CASE (build_dir "finished.txt").Exists ?
    //     C.Error("Can not delete file"._Ecannot2
    //     ": " build_dir "finished.txt")
    //;             
    //mes = Execute_program("cmd.exe", 
    //	"/C start " build_dir "_comp.bat", 0) ==>
    mes = Execute_program(build_dir "_comp.bat", "", 3) //==>
    //DEBUG:
    //"length of messages"._Mleng ": " mes.Len.Str #NL ;
	//wait_file(build_dir "finished.txt", 1000)
    //CASE bat[*] == "exit" ?
    //     bat[*] = "pause"
    //     NONE = m.Save_strings(bat[]) ;
    Split(text[], mes, #NL)
    ----------------- 'write messages to console'
    //DEBUG:
    //     << "::::::::::::::::::::: "
    //        "" ("messages from javac"._Mmess ) " :::::::::::::::"#NL
    //;
    BOOL errors|_in_javac = out_messages_to_console(text[])
    //DEBUG:
    //     << ":::::::::::::::::::::::::::::::::::::::::::::::::::::::"#NL
    //;
    CASE errors ?
         C.Error("There are errors in JAVA code generated"._Ethere )
         RESULT = FALSE ==> ;
    -------------------------------------------- 'set final binary file path'
    C.Executable = build_dir C.Project ".apk"
    CASE !C.Executable.Exists ?
         C.Error("Executable was not created: " C.Executable)
    ELSE
	     C.Time_finished = Now
	     C.Statistics_show
	     << "Executable created: " C.Executable ; .
    
FUN create_subfolder(
	STR Destination,
	STR Folder|_name)
	:
	STR dir|ectory_path = Destination.Trailing_slash Folder
	CASE dir.Directory_exists ? ==> ;
	Create_dir(dir) .
	
METHOD prepare_android_manifest(
	INT From|_data_line, STR Manifest|_lines[])
	:
	CASE From < 0 ?
	     Comp.Error("AndroidManifest.xml source was not found"._EAndroid) ;
	FOR i INDEXING STR IN [From+1 TO DATA[].Count-1] :
	    STR s|tring_at_i = DATA[i].TrimR
	    CASE s == "--" ? ==> ;
	    CASE s.[0] == "?" ?
	         INT space|_index INDEXING STR = s.Find(" ")
	         CASE space < 0 ? space = s.Find(#TAB) ;
	         STR key|word_searching = s.[1 TO space-1]
	         s = Spaces_sequence(space-1) s.[space TO *]
	         CASE key !IN Comp.Defined_name[] ?
	              //DEBUG:
	              //      ------------------- 'check $ORIENTATION'
	              //      CASE key == "$ORIENTATION" ?
	              //      	 << "key " key " is not defined, "
	              //      	 "skip in AndroidManifest" #NL >> ;
	              //;
	              CONTINUE i ;
	         INT index|_of_key_in_defined INDEXING STR 
	         index = Comp.Defined_name[].Find(key)
	         s = s.Replace(key, Comp.Defined_value[index])
	    ELSE
	         CASE"$PROJECT" IN s ?
	              s = s.Replace("$PROJECT", Comp.Project) ;
	         CASE "$COMPANY" IN s ?
	              s = s.Replace("$COMPANY", Company) ;
	         CASE "$SOFT_INPUT_MODE" IN s ?
	              s = s.Replace("$SOFT_INPUT_MODE", windowSoftInputMode) ;
	    ;
	    Manifest[] << s
	; .
	         
METHOD prepare_main_activity(
	INT From|_data_line, STR Result|_source[])
	:
	CASE From < 0 ?
	     Comp.Error("MainActivity.java source was not found"._EMain) ;
	FOR i INDEXING STR IN [From+1 TO DATA[].Count-1] :
	    STR s|tring_at_i = DATA[i].TrimR
	    CASE s == "--" ? ==> ;
	    CASE ?
	    ["$$$" IN s] ?
	         s = s.Replace("$$$", Comp.All_classes[0].Final_name) 
	    ["$PROJECT" IN s] ?
	              s = s.Replace("$PROJECT", Comp.Project) 
	    ["$MAINCLASS" IN s] ?
	              s = s.Replace("$MAINCLASS", Comp.All_classes[0].Final_name) 
	    ;
	    CASE "$COMPANY" IN s ?
	    	 s = s.Replace("$COMPANY", Company) ;
	    Result[] << s ; .
    
FUN out_messages_to_console(STR T|ext_messages[]) ==> BOOL :
    Console_color('CYAN')
    FOR s IN T[] :
        STR ss|_trimed = s.Trim
        CASE Starting(ss, "symbol  :") || (
             Starting(ss, "location:")) || (
             Starting(ss, "symbol:"))
             ?
             INT colon|_pos = s.Find(":")
             Console_color('YELLOW')
             << s.[0 TO colon]
             Console_color('CYAN')
             << s.[colon+1 TO *] #NL
             CONTINUE s ;
        CASE "error:" IN s.Lower ?
             RESULT = TRUE
             INT pos|ition_error = s.Lower.Find("error:")
             << s.[0 TO pos-1]
             Console_color('YELLOW')
             << s.[pos TO pos+5]
             Console_color('CYAN')
             << s.[pos+6 TO *] #NL
        ELSE << s #NL ;
    ;
    Console_color('SILVER')
    //DEBUG: << "last line of messages[" T[*] "]"#NL ;
    .


STR Company|_name = "al4"
STR windowSoftInputMode = "stateHidden|adjustResize"

METHOD do_generate ==> BOOL :
	FINAL_CODE = Comp.Final
    --------------------------------- 'generate project adding system AL4 files'
    generate_project
    
    FOR c IN Comp.All_classes[] :
        STR path|_output = c.Final_name ".java"
        o[].Clear
        CASE !generate_class(c) ? ==> ;
        
        tf|ile_text_temp = {Text_file}(
            Path = Comp.Destination.Trailing_slash
            "" path.Extract_file_name)
            
        CASE Comp.Verbose ? << "Saving"._Msav ": " tf.Path
             " (" o[].Count.Str ")" #NL ;
             
        NONE = tf.Save(o[])
        ----------------------- 'generate correspondent NoneClass_ ...'
        o[].Clear
        CASE !generate_Noneclass(c) ? ==> ;
        CASE Android ?
             o[].Insert(0, "package com." Company "." Comp.Project ";") ;
        
        tf.Path = Comp.Destination.Trailing_slash
            "Noneclass_" path.Extract_file_name
            
        CASE Comp.Verbose ? 
             << "Saving"._Msav2 ": " tf.Path
             	" (" o[].Count.Str ")" #NL
        ;
        NONE = tf.Save(o[]) ;
    -------------------- 'copy also files explicitly specified in options /Copy'
    FOR sf IN Comp.Copy_files[] :
        CASE Starting(sf, "<bin>") ?
             STR dest|ination_name = sf.["<bin>".Len TO *]
        ELSE dest = sf.Extract_file_name ;
        
        copy_file_removing_comments(sf,
            Comp.Destination.Trailing_slash dest)
    ;
    RESULT = TRUE .



METHOD copy_file_removing_comments(
STR Src|_file_path, STR Dst|_file_path)
	:
    -------------------------------------- 'remove old instance'
    CASE Dst.Exists ? Dst.Delete_file ;
    CASE Dst.Exists ? 
         Comp.Error("Can not remove old version of file"._Ecannot4 " " Dst) ;
    -------------------------------------- 'search  source file to copy'
    STR source|_actual = Src
    CASE Starting(Src, "<bin>") ?
         //DEBUG: << "____________________________________copying: " Src #NL >> ;
         source = Src.["<bin>".Len TO *]
         Copy_file(source, Dst) ==> ;
    CASE "\" !IN Src && "/" !IN Src ?
         FOR s IN Comp.Source_paths[] :
             CASE (s.Trailing_slash Src).Exists ?
                  source = s.Trailing_slash Src
                  //DEBUG: << "to copy " Src " was found: " source #NL >> ; 
                  BREAK s ;
         ;
    ;
    CASE Comp.Verbose ? << "COPY"._Mcopy ": " source " to " Dst #NL ;
    ------------------------------------ 'load and remove comments'
    STR text|_copying[]
    temp|_file = {Text_file}(Path = source)
    NONE = temp.Load_strings(text[])
    comment_unnecessary_parts(text[])
    CASE Android && !text[0].Trim.Starting("package") ?
         text[].Insert(0, "package com." Company "." Comp.Project ";");
    ------------------------------------ 'remove comments'
    BOOL no_threads = "$NOTHREADS" IN Comp.Defined_name[]
    FOR s IN text[* DOWNTO 0] :
        CASE s.TrimL.Starting("\\") ?
             CASE no_threads ? s = s.Replace("\\", "//")
             ELSE s = s.Replace("\\", "  ") ; 
             text[s.Index] = s ;
        CASE s.Starting("//?") || s.Starting("//-->") || s.Trim == "//." ?
             CONTINUE s ;
        CASE s.Trim[0 TO 1] == "//" ?
             text[s.Index] = "//-this is a copy only - do not change: "
             "changes will not take effect on the next compile"._Mthis ;
    ;
    ------------------------------- 'save modified text'
    temp.Path = Dst
    BOOL saved|_okay = temp.Save_strings(text[])
    CASE !saved ? 
         Comp.Error("Can not save copy of"._Ecannot5 " " source 
         " " ("to"._Eto ) " " Dst) ; .


METHOD generate_project :
    -------------------- 'copy AL4_system and other .java to destination folder'
    FOR s IN DATA[] :
        CASE s.Starting("--save:") ?
    		 INT first|_save = s.Index
    		 BREAK s ;
    ;
             
    INT save_from INDEXING STR = -1
    FOR i INDEXING STR IN [first TO DATA[].Count-1] :
        STR line|_at_i = DATA[i].TrimR
        CASE Starting(line, "--save:") ?
             CASE save_from >= 0 ?
                  save_file_java_from_DATA(save_from, i-1) ;
             save_from = i
        ;
    ; .
    
METHOD output_all_function_names:
	STR fn|ames_of_all_functions[]
	FOR c IN Comp.All_classes[] :
	    FOR f IN c.Method[] :
	        CASE f.Final_name == "-" ? CONTINUE f ;
	        FOR i|dummy IN [fn[].Count TO f.Global_n] :
	            fn[] << "?" ;
	        INT i_fn INDEXING STR = f.Global_n
	        fn[i_fn] = unique_class_name(c) "." f.Names[0] ;
	;
	FOR s IN fn[]:
	    o[] << #QU s #QU "," ;
	CASE o[*].[*] == "," ? o[*] = o[*].[0 TO *-1] ; .
	
METHOD unique_class_name(
	{Type} Class|_which_name_needed) ==> STR
	:
	FOR c IN Comp.All_classes[]:
	    CASE c == Class ? CONTINUE c ;
	    CASE c.Names[0] == Class.Names[0] ?
	         RESULT = Class.Whole_name ==> ;
	;
	RESULT = Class.Names[0] .

METHOD save_file_java_from_DATA(
INT From INDEXING STR, INT To|_index)
	:
    -------------------------------------- 'collect lines'
    o[].Clear
    CASE Android ? o[] << "package com." Company "." Comp.Project ";" ;
    FOR i IN [From+1 TO To] : 
        STR d|ate_string = DATA[i].TrimR
        CASE ?
        [d == "/" "/#RTTI_type_info"] ?
             CASE "$INTERPRETER" IN Comp.Defined_name[] ?
                  o[] << "public Ref_obj Origin_;"
             ;
             output_RTTI_info_tables
             CONTINUE i
        [Starting(d, "#test:")] ?
             d = sp(6) d.[6 TO *]
             CASE !Comp.TEST_value ? CONTINUE i ;
        [Starting(d, "#not_test:")] ?
             d = sp(10) d.[10 TO *]
             CASE Comp.TEST_value ? CONTINUE i ;
        [d == "#localize"] ?
             add_localize_data
             CONTINUE i 
        [d == "/" "/#function_names"] ?
             o[] << "// all function names to show in Trace of stack"
             output_all_function_names
             CONTINUE i
        ;
        o[] << d ;
    STR name|_java_file = DATA[From]
    -------------------------------------- 'name of java file'
    INT pos|ition_colon = name.Find(":")
    name = name.[pos+1 TO *].Trim
    CASE name == "" ? ==> ;
    -------------------------------------- 'save'
    tf|ile_text_temp = {Text_file}(Path = Comp.Destination.Trailing_slash name)
    NONE = tf.Save(o[])
    o[].Clear .

METHOD add_localize_data :
    STR l_names|_localize_strings[] << sp(6) "public static String[]"
    l_names[] << " Localize_name = new String[] {"
    PUSH generating_localized_strings = TRUE :
         INT start|_index_for_class = 0 
         FOR c IN Comp.All_classes[] :
             CASE c.Localize_n[].Count == 0 ? CONTINUE c ;
             CASE start == 0 ?
				  ---------------- 'add initial values for localized strings'
				  o[] << sp(6) "public static String[] Localize_str = new "
				  "String[] {"
             ;
             o[] << sp(10) #QU#QU ","
             l_names[] << sp(10) #QU "[" c.Names[*] "]"#QU ","
             start += 1
             c.Localize_1st_item = start
             FOR ns IN c.Localize_s[] :
             	 l_names[] << sp(10) #QU c.Localize_n[ns.Index] #QU ","
                 o[] << sp(10) gen_expr(ns) ","
                 start += 1
             ;
         ;
    ;
    CASE start == 0 ? ==> ;
    
    --------------------------- 'finish localization arrays'
    o[*] = o[*].[0 TO *-1] "};"             
    l_names[*] = l_names[*].[0 TO *-1] "};"
    FOR s IN l_names[] : o[] << s ; .
                 
INT tcl|_test_counter_lines[]
BOOL too_deep|_throws_in_tests_of_class
BOOL report_leak_not_supported|_already_shown_warning

METHOD generate_class({Type} Class|_to_generate) ==> BOOL :
    ---------------------------------- 'Prepare to generate entire class file'
    Comp.Current_class = Class
    tcl[].Clear
    stopping_tests = FALSE
    too_deep = FALSE
    ---------------------------------- 'start total_init_var from a new page'
    total_init_var += 999
    total_init_var -= total_init_var % 1000
    CASE Android ?
         o[] << "package com." Company "." Comp.Project ";" ;
    ---------------------------------- 'import used classes'
    o[] << "import java.util.ArrayList;"
    o[] << ""
    ---------------------------------- 'root native code'
    FOR f IN Class.Method[] :
        CASE f.Final_name == "-" ?
                o[] << f.Native_code
        ELSE BREAK f ;
    ;
    ---------------------------------- 'class header'
    CASE Comp.TEST_value ? o[*] = o[*] " //Test" ;
    o[] << ""
    o[*] = o[*] "class " Class.Final_name
    CASE Class.Base_ != NONE ?
         o[*] = o[*] " extends " Class.Base_.Final_name
    ELSE o[*] = o[*] " extends AL4_object" ;
    o[*] = o[*]  " {"
    o[] << "        public static int First_localize_item = "
    o[*] = o[*] Class.Localize_1st_item.Str ";"
    o[] << ""
    ---------------------------------- 'RTTI'
    CASE class_present("{RTTI}") ?
         o[] << sp(8) "@Override"
         o[] << sp(8) "public int RTTI_object_type() {"
         
         o[] << sp(12) "return " (Comp.All_classes[].Find(Class)+7).Str
         		";"
         		
         o[] << sp(8) "}" << ""
         generate_RTTI_methods(Class)
    ;
    ---------------------------------- 'main part of class'
    o[] << "    // generate ref"
    generate_ref(Class)
    o[] << "    // generate NONE"
    generate_NONE(Class)
    --------------------------------- 'enums'
    FOR e IN Class.Enums_[] :
        o[] << "    // generate enum: " e.Final_name
        generate_enum(e) ;
    --------------------------------- 'structures'
    FOR st IN Class.Structures_[] :
        generate_structure_decl(st) ;
    --------------------------------- 'fields'
    FOR v IN Class.Field[] :
        generate_field(v) ;
    --------------------------------- 'constant arrays'
    FOR c IN Class.Constants[] :
        CASE !c.Is_array ? CONTINUE c ;
        generate_constant_array(c) ;
    --------------------------------- 'methods'
    BOOL root_outer|_code = TRUE
    FOR f IN Class.Method[] :
        CASE f.Final_name == "-" && root_outer ? CONTINUE f ;
        CASE f.Overloaded_[].Count > 0 ? CONTINUE f ;
        root_outer = FALSE
        CASE f.Names[0] == "Main" ?
             BOOL any_rec|ursive_fun = f.Calling_any_recursive_fun 
             BOOL overr|ides_recursive = f.Overrides_any_calling_recursive_fun 
             too_deep ||= any_rec || overr ;
        generate_method(f) ;
    --------------------------------- 'Get_CNT (for Report_leaks)'
    CASE Comp.Defined_name[].Find("$REPORT_LEAKS") >= 0 
    	 && !report_leak_not_supported
    	 ?
         Comp.Warning("Option $REPORT_LEAKS is not supported - ignored"
         ""._MIgnoreReportLeaks)
      
         report_leak_not_supported = TRUE   
    ;
    --------------------------------- 'tests'
    CASE "$TEST" IN Comp.Defined_name[] ? // Comp.TEST_value ?
         FOR t IN Class.Test[] :
             //CASE t.Param[].Count == 0 ? BOOL has_tests|_without_params = TRUE ;
             any_rec = t.Calling_any_recursive_fun
             overr = t.Overrides_any_calling_recursive_fun  
             too_deep ||= any_rec || overr 
             generate_method(t) ;
         o[] << #NL "public static void Do_tests() "
         o[*] = o[*] "throws Exception"
         o[*] = o[*] "{"
         CASE stopping_tests ?
              o[] << "try {" ;
         --------------------------- 'generate_init_classes'
         o[] << sp(4) "AL4_system.Clear_test_data(test_lines);"
         CASE Class.Base_.Modifiers['ABSTRACT'] ?
              o[] << sp(4) "AL4_system.Clear_test_data(" Class.Base_.Final_name 
              ".test_lines);" 
              FOR f IN Class.Method[] :
                  remove_overridden_method_lines_from_tests_of_base(f) ;
         ;
         FOR t IN Class.Test[] :
             CASE t.Param[].Count > 0 ? CONTINUE t ;
             o[] << sp(4) t.Final_name "();" ;
         ---------------------------- 'suppress Stop exception in tests'
         CASE stopping_tests ?
              o[] << @ "}"
                       "catch (AL4StopException E_Stop) {"
                       "    AL4_system.Any_exception(E_Stop);"
                       "}"
         ;
         o[] << "}"
         ---------------------------- 'counters array'
         o[] << "" << "public static long[] test_lines = new long[]{"
         FOR line IN tcl[] :
             CASE line >= 0 ?
                  Class.Total_lines_in_test = line.Index + 1 ;
             o[*] = o[*] line.Str ","
             CASE o[*].Len >= 80 ? o[] << "" ;
         ;
         o[] << "-1 };"
         ---------------------------- 'assertions list'
         o[] << "" << "public static ArrayList<Integer> test_assert = null;" <<
                "public static ArrayList<String> test_assert_failed_text"
                " = null;" 
    ;
    --------------------------------- 'main'
    CASE Class == Comp.All_classes[0] ?
         o[] << "    // generate main"
         generate_main(Class) ;
    o[] <<  "}"
    --------------------------------- 'split by #NL'
    split_o_by_NL
    --------------------------------- 'comment portions of code by conditions'
    comment_unnecessary_parts(o[])
    -------------------------------------- 'end'
    RESULT = Comp.Errors_count == 0 .
    
    
METHOD split_o_by_NL :
    FOR i IN [o[].Count-1 DOWNTO 0] :
        STR prev|ios_line_of_o = o[i]
        CASE #NL !IN prev ? CONTINUE i ;
        STR splitted[]
        Split(splitted[], prev, #NL)
        o[].Delete(i)
        FOR s IN splitted[] :
            o[].Insert(i + s.Index, s) ;
    ; .
    
    
METHOD comment_unnecessary_parts( STR Lines|_of_code[] ) :
    STR comment|ing_lines = ""
    FOR s IN Lines[] :
        CASE s.Starting("//?") ?
             STR w|ords_splitted[]
             Split(w[], s.[3 TO *], ".")
             STR class_n|ame = w[0].Trim
             CASE !class_present(class_n) ?
                  comment = comment "."
                  CONTINUE s
             ;
             CASE w[].Count <= 1 ? CONTINUE s ;
             //DEBUG: << "+++++++++++++++++++++++++++++++++++++++++"#NL
             //"check if method " w[1] " is overridden in descendants"
             //" of class " w[0] #NL ;
             -------------------------- '/ / ? {class}.event'
             STR m|ethod_to_check_if_overridden = w[1].Trim
             STR b|ase_class_to_check_descendants_of = w[0].Trim
             w[].Delete(1)
             w[].Delete(0)
             CASE !Comp.Overridden(m, b, w[]) ?
                  comment = comment "." ;
             CONTINUE s ;
    	CASE comment != "" ?
             CASE Starting(s, "//.") && s.Trim == "//." ?
                  comment = comment.[0 TO *-1]
             ELSE Lines[s.Index] = "//-->" s ;
             CONTINUE s ;
    ; .

    
    
METHOD class_present|_in_All_classes(
STR Name|_of_class ) ==> BOOL
	:
    FOR t IN Comp.All_classes[] :
        CASE Name == t.Names[0] ? RESULT = TRUE ==> ;
    ; .
    
FUN Double_trailing_slash( STR Path|_to_append ) ==> STR :
    RESULT = Path
    CASE ! Ending(Path, "\\") ? RESULT = RESULT "\\" ; .

METHOD remove_overridden_method_lines_from_tests_of_base({Fun} F|unction) :
    {Fun} a|ncsector_method = F.Ancestor_
    CASE a == NONE || a.Class != F.Class.Base_ ? ==> ;
    
    o[] << sp(4) "AL4_system.Remove_test_data(" F.Class.Base_.Final_name 
    ".test_lines, " a.Line_start.Str ", " a.Line_end.Str ");" .


METHOD generate_structure_decl(
{Type} Obj|ect_type)
	:
    o[] << sp(4)"public static class " Obj.Final_name " extends Structure_any {"
	--------------------------------- 'constructor of record'
	o[] << sp(8) "public " Obj.Final_name "() {"
	init_object_arrays(o[], Obj, sp(12))
    o[] << sp(8) "}"
    FOR f IN Obj.Field[] :
        o[] << sp(8) "public "
        o[*] = o[*] var_type_gen(f) " " f.Final_name ";" ;
    ------------------------ 'Clone overridden'
    o[] << sp(8) "@Override"
    ..[] << sp(8) "public Ref_obj Clone() {"
    ..[] << sp(12) Obj.Final_name " result = new " Obj.Final_name "();"
    ..[] << sp(12) "result.hard_link = new Ref_obj(result, 2);"
    ..[] << sp(12) "result.weak_link = new Ref_obj(result, 1);"
    ..[] << sp(12) "result.write = result;"
    ..[] << sp(12) "//------------------- fields:"
    ..[] << sp(12) "try {"
    ------------------------ 'assign fields'
    FOR f IN Obj.Field[] :
        CASE f.Is_array ?
        	 o[] << sp(12) "result." f.Final_name " = " 
        	 		"(" type_gen(f.Type_, {type_options}(Array=TRUE, 
                    Fixed=f.Is_fixed, Weak=f.Is_weak)) ")" f.Final_name 
        	 		".Clone_array();"

        	 CONTINUE f ;
    	CASE f.Type_.Kind ?
    	['BOOL', 'ENUM', 'INT', 'REAL', 'STR']:
        	o[] << sp(12) "result." f.Final_name " = " f.Final_name ";"
        	
    	['CLASS']:
    		CASE f.Is_weak ?
        		 o[] << sp(12) "Object_assign_weak("
    		ELSE o[] << sp(12) "Object_assign_hard(" ;
    		o[*] = o[*] "result." f.Final_name ", " f.Final_name ".Obj);"
    		
    	['STRUCTURE']:
        	o[] << sp(12) "result." f.Final_name " = "
        			"((Structure_any)" f.Final_name ".Obj)"
        			".Clone();"
    	;
    ;
    o[] << sp(12) "} catch (Exception ex) {}"
    o[] << sp(12) "return result.hard_link;"
    o[] << sp(8) "}"
    ------------------------------- 'NONE'
	generate_ref(Obj)
    generate_NONE(Obj)
    o[] << sp(4) "}" << "" .


METHOD init_object_arrays|_and_strings(
	STR Out|put_strings[], {Type} Obj|ect_type,
    STR Prefix|_before_field_name)
    :
    FOR f IN Obj.Field[] :
        CASE ?
        [f.Is_fixed] ?
			 CASE f.Size_value == 0 ?
             	  f.Size_value = calculate_size_value(f.Size_n) ;
			 STR nam|e_type = array_type(f.Type_)
			 
             Out[] << Prefix f.Final_name " = new FixA" nam
             		  "(" f.Size_value.Str ");"
             		  
             CONTINUE f
             
        [f.Is_array] ?
        	 nam = array_type(f.Type_)
        	 //DEBUG: Out[] << Prefix "// init object array:" ;
        	 CASE ?
        	 [f.Type_.Kind IN ['CLASS', 'STRUCTURE'] && f.Is_weak] ?
        	      nam = _ "Weak"
        	 [f.Type_.Kind IN ['CLASS', 'STRUCTURE']] ?
        	      nam = _ "Hard"
        	 ELSE 
        	 	Out[] << Prefix f.Final_name " = new DynA" nam "();"
        	 	CONTINUE f ;
        	 Out[] << Prefix f.Final_name " = new DynA" nam "("
        	 CASE f.Type_.Kind == 'STRUCTURE' ?
        	      Out[*] = _ f.Type_.In_class_.Final_name "." ;
        	      
        	 Out[*] = _ f.Type_.Final_name 
        	 		  ".NoneObj_" f.Type_.Final_name ".hard_link"
        	 		  
        	 Out[*] = _ ");"
        	 
        [f.Type_.Kind == 'STR'] ?
             Out[] << Prefix f.Final_name " = " #QU#QU ";"
        ;
    ; .
    
FUN array_type({Type} Type|_of_array) ==> STR :
	CASE Type.Kind ?
    ['BOOL']:  STR nam|e_type = "Bool"
    ['ENUM']:  nam = "Byte"
    ['INT']:   nam = "Int"
    ['STR']:   nam = "Str"
    ['REAL']:  nam = "Real"
    ['CLASS', 'STRUCTURE']: nam = "Obj" ;
    RESULT = nam .
    
                
METHOD calculate_size_value( STR S|tring_value ) ==> INT :
    CASE S.[0] == "{" ?
         {Type} enum|eration = Comp.Current_class.Find_type(S)
         CASE enum == NONE ?
              Comp.Error("Enumeration type was not found"._Eenum 
              ": " S)
         ;
         CASE enum.Kind != 'ENUM' ?
              Comp.Error("Type is not a enumeration"._Etype ": " S) ;
         RESULT = enum.Items[].Count ==> ;
    RESULT = int_from_str(S)
    CASE RESULT <= 0 ?
         Comp.Error("Array size value must be greater "
         "then 0"._Earray) ; .            
         
FUNCTION int_from_str( STR S|tring_only_digits ) ==> INT :
    FOR i IN [0 TO S.Len-1] :
        CASE S.[i] IN "0123456789" ?
             RESULT = RESULT * 10 + S.[i].Ord - "0".Ord
        ELSE ==> ;
    ; .
                 
                 
    
                 


FUN sp|aces_sequence(INT Count|_spaces) ==> STR :
    RESULT = Sp(Count) .



METHOD generate_ref({Type} Class|_to_generate) :
    STR n|ame_of_class = Class.Final_name
    
    o[] << @"" sp(4) "public " n " Write() {"
    "" sp(8) "return (" n ")super.write;"
    "" sp(4) "}"
    ""
    
    o[] << sp(4) "// generating New"
    generate_New(Class, Class.Final_name)
    
    o[] << @""
    "" sp(8) "public static Ref_obj New_owned("
    "" sp(12) "Ref_obj owner)"
    "" sp(8) "{"
    "" sp(8) "    Ref_obj Result = New();"
    "" sp(8) "    Result.Obj.Owned_by(owner);"
    "" sp(8) "    return Result;"
    "" sp(8) "}"
    "" .



METHOD generate_New(
{Type} Class|_to_generate_New, STR N|ame_of_class)
	:
	-------------------------------------- 'New() { ... }'
    o[] << @"" sp(8) "public static Ref_obj New()"
            "" sp(8) "{"
            "" sp(8) "    " N " Result = new " N "();"
            "" sp(8) "    Result.hard_link = new Ref_obj(Result, 0);"
            "" sp(8) "    Result.weak_link = new Ref_obj(Result, 1);"
            "" sp(8) "    Result.write = Result;"
            ""
            
    ------------------------------------ 'Do_init_fields'
    CASE N.Find("Noneclass_") < 0 ?
         STR init|_fields_text = gen_init_fields(Class, FALSE) 
         o[] << init #NL ;
    gen_create_base(Class)
    
    o[] << @""
            "" sp(8) "    return Result.hard_link;"
            "" sp(8) "}" 
            
    ------------------------------------ 'New_nofields'
    o[] << @"" sp(8) "public static Ref_obj New_nofields()"                     
            "" sp(8) "{"                                                 
            "" sp(8) "    " N " Result = new " N "();"                   
            "" sp(8) "    Result.hard_link = new Ref_obj(Result, 2);"
            "" sp(8) "    Result.weak_link = new Ref_obj(Result, 1);"
            "" sp(8) "    Result.write = Result;"
            "" sp(8) "    return Result.hard_link;"
            "" sp(8) "}"
            ""
    .


METHOD gen_create_base(
{Type} Class|_to_generate), RECURSIVE
	:
    CASE Class.Base_ != NONE ?
         gen_create_base(Class.Base_) ;
    INT from|_line = o[].Count
    PUSH new_init = Class.Create_base.Source :
         CASE new_init == NONE ? ==> ;
         o[] << sp(12) "// init base: " Class.Whole_name
         
         f|unction_base_temp = {Fun}(Parse = Class.Parse,
         	A_Name_1 = "CONSTRUCT")
         
         r|esult_def_temp = {Assign}(Line = 0, Function_ = f, Level = 0,
            Dest = {Expr}(
                Operation = 'VAR', Var_arg = {Var}(Line = 0,
                    Type_ = Class)))
                    
         r.Dest.Var_arg.Set_final_name("Result")
         o[] << gen_init_new_obj(r) ;
    FOR line IN [from TO o[].Count-1] :
        STR s|tring_line = o[line]
        CASE s.[0 TO 1] == "//" ? CONTINUE line ;
        INT dot|_position = s.Find(".write).")
        CASE dot > 0 ?
             o[line] = sp(12) "Result" s.[dot+7 TO *] ;
    ; .




INT total_init_fld

METHOD gen_init_fields({Type} Class|_to_generate_fields,
        BOOL Non|e_instance_initializing) ==> STR, RECURSIVE
        :
    FOR f IN Class.Field[] :
        CASE f.Final_name == "DATA" ? CONTINUE f ;
        
        STR s|tring_to_add = #NL sp(12)
            "// init fld: " total_init_fld.Str #NL
            "" sp(12) "Result." f.Final_name " = "
            
        total_init_fld += 1
        CASE f.Is_array ?
                CASE f.Type_.Kind ?
                    ['BOOL']: STR suf|fix_fn = "Bool"
                    ['ENUM']: suf = "Byte"
                    ['INT']: suf = "Int"
                    ['REAL']: suf = "Real"
                    ['STR']: suf = "Str"
                    ['CLASS', 'STRUCTURE']: suf = "Obj" ;
                CASE ?
                [f.Is_fixed && f.Type_.Kind IN ['CLASS', 'STRUCTURE']] ?
                	 RESULT = RESULT s "new FixA" suf 
                	 		"(NoneObj_AL4_object.hard_link);"
                	 		     
                	 CONTINUE f
                [f.Is_fixed] ?
                     RESULT = RESULT s "new FixA" suf
                     RESULT = RESULT "(" f.Size_type_.Items[].Count.Str ");"
                     CONTINUE f ;
                CASE f.Type_.Kind IN ['CLASS', 'STRUCTURE']
                	 && f.Is_weak
                	 ?
                     suf = _ "Weak" ;
                CASE f.Type_.Kind IN ['CLASS', 'STRUCTURE']
                	 && ! f.Is_weak
                	 ?
                     suf = _ "Hard" ;
                s = _ "new DynA" suf
                CASE ?
                [f.Type_.Kind == 'CLASS'] ?
                     s = _ "(" f.Type_.Final_name
                          ".NoneObj_" f.Type_.Final_name
                          ".hard_link)"
                          
                [f.Type_.Kind == 'STRUCTURE'] ?
                     s = _ "(" f.Type_.In_class_.Final_name
                     	  "." f.Type_.Final_name
                          ".NoneObj_" f.Type_.Final_name
                          ".hard_link)"
                          
                ELSE s = _ "()" ;
        ELSE 
             CASE Non && f.Type_.Kind IN ['BOOL', 'INT', 'REAL', 'ENUM'] ?
                  CONTINUE f ;
             CASE ?
             [f.Initial_ != NONE] ? s = _ gen_expr(f.Initial_)
             
             [f.Type_.Kind == 'STRUCTURE'] ?
                  s = _ f.Type_.In_class_.Final_name "." f.Type_.Final_name
                  	   ".New();"
                  	   
             ELSE s = _ gen_none_val(f.Type_) ;
        ;
        RESULT = RESULT s ";" ;
    CASE RESULT != "" ?
        RESULT = #NL sp(12)
        "// init fields: " Class.Final_name #NL RESULT
    ;
    CASE Class.Base_ != NONE ?
        RESULT = gen_init_fields(Class.Base_, FALSE) #NL RESULT ; .    

METHOD generate_NONE({Type} Class|_to_generate) :
    STR n|ame_of_class = Class.Final_name
    STR nn||none_class_name = "Noneclass_" n
    CASE Class.Kind == 'STRUCTURE' ? nn = n ;
    
    o[] << @""
        "" sp(8) "public static " nn " NoneObj_" n ";"
        "" sp(8) "public static " nn " DummyObj_" n ";"
        ""
        "" sp(8) "public static void init_class_" n "()"
        "" sp(8) "{"
        "" sp(8) "    NoneObj_" n " = (" nn ")" nn ""
        "" sp(8) "                        .New_nofields().Obj;"
        "" sp(8) "    DummyObj_" n " = (" nn ")" nn ""
        "" sp(8) "                        .New_nofields().Obj;"
        "" sp(8) "    NoneObj_" n ".write = DummyObj_" n ";"
        "" sp(8) "}"
        ""
        "" sp(8) "@Override"
        "" sp(8) "public AL4_object NONE_base_obj()"
        "" sp(8) "{"
        "" sp(8) "    return "
        
    CASE Class.Base_ == NONE ? o[*] = o[*] "null"
    
    ELSE o[*] = o[*] Class.Base_.Final_name
                 ".NoneObj_" Class.Base_.Final_name
    ;
    o[*] = o[*] ";"
    
    o[] << @"" sp(8) "}"
        ""
        "" sp(8) "@Override"
        "" sp(8) "public Ref_obj NONE_obj_instance()"
        "" sp(8) "{"
        "" sp(8) "    return NoneObj_" n ".hard_link;"
        "" sp(8) "}"
        "" .



METHOD generate_Noneclass(
{Type} Class|_to_generate) ==> BOOL
	:
    -------------------------- 'Noneclass_ is inherited from Methods_ of class'
    STR n|ame_class = Class.Final_name
    
    o[] << @""
            "" sp(4) "public class Noneclass_" n " extends " n
            "" sp(4) "{"
            "" sp(4) "    @Override"
            "" sp(4) "    public void Erase() { }"
            ""
            
    generate_New(Class, "Noneclass_" n)
    
    o[] << @""
            "" sp(4) "    public void Init_none()"
            "" sp(4) "    {"
            "" sp(4) "        Noneclass_" n " Result = this;"
            "" sp(4) "        Result.Is_NONE_object = true;"
            
    STR gen|_init_text = gen_init_fields(Class, TRUE) 
    o[] << gen
    
    o[] << @"" sp(4) "    }"
            ""
    ---------------------------- 'methods for NONE to ignore all calls'
    generate_noneclass_methods(Class)
    
    o[] << @"" sp(4) "}"
            ""
            
    RESULT = TRUE .



METHOD generate_noneclass_methods|_overriden(
{Type} C|lass_to_generate)
	:
    --------------------------------------- 'Generate methods for NoneObj_'
    FOR m IN C.Method[] :
        CASE m == NONE ? CONTINUE m ;
        CASE m.Final_name == "-" ? CONTINUE m ;
        CASE m.Modifiers['STATIC'] ? CONTINUE m ;
        o[] << "" << sp(8) "@Override" << sp(8) "public "
        CASE m.Result !=  NONE ?
             o[*] = o[*] type_gen(m.Result.Type_, {type_options}(Array=FALSE, 
                    Fixed=FALSE, Weak=FALSE)) " "
        ELSE o[*] = o[*] "void " ;
        o[*] = o[*] m.Final_name "( "
        ------------------------------ 'parameters'
        FOR p IN m.Param[] :
            o[] << sp(16) type_gen(p.Type_, {type_options}(Array=p.Is_array, 
                    Fixed=p.Is_fixed, Weak=p.Is_weak)) " " p.Final_name ","
        ;
        CASE m.Modifiers['STORE'] ?
             o[] << sp(16) "Integer " m.Stored_param.Final_name "," ;
        o[*] = o[*].[0 TO *-1] ")"
        ------------------------------ 'body'
        o[] << sp(8) "{"
        CASE m.Result != NONE ?
             o[] << sp(12) "return " gen_none_val(m.Result.Type_) ";" ;
        o[] << sp(8) "}" ; .



METHOD generate_main({Type} Class|_main) :
    ------------------------------------------------ 'Generate main function'
    {Fun} f|unction_main = Class.Search_fun("Main", ONLY_ST | CASE_SEN, TRUE)
    CASE f == NONE ? Comp.Error("Main function was not found") ;
    o[] << "public static void main() "
    o[*] = o[*] "throws Exception"
    o[*] = o[*] " {"
    --------------------------------- 'init classes'
    generate_init_classes
    
    o[] << @""
    "" sp(8) "    try {"
    
    CASE FALSE ? 
         //o[] << sp(16) "Do_tests();"
         //FOR c IN Comp.All_classes[] :
         //    CASE c == Class ? CONTINUE c ;
         //    CASE c.Test[].Count == 0 ? CONTINUE c ;
         //    CASE !c.Class_needs_testing ? CONTINUE c ;
         //    o[] << sp(16) c.Final_name ".Do_tests();" ;
    ELSE o[] << sp(16) f.Final_name "();" ;
     
    o[] << @"" sp(8) "      if (false) throw new AL4StopException(" #QU #QU ");"
            "" sp(8) "    } catch (AL4StopException S) {"
            "" sp(8) "      AL4_system.Any_exception(S);"
            "" sp(8) "      AL4_system.WriteLine("#QU"STOP: "#QU" + "
            "" sp(8) "          S.Stop_message);"
            "" sp(8) "      AL4_system.ReadLine();"
            "" sp(8) "    }"
            "}"
            "" .

METHOD generate_init_classes|_for_main_or_tests :
    o[] << sp(8) "    // init classes"
    o[] << sp(8) "AL4_object.init_class_AL4_object();"
    {Type} list_obj|ect_types_to_init[]
    FOR c IN Comp.All_classes[] :
        STR n|ame_of_class = c.Final_name
        o[] << sp(12) n ".init_class_" n "();"
        FOR st IN c.Structures_[] :
        	list_obj[] << st ; 
    ;
    FOR x IN [0 TO list_obj[].Count-1] :
        CASE list_obj[x] == NONE ? CONTINUE x ;
        do_init_obj(list_obj[], x) ;
    o[] << sp(8) "    // init none objects fields"
    FOR c IN Comp.All_classes[] :
        n = c.Final_name
        o[] << sp(12) n ".NoneObj_" n ".Init_none();"
        
        o[] << sp(12) "((Noneclass_" n ")" n
               ".DummyObj_" n ").Init_none();"
    ; .
    
METHOD do_init_obj(
	{Type} Obj|ects_to_init[], INT Index|_of_object_to_init INDEXING {Type}),
	RECURSIVE
	:
	FOR f IN Obj[Index].Field[] :
	    CASE f.Type_.Kind == 'STRUCTURE' 
	    	 && f.Type_ != Obj[Index] && f.Type_ IN Obj[]
	    	 ?
	    	 INT x|_position INDEXING {Type} = Obj[].Find(f.Type_) 
	         do_init_obj(Obj[], x) ;
	;
	STR obj_n|ame = Obj[Index].Final_name
	
	o[] << sp(12) Obj[Index].In_class_.Final_name "." obj_n 
        	   ".init_class_" obj_n "();"
        	   
	Obj[Index] = NONE . 
    


METHOD generate_enum({Type} E|numeration) :
    o[] << sp(8) "public static String[] Names_" E.Final_name
           " = new String[]{"
    FOR it IN E.Items[] :
        o[] << sp(12) #QU it.Names[0] #QU "," ;
    o[*] = o[*].[0 TO *-1] "};"
    o[] << "" .



INT total_gen_field

METHOD generate_field({Var} V|ariable) :
    o[] << sp(8) "// declare: " total_gen_field.Str
    total_gen_field += 1
    o[] << sp(8) "public "
    CASE V.Final_name == "DATA" ?
         o[*] = o[*] "static " ;
    o[*] = o[*] var_type_gen(V) " " V.Final_name
    CASE V.Is_array ?
         CASE V.Final_name == "DATA" ?
              o[*] = o[*] " = new FixAStr(new String[]{"
              FOR d IN Comp.Current_class.Ending_lines[] :
                  o[] << d.as_str "," ;
              o[] << #QU #QU "})" ;
         o[*] = o[*] ";" ==> ;
    CASE V.Type_.Kind ?
        ['STR']: o[*] = o[*] " = " #QU #QU ";"
        
        ['BOOL', 'INT', 'REAL', 'ENUM', 'CLASS', 'STRUCTURE']:
                 o[*] = o[*] ";"
    ; .

METHOD var_type_gen({Var} V|ariable) ==> STR :
    RESULT = type_gen(V.Type_, {type_options}(Array=V.Is_array, 
                Fixed=V.Is_fixed, Weak=V.Is_weak))
    CASE !Comp.Int32 && RESULT == "long" && V.Is_stored_param ? 
         RESULT = "int" ;
    RESULT = RESULT " " .


STRUCTURE {type_options} :
	BOOL Array|_value
	BOOL Fixed|_array
	BOOL Weak|_object .    

FUNCTION type_gen|erate({Type} T|ype_of_var,
                        {type_options} Op|tions_var) ==> STR
                        :
    ------------------------------------------------ 'Generate type declaration'
    CASE T.Kind ?
         ['BOOL']: RESULT = "boolean"
         ['ENUM']: RESULT = "byte"
         ['INT']: RESULT = "int"
         ['REAL']: RESULT = "double"
         ['STR']: RESULT = "String"
         ['CLASS', 'STRUCTURE']: RESULT = "Ref_obj" ;
    CASE ! Op.Array ? ==> ;
    CASE ! Op.Fixed ?
         CASE T.Kind ?
              ['BOOL']: RESULT = "DynABool"
              ['ENUM']: RESULT = "DynAByte"
              ['INT']: RESULT = "DynAInt"
              ['REAL']: RESULT = "DynAReal"
              ['STR']: RESULT = "DynAStr"
              ['CLASS', 'STRUCTURE']: RESULT = "DynAObj" 
                         CASE Op.Weak ? RESULT = RESULT "Weak"
                         ELSE RESULT = RESULT "Hard" ;
         ;
    ELSE 
         CASE T.Kind ?
              ['BOOL']: RESULT = "FixABool"
              ['ENUM']: RESULT = "FixAByte"
              ['INT']: RESULT = "FixAInt"
              ['REAL']: RESULT = "FixAReal"
              ['STR']: RESULT = "FixAStr"
              ['CLASS', 'STRUCTURE']: RESULT = "FixAObj" ;
    ; .

//FUN shortstr_gen({Var} V|ariable_dummy) ==> STR :
//    RESULT = "String " .

METHOD generate_constant_array(
{Var} C|onstant_array_to_generate)
	:
	o[] << "" << sp(8) "public static final " type_gen(C.Type_, {type_options}) 
		   "[] " C.Final_name " = {"
		   
	o[] << sp(12) 
		   
	FOR it IN C.Items_[] :
	    STR v_gen|erated = gen_const_value(it)
	    CASE o[*].Len >= 50 && o[*].Len + v_gen.Len >= 79 ?
	         o[] << sp(12) ;
	    o[*] = o[*] v_gen ", " ;
		   
	o[*] = o[*].TrimR.Remove_ending(",") "};" .
	


BOOL FINAL_CODE = TRUE
CONST BOOL:
	USE_STACK_OF_VAR|IABLES = FALSE
	USE_STACK_OF_FUN|CTIONS = TRUE .
	

CONST BOOL: DEBUG|GING_METHODS = TRUE .
INT total_init_var
BOOL stopping_tests|_possible_in_class

METHOD generate_method({Fun} F|unction) :
	CASE F == NONE ? ==> ;
    ------------------------------------------- 'Prepare to generate a method'
    CASE F.Final_name == "-" ? o[] << F.Native_code ==> ;
    Comp.Current_fun = F
    Comp.Current_class.Parse.Line = F.Line_start
    o[] << ""
    o[] << "// fun: " F.Total_fn.Str " " F.Names[0]
    spaces = ""
    new_init = NONE
    --------------------------------- 'start total_init_var from a new page 100'
    total_init_var += 99
    total_init_var -= total_init_var % 100
    ---------------------------- 'header'
    CASE DEBUG ?
        o[] << "public static int CNT_" F.Final_name ";" << "" ;
    ---------------------------- '@Override ?'
    CASE F.Ancestor_ != NONE ?
          CASE F.Modifiers['STATIC'] ?
               Comp.Error("Internal error: static function can "
               "not be override"._Einternal )
          ELSE o[] << "@Override" ;
    ;
    o[] << "public "
    CASE F.Modifiers['STATIC'] ? o[*] = o[*] "static " ;
    CASE F.Result == NONE ? o[*] = o[*] "void "
    
    ELSE o[*] = o[*] type_gen(F.Result.Type_, {type_options}(Array=FALSE, 
            Fixed=FALSE, Weak=FALSE)) " "
    ;

    o[*] = o[*] F.Final_name "(" sp(1)
    ---------------------------- 'parameters'
    FOR p IN F.Param[] :
        o[] << sp(8) type_gen(p.Type_, {type_options}(Array=p.Is_array, 
                Fixed=p.Is_fixed, Weak=p.Is_weak))
               " " p.Final_name ","
    ;
    CASE F.Modifiers['STORE'] ?
         o[] << sp(16) "Integer " F.Stored_param.Final_name "," ;
    o[*] = o[*].[0 TO *-1] ")"
    ----------------------------- 'declare can throw exceptions'
    CASE F.Is_test ?
         NONE = F.Check_recursive ;
    BOOL recur|sion = F.Modifiers['RECURSIVE_FUN']
    o[*] = o[*] " throws Exception"
    o[*] = o[*] " {"
    CASE DEBUG ? 
         o[] << "    if (++CNT_" F.Final_name " == 0 )" #NL
         		"    { }"
	;
    CASE trace_fun ?
         STR f_w|hole_name = F.Whole_name
          
         o[] << "AL4_system.WriteLine(" #QU "trace_fun:" F.Class.Names[0]
                "." f_w #QU ");" ;
	---------------------------- 'functions stack needed ?'
	CASE Comp.Debugging && USE_STACK_OF_FUN && !FINAL_CODE ?
	     BOOL stack_of_fun|ctions = TRUE
	     o[] << "	try"
	     o[]<< "	{"
	     
	     o[]<< "		AL4_system.Stack_functions["
	      	   "AL4_system.SP_fun++] = " F.Global_n.Str ";"
	      	   
	     o[]<< "		AL4_system.Stack_functions["
	 		   "AL4_system.SP_fun++] = CNT_" F.Final_name ";"
	 		   
	     spaces = spaces sp(4)
	;
    
    ---------------------------- 'CONSTRUCT ?'
    CASE F == F.Class.Construct && F.Class.Base_ != NONE ?
         o[] << spaces sp(4) "super.CONSTRUCT();" ;
    ---------------------------- 'local variables'
    object_var = FALSE
    dynamic_arr = FALSE
    init_local_vars(F, NONE)
    ------------------------------------ 'LIMIT FUN present'
    CASE Comp.Has_LIMIT_FUNC ? 
         o[] << spaces sp(4) "AL4_system.total_func += 1;"
    ;
    ---------------------------- 'need try ?'
    BOOL need_try = F.Has_add || recur || object_var || dynamic_arr
    CASE !need_try ?
         need_try = F.Is_test
         need_try &&= F.Calling_any_recursive_fun ;
	need_try ||= F.Overrides_any_calling_recursive_fun
	need_try ||= F.Modifiers['NATIVE_FUN']  
    CASE need_try ?
         o[] << spaces "try {"
         spaces = _ sp(4) 
	     ---------------------------- 'recursive ?'
	     CASE recur ?
	          o[] << spaces "if (AL4_system.Recursion_counter"
	                 " > AL4_system.Max_recursion_deep)" #NL
	                 "" spaces sp(4) "throw new "
	                 "TooDeepRecursionException();"
	          o[] << spaces "AL4_system.Recursion_counter++;" ;
    ;
    ---------------------------- 'statements'
    BOOL last_is_infinite|_block = FALSE
    CASE F.Class == Comp.All_classes[0]
    	 && F.Names[0] == "threaded_run"
    	 && "$TEST" IN Comp.Defined_name[]
    	 ?
		 FOR c IN Comp.All_classes[] :
	         CASE c.Test[].Count == 0 ? CONTINUE c ;
	         CASE !c.Class_needs_testing ? CONTINUE c ;
	         o[] << #TAB#TAB c.Final_name ".Do_tests();" ;
    ELSE
    	 FOR st IN F.Block[] : 
    	     statement_gen(st)
    	 ;
    	 last_is_infinite = if_last_is_infinite(F.Block[])
    ;
    ---------------------------- 'native ?'
    CASE F.Modifiers['NATIVE_FUN'] ?
         CASE Comp.TEST_value && Comp.Current_class.Modifiers['TESTED'] ?
              INT line|_of_native_fun INDEXING INT = F.Line_start + 1
              FOR i|dummy IN [tcl[].Count TO line] : tcl[] << -1 ;
              tcl[line] = 0
              o[] << "    test_lines" "[" line.Str "] = AL4_system.Test_caller;"
         ;
         o[] << F.Native_code
    ;
    ----------------------------- 'return RESULT'
    CASE F.Result != NONE && !F.Block[*].Is_jump && !last_is_infinite ?
         o[] << spaces "return RESULT; /" "*X*" "/" ;
    ----------------------------- 'catch OutOfMemory'
    CASE F.Has_add ?
         o[] << spaces @"} catch (OutOfMemoryError E_mem) {"
             "" spaces "  AL4_system.Any_exception(E_mem);"
             "" spaces "  if (AL4_system.Recursion_counter > 1)"
             "" spaces "     throw E_mem;"
             "" spaces "  return"
         CASE F.Result != NONE ?
              o[*] = o[*] " " gen_none_val(F.Result.Type_) ;
         o[*] = o[*] ";" ;
    ---------------------------- 'catch recursion too deep'
    BOOL recur_too_deep|_recursion_catch = recur
    CASE !recur_too_deep ?
         recur_too_deep = F.Is_test
         CASE recur_too_deep ?
              recur_too_deep = F.Calling_any_recursive_fun
              recur_too_deep ||= F.Overrides_any_calling_recursive_fun ;
    ;  
    CASE recur_too_deep ?
         o[] << spaces.[0 TO *-4] "}"
         o[] << spaces.[0 TO *-4] "catch (TooDeepRecursionException E_rec) {"
         o[] << spaces "AL4_system.Any_exception(E_rec);"
         CASE !F.Is_test ?
              o[] << spaces "  if (AL4_system.Recursion_counter > 1)"
              o[] << spaces "     throw E_rec;"
         ;
         o[] << "" spaces "  return"
         CASE F.Result != NONE ?
              o[*] = o[*] " " gen_none_val(F.Result.Type_) ;
         o[*] = o[*] ";" ;
    ---------------------------- 'catch any exception in native code'
    CASE F.Modifiers['NATIVE_FUN'] ?
         o[] << spaces.[0 TO *-4] @"}"
         "" spaces.[0 TO *-4] "catch (Exception E_any) {"
         "" spaces "AL4_system.Any_exception(E_any);"
         o[] << "" spaces "  return"
         CASE F.Result != NONE ?
              o[*] = o[*] " " gen_none_val(F.Result.Type_) ;
         o[*] = o[*] ";" ;
    ---------------------------- 'finally...'
    CASE need_try ?
         spaces = spaces.[0 TO * - 4]
         o[] << spaces "} finally {"
         CASE recur ?
              o[] << spaces "  AL4_system.Recursion_counter--;" ;
         PUSH spaces = spaces sp(4) :
              dispose_local_vars(F, NONE)
         ;
         -------------------------------------- 'DESTRUCTOR ?'
         CASE F == F.Class.Destruct && F.Class.Base_ != NONE ?
              o[] << spaces sp(4) "super.DESTRUCT();" ;
         o[] << spaces "}"
         spaces = spaces.[0 TO * - 4] ;
    CASE !FINAL_CODE && stack_of_fun ?
         spaces = spaces.[0 TO * - 4]
         o[]<< "	} finally "
         o[]<< "	{"
         o[]<< "		AL4_system.SP_fun -= 2;"
         o[]<< "	}" ;
    o[] << "}" .
    
BOOL object_var|iables_present   
BOOL dynamic_arr|ays_present 
    
METHOD init_local_vars(
{Fun} F|unction, {Local} Loc|al_block) 
    :
    FOR v IN F.Local_var[] :
        CASE v.In_local_ != Loc ? CONTINUE v ;
		CASE v.Names[0] != "RESULT" ? 
			 CASE v.Is_param || v.Names[*] == "THIS" ? CONTINUE v ;
		;
        CASE v.Declared_in_debug && Comp.Final ? CONTINUE v ;
        o[] << spaces "// init var: " total_init_var.Str
        total_init_var += 1
        
        o[] << spaces "/*1*/" type_gen(v.Type_, {type_options}(Array=v.Is_array, 
                Fixed=v.Is_fixed, Weak=v.Is_weak)) " " v.Final_name " = "
                
        CASE v.Type_.Kind ?
            ['BOOL']: STR iv|_initial = "false"
            ['INT', 'ENUM', 'REAL']: iv = "0"
            ['STR']: iv = #QU #QU
            
            ['CLASS']: iv = v.Type_.Final_name
                iv = _ ".NoneObj_" iv ".hard_link"
                object_var = TRUE
                
            ['STRUCTURE']:
                iv = v.Type_.In_class_.Final_name "." v.Type_.Final_name 
                	 ".New()"
                	 
                object_var = TRUE
        ;
        CASE v.Is_array ?
             iv = "new " "/*2*/" type_gen(v.Type_, {type_options}(Array=TRUE, 
                    Fixed=v.Is_fixed, Weak=v.Is_weak)) "("
             CASE ?
             [v.Type_.Kind == 'CLASS'] ?
                  STR t|ype_name = v.Type_.Final_name
                  iv = _ t ".NoneObj_" t ".hard_link" "/*3c*/"
             [v.Type_.Kind == 'STRUCTURE'] ?
                  t = v.Type_.Final_name
                  
                  iv = _ v.Type_.In_class_.Final_name 
                  		"." t ".NoneObj_" t ".hard_link" "/*3o*/"
                  		
             [v.Is_fixed] ? iv = _ "0" "/*6*/"
             ;
             iv = _ ")"
             CASE !v.Is_fixed ?
                  dynamic_arr = TRUE ;
        ;
        o[*] = o[*] iv ";" ;
    .
    
METHOD dispose_local_vars(
{Fun} F|unction,
{Local} Loc|al_block)
	:
    FOR v IN F.Local_var[] :
        CASE v.In_local_ != Loc ? CONTINUE v ;
        CASE v IN F.Param[] || v.Names[0] IN ["THIS", "RESULT"] ?
             CONTINUE v ;
        CASE v.Declared_in_debug && !Comp.Debugging ? CONTINUE v ;
        gen_dispose_var(v) ;
    .
    
FUNCTION if_last_is_infinite(
{Statement} Block|_generated[]) ==> BOOL, RECURSIVE
	:
	FOR st IN Block[* DOWNTO 0] :
	    //CASE st.Work == 'FOREVER' ? RESULT = TRUE ==> ;
	    CASE st.Work == 'FOR' && st.{For}.Infinite ? RESULT = TRUE ==> ;
	    CASE st.Work IN ['CASE', 'FOR'] ? ==> ;
	    RESULT = if_last_is_infinite(st.Block_[])
	    CASE RESULT ? ==> ;
	; .
	


METHOD gen_dispose_var({Var} V|ariable_local) :
    CASE V.Is_array ?
         CASE V.Type_.Kind == 'CLASS' ?
              o[] << spaces V.Final_name ".Dispose();"
         ELSE o[] << spaces V.Final_name ".Dispose();" ;
    ELSE 
         CASE V.Type_.Kind == 'CLASS' ?
         o[] << spaces V.Final_name ".Ref_dec_hard();" ;
    ; .



INT level_expr|ession
BOOL is_left_side
BOOL close_br|acket_right_side
//INT total_stmt|_output_index
INT line_current_statement|_will_be_placed
//BOOL is_last|_statement_in_functions
//INT f1st_line|_of_function_code

STR add_after[]

METHOD statement_gen|erate(
{Statement} St|atement), RECURSIVE
	:
    ------------------------ 'prevent java from stop compiling'
    ------------------------ 'if it founds unreachable statements:'
    CASE o[*].Trim == "return;" || o[*].Trim.Starting("return ") ?
         o[*] = spaces "if (true) " o[*].Trim ;
    ------------------------ 'stmt:'
    //o[] << spaces "// stmt: " total_stmt++.Str " (Line:" (St.Line+1).Str ")"
    
    o[] << spaces "// stmt: " St.Total_stmt.Str 
        " obj: " Total_obj_index(St).Str
        " (Line:" (St.Line+1).Str ")"
        
    CASE St.Total_stmt == 0 ? NONE ;
        
    CASE St.Inline_index != "" ?
         o[*] = o[*] " INLINE: " St.Inline_index 
                 " (" St.Total_stmt.Str ")"
    ;           
    CASE St.Line > 0 && trace_lines != "" && (
         trace_lines IN Comp.Current_fun.Names[] )
         ?
         o[] << spaces "AL4_system.WriteLine(" #QU "trace " trace_lines 
         ", line:" St.Line.Str #QU ");"
	; 
    CASE Comp.TEST_value && Comp.Generating_test && St.Line > 0 ?
         o[] << spaces "AL4_system.Test_caller = "
         CASE Comp.Current_class.Modifiers['ABSTRACT'] ?
              -------------- 'all tests of abstract class are secondary'
              o[*] = o[*] "AL4_system.Test_caller % 1000000L + " St.Line.Str
              " * 1000000L;"
              
         ELSE o[*] = o[*] St.Line.Str ";" ;
    ;
    CASE Comp.TEST_value && !Comp.Generating_test && St.Line > 0 && (
         St.Work != 'CASE')
         ?
         FOR i|dummy IN [tcl[].Count TO St.Line] : tcl[] << -1 ;
         CASE !(Comp.Current_fun.Is_trivial && (
              Comp.Current_class.Modifiers['NATIVE']))
              ?
              INT i_tcl INDEXING (INT,STR) = St.Line
              tcl[i_tcl] = 0 ;
              
         o[] << spaces "if (test_lines[" St.Line.Str "] == 0) "
         "test_lines[" St.Line.Str "] = AL4_system.Test_caller;"
    ;
    ------------------------------------------ 'by statement type'
    line_current_statement = o[].Count
    CASE St.Work ?
        ['ASSIGN']: STR assign_g|enerated = generate_assign(St.{Assign})
        			o[] << assign_g 
        ['APPEND']: STR append_g|enerated = generate_append(St.{Assign})  
             		o[] << append_g
        ['OUTPUT']: generate_output(St.{Assign})
        ['INPUT']:  generate_input(St.{Assign})
        ['BREAK']:  generate_break(St.{For})
        ['CONTINUE', 'NEXT']: generate_cont(St.{For})
        ['RETURN']: generate_return(St.{Case})
        ['CASE', 'ELSE']: gen_case(St.{Case})
        ['LIMIT']: gen_limit(St.{Limit})
        ['LOCAL']: gen_local(St.{Local})
        ['FOR']: generate_for(St.{For})
        ['PUSH']:   generate_push(St.{Assign})
        ['STOP']:   generate_stop(St.{Case})
        ['ASSERT']: generate_assert(St.{Case})
        ['DEBUG']:  
                    CASE !Comp.Final ?
                         generate_block(St.Block_[]) ;
        ['COMMENT']: gen_comment_block(St.{Assign})
        ['CALL_NATIVE']: NONE ;
    ------------- 'if something should be added after the statement generated:'
    FOR aa IN add_after[] : o[] << aa ;
    add_after[].Clear .

METHOD generate_assign(
{Assign} A|ssignment) ==> STR, RECURSIVE
	:
    ------------------------------- 'Assigning a value'
    close_br = FALSE
    CASE ?
    [A.Dest != NONE && A.Dest.Var_arg != Comp.NONE_c] ?
         ------------------------------------ 'assign to a single symbol'
         CASE A.Dest.Operation == 'INDEX' && A.Dest.Arg1_.Operation == 'INDEX' ?
              RESULT = RESULT spaces 
              .. = _ gen_expr(A.Dest.Arg1_.Arg1_) 
              .. = _ ".Set_item(" gen_expr(A.Dest.Arg1_.Arg2_)
              .. = _ ", AL4_system.Change_single_symbol(" 
              .. = _  gen_expr(A.Dest.Arg1_.Arg1_)
              .. = _ ".Get_item(" gen_expr(A.Dest.Arg1_.Arg2_) 
              .. = _ "), " gen_expr(A.Dest.Arg2_) 
              .. = _ ", " gen_expr(A.Source) "));" 
              
              ==> ;
              
         BOOL single_sym|bol = A.Dest.Operation == 'INDEX' 
         	  single_sym &&= A.Dest.Type_expr.Kind == 'STR'
         	  single_sym &&= ! A.Dest.Arg1_.Is_array
         	  single_sym &&= A.Dest.Arg3_ == NONE   
         CASE single_sym ?
              RESULT = RESULT spaces
              RESULT = RESULT gen_expr(A.Dest.Arg1_) 
              RESULT = RESULT " = AL4_system.Change_single_symbol("
              PUSH is_left_side = TRUE :
                   RESULT = RESULT gen_expr(A.Dest.Arg1_) ;
              RESULT = RESULT ", " gen_expr(A.Dest.Arg2_) 
              RESULT = RESULT ", " gen_expr(A.Source) ");"
              ==> ;
         ------------------------------ 'to an item of an objects array'
         CASE A.Dest.Type_expr.Kind IN ['CLASS', 'STRUCTURE'] 
         	  && A.Dest.Operation == 'INDEX'
              ?
              PUSH is_left_side = TRUE :
                   RESULT = RESULT spaces gen_expr(A.Dest.Arg1_) ;
                   
              RESULT = RESULT ".Set_item(" gen_expr(A.Dest.Arg2_) 
              RESULT = RESULT ", " gen_obj_expr(A.Source, A.Dest.Type_expr) ");"
                     
              CASE A.Source.Operation == 'FUN' && ! A.Dest.Is_weak ?
                   RESULT = RESULT #NL spaces 
                   RESULT = RESULT gen_expr(A.Dest) 
                   RESULT = RESULT ".Ref_dec_hard();"
              ;
              CASE A.Source.Operation == 'FUN' && A.Dest.Is_weak ?
                   RESULT = RESULT #NL spaces 
                   RESULT = RESULT gen_expr(A.Dest) 
                   RESULT = RESULT ".Ref_dec_weak();"
              ;
              RESULT = RESULT finish_assign_object(A) ==> ;
         ------------------------------ 'to an item of an array'
         CASE A.Dest.Operation == 'INDEX' && A.Dest.Arg1_.Is_array ?
              PUSH is_left_side = TRUE :
                   RESULT = RESULT spaces gen_expr(A.Dest.Arg1_) ;
                   
              RESULT = RESULT ".Set_item(" gen_expr(A.Dest.Arg2_) 
              RESULT = RESULT ", " gen_obj_expr(A.Source, A.Dest.Type_expr) ");" 
              ==>
         ;
         --------------------------------- 'to a scalar object variable'
         BOOL scalar_obj = ! A.Dest.Is_array
         	  scalar_obj &&= A.Dest.Type_expr.Kind IN ['CLASS', 'STRUCTURE']  
         CASE scalar_obj ?
              PUSH is_left_side = TRUE :
                   RESULT = RESULT spaces gen_expr(A.Dest) ;
              RESULT = RESULT " = AL4_object.Object_assign_"
              CASE A.Dest.Is_weak ? RESULT = RESULT "weak"
              ELSE RESULT = RESULT "hard" ;
              CASE A.Source.Operation == 'FUN' ? RESULT = RESULT "_noincref" ;
              PUSH is_left_side = TRUE :
                   RESULT = RESULT "(" gen_expr(A.Dest) ;
                   
              RESULT = RESULT ", " gen_obj_expr(A.Source, A.Dest.Type_expr) 
              RESULT = RESULT ".Obj);" finish_assign_object(A) ==> 
         ;
         ------------------------------ 'to an object which can be NONE'
         BOOL obj_none|_possible = A.Dest.Operation == 'FIELD'
         	  obj_none &&= A.Dest.Type_expr.Kind IN ['CLASS', 'STRUCTURE']
         	  {Expr} a1|_A_Dest_Arg1 = A.Dest.Arg1_
         	  obj_none &&= a1.Type_expr.Kind IN ['CLASS', 'STRUCTURE']
         	  obj_none &&= a1.Type_expr.Has_destructors 
         CASE obj_none ?
              RESULT = RESULT spaces "if (!("
              RESULT = RESULT gen_expr(a1) ")"
              CASE !Ending(RESULT, "(Result)") ? RESULT = RESULT ".Obj" ;
              RESULT = RESULT ".Is_NONE_object)" ;
         PUSH is_left_side = TRUE :
              CASE A.Dest.Is_fixed && A.Source.Operation == 'INDEX' && (
                   A.Source.Arg3_ != NONE)
                   ?
                   ------ 'special assign A[x TO y] to temp fixed array'
                   RESULT = RESULT spaces gen_expr(A.Dest) ".Dispose();"
                   
                   RESULT = RESULT spaces gen_expr(A.Dest) " = "
                   "new " type_gen(A.Dest.Type_expr, {type_options}(Array=TRUE, 
                        Fixed=TRUE, Weak=FALSE))
                   "(" gen_expr(A.Source.Arg1_)
                   ", " gen_expr(A.Source.Arg2_)
                   ", " gen_expr(A.Source.Arg3_) ");" ==>
              ;
              CASE A.Dest.Is_array ?
                   RESULT = RESULT spaces gen_expr(A.Dest) ".Clear();" ==> ;
              RESULT = RESULT spaces gen_expr(A.Dest) ;
         CASE !close_br && A.Source != NONE ? RESULT = RESULT " = " ;
    [A.Source.Operation IN ['VAR', 'FIELD', 'INDEX']] ? ==>
    ELSE RESULT = RESULT spaces ;
    ------------------------------------------------ 'assign right side'
    CASE A.Source != NONE ?
         PUSH A.Dest :
              CASE A.Dest.Var_arg == Comp.NONE_c
                   && A.Source.Operation == 'NEW_OBJ'
                   ?
                   dummy_var += 1 
        	       RESULT = spaces "Ref_obj" 
        	       RESULT = RESULT " dummy" dummy_var.Str " = " 
        	       
        	       A.Dest = {Expr}(Operation = 'VAR',
        	       	Var_arg = {Var}(Line = 0,
        	       	Type_ = A.Source.Type_expr))
        	       	
        	       A.Dest.Var_arg.Set_final_name("dummy" dummy_var.Str)
              ;
	          CASE A.Source.Var_arg == Comp.NONE_c ?
	               RESULT = RESULT gen_none_val(A.Dest.Type_expr)
	          ELSE STR r|ight_side = gen_expr(A.Source).Remove_br
	        	   BOOL to_byte|_convert = A.Dest.Type_expr.Kind == 'ENUM'
	        	 	    to_byte &&= A.Source.Type_expr.Kind != 'ENUM'  
	               CASE to_byte ? r = "(byte)(" r ")" ;
	               RESULT = RESULT r ;
	          CASE close_br ? RESULT = RESULT ")" ;
	          close_br = FALSE     
	          RESULT = RESULT ";" finish_assign_object(A) ==>
         ;
    ;
    RESULT = RESULT ";"
    close_br = FALSE .
    
INT dummy_var|iables_count

         
METHOD gen_obj_expr(
{Expr} E|xpression, {Type} T|ype_of_object) ==> STR
    :
    ------------------------------------ 'NONE'
    CASE E.Var_arg == Comp.NONE_c ?
         RESULT = gen_none_val(T)
    ------------------------------------ 'not NONE'
    ELSE RESULT = gen_expr(E) ; 
    ------------------------------------ '{new object}(), OWNED BY'
    CASE E.Owned_ != NONE ?
         RESULT = RESULT ".Obj.Owned_by(" gen_expr(E.Owned_) ")" ; .
         
         
METHOD finish_assign_object(
{Assign} A|ssignment) ==> STR
    :
   ------------------------ 'assign of new obj, init its fields'
   CASE new_init != NONE ?
        {Type} t|ype_object = new_init.Type_expr
        RESULT = RESULT #NL gen_init_new_obj(A)
        CASE A.Dest != NONE ? 
             STR call|_construct = gen_call_construct(t, gen_expr(A.Dest))
        ;
        CASE call != "" ? RESULT = RESULT #NL spaces call ;
   ;
   ------------------------ ', >> array[]'
   CASE A.Source.Array_ != NONE ?
        RESULT = RESULT #NL spaces 
        RESULT = RESULT gen_expr(A.Source.Array_) 
        RESULT = RESULT ".Add(" gen_expr(A.Dest) ");" ; .

FUN gen_call_construct({Type} C|lass_constructing_obj,
    STR Th|is_obj) ==> STR
    :
    ----------------------------------------------- 'Calling a constructor'
    {Type} cf|un_class = C
    FOR i|dummy IN [0 TO MAX_INT-1] :
        CASE cf == NONE ? BREAK i ;
        CASE cf.Construct != NONE ?
            RESULT = "((" cf.Final_name ")(" Th
            CASE Th != "this" ? RESULT = RESULT ".Obj" ;
            RESULT = RESULT "))." cf.Construct.Final_name "();" ==> ;
        cf = cf.Base_
    ; .



METHOD gen_init_new_obj({Assign} A|ssignment) ==> STR :
    {Expr} init_expr = new_init
    new_init = NONE
    //CASE init_expr.Assignments_[].Count > 0 ?
    //     RESULT  << "//init fields of new object:" ;
    FOR a IN init_expr.Assignments_[] :
        {Assign} aa|ssign_a = a.{Assign}
        CASE aa.Dest.Operation ?
            ['FIELD']:
                PUSH aa.Dest.Arg1_ = A.Dest :
                     RESULT = RESULT #NL generate_assign_or_append(aa) ;
            ['INDEX']:
                CASE aa.Dest.Arg1_.Operation == 'FIELD' ?
                     PUSH aa.Dest.Arg1_.Arg1_ = A.Dest :
                          RESULT = RESULT #NL generate_assign_or_append(aa) ;
                          
                ELSE Comp.Error("Init indexed"._Einit
                     " " aa.Dest.Arg1_.Operation.Name "?")
                ;
            ['VAR']:
                PUSH init_expr = NONE :
                     RESULT = RESULT #NL generate_assign_or_append(aa) ;
                     
            ['BINARY', 'FUN', 'BASE_FUN', 'SYSTEM_FUN', 
             'NEW_OBJ', 'ARRAY', 'AS', 'CONSTANT', 'UNKNOWN',
             'INT2REAL', 'NOT_B', 'NOT', 'NEG']:
                Comp.Error("Unknown init of"._Eunk 
                " " aa.Dest.Operation.Name) ;
    ; .



METHOD generate_assign_or_append({Assign} A|ssign_or_append) ==> STR :
    CASE A.Work ?
        ['ASSIGN']: RESULT = RESULT generate_assign(A)
        ['APPEND']: RESULT = RESULT generate_append(A)
        
        ['OUTPUT', 'INPUT', 'BREAK', 'NEXT', 'CONTINUE', 'RETURN', 'CASE', 
         'LIMIT', 'LOCAL', 'ELSE', 'FOR', 'PUSH', 'STOP', 'ASSERT', 
          'COMMENT', 'DEBUG', 'CALL_NATIVE']:
          Comp.Error("Invalid field initialization operation"._Einvalid2 ) ; .


METHOD generate_append({Assign} A|ppend_stmt) ==> STR :
    {Expr} source|_to_append = A.Source
    PUSH close_br = FALSE :
         CASE A.Dest.Operation == 'INDEX' && A.Dest.Type_expr.Kind == 'STR' ?
              RESULT = RESULT spaces gen_expr(A.Dest.Arg1_) 
              ".Set_item(" gen_expr(A.Dest.Arg2_) 
              ", " gen_expr(A.Dest.Arg1_) ".Get_item(" 
              RESULT = RESULT gen_expr(A.Dest.Arg2_)
              ") + " gen_expr(source) ");" ==>
         ;
         PUSH is_left_side = TRUE : RESULT = RESULT spaces gen_expr(A.Dest) ;
         CASE A.Dest.Is_array ?
              STR app|ending = ".Add(" 
              CASE A.Source.Var_arg == Comp.NONE_c ?
                   app = _ gen_none_val(A.Dest.Type_expr)
                   
              ELSE app = _ byte_typecast_if_need(
                   A.Dest.Type_expr, source, gen_expr(source).Remove_br)
              ;
              RESULT = RESULT app  ");" ==> ;
         CASE close_br ?
              app = gen_expr(A.Dest) " + "
         ELSE app = " += " ;
         RESULT = RESULT app gen_expr(source).Remove_br
         CASE close_br ? RESULT = RESULT ")" ;
         RESULT = RESULT ";" ; .



METHOD generate_output({Assign} A|_output) :
    STR s|tring_expr = gen_expr(A.Source)
    //o[] << "// " s
    s = Remove_br(s)
    //o[] << "// " s
    o[] << spaces "AL4_system.Write(" s ");" .



METHOD generate_input({Assign} A|_input_stmt) :
    CASE A.Dest == NONE ?
         //CASE Comp.TEST_value ? ==> ;
         o[] << spaces "AL4_system.ReadLine();" ==> ;
    CASE A.Dest.Type_expr.Kind == 'STR' ?
        STR line_in|put_statement = spaces
        line_in = _ gen_expr(A.Dest) 
        line_in = _ " = AL4_system.ReadLine();" 
        o[] << line_in ==> ;
    STR temp|_name = "tmp" A.Line.Str
    o[] << spaces "string " temp ";"
    o[] << spaces "AL4_system.ReadLine(" temp ");"
    PUSH is_left_side = TRUE : o[] << spaces gen_expr(A.Dest) ;
    o[*] = o[*] " = Safe_convert(" temp ");" .



METHOD generate_break({For} Br|eak_stmt) :
    CASE Br.Loop_ == nesting_for[*] ?
         CASE generating_case > 0 ?
              o[] << spaces "brkU_" Br.Loop_.Total_stmt.Str " = true;"
         ELSE o[] << spaces "break;" ==> ;
    ;
    FOR i IN [nesting_for[].Count-2 DOWNTO 0] :
        {For} n|esting_i = nesting_for[i]
        o[] << spaces "brkU_" n.Total_stmt.Str " = true;"
        CASE n == Br.Loop_ ? BREAK i ;
    ;
    o[] << spaces "break;" .


METHOD generate_cont({For} Cont|inue_stmt) :
	CASE Cont.Work=='NEXT' ? 
	     o[] << spaces "inc" Cont.Loop_.Index_var 
	     	" = Math.max(1, " gen_expr(Cont.By) ");" ;
    CASE Cont.Loop_ == nesting_for[*] ?
         o[] << spaces "continue;" ==> ;
    o[] << spaces "contU_" Cont.Loop_.Total_stmt.Str " = true;"
    FOR i IN [nesting_for[].Count-2 DOWNTO 0] :
        {For} n|esting_i = nesting_for[i]
        CASE n == Cont.Loop_ ? BREAK i ;
        o[] << spaces "brkU_" n.Total_stmt.Str " = true;"
    ;
    o[] << spaces "break;" .



METHOD generate_return({Case} Ret|urn_dummy) :
    --------------------------------------------------------------------- ''
    o[] << spaces
    CASE Comp.Current_fun.Result == NONE ?
        o[*] = o[*] "return;" ==> ;
    o[*] = o[*] "return RESULT;" "/" "*Y*" "/" .


INT generating_case|_level
INT total_stmt_case|_counter

METHOD gen_case||generate_case({Case} Sw|itch_stmt) :
    ------------------------------------- 'sequential ?'
    CASE Sw.Condition == NONE ?
         STR text_cond = gen_expr(Sw.Block_[0].{Case}.Condition).Remove_br 
         o[] << spaces "if (" text_cond ") {"
         generate_block(Sw.Block_[0].{Case}.Block_[])
         FOR i IN [1 TO Sw.Block_[].Count-1] :
             CASE Sw.Block_[i].Work == 'ELSE' ?
                  o[] << spaces "} else {"
             ELSE text_cond = gen_expr(Sw.Block_[i].{Case}.Condition).Remove_br  
             	  o[] << spaces "} else if (" text_cond ") {"
             ;
             generate_block(Sw.Block_[i].{Case}.Block_[]) ;
         o[] << spaces "}" ==> ;
    ------------------------------------- 'by type of expression'
    PUSH generating_case = generating_case + 1 :
         CASE Sw.Condition.Type_expr.Kind ?
         ['BOOL']:
                PUSH generating_case = generating_case - 1 :
                     o[] << spaces "if (" gen_expr(Sw.Condition).Remove_br ") {"
                     CASE Sw.Block_[0].Work != 'ELSE' ?
                          generate_block(Sw.Block_[0].Block_[]) ;
                     CASE Sw.Block_[*].Work == 'ELSE' ?
                          o[] << spaces "} else {"
                          generate_block(Sw.Block_[*].Block_[]) ;
                ;
         ['STR']:
         		total_stmt_case += 1
                STR t|emp_index = Sw.Line.Str "_" total_stmt_case.S
                o[] << spaces "int tmp" t " = -1;"
                
                o[] << spaces "String str" t
                        " = " gen_expr(Sw.Condition) ";"
                        
                gen_calc_str_index(Sw, t)
                o[] << spaces "switch (tmp" t ") {"
                FOR case1 IN Sw.Block_[] :
                    CASE case1.Work != 'ELSE' ?
                         o[] << spaces sp(4) "case " case1.Index.Str ":"
                    ELSE o[] << spaces sp(4) "default:" ;
                    PUSH spaces = spaces sp(8) :
                        generate_block(case1.Block_[])
                        CASE !case1.Block_[*].Is_jump ?
                             o[] << spaces "break;" ;
                    ;
                ;
        //['BYTE']:
        //        o[] << spaces "switch (AL4_system.Byte_as_unsigned"
        //        "(" gen_expr(Sw.Condition) ")) {"
        //        gen_switch_int_enum_cases(Sw)
        ['ENUM', 'INT']:
                o[] << spaces "switch (" gen_expr(Sw.Condition) ") {"
                gen_switch_int_enum_cases(Sw)
        ['REAL', 'CLASS', 'STRUCTURE']: NONE ;
        o[] << spaces "}" ;
    ----------------------------- 'break above level loops'
    CASE Sw.Condition.Type_expr.Kind != 'BOOL' ?
         FOR i IN [nesting_for[].Count-1 DOWNTO 0] :
             {For} f|or_statement = nesting_for[i]
             CASE has_breaks_of_for(f, Sw.Block_[]) ?
                  o[] << spaces "if (brkU_" f.Total_stmt.Str ") break;" ;
         ;
    ; .


FUN has_breaks_of_for|_loop({For} F|or_is_broken,
    {Statement} B|lock_of_stmt[]) ==> BOOL, RECURSIVE
    :
    ------------------------- 'Java hates goto so we should use additional code'
    FOR s IN B[] :
        CASE s.Work == 'BREAK' ?
             CASE s.{For}.Loop_ == F ? RESULT = TRUE ==> ;
        ;
        CASE s.Block_[].Count > 0 ?
             RESULT = has_breaks_of_for(F, s.Block_[])
             CASE RESULT ? ==> ;
        ;
    ; .


INT total_case|_count

METHOD gen_calc_str_index({Case} Sw|itch_by_str, STR T|emp_index) :
    o[] << spaces "switch ((str" T " + (char)0).charAt(0)) {"
    STR all_s|trings[]
    INT all_i|ndexes[]
    FOR case1 IN Sw.Block_[] :
        FOR val IN case1.{Case}.Values[] :
            all_s[] << val.Str_c
            all_i[] << case1.Index ;
    ;
    FOR s IN all_s[] :
        CASE all_i[s.Index] < 0 ? CONTINUE s ;
        o[] << spaces "case " s.as_char ": // case " total_case.Str
        total_case += 1
        
        o[] << spaces sp(4) "if (str" T ".equals(" s.as_str.Remove_br
            ")) tmp" T " = " all_i[s.Index].Str ";"
            
        FOR i INDEXING (INT, STR) IN [s.Index+1 TO all_s[].Count-1] :
            CASE s.[0] != all_s[i].[0] ? CONTINUE i ;
            
            o[] << spaces sp(4) "else if (str" T ".equals(" all_s[i].as_str
                   ")) tmp" T " = " all_i[i].Str ";"
                   
            all_i[i] = -1 ;
        o[] << spaces sp(4) "break;" ;
    o[] << spaces "}" .



METHOD gen_switch_int_enum_cases({Case} Sw|itch_stmt) :
    FOR case1 IN Sw.Block_[] :
        {Case} c|ase_of_switch = case1.{Case}
        CASE c.Work == 'CASE' && c.Values[].Count > 0 ?
             FOR v IN case1.{Case}.Values[] :
                 o[] << spaces sp(4) "case " v.Int_c.Str ":" ;
        ;
        CASE c.Work == 'CASE' && c.Values[].Count == 0 ?
             FOR r IN [c.Range1.Var_arg.Int_c TO (
                       c.Range2.Var_arg.Int_c)] :
                 o[] << spaces sp(4) "case " r.Str ":" ;
        ;
        CASE case1.Work == 'ELSE' ?
             o[] << spaces sp(4) "default:" ;
        PUSH spaces = spaces sp(8) :
             generate_block(case1.Block_[])
             CASE case1.Block_[].Count == 0 || !case1.Block_[*].Is_jump ?
                  o[] << spaces "break;" ;
        ;
    ; .



FUNCTION as_char|acter(STR S|tr_where_from) ==> STR :
    CASE S == "" ? RESULT = "(char)0" ==> ;
    CASE S.[0].Ord < " ".Ord || S.[0] IN "'\"#QU ?
        RESULT = "(char)" (S (0).Char).[0].Ord.Str ==> ;
    RESULT = "'" S.[0] "'" .



FUNCTION as_str|ing(STR S|tr_where_from) ==> STR :
    BOOL in_str|ing = TRUE
    RESULT = #QU
    FOR i IN [0 TO S.Len-1] :
        CASE S.[i].Ord < " ".Ord || S.[i] == #QU ?
             CASE in_str ?
                  in_str = FALSE
                  RESULT = RESULT #QU ;
             RESULT = RESULT " + (char)" S.[i].Ord.Str
        ELSE 
             CASE !in_str ?
                  in_str = TRUE
                  RESULT = RESULT " + " #QU ;
             RESULT = RESULT S.[i]
             CASE S.[i] == "\" ? RESULT = RESULT "\" ;
        ;
    ;
    CASE in_str ? RESULT = RESULT #QU ;
    CASE "+" IN RESULT ? RESULT = "(" RESULT ")" ; .


INT total_lim|it_statements
	
METHOD gen_limit({Limit} Lim|it_statement) :
    total_lim += 1
	STR tl|_variable = "limit_st" total_lim.S
    o[] << spaces "int " tl " = AL4_system.limit_by_"
    CASE Lim.By_what ? 
    ['TIME']: o[*] = o[*] "time"
    ['FUNC']: o[*] = o[*] "func"
    ['LOOPS']: o[*] = o[*] "loop" ;
	o[*] = o[*] "(" gen_expr(Lim.Condition)
	CASE Lim.By_what == 'TIME' ? 
	     o[*] = o[*] ", " 
	     CASE Lim.Units ? 
	     ['MILLISEC']: o[*] = o[*] "0"
	     ['SEC']: o[*] = o[*] "1"
	     ['MIN']: o[*] = o[*] "2"
	     ['HOUR']: o[*] = o[*] "3"
	     ['DAYS']: o[*] = o[*] "4" ;
	;
	o[*] = o[*] ");"
	o[] << spaces "try {"
	PUSH spaces = spaces #TAB :
	     o[] << spaces "try {"
	     PUSH spaces = spaces #TAB :
	          generate_block(Lim.Block_[]) ;
	     o[] << spaces "}" 
	     o[] << spaces "catch(E_Limit_exceeded eL) { "
	     o[] << spaces #TAB "if (eL.id != " tl ")"
	     o[] << spaces #TAB#TAB "throw eL;"
	     o[] << spaces "}"
	;
	o[] << spaces "}"
	o[] << spaces "finally {"
	o[] << spaces #TAB "AL4_system.dismiss_limit(" tl ");"
	o[] << spaces "}" .

METHOD gen_local({Local} Loc|it_statement) :
	INT o_count|_lines = o[].Count
	init_local_vars(Comp.Current_fun, Loc)
	BOOL need_try = o_count < o[].Count
	CASE need_try ? 
	     o[] << spaces "try {" ;
	PUSH spaces = spaces #TAB :
	     PUSH spaces = spaces #TAB :
	          generate_block(Loc.Block_[]) ;
	;
	CASE need_try ? 
		 o[] << spaces "}"
		 o[] << spaces "finally {"
		 dispose_local_vars(Comp.Current_fun, Loc)
		 o[] << spaces "}" ; .

{For} nesting_for|_statements[]
INT total_for|_counter

METHOD generate_for({For} F|or_loop) :
    -------------------------------------- 'Generate FOR statement'
    PUSH generating_case = 0 :
         nesting_for[] << F
         //CASE F.Work == 'FOREVER' ? o[] << spaces "while (true) {"
         CASE F.Infinite ? o[] << spaces "while (true) {"
         ELSE STR v|ar_loop = F.Var.Final_name
         	  CASE F.Var.Type_.Kind == 'ENUM' ?
         	  	   STR to_b|yte_if_need = "(byte)" ;
              total_for += 1
              STR t|mp_indx = total_for.Str
              STR i|ndex_var = "idx_" t
              F.Index_var = i
              {For} u|pper_for = nesting_for[*-1]
              CASE nesting_for[].Count > 1 && (
                   u.Continued) && for_continued(u, F.Block_[])
                   ?
                   BOOL contU|_flag = TRUE
                   o[] << spaces "boolean contU_" u.Total_stmt.Str " = false;" ;
              CASE F.Breaked ?
                   o[] << spaces "boolean brkU_" F.Total_stmt.Str " = false;" ;
              CASE ?
              [F.Has_next] ?
                   STR inc|rement_value = "incidx_" t
                   o[] << spaces "int " inc "=" if_else(F.Downto, "-1","+1") ";"
              [F.Downto] ? inc = "-1"
              ELSE inc = "+1" ;
              -------------------------------------- 'FOR loop header'
              CASE ?
              [F.Range1 != NONE] ?
                   STR assign_from =  "int from" t " = "
                   -------------------------- 'from'
                   CASE ?
                   [F.Array != NONE] ?
                        assign_from = _ gen_expr(F.Range1).Remove_br ";"
                           		  
                   ELSE assign_from = _ gen_expr(F.Range1).Remove_br ";"
                   ;
                   o[] << spaces assign_from
                   --------------------------- 'to'
                   STR assign_to = "int to" t " = "
                   CASE ?
                   [F.Array != NONE && F.Downto] ?
                        assign_to = _ gen_expr(F.Range2).Remove_br "; to" t "--;"
                       		    
                        F.Index_var = i
                        o[] << spaces assign_to
                        
                        o[] << spaces "for (int " i " = from" t "; " i 
                        " > to" t "; " i "+=" inc ") {"
                        
                   [F.Downto] ?
                        assign_to = _ gen_expr(F.Range2).Remove_br "; to" t "--;"
                       		   
                        o[] << spaces assign_to
                        
                        o[] << spaces "for (" v " = from" t "; " v 
                       		   " > to" t "; " v "+=" inc ") {"
                       		   
                   [F.Array != NONE] ?
                        assign_to = _ gen_expr(F.Range2).Remove_br "; to" t "++;"
                        F.Index_var = i
                        o[] << spaces assign_to
                        
                  	    o[] << spaces "for (int " i " = from" t "; " i 
                        " < to" t "; " i "+=" inc ") {"
                   ELSE 
                        assign_to = _ gen_expr(F.Range2).Remove_br "; to" t "++;"
                        o[] << spaces assign_to
                        
                  	    o[] << spaces "for (" v " = " to_b " from" t 
                  	   		   "; " v " < " to_b "to" t "; " v "+=" inc ") {"
                   ; 
                   
              [F.Array.Operation == 'CONSTANT'] ?
              	   assign_to = "int to" t " = "
              	   .. = assign_to F.Array.Var_arg.Items_[].Count.S ";"
              	   o[] << spaces assign_to
              	   
                   o[] << spaces "for (int " i " = 0; " i 
                       		   " < to" t "; " i "+=" inc ") {"

              ELSE F.Index_var = i
               
              	   o[] << spaces "int count" t " = " gen_expr(F.Array)
                   ".Count();"
                   
                   o[] << spaces "for (int " i " = 0; " i
                   " < count" t "; " i "+=" inc ") {"
                   
                   //CASE F.Array.Type_expr.Kind == 'CLASS' ?
                   //     o[*] << spaces sp(4) v " = Object_assign_hard(" v
                   //     ", " gen_expr(F.Array) ".Get_item(" i ").Obj);"
                        
                   //ELSE o[] << spaces sp(4) v " = " gen_expr(F.Array)
                   //     ".Get_item(" i ");"
                   //;
              ;
             CASE ?
             [F.Array.Operation=='CONSTANT'] ?
                 STR a_t|ype_expr = type_gen(
                 	F.Array.Var_arg.Type_, {type_options})
                 	
                 o[] << spaces sp(4) v "= AL4_system.Array_item_" a_t.Lower
                 		"(" F.Array.Var_arg.Final_name 
                 		", " F.Array.Var_arg.Items_[].Count.S
                 		", " i ");"
             [F.Array != NONE] ?
                  CASE F.Array.Type_expr.Kind ?
                  ['CLASS', 'STRUCTURE']:
                       o[] << spaces sp(4) 
                       "" v " = AL4_object.Object_assign_hard(" 
                       "" v ", " gen_expr(F.Array) ".Get_item(" i 
                       ").Obj);"
                  ['ENUM']:
	     			   o[] << spaces sp(4) v " = " gen_expr(F.Array)
                       ".Get_item(" i ");"
                  ['BOOL']:
	     			   o[] << spaces sp(4) v " = " gen_expr(F.Array)
                       ".Get_item(" i ");"
                  ['INT']:
	     			   o[] << spaces sp(4) v " = " gen_expr(F.Array)
                       ".Get_item(" i ");"
                  ['REAL']:
	     			   o[] << spaces sp(4) v " = " gen_expr(F.Array)
                       ".Get_item(" i ");"
                  ['STR']:
	     			   o[] << spaces sp(4) v " = " gen_expr(F.Array)
                       ".Get_item(" i ");"
                  ;
             ;
         ;
         ------------------------------------ 'LIMIT LOOPS present'
         CASE Comp.Has_LIMIT_LOOPS ? 
              o[] << spaces sp(4) "AL4_system.total_loops += 1;"
         ;
         ------------------------------------ 'do not stop response'
         o[] << spaces sp(4) "if (--AL4_system.global_activity_counter < 0)"
         o[] << spaces sp(8) "AL4_system.check_long_operation();"
         --------------------------------- 'generate loop body'
         generate_block(F.Block_[])
         o[] << spaces "}"
         ---------------------------- 'break / cont to upper level FOR by flags'
         CASE contU ?
              o[] << spaces "if (contU_" u.Total_stmt.Str ") continue;" ;
         nesting_for[].Remove(F) ;
         FOR f IN nesting_for[] :
             CASE has_breaks_of_for(f, F.Block_[]) ?
                  o[] << spaces "if (brkU_" f.Total_stmt.Str ") break;" ;
         ; .

//FUNCTION min_max|_may_be_not_call(
//STR F|un_min_max, STR A|_operand1, STR B|_operand2) ==> STR
//    :
//    CASE A == B ? RESULT = A ==> ;
//    RESULT = "AL4_system." F "(" A ", " B ")" .
		
FUN for_continued( {For} F|or_statement,
                   {Statement} B|lock_of_statements[]) ==> BOOL,
                   RECURSIVE
                   :
    ----------------------- 'Java hates goto so we should use additional code'
    FOR s IN B[] :
        CASE s.Work ?
        ['CONTINUE', 'NEXT']: 
                 CASE s.{For}.Loop_ == F ? RESULT = TRUE ==> ;
        ['CASE', 'ELSE', 'FOR', 'PUSH', 'LIMIT', 'LOCAL']:
                 RESULT = for_continued(F, s.Block_[])
                 CASE RESULT ? ==> ;
                 
        ['ASSIGN', 'APPEND', 'OUTPUT', 'INPUT', 'BREAK', 'RETURN', 'STOP',
         'ASSERT', 'COMMENT', 'DEBUG', 'CALL_NATIVE']:
        		 NONE ;
    ; .

METHOD upper_for_break(
{Statement} B|lock_of_statements[]) ==> BOOL, RECURSIVE
	:
    FOR s IN B[] :
        CASE s.Work ?
        ['BREAK']: 
                 CASE is_break_upper_for(s.{For}.Loop_) ? RESULT = TRUE ==> ;
        ['CASE', 'ELSE', 'FOR', 'PUSH', 'LIMIT', 'LOCAL']:
                 RESULT = upper_for_break(s.Block_[])
                 CASE RESULT ? ==> ;
                 
        ['ASSIGN', 'APPEND', 'OUTPUT', 'INPUT', 'NEXT', 'CONTINUE', 
         'RETURN', 'STOP', 'ASSERT', 'COMMENT', 'DEBUG', 'CALL_NATIVE']: NONE 
        ;
    ; .

METHOD is_break_upper_for({For} F|or_which_break) ==> BOOL :
    FOR f IN nesting_for[] :
        CASE f == nesting_for[*] ? ==> ;
        CASE f == F ? RESULT = TRUE ==> ;
    ; .


INT total_push|_counter

METHOD generate_push({Assign} A|_push_stmt) :
	total_push += 1
    STR tmp|_save_var = "save" total_push.Str
    CASE A.Dest.Operation == 'FUN' && A.Dest.Fun_.Pop_method_ != NONE ?
         ------------------------------------- 'call method'
         {Fun} pop|_method = A.Dest.Fun_.Pop_method_
         STR call_push|_method = gen_fun_call(A.Dest) 
         o[] << spaces call_push ";"
    ELSE
         -------------------------------------- 'declare save variable'
         STR type|_text = type_gen(A.Dest.Type_expr, 
         	 {type_options}(Array=FALSE, Fixed=FALSE, Weak=FALSE))
         	  
         STR none|_value_text = gen_none_val(A.Dest.Type_expr) 
         o[] << spaces type " " tmp " = " none ";"
                
         -------------------------------------- 'save variable'
         {Type} type_e|xpr = A.Dest.Type_expr
         
         sav|e_statement_temp = {Assign}(Line = 0, Level = A.Level,
                    Function_ = Comp.Current_fun,
                    Dest = {Expr}(Operation = 'VAR', 
                       Var_arg = {Var}(Line = 0, Type_ = type_e)), 
                    Source = A.Dest)
                    
         sav.Dest.Var_arg.Set_final_name(tmp)
         STR save_assign = generate_assign(sav) 
         o[] << save_assign 
    ;
    ------------------------------------------ 'PUSH block in try-finally'
    o[] << spaces "try {"
    PUSH spaces = spaces sp(4) :
         CASE A.Source != NONE ? o[] << generate_assign(A) ;
         
         b|ack_assign_temp = {Assign}(Dest = A.Dest, Line = 0, Level = A.Level,
                Function_ = A.Function_,
                Source = {Expr}(Operation = 'VAR', 
                  Var_arg = {Var}(Line = 0,
                    Type_ = A.Dest.Type_expr)) )
                    
         b.Source.Var_arg.Set_final_name(tmp)
         A.Back_ = b
         generate_block(A.Block_[]) ;
    o[] << spaces "} finally {"
    CASE pop != NONE ?
         ------------------------------------- 'pop method'
         {Expr} call|_pop_method_TEMP = {Expr}(Operation = 'FUN', Fun_ = pop,
                This_ = A.Dest.This_)
                
         CASE pop !IN Comp.Current_fun.Call_functions_[] ?
         	  Comp.Current_fun.Call_functions_[] << pop ;
         STR call_pop = gen_fun_call(call) 
         o[] << spaces sp(4) call_pop ";"
    ELSE
         ------------------------------------- 'restore variable'
         PUSH spaces = spaces sp(4) :
         	  o[] << generate_assign(b) ;
    ;
    o[] << spaces "}" .



METHOD generate_stop({Case} Stop|_statement) :
	STR stop_text = gen_expr(Stop.Condition) 
    o[] << spaces "AL4_system.STOP(" stop_text ");" .



METHOD generate_assert({Case} A|ssert_stmt) :
	STR cond|ition_assert = gen_expr(A.Condition) 
    o[] << spaces "if (!" cond ") {"
    
    o[] << spaces "   test_assert = AL4_system.Assertion_failed(" A.Line.Str
           ", test_assert);"
           
    CASE A.Formatted != NONE ?
         STR f|ormatted = gen_expr(A.Formatted)
    ELSE f = #QU #QU ;
    
    o[] << spaces "   test_assert_failed_text = AL4_system.Assertion_failed2("
           "" f ", test_assert_failed_text);"
           
    o[] << spaces "   AL4_system.WriteLine("
    ''"\nAssertion_failed in ''
    "" A.Function_.Class.Names[*] ""
    '' (" + ''
    "" (A.Line+1).S ""
    '' + "): " + test_assert_failed_text);''
    
    o[] << spaces "   AL4_system.ReadLine();"
    o[] << spaces "}" .



METHOD gen_comment_block({Assign} A|_comment_block) :
    o[] << spaces "//----------------------- " A.Source.Var_arg.Str_c .



METHOD generate_block|_of_statements(
{Statement} Block|_of_stmt[])
	:
    PUSH spaces = spaces sp(4) :
        CASE Comp.Verbose ?
             o[] << spaces 
             "// generate block (" Block[].Count.Str " statements):"
        ;
        FOR s IN Block[] : statement_gen(s) ;
    ; .

BOOL generating_localized_strings

METHOD gen_expr|ession(
{Expr} E|xpression) ==> STR, RECURSIVE
	:
    ----------------------------------- 'generate Before_assign_[] ?'
    CASE E.Before_assign_[].Count > 0 ?
         STR save_lines|_already_added[]
         FOR i IN [line_current_statement TO o[].Count-1] :
             save_lines[] << o[i] ;
         FOR i IN [o[].Count-1 DOWNTO line_current_statement] :
             o[].Delete(i) ;
         {Assign} a|ssignments[]
         FOR x IN E.Before_assign_[] : a[] << x.{Assign} ;
         E.Before_assign_[].Clear
         FOR y IN a[] :
             STR g|enerated = generate_assign(y) 
             o[] << g ;
         ------------------------------------- 'restore o[]'
         line_current_statement = o[].Count
         FOR s IN save_lines[] : o[] << s ;
         FOR y IN a[] : E.Before_assign_[] << y ;
    ;
    --------------------------------------- 'localized string constant?'
    CASE E.Localize_n != "" && !generating_localized_strings ?
         RESULT = "AL4_system.Localize_str["
         "" E.Localize_i.Str 
         " + " Comp.Current_class.Final_name
         ".First_localize_item]" ==> ;
    --------------------------------------- 'generate expression'
    CASE E.Replace_index != ""  ?
         RESULT = "/" "*R:" E.Replace_index ":"
         RESULT = _ {System_functions}.Total_obj_index(E).Str "*" "/" ;

    PUSH level_expr = level_expr + 1 :
        CASE E.Operation ?
            ['BINARY']:  RESULT = RESULT gen_binary(E)
            ['FUN', 'BASE_FUN', 'SYSTEM_FUN']:
         				 RESULT = RESULT gen_fun_call(E)
            ['VAR']:     STR v|ariable_expression = gen_variable(E)
                         CASE v == "this" ?
                              v = v ".hard_link" ;
                         RESULT = RESULT v
            ['INDEX']:   RESULT = RESULT gen_index(E)
            ['FIELD']:   RESULT = RESULT gen_field(E)
            ['NEW_OBJ']: RESULT = RESULT gen_new_obj(E)
            ['ARRAY']:   RESULT = RESULT gen_array(E)
            ['AS']:      RESULT = RESULT gen_as_obj(E)
            ['CONST']:   RESULT = RESULT gen_const(E)
        	['INT2REAL']:RESULT = RESULT gen_expr(E.Arg1_)
        	['NOT_B']:	 RESULT = RESULT "~" gen_expr(E.Arg1_)
        	['NOT']:	 RESULT = RESULT "!" gen_expr(E.Arg1_)
        	['NEG']:	 RESULT = RESULT "-" gen_expr(E.Arg1_)
            ['UNKNOWN']: Comp.Error("Generating unknown operation"._Egen ) ;
        CASE RESULT == "" ?
             {Parser} p|arser_of_cur_class = Comp.Current_class.Parse
             PUSH p.Line = E.At_line :
                  PUSH p.Pos = E.At_pos :
                       Comp.Error("Error generating expression"._Egen2 
                       ": " p.Next20) ;
             ;
        ;
    ; .



METHOD gen_binary({Expr} E|xpression) ==> STR :
    --------------------------------- 'special case: long concatenation'
	CASE E.Sign == 'CONCAT' && E.Items_[].Count > 0 ?
		 RESULT = "("
		 FOR i IN E.Items_[] : RESULT = RESULT gen_expr(i) " + " ;
		 RESULT = RESULT.[0 TO *-3] ")" ==> ;
	--------------------------------- 'other operations'
	CASE E.Sign ?
	     ['UNDEFINED']: NONE
         ['PLUS', 'CONCAT']: STR s|ign_operation = "+"
         ['MINUS']:  s = "-"
         ['MULT']:   s = "*"
         ['DIV']:    RESULT = "AL4_system.Safe_div"
         			 BOOL both_int = E.Arg1_.Type_expr.Kind == 'INT'
         			 	  both_int &&= E.Arg2_.Type_expr.Kind == 'INT'  
                     CASE both_int ? RESULT = RESULT "_int" ;
                          
                     RESULT = RESULT "(" gen_expr(E.Arg1_)
                     RESULT = RESULT ", " gen_expr(E.Arg2_) ")" ==>
                     
         ['REST']:   RESULT = "AL4_system.Safe_rest(" gen_expr(E.Arg1_)
                     RESULT = RESULT ", " gen_expr(E.Arg2_) ")" ==>
                     
         ['AND_B']:  s = "&"
         ['OR_B']:   s = "|"
         ['XOR_B']:  s = "^"
         ['AND']:    s = "&&"
         ['OR']:     s = "||"
         ['IN', 'NOT_IN']:     
                     CASE E.Sign == 'NOT_IN' ? RESULT = "!" ;
                     BOOL single_s|tring = E.Arg2_.Type_expr.Kind == 'STR'
                     	  single_s &&= !E.Arg2_.Is_array  
                     CASE single_s ?
                          RESULT = RESULT "(" gen_expr(E.Arg2_)
                          RESULT = RESULT ".indexOf(" gen_expr(E.Arg1_) ") >= 0)"
                          ==>
                     ;
                     CASE E.Arg2_.Operation == 'ARRAY' && (
                     	  E.Arg2_.Type_expr.Kind IN ['INT', 'STR', 'ENUM'])
                          ?
                          RESULT = RESULT "AL4_system.ArrayContains" 
                          RESULT = RESULT kind_to_name(E.Arg2_.Type_expr.Kind) 
                          RESULT = RESULT "(" gen_const_array(E.Arg2_) 
                          RESULT = RESULT ", " gen_expr(E.Arg1_) ")" ==>
                     ;
                     RESULT = RESULT gen_expr(E.Arg2_)
                     RESULT = RESULT ".Contains(" gen_expr(E.Arg1_) ")" ==>
                     
         ['LIKE', 'UNLIKE']:     
                     CASE E.Sign == 'UNLIKE' ? RESULT = "!" ;
                     RESULT = RESULT "AL4_system.like_str(" gen_expr(E.Arg1_)
                     RESULT = RESULT ", " gen_expr(E.Arg2_) ")" ==>

         ['EQUAL']:  RESULT = gen_compare(E, "==") ==>
         ['NOT_EQ']: RESULT = gen_compare(E, "!=") ==>
         ['LESS']:   RESULT = gen_compare(E, "<") ==>
         ['LESS_OR_EQ']: RESULT = gen_compare(E, "<=") ==>
         ['GREATER']:RESULT = gen_compare(E, ">") ==>
         ['GREATER_OR_EQ']:  RESULT = gen_compare(E, ">=") ==> ;
    STR x|operand = gen_expr(E.Arg1_)
    STR y|operand = gen_expr(E.Arg2_)
    CASE x == "" || y == "" ? RESULT = "" ==> ;
    //CASE E.Sign IN ['PLUS', 'MINUS', 'MULT', 'DIV',
    //     'AND_B', 'OR_B', 'XOR_B'] && E.Type_expr.Kind == 'INT'
    //     ?
    //     CASE E.Arg1_.Type_expr.Kind == 'BYTE' ?
    //          x = "AL4_system.Byte_as_unsigned(" x ")" ;
    //     CASE E.Arg2_.Type_expr.Kind == 'BYTE' ?
    //          y = "AL4_system.Byte_as_unsigned(" y ")" ;
    //;
    RESULT = "(" x " " s " " y ")" .

FUN kind_to_name|byte_int_str(
{Type}.{kind_type} K|ind_of_type_int_byte_str ) ==> STR
    :
    ----------------------------- 'Suffix for name of function ArrayContainsXXX'
    CASE K.Name ?
    ["'BYTE'", "'ENUM'"]: RESULT = "Byte"
    ["'INT'"]: RESULT = "Int"
    ["'STR'"]: RESULT = "Str" ; .



METHOD gen_compare({Expr} E|xpression, STR S|ign_compare) ==> STR :
    CASE E.Arg1_.Type_expr.Kind ?
        ['BOOL', 'INT', 'REAL', 'ENUM']: NONE
        
        ['STR']: STR x|_operand = gen_expr(E.Arg1_)
                 STR y|_operand = gen_expr(E.Arg2_).Remove_br
                 CASE S ?
                 ["=="]: RESULT = x ".equals(" y ")"
                 ["!="]: RESULT = "!" x ".equals(" y ")"
                 ELSE RESULT = "(" x.Remove_br ".compareTo(" y ")" S "0)" ;
                 ==>
        ['CLASS', 'STRUCTURE']:
            CASE E.Arg1_.Var_arg == Comp.NONE_c ?
                RESULT = "(AL4_system.Is_none(" gen_expr(E.Arg2_) ")" S
                    " true)" ==>
            ;
            CASE E.Arg2_.Var_arg == Comp.NONE_c ?
                RESULT = "(AL4_system.Is_none(" gen_expr(E.Arg1_) ")" S
                    " true)" ==>
            ;
            x = gen_expr(E.Arg1_)
            y = gen_expr(E.Arg2_)
            RESULT = "(" x ".Obj " S " " y ".Obj)" ==> ;
    x = gen_expr(E.Arg1_)
    y = gen_expr(E.Arg2_)
    //BOOL int_real = E.Arg1_.Type_expr.Kind IN ['INT', 'REAL']
    //     int_real ||= E.Arg2_.Type_expr.Kind IN ['INT', 'REAL']
    //CASE int_real ?
    //     CASE E.Arg1_.Type_expr.Kind == 'BYTE' ?
    //          x = "AL4_system.Byte_as_unsigned(" x ")" ;
    //     CASE E.Arg2_.Type_expr.Kind == 'BYTE' ?
    //          y = "AL4_system.Byte_as_unsigned(" y ")" ;
    //;
    RESULT = "(" x S y ")" .



METHOD gen_fun_call({Expr} E|xpr_calling_fun) ==> STR :
    CASE E.Fun_.Final_name == "" && E.Fun_.Is_system ?
        RESULT = gen_system_fun(E) ==> ;
    CASE E.Fun_.Modifiers['STATIC'] ?
            CASE E.Fun_.Is_system ?
                 RESULT = "AL4_system."
            ELSE RESULT = E.Fun_.Class.Final_name "." ;
    ELSE 
         CASE E.This_ != Comp.THIS_expr && E.This_ != NONE ?
              CASE ?
              [E.This_.Is_array] ?
                   RESULT = gen_expr(E.This_) "."
                   
              [E.Operation == 'BASE_FUN'] ? NONE
              
              [E.This_.Var_arg.Names[0] == "THIS"] ?
                   RESULT = "this."
                   BOOL this_prefix|_is_set_already = TRUE
                   
              ELSE RESULT = "((" E.This_.Type_expr.Final_name
              	   RESULT = RESULT ")" gen_expr(E.This_) ".Obj)."
              		
              	   this_prefix = TRUE 
              ;
         ;
    ;
    CASE E.Operation == 'BASE_FUN' ?
         RESULT = "super" "." 
    ELSE 
    	 CASE !E.Fun_.Modifiers['STATIC'] ?
    	      CASE !Comp.Current_fun.Modifiers['STATIC'] && !this_prefix ?
    	           RESULT = RESULT "this." ;
    	 ;
    ;
    --------------- 'for TRAP function replace it to caller of TRAP fun'
    CASE E.Fun_.Modifiers['TRAP_FUN'] ?
         {Var} tf|eild_trapping = E.Fun_.Trap_field
         //RESULT = gen_expr(E.This_)
         CASE ?
         [tf.Trap_read_ == E.Fun_] ?
         	  RESULT = RESULT "Trap_read_" tf.Final_name "("
         [tf.Trap_write_ == E.Fun_] ?
         	  RESULT = RESULT "Trap_write_" tf.Final_name "("
         ELSE RESULT = RESULT E.Fun_.Final_name "(" ;
    ELSE RESULT = RESULT E.Fun_.Final_name "(" ;
    ----------------------------------- 'parameters'
    CASE E.Fun_.Param[].Count > 0 ?
        FOR p IN E.Items_[] :
            CASE p.Var_arg == Comp.NONE_c ?
                 RESULT = RESULT gen_none_val(E.Fun_.Param[p.Index].Type_)
                 ","
                 
            ELSE STR s|tring_parameter = gen_expr(p).Remove_brackets
            
            	 CASE E.Fun_.Param[p.Index].Is_fixed
            	 	  && !p.Is_fixed
            	 	  ?
            	      s = "new " type_gen(p.Type_expr, {type_options}(
            	      	Array=TRUE, Fixed=TRUE, Weak=p.Is_weak))
            	      	"(" s ", 0, -1)"
            	 ;     
            
                 RESULT = RESULT byte_typecast_if_need(
                 	E.Fun_.Param[p.Index].Type_, p, s) ","
            ;
        ;
        RESULT = RESULT.[0 TO *-1] ;
    RESULT = RESULT ")" .


FUN byte_typecast_if_need( {Type} D|destination_type,
                           {Expr} A|ctual_parameter_expression,
                           STR S|ource_parameter) ==> STR
                           :
    ------------------------ 'Java requires to write (byte)0 rather then just 0'
    RESULT = S
    CASE D.Kind == 'ENUM' && !A.Is_array ?
         RESULT = "(byte)" S ; 
         //RESULT = "(byte)" S ==> ; 
    //{Type} t|ype_expr_of_A = A.Type_expr
    //CASE D.Kind == 'INT' && t.Kind == 'BYTE' && !A.Is_array ?
    //     RESULT = "AL4_system.Byte_as_unsigned(" S ")" ;
    .


METHOD gen_system_fun|ction_special_call(
{Expr} E|xpr_calling) ==> STR
	:
    CASE E.Fun_.System_fun ?
        ['SYSFUN_Len']:    RESULT = gen_expr(E.Items_[0]) ".length()"
        
        ['SYSFUN_Name']:   
            RESULT = E.Items_[0].Type_expr.Base_.Final_name
            .. = RESULT ".Names_" E.Items_[0].Type_expr.Final_name
            .. = RESULT "[" gen_expr(E.Items_[0]).Remove_br
            CASE E.Items_[0].Type_expr.Kind == 'BOOL' ? .. =_ "? 1 : 0" ;
            .. =_ "]"
                    
        ['SYSFUN_Clear']:  RESULT = gen_expr(E.Items_[0]) ".Clear()"
        
        ['SYSFUN_Count']:
            CASE E.Items_[0].Operation == 'CONSTANT' ? 
            	 RESULT = E.Items_[0].Var_arg.Items_[].Count.S
            ELSE RESULT = gen_expr(E.Items_[0]) ".Count()" ;
        
        ['SYSFUN_Allocate']: 
                    RESULT = RESULT gen_expr(E.Items_[0])
                    RESULT = RESULT ".Allocate(" gen_expr(E.Items_[1]) ")"
                    
        ['SYSFUN_Insert']: {Expr} source|_inserting = E.Items_[2]
        
                    RESULT = RESULT gen_expr(E.Items_[0])
                    RESULT = RESULT ".Insert(" gen_expr(E.Items_[1]) ", " 
                    
                    CASE E.Items_[0].Type_expr.Kind == 'ENUM' ?
                         RESULT = RESULT "(byte)" ;
                    RESULT = RESULT gen_expr(source) ")"
                    
        ['SYSFUN_Delete']: STR index|_value = gen_expr(E.Items_[1])
                    CASE E.Items_[].Count > 2 ?
					 	 RESULT = spaces 
					 	 RESULT = RESULT gen_expr(E.Items_[0])
					 	 RESULT = RESULT ".Delete_range(" index
					 	 RESULT = RESULT ", " gen_expr(E.Items_[2]) ")"
	                         
					ELSE RESULT = gen_expr(E.Items_[0]) ".Delete(" index ")"
					;
                    
        ['SYSFUN_Remove']: RESULT = gen_expr(E.Items_[0])
                    	   RESULT = RESULT ".Remove(" gen_expr(E.Items_[1]) ")"
                    
        ['SYSFUN_Find_item']:   
					RESULT = gen_expr(E.Items_[0])
					RESULT = RESULT ".indexOf(" gen_expr(E.Items_[1]) ")"
                    
        ['SYSFUN_Index']:  
                    FOR f IN nesting_for[] :
                        CASE E.Items_[0].Var_arg == f.Var ?
                            RESULT = f.Index_var ==> ;
                    ;
                    Comp.Error("Can not find Index of FOR loop"._Ecannot6 )
        ['SYSFUN_Swap']:
            	RESULT = gen_expr(E.Items_[0])
            	RESULT = RESULT ".Swap(" gen_expr(E.Items_[1])
            	RESULT = RESULT "," gen_expr(E.Items_[2]) ")"
        
        ['SYSFUN_First']:
            	RESULT = "(byte)0"
        ['SYSFUN_Last']:
	        	RESULT = "(byte)" (E.Items_[0].Type_expr.Items[
	        			].Count-1).Str
        ['SYSFUN_Previous']:
	        	RESULT = "(byte)Math.max(0, " gen_expr(E.Items_[0]) "-1)"
        ['SYSFUN_Next']:
	        	RESULT = "(byte)Math.min("
	        	RESULT = RESULT (E.Items_[0].Type_expr.Items[].Count-1).Str
	        	RESULT = RESULT ", " gen_expr(E.Items_[0]) "+1)"

        ['SYSFUN_Find_str']:
        	RESULT = gen_expr(E.Items_[0]) ".indexOf("
        	RESULT = RESULT gen_expr(E.Items_[1]) ")"
        	
        ['SYSFUN_Str', 'SYSFUN_BoolStr']:
        	RESULT = gen_expr(E.Items_[0]) ".toString()"
        	
        ['SYSFUN_RealStr']:
        	RESULT = "AL4_system.Str(" gen_expr(E.Items_[0]) ")"
        			 
        ['SYSFUN_StrInt']:
        	RESULT = "AL4.Int(" gen_expr(E.Items_[0]) ")"
        	
        ['SYSFUN_RealInt']:
        	RESULT = "((int)" gen_expr(E.Items_[0]) ")"
        	
        ['SYSFUN_EnumInt']:
        	RESULT = gen_expr(E.Items_[0])
        	
        ['SYSFUN_Byte']:
        	RESULT = "((byte)"gen_expr(E.Items_[0]) ")"
        	
        ['SYSFUN_StrHex16']:
        	RESULT = "AL4.hex16(" gen_expr(E.Items_[0]) 
        	RESULT = RESULT ", " gen_expr(E.Items_[1]) ")"
        		
        ['SYSFUN_Shl']:
        	RESULT = "(" gen_expr(E.Items_[0]) " << " 
        	RESULT = RESULT gen_expr(E.Items_[1]) ")"
        		
        ['SYSFUN_Shr']:
        	RESULT = "(" gen_expr(E.Items_[0]) " >>> " 
        	RESULT = RESULT gen_expr( E.Items_[1]) ")"
        		
        ['SYSFUN_Rol']:
        	RESULT = "AL4.RotateLeft(" gen_expr(E.Items_[0]) 
        	RESULT = RESULT ", " gen_expr(E.Items_[1]) ")"
        		
        ['SYSFUN_Ror']:
        	RESULT = "AL4.RotateRight(" gen_expr(E.Items_[0]) 
        	RESULT = RESULT ", " gen_expr(E.Items_[1]) ")"
        		
        ['SYSFUN_Compare_substrings']:
        	RESULT = "AL4.CompareSubstrings(" 
        	RESULT = RESULT gen_expr(E.Items_[0])
        	RESULT = RESULT ", " gen_expr(E.Items_[1]) 
        	RESULT = RESULT ", " gen_expr(E.Items_[2])
        	RESULT = RESULT ", " gen_expr(E.Items_[3])
        	RESULT = RESULT ", " gen_expr(E.Items_[4])
        	RESULT = RESULT ", " gen_expr(E.Items_[5]) ")"
        		
        ['SYSFUN_Compare_substr1']:
        	RESULT = "AL4.CompareSubstr1(" gen_expr(E.Items_[0])
        	RESULT = RESULT ", " gen_expr(E.Items_[1]) 
        	RESULT = RESULT ", " gen_expr(E.Items_[2])
        	RESULT = RESULT ", " gen_expr(E.Items_[3]) ")"
        		
        ['SYSFUN_Clone']:
        	RESULT = "((Structure_any)" gen_expr(E.Items_[0]) ".Obj)" 
        	RESULT = RESULT ".Clone()"
        	
        ['SYSFUN_Dismiss']:
        	CASE E.Items_[0].Operation == 'INDEX' ?
        	     RESULT = "Structure_any.Dismiss_array_item("
        	     RESULT = RESULT gen_expr(E.Items_[0].Arg1_) 
        	     RESULT = RESULT " ," gen_expr(E.Items_[0].Arg2_) ")"

        	ELSE //{Type} ts|tructure_type = E.Items_[0].Type_expr
        		 STR e0|_generated_expression = gen_expr(E.Items_[0])
        		 RESULT = "Structure_any.Dismiss_structure(" e0 ")"
        		 add_after[] << spaces e0 " = Object_assign_hard(" e0 ", "
        		 add_after[*] = add_after[*] e0 ".Obj.NONE_obj_instance().Obj);"
        	;

    	['SYSFUN_UNDEFINED']:
    		Comp.Error("Don't know how to call system function"._Edont
         	": " E.Fun_.Names[0]) ; .

FUNCTION gen_variable({Expr} E|_variable) ==> STR :
    RESULT =  E.Var_arg.Final_name .

METHOD gen_index({Expr} E|_index_operation) ==> STR :
    CASE E.Arg1_.Is_array ?
        CASE E.Arg1_.Is_fixed && (
             E.Arg3_ != NONE) && E.Arg2_.Operation == 'CONST' && (
             E.Arg2_.Var_arg.Type_.Kind == 'INT') && (
             E.Arg2_.Var_arg.Int_c == 0) && (
             E.Arg3_.Is_star_operation)
             ?
             RESULT = RESULT gen_expr(E.Arg1_) ==> ;
    
        CASE E.Arg3_ != NONE ?
                RESULT = "new FixA"
                CASE E.Arg1_.Type_expr.Kind ?
                ['BOOL']: RESULT = RESULT "Bool"
                ['ENUM']: RESULT = RESULT "Byte"
                ['INT']: RESULT = RESULT "Int"
                ['REAL']: RESULT = RESULT "Real"
                ['STR']: RESULT = RESULT "Str"
                ['CLASS', 'STRUCTURE']: RESULT = RESULT "Obj" ;
                
                RESULT = RESULT "(" gen_expr(E.Arg1_)
                RESULT = RESULT ", " gen_expr(E.Arg2_) 
                RESULT = RESULT ", " gen_expr(E.Arg3_) ")" ==>
        ;
        CASE level_expr == 1 && is_left_side ?
             RESULT = gen_expr(E.Arg1_) ".Set_item(" 
             RESULT = RESULT gen_expr(E.Arg2_) ","
             close_br = TRUE ==> ;
        CASE E.Arg1_.Var_arg.Is_const ?
        	 STR t|ype_expr = type_gen(E.Arg1_.Var_arg.Type_, {type_options})
        	 
             RESULT = "AL4_system.Array_item_" t.Lower 
                "(" E.Arg1_.Var_arg.Final_name 
             	", " E.Arg1_.Var_arg.Size_value.Str 
             	", " gen_expr(E.Arg2_) ")" ==>
        ; 
        RESULT = gen_expr(E.Arg1_) ".Get_item(" 
        RESULT = RESULT gen_expr(E.Arg2_) ")" ==> ;
    CASE E.Arg3_ != NONE ?
        RESULT = "AL4_system.Substring(" gen_expr(E.Arg1_).Remove_br
        RESULT = RESULT ", " gen_expr(E.Arg2_).Remove_br
        RESULT = RESULT ", " gen_expr(E.Arg3_).Remove_br ")" ==>
    ;
    CASE level_expr == 1 && is_left_side ?
        close_br = TRUE
        RESULT = gen_expr(E.Arg1_).Remove_br
        RESULT = RESULT " = AL4_system.Replace_symbol(" 
        RESULT = RESULT gen_expr(E.Arg1_).Remove_br
        RESULT = RESULT ", " gen_expr(E.Arg2_).Remove_br "," ==>
    ;
    RESULT = "AL4_system.Single_symbol(" gen_expr(E.Arg1_).Remove_br
    RESULT = RESULT ", " gen_expr(E.Arg2_).Remove_br ")" .



FUNCTION gen_none_val({Type} T|ype_NONE) ==> STR :
    CASE T.Kind ?
        ['BOOL']: RESULT = "false"
        ['INT', 'REAL', 'ENUM']: RESULT = "0"
        ['STR']: RESULT = #QU #QU
        
        ['CLASS']: RESULT = T.Final_name
                ".NoneObj_" T.Final_name ".hard_link" 

        ['STRUCTURE']:
			RESULT = T.In_class_.Final_name "." T.Final_name
                ".NoneObj_" T.Final_name ".hard_link" 
    ; .



METHOD gen_field({Expr} E|_field_of_obj) ==> STR :
    CASE ?
    [E.Arg1_.Type_expr.Kind == 'CLASS'] ?
        CASE E.Var_arg.Type_.Kind == 'STR' 
        	 && E.Var_arg.Final_name == "DATA"
        	 ?
             RESULT = E.Arg1_.Type_expr.Final_name ".DATA"
        ELSE 
	         RESULT = "((" E.Arg1_.Type_expr.Final_name ")" 
	         RESULT = RESULT gen_expr(E.Arg1_) 
	         CASE !RESULT.Ending( ")Result" ) ? RESULT = RESULT".Obj" ;
	         CASE is_left_side ? RESULT = RESULT ".write" ;
	         RESULT = RESULT ")." E.Var_arg.Final_name
        ;
         
    [E.Arg1_.Type_expr.Kind == 'STRUCTURE'] ?
         RESULT = "((" E.Arg1_.Type_expr.In_class_.Final_name "."
         		  "" E.Arg1_.Type_expr.Final_name ")" 
         RESULT = RESULT gen_expr(E.Arg1_) 
         CASE !RESULT.Ending( ")Result" ) ? RESULT = RESULT".Obj" ;
         CASE is_left_side ? RESULT = RESULT ".write" ;
         RESULT = RESULT ")." E.Var_arg.Final_name

         
    ELSE {Type} rec|ord_type = E.Arg1_.Type_expr
    
    	 RESULT = "((" rec.Base_.Final_name "." rec.Final_name 
    	 RESULT = RESULT ")" gen_expr(E.Arg1_) ")." 
    	 RESULT = RESULT E.Var_arg.Final_name ; .



METHOD gen_const({Expr} E|_constant) ==> STR :
	RESULT = gen_const_value(E.Var_arg) .
	
METHOD gen_const_value({Var} V|alue_to_generate) ==> STR :
    CASE V.Type_.Kind ?
        ['BOOL']: 
                  CASE V.Int_c != 0 ? RESULT = "true"
                  ELSE RESULT = "false" ;
        ['INT', 'ENUM']:
            CASE V.Int_c > MAX_INT || V.Int_c < MIN_INT ? 
                 RESULT = "0x" V.Int_c.Hex(8)
            ELSE RESULT = V.Int_c.Str ;
        ['REAL']: RESULT = V.Real_c.Str
                  CASE "." !IN RESULT && "E" !IN RESULT ? RESULT = RESULT ".0" ;
                  CASE ? 
                  [V == Comp.INFINITY_c] ?
                       RESULT = "Double.POSITIVE_INFINITY"
                  [V.Real_c.Is_INF] ?
                       CASE V.Real_c < 0 ?
                            RESULT = "Double.NEGATIVE_INFINITY"
                       ELSE RESULT = "Double.POSITIVE_INFINITY" ;
                  [V == Comp.NAN_c || V.Real_c.Is_NAN] ?
                       RESULT = "Double.NaN" ;
        ['STR']: RESULT = V.Str_c.as_str
        
        ['CLASS', 'STRUCTURE']:
			Comp.Current_class.Parse.Line = V.Line
            Comp.Error("Generating class constant!"._Egen4 ) ; .



METHOD gen_as_obj({Expr} E|_as_operation) ==> STR :
    STR t|ype_final_name = E.Type_expr.Final_name
    
    RESULT = "AL4_system.As_obj(" gen_expr(E.Arg1_)
    ", " t ".NoneObj_" t ".hard_link)" .



METHOD gen_array({Expr} E|_array_obj) ==> STR :
    CASE E.Type_expr.Kind ?
        ['BOOL']: STR n|ames_type[] << "Bool" << "boolean"
        ['ENUM']: n[] << "Byte" << "byte"
        ['INT']: n[] << "Int" << "int"
        ['REAL']: n[] << "Real" << "double"
        ['STR']: n[] << "Str" << "String"
        ['CLASS', 'STRUCTURE']:
			Comp.Error("Constant array of objects?"._Econst2 )
    ;
    RESULT = "new FixA" n[0] "(new " n[1] "[]{"
    FOR it IN E.Items_[] :
        RESULT = RESULT gen_expr(it) ", " ;
    RESULT = RESULT.[0 TO *-2] "})" .

METHOD gen_const_array({Expr} E|_array_obj) ==> STR :
    CASE E.Type_expr.Kind ?
        ['BOOL']: STR n|ames_type[] << "Bool" << "boolean"
        ['ENUM']: n[] << "Byte" << "byte"
        ['INT']: n[] << "Int" << "int"
        ['REAL']: n[] << "Real" << "double"
        ['STR']: n[] << "Str" << "String"
        ['CLASS', 'STRUCTURE']:
			Comp.Error("Constant array of objects?"._Econst4 )
    ;
    RESULT = "new " n[1] "[]{"
    FOR it IN E.Items_[] :
        RESULT = RESULT gen_expr(it) ", " ;
    RESULT = RESULT.[0 TO *-2] "}" .



{Expr} new_init|_statement

METHOD gen_new_obj({Expr} E|_new_obj) ==> STR :
    new_init = E
    CASE E.Type_obj_.Kind == 'STRUCTURE' ?
         RESULT = E.Type_obj_.In_class_.Final_name "." ;
    RESULT = RESULT E.Type_obj_.Final_name ".New()" .


------------------------------------------------------------- 'RTTI'

METHOD output_RTTI_info_tables :
	STR all_r|ecords_and_enums_list[]
	STR all_e|num_items[]
	STR k|inds_array[] << sp(4) "public static int RTTI_type_kinds[] = {"
	STR add_k|inds_array[]
	o[] << sp(4) "public static String[] RTTI_type_info = {"
	-------------------- '{Object} base for all objects always number 0'
	k[] << sp(8) "7, "
	o[] << sp(8) #QU "{|Object}" #QU ","
	-------------------- '5 simple types always numbers are 1 to 6'
	k[] << sp(8) "0, 1, 2, 3, 4, "
	o[] << sp(8) #QU "BOOL|EAN" #QU ","
	o[] << sp(8) #QU "BYTE" #QU ","
	o[] << sp(8) #QU "INT|EGER" #QU ","
	o[] << sp(8) #QU "REAL" #QU ","
	o[] << sp(8) #QU "STR|ING" #QU ","
	-------------------- 'rest of all classes, then all records & enums'
	FOR c IN Comp.All_classes[] :
	    c.Type_total_index = renumber(c.Type_total_index,  6 + c.Index)
	    k[] << sp(8) "7, // " c.Names[0]
	    STR c_w|hole_name = c.Whole_name 
	    o[] << sp(8) #QU c_w
	    CASE c.Base_ != NONE ?
	         o[*] = o[*] ",base:" (Comp.All_classes[].Find(c.Base_) + 6).Str ;
	    CASE c.Enums_[].Count + c.Structures_[].Count > 0 ?
	    	 o[*] = o[*] ",rec:" (6 + Comp.All_classes[].Count + all_r[].Count).Str
	    	 		 ",count:" (c.Enums_[].Count + c.Structures_[].Count).Str 
	    	 FOR e IN c.Enums_[] :
	    	 	 e.Type_total_index = renumber(e.Type_total_index, 6 
	    	 	 	+ Comp.All_classes[].Count + all_r[].Count)
	    	 	 add_k[] << sp(14) "5, //" e.Names[0]
	    	 	 
	    	     all_r[] << sp(14) #QU e.Whole_name
	    	     			",items:" all_e[].Count.Str 
	    	     			",count:" e.Items[].Count.Str #QU ","
	    	     			
	    	     add_items_of_enum(all_e[], e)
	    	 ;
	    	 FOR st IN c.Structures_[] :
	    	     st.Type_total_index = renumber(st.Type_total_index, 6 
	    	 	 	+ Comp.All_classes[].Count + all_r[].Count)
	    	     add_k[] << sp(14) "7, //" c.Names[0] "." st.Names[0]
	    	     all_r[] << sp(14) #QU st.Whole_name #QU "," ;
	    ;
	    o[*] = o[*] #QU ","
	    //DEBUG: o[*] << " // " (6 + c.Index).Str ; 
	;
	FOR sr IN add_k[] : k[] << sr ;
	FOR sr IN all_r[] : o[] << sr ;
	k[] << sp(8) "-1 };" << ""
	o[*] = Remove_trailing(o[*], ",")
	o[] << sp(4) "};" << ""
	FOR sr IN k[] : o[] << sr ; 
	---------------------------- 'all enum item names'
	o[] << sp(4) "public static String[] RTTI_enum_items = {"
	FOR se IN all_e[] : o[] << se ;
	o[*] = Remove_trailing(o[*], ",")
	o[] << sp(4) "};" << ""
	---------------------------- 'base RTTI methods to work with fields'
	o[] << sp(4) "public int RTTI_object_field_count()"
	o[] << sp(4) "{"
	o[] << sp(8) "return 0;"
	o[] << sp(4) "}"
    ---------------------------- 'get object field name'
	o[] << sp(4) "public String RTTI_object_field_name(int index)"
	o[] << sp(4) "{"
	o[] << sp(8) "return "#QU#QU";"
	o[] << sp(4) "}"
	---------------------------------------- 'get object field info'
	o[] << sp(4) "public int RTTI_object_info_field("
				 "int index, int What)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return  0;"
	o[] << sp(4) "}"
	------------------ 'get object field (simple types only, w/o STR)'
	o[] << sp(4) "public boolean RTTI_object_get_bool("
				 "int index, int Index_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return false;"
	o[] << sp(4) "}"
	--------------------- ', get byte'
	o[] << sp(4) "public byte RTTI_object_get_byte("
				 "int index, int Index_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return 0;"
	o[] << sp(4) "}"
	--------------------- ', get int'
	o[] << sp(4) "public int RTTI_object_get_int("
				 "int index, int Index_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return 0;"
	o[] << sp(4) "}"
	--------------------- ', get real'
	o[] << sp(4) "public double RTTI_object_get_real("
				 "int index, int Index_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return 0;"
	o[] << sp(4) "}"
	--------------------- ', get array'
	o[] << sp(4) "public ArrayAny RTTI_object_get_array(int index)"
	o[] << sp(4) "{"
	o[] << sp(8) "return null;"
	o[] << sp(4) "}"
	------------------ 'set object field (simple types only, w/o STR)'
	o[] << sp(4) "public boolean RTTI_object_set_bool("
				 "int index, boolean Value, int Index_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return false;"
	o[] << sp(4) "}"
	-------------------- ', byte'
	o[] << sp(4) "public boolean RTTI_object_set_byte("
				 "int index, int Value, int Index_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return false;"
	o[] << sp(4) "}"
	-------------------- ', int'
	o[] << sp(4) "public boolean RTTI_object_set_int("
				 "int index, int Value, int Index_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return false;"
	o[] << sp(4) "}"
	------------------- ', real'
	o[] << sp(4) "public boolean RTTI_object_set_real("
				 "int index, double Value, int Index_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return false;"
	o[] << sp(4) "}"
	------------------------------------------------------------ 'strings'
	o[] << sp(4) "public String RTTI_object_get_string("
				 "int index, int Index_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return "#QU#QU";"
	o[] << sp(4) "}"
	---------------- 'set object field of type STR value'
	o[] << sp(4) "public boolean RTTI_object_set_string("
				 "int index, String Value, int Index_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return false;"
	o[] << sp(4) "}"
	----------------------------------------------------------- 'objects'
	o[] << sp(4) "public Ref_obj RTTI_object_get_object("
				 "int index, int Index_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return NoneObj_AL4_object.hard_link;"
	o[] << sp(4) "}"
	---------------- 'set object field of object type value'
	o[] << sp(4) "public boolean RTTI_object_set_object("
				 "int index, Ref_obj Value, int Index_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(8) "return false;"
	o[] << sp(4) "}"
	---------------- 'insert item into array field of object'
	o[] << sp(4) "public void RTTI_object_field_array_insert("
				 "int index, int Insert_pos_in_array)"
				 
	o[] << sp(4) "{"
	o[] << sp(4) "}"
	---------------- 'delete item in array field of object'
	o[] << sp(4) "public void RTTI_object_field_array_delete("
				 "int index, int Delete_pos_in_array, int Count_to_delete)"
				 
	o[] << sp(4) "{"
	o[] << sp(4) "}"
	---------------- 'allocate items in array field of object'
	o[] << sp(4) "public void RTTI_object_field_array_allocate("
				 "int index, int Count_to_allocate)"
				 
	o[] << sp(4) "{"
	o[] << sp(4) "}"
	
	.
	
ENUM {what_return} :
	'FIELD_COUNT',
	'FIELD_NAME',
	'FIELD_INFO',
	'GET_STRING',
	'SET_BOOL',
	'SET_INT',
	'SET_REAL',
	'SET_STRING',
	'GET_OBJECT',
	'SET_OBJECT' .
	
METHOD generate_RTTI_methods({Type} Class|_generate_for) :
	generate_1_RTTI_method(Class,
		"int RTTI_object_field_count", 'FIELD_COUNT')
		
	generate_1_RTTI_method(Class,
		"String RTTI_object_field_name", 'FIELD_NAME')
		
	generate_1_RTTI_method(Class,
		"int RTTI_object_info_field", 'FIELD_INFO')
		
	generate_1_RTTI_method(Class,
		"String RTTI_object_get_string", 'GET_STRING')
		---------------------------- 'simple types value set'
	generate_1_RTTI_method(Class,
		"boolean RTTI_object_set_bool", 'SET_BOOL')
		
	generate_1_RTTI_method(Class,
		"boolean RTTI_object_set_int", 'SET_INT')
		
	generate_1_RTTI_method(Class,
		"boolean RTTI_object_set_real", 'SET_REAL')
		
	generate_1_RTTI_method(Class,
		"boolean RTTI_object_set_string", 'SET_STRING') .
	
	
METHOD generate_1_RTTI_method(
{Type} Class|_generate_for,
STR Method_name|_together_with_return_type,
{what_return} What|_return_or_do_in_method)
	:
	o[] << sp(4) "@Override"
	o[] << sp(4) "public " Method_name "("
	CASE What != 'FIELD_COUNT' ? o[*] = o[*] "int index" ;
	CASE What ?
	['SET_BOOL']: o[*] = o[*] ", boolean Value, int Index_in_array"
	['SET_INT']: o[*] = o[*] ", int Value, int Index_in_array"
	['SET_REAL']: o[*] = o[*] ", double Value, int Index_in_array"
	['SET_STRING']: o[*] = o[*] ", String Value, int Index_in_array"
	['GET_STRING', 'GET_OBJECT', 'SET_OBJECT']:
					o[*] = o[*] ", int Index_in_array"
	['FIELD_COUNT', 'FIELD_NAME']: NONE
	['FIELD_INFO']: o[*] = o[*] ", int What"
	;
	o[*] = o[*] ")"
	--------------------- 'body'
	o[] << sp(4) "{"
	CASE What != 'FIELD_COUNT' ?
		 o[] << sp(8) "switch(index)" ;
	o[] << sp(8) "{"
	INT x|_dummy_not_used = generate_RTTI_fields(Class, 0, What)
	o[] << sp(8) "}"
	CASE What ?
	['FIELD_COUNT']:
		STR rtti_f|ields = generate_RTTI_fields(Class, 0, What).S
		o[] << sp(8) "return " rtti_f ";"
	['GET_STRING', 'FIELD_NAME']: o[] << sp(8) "return "#QU#QU";"
	['SET_BOOL', 'SET_INT', 'SET_REAL', 'SET_STRING', 'SET_OBJECT']:
					o[] << sp(8) "return false;"
	['GET_OBJECT']: o[] << sp(8) "return NoneObj_AL4_object;"
	['FIELD_INFO']: NONE ;
	CASE What == 'FIELD_INFO' ? o[] << sp(8) "return 0;" ;
	o[] << sp(4) "}" << ""
	.
	
STR RTTI_prefix|_name	

METHOD generate_RTTI_fields(
{Type} Class|_generate_for,
INT Case|_start_from,
{what_return} What|_return) ==> INT //RESULT|_continue_case_from
, RECURSIVE
	:
	INT current|_case = Case
	CASE Class.Kind == 'CLASS' && Class.Base_ != NONE ?
		 current = generate_RTTI_fields(Class.Base_, current, What) ;
	FOR f IN Class.Field[] :
	    CASE What == 'FIELD_COUNT' ?
	         current += 1
	         CONTINUE f ;
	    o[] << sp(12) "case " current.Str ":"
	    current += 1
	    CASE What ?
	    ['FIELD_COUNT']: NONE

	    ['FIELD_NAME']:
	    	o[] << sp(16) "return " #QU RTTI_prefix f.Names[0] #QU";"
	    	CONTINUE f

		['SET_BOOL', 'SET_INT', 'SET_REAL']:
			o[*] = o[*] "// " What.Name ": " RTTI_prefix f.Final_name
	    	CASE f.Is_array || f.Type_.Kind IN ['CLASS', 'STRUCTURE', 'STR'] ?
	    	     o[] << sp(16) "return false;"
	    	     CONTINUE f
	    	;
	    	CASE f.Type_.Kind == 'BOOL' && What != 'SET_BOOL' || (
	    		 f.Type_.Kind == 'REAL' && What != 'SET_REAL') || (
	    		 f.Type_.Kind IN ['INT', 'ENUM'] && What != 'SET_INT')
	    		 ?
	    	     o[] << sp(16) "return false;"
	    	     CONTINUE f ;
	    	o[] << sp(16) RTTI_prefix f.Final_name " = "
	    	CASE f.Type_.Kind ?
	    	['BOOL', 'INT', 'REAL']: o[*] = o[*] "Value;"
	    	['ENUM']: o[*] = o[*] "(byte)Value;"
	    	['STR', 'CLASS', 'STRUCTURE']:
	    		o[*] = sp(16) "return false;"
	    		CONTINUE f
	    	;
	    	o[] << sp(16) "return true;"
	    	CONTINUE f

		['GET_STRING']:
	    	CASE f.Is_array || f.Type_.Kind != 'STR' ?
	    	     o[] << sp(16) "return "#QU#QU";"
	    	     CONTINUE f ;
	    	o[] << sp(16) "return " RTTI_prefix f.Final_name ";"
	    	CONTINUE f

		['GET_OBJECT']:
	    	CASE ?
	    	[f.Is_array && f.Type_.Kind IN ['CLASS', 'STRUCTURE']] ?
	    	     o[] << sp(16) "return " RTTI_prefix f.Final_name
	    	     		".GetObjects(Index_in_array);"
	    	[f.Type_.Kind IN ['CLASS', 'STRUCTURE']] ?
	    		 o[] << sp(16) "return " RTTI_prefix f.Final_name" ;"
	    	ELSE o[] << sp(16) "return "#QU#QU";" ;
	    	CONTINUE f

		['SET_STRING']:
			o[*] = o[*] "// SET_STRING: " RTTI_prefix f.Final_name
	    	CASE f.Is_array || f.Type_.Kind != 'STR' ?
	    	     o[] << sp(16) "return false;"
	    	     CONTINUE f ;
	    	     
	    	o[] << sp(16) RTTI_prefix f.Final_name " = Value;"
	    	o[] << sp(16) "break;"
	    	CONTINUE f

		['SET_OBJECT']:
			o[*] = o[*] "// SET_OBJECT: " RTTI_prefix f.Final_name
	    	CASE ?
	    	[f.Is_array && f.Type_.Kind IN ['CLASS', 'STRUCTURE']] ?
	    	     o[] << sp(16) RTTI_prefix f.Final_name
	    	     		".SetObjects(Index_in_array, Value);"
	    	     o[] << sp(16) "return true;"
	    	[f.Type_.Kind IN ['CLASS', 'STRUCTURE'] && f.Is_weak] ?
	    	     o[] << sp(16) "Object_assign_weak("
	    	     		"" RTTI_prefix f.Final_name ", Value);"
	    	     o[] << sp(16) "return true;"
	    	[f.Type_.Kind IN ['CLASS', 'STRUCTURE']] ?
	    	     o[] << sp(16) "Object_assign_hard("
	    	     		"" RTTI_prefix f.Final_name ", Value);"
	    	     o[] << sp(16) "return true;"
	    	ELSE o[] << sp(16) "return false;" ;
	    	CONTINUE f

	    ['FIELD_INFO']: NONE ;
	    o[*] = o[*] "// FIELD_INFO: " RTTI_prefix f.Names[0]
	    o[] << sp(16) "switch(What)"
	    o[] << sp(16) "{"
	    -------------------------- 'TYPE_INDEX'
	    o[] << sp(20) "case 0:"
	    o[] << sp(24) "return " f.Type_.Type_total_index.Str ";"
	    -------------------------- 'IS_ARRAY'
	    o[] << sp(20) "case 1:"
	    o[] << sp(24) "return " f.Is_array.bool_as_int.Str ";"
	    -------------------------- 'IS_FIXED|_ARRAY'
	    o[] << sp(20) "case 2:"
	    o[] << sp(24) "return " f.Is_fixed.bool_as_int.Str ";"
	    -------------------------- 'IS_PUBLIC'
	    o[] << sp(20) "case 3:"

	    o[] << sp(24) "return " (f.Names[0].[0].Upper == f.Names[
	    	   0].[0]).bool_as_int.Str ";"
	    -------------------------- 'SIZE_ARRAY'
	    o[] << sp(20) "case 4:"
	    CASE f.Is_array ? o[] << sp(24) "return " f.Final_name ".Count();"
	    ELSE
	    o[] << sp(24) "return 0;" ;
	    o[] << sp(16) "}"
	    o[] << sp(16) "break;"
	;
	RESULT = current .
	
FUN bool_as_int(BOOL Value|_to_represent) ==> INT :
	CASE Value ? RESULT = 1 ; .
	
FUNCTION add_items_of_enum(
STR List|_of_enum_items[], {Type} E|numeration)
	:
	FOR v IN E.Items[] :
		List[] << sp(8) #QU  v.Whole_name #QU "," ; .
            
BOOL renumber_classes
		
METHOD renumber|_type(
INT Curr|ent_value, INT Next|_value) ==> INT
	:
	CASE renumber_classes ? RESULT = Next ==> ;
	RESULT = Curr .


END

--AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.$COMPANY.$PROJECT">
    
?$SDK <uses-sdk android:targetSdkVersion="$SDK" />
?$permission.INTERNET <uses-permission android:name="android.permission.INTERNET" />
?$permission.READ_CONTACTS <uses-permission android:name="android.permission.READ_CONTACTS" />
?$permission.BLUETOOTH <uses-permission android:name="android.permission.BLUETOOTH" />
?$permission.CAMERA <uses-permission android:name="android.permission.CAMERA" />

?$permission.ACCEPT_HANDOVER <uses-permission android:name="android.permission.ACCEPT_HANDOVER" />
?$permission.ACCESS_BACKGROUND_LOCATION <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
?$permission.ACCESS_COARSE_LOCATION <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
?$permission.ACCESS_FINE_LOCATION <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
?$permission.ACCESS_LOCATION_EXTRA_COMMANDS <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
?$permission.ACCESS_MEDIA_LOCATION <uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
?$permission.ACCESS_NETWORK_STATE <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
?$permission.ACCESS_WIFI_STATE <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
?$permission.ACTIVITY_RECOGNITION <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
?$permission.ANSWER_PHONE_CALLS <uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
?$permission.BATTERY_STATS <uses-permission android:name="android.permission.BATTERY_STATS" />
?$permission.BODY_SENSORS <uses-permission android:name="android.permission.BODY_SENSORS" />
?$permission.CALL_PHONE <uses-permission android:name="android.permission.CALL_PHONE" />
?$permission.CALL_PRIVILEGED <uses-permission android:name="android.permission.CALL_PRIVILEGED" />
?$permission.CAPTURE_AUDIO_OUTPUT <uses-permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT" />
?$permission.CHANGE_COMPONENT_ENABLED_STATE <uses-permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE" />
?$permission.CHANGE_CONFIGURATION <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
?$permission.CHANGE_NETWORK_STATE <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
?$permission.CHANGE_WIFI_MULTICAST_STATE <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
?$permission.CHANGE_WIFI_STATE <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
?$permission.DELETE_PACKAGES <uses-permission android:name="android.permission.DELETE_PACKAGES" />
?$permission.EXPAND_STATUS_BAR <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
?$permission.FOREGROUND_SERVICE <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
?$permission.GET_PACKAGE_SIZE <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
?$permission.INSTALL_SHORTCUT <uses-permission android:name="android.permission.INSTALL_SHORTCUT" />
?$permission.INSTANT_APP_FOREGROUND_SERVICE <uses-permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE" />
?$permission.KILL_BACKGROUND_PROCESSES <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
?$permission.LOCATION_HARDWARE <uses-permission android:name="android.permission.LOCATION_HARDWARE" />
?$permission.MODIFY_AUDIO_SETTINGS <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
?$permission.MODIFY_PHONE_STATE <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
?$permission.MOUNT_FORMAT_FILESYSTEMS <uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
?$permission.MOUNT_UNMOUNT_FILESYSTEMS <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
?$permission.READ_CALENDAR <uses-permission android:name="android.permission.READ_CALENDAR" />
?$permission.READ_EXTERNAL_STORAGE <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
?$permission.READ_CALL_LOG <uses-permission android:name="android.permission.READ_CALL_LOG" />
?$permission.READ_PHONE_NUMBERS <uses-permission android:name="android.permission.READ_PHONE_NUMBERS" />
?$permission.READ_SMS <uses-permission android:name="android.permission.READ_SMS" />
?$permission.REBOOT <uses-permission android:name="android.permission.REBOOT" />
?$permission.RECEIVE_BOOT_COMPLETED <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
?$permission.RECEIVE_SMS <uses-permission android:name="android.permission.RECEIVE_SMS" />
?$permission.RECORD_AUDIO <uses-permission android:name="android.permission.RECORD_AUDIO" />
?$permission.SEND_SMS <uses-permission android:name="android.permission.SEND_SMS" />
?$permission.SET_ALARM <uses-permission android:name="android.permission.SET_ALARM" />
?$permission.SET_TIME <uses-permission android:name="android.permission.SET_TIME" />
?$permission.SET_TIME_ZONE <uses-permission android:name="android.permission.SET_TIME_ZONE" />
?$permission.SET_WALLPAPER <uses-permission android:name="android.permission.SET_WALLPAPER" />
?$permission.SMS_FINANCIAL_TRANSACTIONS <uses-permission android:name="android.permission.SMS_FINANCIAL_TRANSACTIONS" />
?$permission.STATUS_BAR <uses-permission android:name="android.permission.STATUS_BAR" />
?$permission.SYSTEM_ALERT_WINDOW <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
?$permission.USE_BIOMETRIC <uses-permission android:name="android.permission.USE_BIOMETRIC" />
?$permission.USE_FULL_SCREEN_INTENT <uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
?$permission.VIBRATE <uses-permission android:name="android.permission.VIBRATE" />
?$permission.WAKE_LOCK <uses-permission android:name="android.permission.WAKE_LOCK" />
?$permission.WRITE_CALENDAR <uses-permission android:name="android.permission.WRITE_CALENDAR" />
?$permission.WRITE_CONTACTS <uses-permission android:name="android.permission.WRITE_CONTACTS" />
?$permission.WRITE_EXTERNAL_STORAGE <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
?$ICON  android:icon="@mipmap/$ICON"
        android:label="$PROJECT"
?$THEME android:theme="@style/AppTheme"
?$NOTITLE android:theme="@android:style/Theme.Black.NoTitleBar"
        android:supportsRtl="false">
        
        <activity 
         android:name=".MainActivity"
         android:windowSoftInputMode="$SOFT_INPUT_MODE"
         android:fitsSystemWindows="true"
?$ORIENTATION	android:screenOrientation="$ORIENTATION"
         android:configChanges="orientation|keyboardHidden|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>
--
         android:launchMode="singleTop"

--MainActivity.java
package com.$COMPANY.$PROJECT;

import android.os.Bundle;
import android.widget.*;
import android.widget.LinearLayout.*;
import android.content.*;
import android.app.*;
import android.view.Menu;

import java.lang.*;

import android.text.method.*;
import android.view.KeyEvent;

import android.view.ViewTreeObserver;
import android.graphics.Rect;
import android.view.View;

import android.content.res.Configuration;

public class MainActivity extends Activity
{

    public static MainActivity main_activity;
    //public FrameLayout FView;
    public LinearLayout HView;
    public static Rect decorWindowRect = new Rect();

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//getActionBar().setDisplayHomeAsUpEnabled(false);
		try {
		    
		    main_activity = this;
		    
			HView = new LinearLayout(this);
		    setContentView(HView);

		    
            HView.getViewTreeObserver().addOnGlobalLayoutListener(
                new ViewTreeObserver.OnGlobalLayoutListener() {
                    public void onGlobalLayout() {
                    	int prev_decor_bottom = decorWindowRect.bottom;
                        View v = getWindow().getDecorView();
                        v.getWindowVisibleDisplayFrame(decorWindowRect);
                        
        //try { //////////////////////////////////////////////////////////////////
        //C_Log_html.M_Log_colored(0, "--------decor change: " + decorWindowRect +
        //'\n'); } catch(Exception ex){} /////////////////////////////////////////
        
        				if (prev_decor_bottom != decorWindowRect.bottom) {
        					AL4_form.layout_changed();
        				}
        
                    }
                }
            );
		    
			$MAINCLASS.main();
            //Toast.makeText(this, "__Hello, World!__",
            //    Toast.LENGTH_LONG).show();
		}
		catch (Exception ex) {
		    StringBuilder strace = new StringBuilder();
		    for (StackTraceElement se : ex.getStackTrace())
		    	strace.append(se.toString() + '\n');
		    
		    new AlertDialog.Builder(main_activity)
				.setTitle("exception")
				.setMessage(ex.getMessage() + '\n' + strace)
				.setIcon(android.R.drawable.ic_dialog_alert)
				.setPositiveButton("OK", new DialogInterface.OnClickListener() {
					    public void onClick(DialogInterface dialog, int which) {
				            dialog.dismiss();
					    }
					 })
				.create().show();
		}
		
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		return true;
	}
	
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
            //Toast.makeText(this, "__Hello, World!__",
            //    Toast.LENGTH_LONG).show();
	    AL4_form.Prepare_main_menu(menu);
	    //return true;
	    return super.onPrepareOptionsMenu(menu);
	}
	
	@Override
	public void onBackPressed(){
    //try {
//C_Log_html.M_Log_colored(0xFF000000, "back pressed\n");
    //} catch(Exception ex) {}
	    //finish();
	    ////////////////////////AL4_form.Back_pressed();
	    //super.onBackPressed();
	}
	
    @Override
    public boolean dispatchKeyEvent(KeyEvent ke) {
//AL4_system.WriteLine("*** key event " + ke.getAction() + " key code " +
//ke.getKeyCode() + "[" + ke.getUnicodeChar() + "]");
        if (ke.getKeyCode() == 4) {
        	if (ke.getAction() == KeyEvent.ACTION_DOWN) {
        		AL4_form.Back_pressed();
        	}
            return false;
        }
		if (ke.getAction() == KeyEvent.ACTION_UP) {
            //if (ke.getKeyCode() == 4) {
            //    //onBackPressed();
            //    return false;
            //}
			if (ke.getKeyCode() == 82) {
				openOptionsMenu();
				return true;
			}
		}
        //if (AL4_form.dispatchKeyEvent(ke)) return true;
        return super.dispatchKeyEvent(ke);
    }
    
    @Override
    public void onPause() {
    	AL4_form.need_save_state();
    	super.onPause();
    }
    
    @Override
    public void onStop() {
    	AL4_form.activity_stopped();
    	super.onStop();
    }
    
    @Override
    public void onStart() {
    	super.onStart();
    	AL4_form.activity_started();
    }
    
}

--

--save: AL4_system.java

//-------------------------------------- AL4_system.java (created 2016-12-01)
import java.util.ArrayList;
import java.io.File;
import java.io.Console;
import java.io.PrintWriter;

import android.app.*;
import android.content.DialogInterface;

import java.util.Calendar;
import java.util.GregorianCalendar;

public class AL4_system {

    public static int imin(int a, int b)
    {
    	if (a < b) return a;
    	else return b;
    }

    public static int imax(int a, int b)
    {
    	if (a > b) return a;
    	else return b;
    }
    
    public static boolean Array_item_boolean(boolean[] A, int Size, int Index) {
    	if (Index < 0 || Index >= Size) return false;
    	return A[Index];
    }

    public static byte Array_item_byte(byte[] A, int Size, int Index) {
    	if (Index < 0 || Index >= Size) return 0;
    	return A[Index];
    }

    public static int Array_item_int(int[] A, int Size, int Index) {
    	if (Index < 0 || Index >= Size) return 0;
    	return A[Index];
    }

    public static double Array_item_double(double[] A, int Size, int Index) {
    	if (Index < 0 || Index >= Size) return 0;
    	return A[Index];
    }

    public static String Array_item_string(String[] A, int Size, int Index) {
    	if (Index < 0 || Index >= Size) return "";
    	return A[Index];
    }    

	public static String[] Function_names = new String[] {
//#function_names
    };
    
	public static int Get_trace_levels()
	{
		return SP_fun / 2;
	}
	
	public static String Get_trace_fun(int level)
	{
		if (level >= 0 && level < SP_fun / 2)
			return Function_names[
					Stack_functions[SP_fun - 2 - level * 2]];
		else return "";
	}
	
	public static int Get_trace_counter(int level)
	{
		if (level >= 0 && level < SP_fun / 2)
			return Stack_functions[SP_fun - 1 - level * 2];
		else return 0;
	}
	
	public static int[] Stack_functions = new int[4096];
	public static int SP_fun = 0;

    public static int Recursion_counter = 0;
    public static int Max_recursion_deep = 128;
    public static long Test_caller;
                       // lower 6 decimal digits = #of source code line in test function
                       //    calling ordinary code and test functions of level 2
                       // next 6 decimal digits = #of source code line in secondary test
                       //    functions calling ordinary functions.
    
    //-------------------------------------
    // in Java, byte is signed, in range [-128 TO 127]. 
    // So, we convert it to a range [0 TO 255] representing it as INT.
    public static int Byte_as_unsigned(byte b) {
        int Result = b;
        return Result & 0xFF;
    }

    //-------------------------------------
    // Safe operation S[i] (String S, int i)
    public static String Single_symbol(String S, int Pos) {
        if (S != null && Pos >= 0 && S.length() > Pos)
            return S.substring(Pos, Pos+1) + "";
        return (char)0 + "";
    }

    public static String Change_single_symbol(String S, int Pos, 
           String New_char) {
        return Substring(S, 0, Pos-1) + (New_char + (char)0).substring(0,1) + 
            Substring(S, Pos+1, S.length());
    }

    //---------------------------
    // Safe Substring() of String
    public static String Substring(String S, int from, int to) {
        if (to < from || S.length() <= from) return "";
        if (from < 0) from = 0;
        if (S.length() <= to) to = S.length() - 1;
        return S.substring(from, to + 1);
    }
    
    //---------------------------
    // Optimized comparison of two sub-strings
    public static int CompareSubstrings(String S1, String S2, 
        int from1, int to1, int from2, int to2)
    {
        if (from1 < 0) from1 = 0;
        if (from2 < 0) from2 = 0;
        int last1 = to1;
        if (last1 >= S1.length()) last1 = S1.length() - 1;
        int last2 = to2;
        if (last2 >= S2.length()) last2 = S2.length() - 1;
        int j = from2;
        for (int i = from1; i <= last1; i++, j++)
        {
            if (j > last2) 
            {
                if (i <= last1) return 1;
                break;
            }
            int Result = (int)S1.charAt(i) - (int)S2.charAt(j);
            if (Result != 0) return Result;
        }
        if (j <= last2) return -1;
        return 0;
    }
    
    //---------------------------
    // Optimized comparison of a sub-string with a string
    public static int CompareSubstrWithStr(String S1,  
        int from1, int to1, String S2)
    {
        int last1 = to1;
        if (from1 < 0) from1 = 0;
        if (last1 >= S1.length()) last1 = S1.length() - 1;
        int j = 0;
        for (int i = from1; i <= last1; i++, j++)
        {
            if (j >= S2.length()) 
            {
                if (i <= last1) return 1;
                break;
            }
            int Result = (int)S1.charAt(i) - (int)S2.charAt(j);
            if (Result != 0) return Result;
        }
        if (j < S2.length()) return -1;
        return 0;
    }
    
    public static boolean like_str(String S1, String S2)
    {
    	String s1 = S1.toUpperCase();
    	String s2 = S2.toUpperCase();
    	boolean result = s1 == s2;
    	if (result) return true;
    	if (!s2.contains("%") && !s2.contains("?")) return false;
//?{String_functions}
    	//return like_pattern(s1, s2);
    	try {
    		result = C_String_functions.M_Like(s1, s2);
    	}
    	catch(Exception e) { } 
//.
		return result;
    }
    
    //--------------------------------------------
    // Optimized x IN A[]
    public static boolean ArrayContainsInt(int[] A, int X) {
        for (int i = 0; i < A.length; i++) 
            if (A[i] == X) return true;
        return false;
    }

    public static boolean ArrayContainsByte(byte[] A, byte X) {
        for (int i = 0; i < A.length; i++) 
            if (A[i] == X) return true;
        return false;
    }

    public static boolean ArrayContainsStr(String[] A, String X) {
        for (int i = 0; i < A.length; i++) 
            if (A[i].compareTo(X) == 0) return true;
        return false;
    }

    

    //-----------------------------------------
    // Operation S[i] = c (not available in C#)
    public static String Replace_symbol(String S, int i, String r) {
        if (i < 0 || i >= S.length()) return S;
        return S.substring(0, i) + r + S.substring(i + 1);
    }

    //----------------------
    // Convert int to String
    public static String Str(int x) {
        return Integer.toString(x).trim();
    }

    //-------------------------
    // Convert double to String
    public static String Str(double x) {
    try {
        String result = String.format("%.18f", x).replace(',', '.').trim();
        if (result.charAt(result.length()-1) == '.')
        	result = result.substring(0, result.length()-2);
        if (result.indexOf('.') >= 0 && 
        	result.toLowerCase().indexOf('e') < 0)
        {
        	for (int i = result.length()-1; i > 0; i--) {
        		if (result.charAt(i) == '0')
        			result = result.substring(0, i);
        		else if (result.charAt(i) == '.') {
        			result = result.substring(0, i);
        			break;
        		}
        		else break;
        	}
        }
        return result;
    }
    catch (Exception ex) {
		    StringBuilder strace = new StringBuilder();
		    for (StackTraceElement se : ex.getStackTrace())
		    	strace.append(se.toString() + '\n');
		    
		    new AlertDialog.Builder(AL4_form.context_activity)
				.setTitle("exception")
				.setMessage(ex.getMessage() + '\n' + strace)
				.setIcon(android.R.drawable.ic_dialog_alert)
				.setPositiveButton("OK", new DialogInterface.OnClickListener() {
					    public void onClick(DialogInterface dialog, int which) {
				            dialog.dismiss();
					    }
					 })
				.create().show();
    }
    	return "";
    }

    //-------------------------
    // Convert boolean to String
    public static String Str(boolean x) {
        if (x) return "TRUE";
        return "FALSE";
    }

    public static int Int(String s) {
        int Result = 0;
        boolean Neg = false;
        if (s.equals("")) return Result;
        int i = 0;
        if (s.charAt(i) == '-') {
            i++;
            Neg = true;
        }
        else if (s.charAt(i) == '+') i++;
        for (int j = i; j < s.length(); j++) {
            if (s.charAt(j) == '_') continue;
            if (s.charAt(j) >= '0' && s.charAt(j) <= '9')
                Result = Result * 10 + (int)s.charAt(j) - (int)'0';
            else break;
        }
        if (Neg) return -Result;
        return Result;
    }

    public static int RealAsInt(double X) {
        return (int)X;
    }

    //------------- 'string as a sequence of hexadecimal, 4 digits per char'
    private static String hex16(int value16)
    {
        String Result = "";
        for (int i = 0; i < 4; i++)
        {
            int digit = (value16 >> 12) & 0xf;
            value16 = value16 << 4;
            if (digit < 10) Result += "" + (char)((int)'0' + digit);
            else Result += "" + (char)((int)'A' + digit - 10);
        }
        return Result;
    }

    public static String StrHex16(String s)
    {
        String Result = "";
        for (int i = 0; i < s.length(); i++)
            Result += hex16((int)s.charAt(i));
        return Result;
    }

    public static int ShiftLeft(int i, int n) {
        return i << n;
    }

    public static int ShiftRight(int i, int n) {
        return i >>> n;
    }

    public static int RotateLeft(int i, int m) {
		int mask = (0xFFFFffff << (m-1))<<1;
    	int r = (mask & i) 
    		   | ((i << 1) & ~mask) 
    		   | ((i & ~mask) >>> (m-1));
    	return r;    
    }

    public static int RotateRight(int i, int m) {
		int mask = (0xFFFFffff << (m-1))<<1;
    	int r = (mask & i) 
    		   | ((i >>> 1) & ~mask) 
    		   | ((i & ~mask) << (m-1));
    	return r;    
    }

    public static String Restrict_length(String src, int len) {
        String Result = src;
        if (Result.length() > len)
           Result = Result.substring(0, len);
        return Result;
    }

    //------------------------------------------
    // Find substring first position in a String
    public static int Find_str(String S, String Pattern) {
        if (S == null) return -1;
        int r = S.indexOf(Pattern);
        return r;
    }

    //--------------------------------------
    // Is object variable referencing NONE ?
    public static boolean Is_none(Ref_obj obj) {
        return obj.Obj.Is_NONE_object;
    }

    //---------------------------------------------------------------
    // Safe division of real numbers. Returns INF or NaN in bad cases
    public static double Safe_div(double X, double Y) {
        if (Y == 0) return X > 0 ?
            Double.POSITIVE_INFINITY : Double.NEGATIVE_INFINITY;
        try {
            return X / Y;
        }
        catch(ArithmeticException E_AE) {
            AL4_system.Any_exception(E_AE);
            return Double.NaN;
        }
    }

    //-------------------------------------------------
    // Safe division of int numbers. Returns very large
    // or negative large integer number in bad cases.
    public static int Safe_div_int(int X, int Y) {
        if (Y == 0) return X > 0 ?
            Integer.MAX_VALUE : Integer.MIN_VALUE;
        return X / Y;
    }

    //---------------------------------
    // Safe rest of division operation.
    public static int Safe_rest(int X, int Y) {
        if (Y == 0) return X;
        return X % Y;
    }

    //-----------------------
    // STOP operation
    public static void STOP(String message) throws Exception {
        throw new AL4StopException(message);
    }
    
    public static class Strings {
        public ArrayList<String> list = new ArrayList<String>();
    }
    
    public static Strings Errors = null;
    
    public static void Any_exception(Throwable e) {
    	Add_error_descr(e.getClass().getName() + ": " + e.getMessage());
    }
    
    public static void Add_error_descr(String s) {
        if (Errors == null)
            Errors = new Strings();
        if (Errors.list.size() >= 10) {
            Errors.list.remove(5);
            Errors.list.set(5, "");
        }
        Errors.list.add(s);
    }
    
    public static void Reset_errors() {
        Errors = null;
    }
    
    public static int Errors_count() {
        if (Errors == null) return 0;
        return Errors.list.size(); 
    }
    
    public static String Errors_info(int index) {
        if (Errors == null || index < 0 || index >= Errors.list.size())
            return "";
        return Errors.list.get(index);
    }


    //------------------------------------------------------------
    // Operation X.{Type}. Returns NONE is X is not of type {Type}.
    public static Ref_obj As_obj(Ref_obj X, Ref_obj None_y) {
        AL4_object probe = X.Obj;
        try {
        while (probe != null) {
            if (probe.NONE_obj_instance().Obj == None_y.Obj)
                return X;
            probe = probe.NONE_base_obj();
        }
        }
        catch (Exception ex) {
            //if (None_y == null)
            //    AL4_system.WriteLine("!!! None_y == null");
            //ex.printStackTrace();
        }
        return None_y;
    }

    //----------------------------------------------------------
    // Application startup directory
    public static String Start_dir()
    {
        return Startup_path();
    }

    //----------------------------------------------------------
    // Application startup directory
    public static String Startup_path()
    {
        try {
            File f = new File(".");
            String s = f.getCanonicalPath();
            return s;
        }
        catch(Exception E) {
            AL4_system.Any_exception(E);
            return "";
        }
    }

    //---------------------------------------------------------
    // Clear test data
    public static void Clear_test_data(long[] test_lines)
    {
        for (int i = 0; i < test_lines.length; i++)
        {
            if (test_lines[i] == -1) continue;
            test_lines[i] = 0;
        }
    }

    //---------------------------------------------------------
    // Remove a range from test data
    public static void Remove_test_data(long[] test_lines, int from, int to)
    {
        for (int i = from; i <= to; i++)
        {
            if (i >= test_lines.length) return;
            if (test_lines[i] < 0) continue;
            if (test_lines[i] == 0) test_lines[i] = -9;
        }
    }

    // adding an assertion failed to list of failed assertions:
    public static ArrayList<Integer> Assertion_failed(int line,
           ArrayList<Integer> test_assert)
    {
        if (test_assert == null) test_assert = new ArrayList<Integer>();
        test_assert.add(line);
        return test_assert;
    }

    public static ArrayList<String> Assertion_failed2(String assert_failed_text,
           ArrayList<String> test_assert_failed_text)
    {
        if (test_assert_failed_text == null)
            test_assert_failed_text = new ArrayList<String>();
        test_assert_failed_text.add(assert_failed_text);
        return test_assert_failed_text;
    }
    
    /////////////////////////////////////////////// W R I T E
    public interface Sim_Write {
    	public void do_write(String S);
    }
    
    public static boolean dup_Write;
    public static Sim_Write sim_Write;  

    public static void Write(String S) {
        try {
    //C_Log_html.M_Log_colored(0,"before Write, sim_Write==Null?" +
    //(sim_Write==null));
			if (null != sim_Write) {
				sim_Write.do_write(S);
				if (!dup_Write) return;
			}
            Console c = System.console();
            if  (c != null) {
                c.printf("%s", S);
            }
        }
        catch(Exception ex) {
            AL4_system.Any_exception(ex);
            ex.printStackTrace();
        }

    }

    public static void WriteLine(String S) {
        Write(S + "\r\n");
    }
    
	//////////////////////////////////////////////// R E A D
	public interface Sim_Read {
		public String do_read();
		public String do_get_char();
		public boolean is_char_ready();
	}
	
	public static Sim_Read sim_Read;
	
    public static String ReadLine() {
        try {
        	if (null != sim_Read) {
        		return sim_Read.do_read();
        	}
            Console c = System.console();
            if  (c != null) {
                String s = c.readLine("");
                return s;
            }
        }
        catch(Exception ex) {
            AL4_system.Any_exception(ex);
            ex.printStackTrace();
        }
        return "";
    }

    public static String GetChar() {
        try {
        	if (null != sim_Read) {
        		return sim_Read.do_get_char();
        	}
        }
        catch(Exception ex) { AL4_form.report(ex); }
        return "";
    }

    public static boolean CharAvailable() {
        try {
        	if (null != sim_Read) {
        		return sim_Read.is_char_ready();
        	}
        }
        catch(Exception ex) { AL4_form.report(ex); }
        return false;
    }

    public static void Save_strings(ArrayList<String> L, String Path) {
        try {
            String nl = System.getProperty("line.separator");
            java.io.BufferedWriter bw = null;
            bw = new java.io.BufferedWriter(
                new java.io.OutputStreamWriter(
                new java.io.FileOutputStream(Path, false)));
            for (int i = 0; i < L.size(); i++)
                 bw.append(L.get(i)).append(nl);
        }
        catch (Exception E_io) {}
    }
    
    public static boolean Is_TEST_stage()
    {
#test:      return true;
#not_test:  return false;
    }
    
	public static int global_activity_counter = 65535;
	public static ArrayList<AL4_handler> long_operation_handlers 
		= new ArrayList<AL4_handler>();
	
	public static void check_long_operation() throws Exception
	{
		try {
		global_activity_counter = 65535;
		if (long_operation_handlers == null) return;
		//AL4_system.WriteLine("check long operation calls Handler");
		for (int i = long_operation_handlers.size()-1; i >= 0; i--)
			long_operation_handlers.get(i).Handler();
		} catch(Exception E) {
			E.printStackTrace();
		}
	}
	
	public static ArrayList<Integer> id_limits = new ArrayList<Integer>();
	public static ArrayList<Integer> kind_limits = new ArrayList<Integer>();
	public static ArrayList<Long> value_limits = new ArrayList<Long>();
	public static int total_id_limits;

	public static int limit_by_time(double time, int units) {
		total_id_limits += 1;
		int id = total_id_limits;
		id_limits.add(id);
		kind_limits.add(0);
		
		GregorianCalendar d = new GregorianCalendar();
		long span = d.getTimeInMillis();
		switch (units)
		{
			case 0: span += Math.ceil(time);
					break;
			case 1: span += Math.ceil(time * 1000);
					break;
			case 2: span += Math.ceil(time * 60000);
					break;
			case 3: span += Math.ceil(time * 3600000);
					break;
			case 4: span += Math.ceil(time * 3600000 * 24);
					break;
		}
		
		value_limits.add(span);
		add_limit_handler();
		return id;
	}
	
	public static long total_func;

	public static int limit_by_func(long limit_func) {
		total_id_limits += 1;
		int id = total_id_limits;
		id_limits.add(id);
		kind_limits.add(1);
		value_limits.add(total_func + limit_func);
		add_limit_handler();
		return id;
	}

	public static long total_loops;

	public static int limit_by_loops(long limit_loops) {
		total_id_limits += 1;
		int id = total_id_limits;
		id_limits.add(id);
		kind_limits.add(1);
		value_limits.add(total_loops + limit_loops);
		add_limit_handler();
		return id;
	}
	
	public static void dismiss_limit(int id)
	{
		for (int i= id_limits.size()-1; i >= 0; i--)
		{
			if (id_limits.get(i) != id) continue;
			id_limits.remove(i);
			kind_limits.remove(i);
			value_limits.remove(i);
			return;
		}
	}
	
	public static boolean limit_handler_added;
	
	public static void add_limit_handler()
	{
		if (limit_handler_added) return;
		limit_handler_added = true;
		Limit_handler lh = new Limit_handler();
		long_operation_handlers.add(lh); 
	}
	

#localize

} // end of AL4_system class

--save: E_Limit_exceeded.java

	public class E_Limit_exceeded extends AL4_Exception
    {
    	public int id;
    	
    	public E_Limit_exceeded(int id_exception)
    	{
    		id = id_exception;
    	}
    }	
    
--save: Limit_handler.java    

	import java.util.Calendar;
	import java.util.GregorianCalendar;
	
	public class Limit_handler extends AL4_handler
    {
	        
		@Override
        public void Handler() throws Exception
    	{
    		for (int i= 0; i < AL4_system.id_limits.size(); i++)
    		{
    			switch (AL4_system.kind_limits.get(i))
    			{
    				case 0:
		                 GregorianCalendar d = new GregorianCalendar();
						 long span = d.getTimeInMillis();
		                 if (span > AL4_system.value_limits.get(i))
		                 {
		                 	throw new E_Limit_exceeded(AL4_system.id_limits.get(i));
		                 }
		                 break;
    				case 1:
		    			 if (AL4_system.total_func > AL4_system.value_limits.get(i))
		    			 {
		                 	throw new E_Limit_exceeded(AL4_system.id_limits.get(i));
		    			 }
		    			 break;
    				case 2:
		    			 if (AL4_system.total_loops > AL4_system.value_limits.get(i))
		    			 {
		                 	throw new E_Limit_exceeded(AL4_system.id_limits.get(i));
		    			 }
		    			 break;
    			}
    		}
    	}        
    }	
	
--save: AL4_handler.java

public class AL4_handler
{
	public void Handler() throws Exception { }
}	

--save: AL4_object.java

import java.util.ArrayList;

public class AL4_object  {

//?{RTTI}
		public int RTTI_object_type() {return 0;}
//#RTTI_type_info

		public static String RTTI_type_name(int index, int flags)
		{
			String info[] = RTTI_type_info[index].split(",");
			String result = info[0];
			int pos = result.indexOf('|');
			switch (flags)
			{
			case 0: if (pos >= 0)
					{
						result = result.substring(0, pos);
						if (result.charAt(0) == '{') result += "}";
					}
					break;
			case 1: if (pos >= 0)
						result = result.substring(0, pos-1) + 
								 result.substring(pos+1);
					break;
			}
			return result;
		}
		
		public static int RTTI_type_kind(int index)
		{
			return RTTI_type_kinds[index];
		}
		
		public static int RTTI_count_classes()
		{
			int result = RTTI_type_info.length;
			return result;
		}
		
		public static int RTTI_base_class(int class_index)
		{
			String info = RTTI_type_info[class_index];
			int pos = info.indexOf(",base:");
			if (pos < 0) return -1;
			String[] ss = info.substring(pos+6).split(",");
			return Integer.parseInt(ss[0]);
		}
		
		public static int RTTI_starting_class_record_index(int class_index)
		{
			String info = RTTI_type_info[class_index];
			int pos = info.indexOf(",rec:");
			if (pos < 0) return -1;
			String[] ss = info.substring(pos+5).split(",");
			int start = Integer.parseInt(ss[0]);
			return start;
		}
		
		public static int RTTI_count_class_records(int class_index)
		{
			String info = RTTI_type_info[class_index];
			int pos = info.indexOf(",rec:");
			if (pos < 0) return -1;
			String[] ss = info.substring(pos+5).split(",");
			if (ss[1].substring(0, 6) != "count:") return -1;
			int count = Integer.parseInt(ss[1].substring(7));
			return count;
		}

		public static void RTTI_class_records(
			int class_index, ArrayInt records)
		{
			records.Clear();
			int base_index = RTTI_base_class(class_index);
			if (base_index >= 0)
				RTTI_class_records(base_index, records);
			
			int start = RTTI_starting_class_record_index(class_index);
			int count = RTTI_count_class_records(class_index);
			
			for (int i = start; count-- > 0; i++)
			{
				String info = RTTI_type_info[i];
				if (info.contains(",items:")) continue;
				records.Add(i);
			}
		}
		
		public static void RTTI_class_enums(
			int class_index, ArrayInt enums)
		{
			enums.Clear();
			int base_index = RTTI_base_class(class_index);
			if (base_index >= 0)
				RTTI_class_enums(base_index, enums);
			
			int start = RTTI_starting_class_record_index(class_index);
			int count = RTTI_count_class_records(class_index);
			
			for (int i = start; count-- > 0; i++)
			{
				String info = RTTI_type_info[i];
				if (!info.contains(",items:")) continue;
				enums.Add(i);
			}
		}

		public static int RTTI_starting_enum_items_index(int enum_type_index)
		{
			String info = RTTI_type_info[enum_type_index];
			int pos = info.indexOf(",items:");
			if (pos < 0) return -1;
			String[] ss = info.substring(pos+7).split(",");
			int start = Integer.parseInt(ss[0]);
			return start;
		}
		
		public static int RTTI_enum_count(int enum_type_index)
		{
			String info = RTTI_type_info[enum_type_index];
			int pos = info.indexOf(",count:");
			if (pos < 0) return 0;
			int count = Integer.parseInt(info.substring(pos+7));
			return count;
		}

		public static String RTTI_enum_item(
			int enum_type_index, int index_item)
		{
			int start = RTTI_starting_enum_items_index(enum_type_index);
			int count = RTTI_enum_count(enum_type_index);
			if (index_item < 0 || index_item >= count) return "";
			return RTTI_enum_items[start + index_item];
		}
		
//.

    //just for debugging:
    public static int total_obj_counter;
    // Object NONE instance (single for a class)
    public static Ref_obj None_obj;
    // Object Dummy instance (single for a class)
    public static Ref_obj Dummy_obj;

    public int TOTAL_obj_index;
    public AL4_object() {
        TOTAL_obj_index = ++total_obj_counter;
        if (TOTAL_obj_index == 999)
        { }
    }

    // Fastest way to check if a variable is referencing the NONE
    public boolean Is_NONE_object = false;

    // Back reference to a Ref_obj, containing a hard link onto the object
    public Ref_obj hard_link;

    // Back reference to a Ref_obj, containing a weak link to the object
    public Ref_obj weak_link;

    // Additional link onto the object itself to make changes in fields.
    // For the NONE object, it is referencing the dummy_obj, so NONE is never
    // changed (though it is not necessary to check value for NONE).
    public AL4_object write;


    //------------- for OWNED BY children:
    protected ArrayList<Ref_obj> children = null;

    public Ref_obj NONE_obj_instance() {
        return None_obj;
    }

    public AL4_object NONE_base_obj() {
           return null;
    }

    public void Erase () throws Exception {
        if (TOTAL_obj_index == 37)
        { }
        //AL4_system.WriteLine("Erase");

        // 1st, destroy children if those are present:
        if (children != null)
        {
            for (Ref_obj c : children)
                c.Obj.Erase();
            children.clear();
        }
        children = null;
        
        DESTRUCT();

        // destroy the object removeing all three references onto it:
        Ref_obj none = NONE_obj_instance();

        weak_link.Obj = none.Obj;
        hard_link.Obj = none.Obj;
        write = none.Obj.write;

        hard_link = none;
        weak_link = none;
    }
    
    public void CONSTRUCT() throws Exception {
    }

    public void DESTRUCT() throws Exception {
    }

    static Ref_obj Object_assign_hard(Ref_obj Dest, AL4_object Src)
           throws Exception {
        if (Dest == null) return null;
        Src.hard_link.Count += 2;
        Dest.Ref_dec_hard();
        return Src.hard_link;
    }
    
    static Ref_obj Object_assign_weak(Ref_obj Dest, AL4_object Src)
           throws Exception {
        if (Dest == null) return null;
        Src.weak_link.Count += 2;
        Dest.Ref_dec_weak();
        return Src.weak_link;
    }
    
    static Ref_obj Object_assign_hard_noincref(Ref_obj Dest, AL4_object Src)
           throws Exception {
        if (Dest == null) return null;
        Dest.Ref_dec_hard();
        return Src.hard_link;
    }
    
    static Ref_obj Object_assign_weak_noincref(Ref_obj Dest, AL4_object Src)
           throws Exception {
        if (Dest == null) return null;
        Dest.Ref_dec_weak();
        return Src.weak_link;
    }
    
    // Is calling from New_owned() when an object is created with its
    // exclusive owner but without a counter in its hard_link.
    public Ref_obj Owned_by(Ref_obj owner)
    {
        if (owner.Obj.Is_NONE_object) return hard_link;
        if (owner.Obj.children == null)
            owner.Obj.children = new ArrayList<Ref_obj>();
        owner.Obj.children.add(this.hard_link);
        this.hard_link.Count |= 1;
        return hard_link;
    }

    public int Int_value(String Name_value)
    {
        return 0;
    }

    public String Str_value(String Name_value)
    {
        return "";
    }

    public boolean Bool_value(String Name_value)
    {
        return false;
    }
    
    public static AL4_object NoneObj_AL4_object;
    public static AL4_object DummyObj_AL4_object;

    public static void init_class_AL4_object() {
		NoneObj_AL4_object = (AL4_object)Noneclass_AL4_object.New_nofields().Obj;                    			
        NoneObj_AL4_object.Is_NONE_object = true;
        None_obj = NoneObj_AL4_object.hard_link;
        DummyObj_AL4_object = (AL4_object)Noneclass_AL4_object.New_nofields().Obj;
        NoneObj_AL4_object.write = DummyObj_AL4_object;
    }
    
    public static Ref_obj New_nofields() {
        AL4_object Result = new AL4_object();
        Result.hard_link = new Ref_obj(Result, 2);
        Result.weak_link = new Ref_obj(Result, 1);
        Result.write = Result;
        return Result.hard_link;
    }
    
    public static Ref_obj New()
    {
        AL4_object Result = new AL4_object();
        Result.hard_link = new Ref_obj(Result, 0);
        Result.weak_link = new Ref_obj(Result, 1);
        Result.write = Result;
        return Result.hard_link;
    }
    

}

--save: Noneclass_AL4_object.java

public class Noneclass_AL4_object extends AL4_object    {
    @Override
    public void Erase() { }

    public static Ref_obj New()
    {
        Noneclass_AL4_object Result = new Noneclass_AL4_object();
        Result.hard_link = new Ref_obj(Result, 0);
        Result.weak_link = new Ref_obj(Result, 1);
        Result.write = Result;
        return Result.hard_link;
    }

    public void Init_none()
    {
        Noneclass_AL4_object Result = this;
        Result.Is_NONE_object = true;
    }

    @Override
    public void CONSTRUCT()
    {
    }

    @Override
    public void DESTRUCT()
    {
    }

}

--save: Structure_any.java

public class Structure_any extends AL4_object {

	public Ref_obj Clone() { return null; }
	
	public static Ref_obj Dismiss_structure(Ref_obj source) {
		Ref_obj result = source;
		result.Count += 2;
		return result;
	}
	
	public static Ref_obj Dismiss_array_item(ArrayObjHard array, int Index) {
		Ref_obj result = array.Get_item(Index);
		result.Count += 2;
		array.Set_item(Index, result.Obj.NONE_obj_instance());
		return result;
	}
}

--save: Ref_obj.java

public class Ref_obj {
    public AL4_object Obj;
    public int Count;
//?{Thread}        
	public int Thread_handle;
	public Ref_obj Migrated_ref;
	public Ref_obj Parent_ref;
//.    

    public Ref_obj(AL4_object obj, int count)
    {
        Obj = obj;
        Count = count;
    }

    public void Ref_dec_weak()
    {
        Obj.weak_link.Count -= 2;
        //--if (Count <= 1 && Obj.Is_NONE_object)
        {
            // in platforms without garbage collector,
            // place here code to destroy this Ref_obj
            // representing Weak reference to the object
            // which was already destroyed

            // in case of DotNet platform, it will be
            // destroyed automatically since there are
            // no more references to it.
        }
    }

    public void Ref_dec_hard() throws Exception {
        Obj.hard_link.Count -= 2;
        if (Obj.hard_link.Count == 0)
        {
            // destroy was_Dest object
            // Since there are only two links onto the 
            // object (from its Hard_link and Weak_link
            // small linking objects), it is sufficiently
            // to replace those with other values to
            // destroy the object.
            Obj.Erase();
        }
    }

    public AL4_object Write() {
           return Obj.write;
    }

}

--save: ArrayAny.java

public class ArrayAny {

    public ArrayAny() { }
    
    public ArrayAny Clone_array() { return null; }
    
}

--save: ArrayObjHard.java

public class ArrayObjHard extends ArrayAny {

    public Ref_obj none_obj;
    public ArrayObjHard(Ref_obj none) {
           none_obj = none ;
    }
    public Ref_obj Get_item(int index) { return null; }
    public void Set_item(int index, Ref_obj value) { }
    public void Add(Ref_obj X) { }
    public void Insert(int index, Ref_obj X) { }
    public void Remove(Ref_obj value) throws Exception { }
    public void Delete(int i) throws Exception { }
    public void Delete_range(int i, int count) throws Exception {
    	if (i <= 0 && i + count >= Count()) Clear();
    	else
    	for (int j = i + count-1; j >= i; j--) Delete(j); 
    }
    public void Dispose() throws Exception { }
    public int Count() { return 0; }
    public void Clear() throws Exception {
        Dispose();
    }
    public int indexOf(Ref_obj value) { return -1; }
    public boolean Contains(Ref_obj value) {
        return indexOf(value) >= 0;
    }
    public void Swap(int i, int j) {
    	Ref_obj x = Get_item(i);
    	Ref_obj y = Get_item(j);
    	Set_item(i, y);
    	Set_item(j, x);
    }
    
}

--save: DynAObjHard.java

import java.util.ArrayList;

public class DynAObjHard extends ArrayObjHard {

    protected ArrayList<Ref_obj> List;
    
    public DynAObjHard(Ref_obj none) {
        super(none);
        List = new ArrayList<Ref_obj>();
    }

    @Override
    public ArrayAny Clone_array() { 
    	DynAObjHard result = new DynAObjHard(none_obj);
    	for (int i = 0; i < Count(); i++)
    		result.Add(Get_item(i));
    	return result;
    }

    @Override
    public Ref_obj Get_item(int index) {
            if (index < 0 || index >= Count())
                return none_obj;
            return List.get(index);
    }
	
    @Override
    public void Set_item(int index, Ref_obj value) {
            if (index < 0 || index >= Count())
                return;
            value.Obj.hard_link.Count += 2;
            List.set(index, value);
    }

    @Override
    public void Add(Ref_obj X) {
        List.add(X);
        X.Obj.hard_link.Count += 2;
    }

    public void Add_noincref(Ref_obj X) {
        List.add(X);
    }

    @Override
    public void Insert(int index, Ref_obj X) {
        X.Obj.hard_link.Count += 2;
        List.add(index, X);
    }

    @Override
    public void Remove(Ref_obj value) throws Exception {
        for (int i = Count()-1; i>=0; i--)
            if (Get_item(i).Obj == value.Obj)
                Delete(i);
    }

    @Override
    public void Delete(int i) throws Exception {
        if  (i < 0 || i >= Count()) return;
        Ref_obj del = Get_item(i);
        List.remove(i);
        del.Ref_dec_hard();
    }

    // Used only in case when new oject is added to an array
    // of hard links, to provide correct usage Count value
    public void Ref_dec_last() throws Exception {
        if (Count() == 0) return;
        List.get(Count() - 1).Ref_dec_hard();
    }

    @Override
    public void Dispose() throws Exception {
        for (int i = Count()-1; i >= 0; i--) {
            Ref_obj obj = List.get(i);
            obj.Ref_dec_hard();
        }
        List.clear();
    }
		
    @Override
    public int Count() {
        return List.size();
    }
		
    @Override
    public int indexOf(Ref_obj value) {
        return List.indexOf(value);
    }

    public void Allocate(int New_size) {
        List.ensureCapacity(New_size);
    	while (Count() < New_size) List.add(none_obj);
    	while (Count() > New_size) List.remove(Count()-1);
    }
}

--save: DynAObjWeak.java

import java.util.ArrayList;

public class DynAObjWeak extends DynAObjHard {

    public DynAObjWeak(Ref_obj none) {
        super(none);
        none_obj = none;
        List = new ArrayList<Ref_obj>();
    }

    @Override
    public ArrayAny Clone_array() { 
    	DynAObjWeak result = new DynAObjWeak(none_obj);
    	for (int i = 0; i < Count(); i++)
    		result.Add(Get_item(i));
    	return result;
    }

    @Override
    public void Set_item(int index, Ref_obj value) {
            if (index < 0 || index >= Count())
                return;
            value.Obj.weak_link.Count += 2;
            List.set(index, value);
    }

    @Override
    public void Add(Ref_obj X) {
        List.add(X);
        X.Obj.weak_link.Count += 2;
    }

    @Override
    public void Insert(int index, Ref_obj X) {
        X.Obj.weak_link.Count += 2;
        List.add(index, X);
    }

    @Override
    public void Delete(int i) {
        if  (i < 0 || i >= Count()) return;
        Get_item(i).Ref_dec_weak();
        List.remove(i);
    }

    // Used only in case when new oject is added to an array
    // of hard links, to provide correct usage Count value
    @Override
    public void Ref_dec_last() {
        if (Count() == 0) return;
        List.get(Count() - 1).Ref_dec_weak();
    }

    @Override
    public void Dispose() {
        for (int i = Count()-1; i >= 0; i--) {
            Ref_obj obj = List.get(i);
            obj.Ref_dec_weak();
        }
        List.clear();
    }
		
}

--save: ArrayInt.java

public class ArrayInt extends ArrayAny {

    public ArrayInt() { }
    public int Get_item(int index) { return 0; }
    public void Set_item(int index, int value) { }
    public void Dispose() { }
    public int Count() { return 0; }
    public void Add(int value) { }
    public void Insert(int index, int value) { }
    public void Delete(int index) { }
    public void Remove(int value) {
    	for (int j = Count()-1; j >= 0; j--) 
    		if (Get_item(j) == value) Delete(j);
    }
    public void Delete_range(int i, int count) throws Exception {
    	if (i <= 0 && i + count >= Count()) Clear();
    	else
    	for (int j = i + count-1; j >= i; j--) Delete(j); 
    }

    public void Clear() { }
    public int indexOf(int value) { return -1; }
    public boolean Contains(int value) {
        return indexOf(value) >= 0;
    }
    public void Swap(int i, int j) {
    	int x = Get_item(i);
    	int y = Get_item(j);
    	Set_item(i, y);
    	Set_item(j, x);
    }
}

--save: DynAInt.java

import java.util.ArrayList;

public class DynAInt extends ArrayInt {

   protected ArrayList<Integer> List;

   public DynAInt() {
          List = new ArrayList<Integer>();
   }

    @Override
    public ArrayAny Clone_array() { 
    	DynAInt result = new DynAInt();
    	for (int i = 0; i < Count(); i++)
    		result.Add(Get_item(i));
    	return result;
    }

   @Override
   public int Get_item(int index) {
       if (index < 0 || index >= Count())
           return 0;
       return List.get(index);
   }

   @Override
   public void Set_item(int index, int value) {
       if (index < 0 || index >= Count())
           return;
       List.set(index, value);
   }

   @Override
   public void Dispose() {
       List.clear();
   }

   @Override
    public int Count() {
        return List.size();
    }
	
    @Override
    public void Add(int value) {
        List.add(value);
    }
		
    @Override
    public void Insert(int index, int value) {
        List.add(index, value);
    }
	
	@Override
    public void Delete(int index) {
        if (index < 0 || index >= Count()) return;
        List.remove(index);
    }
		
    @Override
    public void Clear() {
        List.clear();
    }

    @Override
    public int indexOf(int value) {
        return List.indexOf(value);
    }

    public void Allocate(int New_size) {
        List.ensureCapacity(New_size);
    	while (Count() < New_size) List.add(0);
    	while (Count() > New_size) List.remove(Count()-1);
    }
}

--save: ArrayReal.java

public class ArrayReal extends ArrayAny {

   public double Get_item(int index) { return 0; }
   public void Set_item(int index, double value) { }
   public void Dispose() { }
    public int Count() { return 0; }
    public void Add(double value) { }
    public void Insert(int index, double value) { }
    public void Delete(int index) { }
    public void Delete_range(int i, int count) throws Exception {
    	if (i <= 0 && i + count >= Count()) Clear();
    	else
    	for (int j = i + count-1; j >= i; j--) Delete(j); 
    }
    
    public void Clear() { }
    public int indexOf(double value) { return -1; }
    public boolean Contains(double value) {
        return indexOf(value) >= 0;
    }
    public void Swap(int i, int j) {
    	double x = Get_item(i);
    	double y = Get_item(j);
    	Set_item(i, y);
    	Set_item(j, x);
    }

}

--save: DynAReal.java

import java.util.ArrayList;

public class DynAReal extends ArrayReal {

   protected ArrayList<Double> List;

   public DynAReal() {
          List = new ArrayList<Double>();
   }

    @Override
    public ArrayAny Clone_array() { 
    	DynAReal result = new DynAReal();
    	for (int i = 0; i < Count(); i++)
    		result.Add(Get_item(i));
    	return result;
    }

   @Override
   public double Get_item(int index) {
        if (index < 0 || index >= Count())
            return 0;
        return List.get(index);
   }

   @Override
   public void Set_item(int index, double value) {
        if (index < 0 || index >= Count())
            return;
        List.set(index, value);
   }

   @Override
   public void Dispose() {
       List.clear();
   }

    @Override
    public int Count() {
        return List.size();
    }
	
	@Override
    public void Add(double value) {
        List.add(value);
    }
		
    @Override
    public void Insert(int index, double value) {
        List.add(index, value);
    }
		
    @Override
    public void Delete(int index) {
        if (index < 0 || index >= Count()) return;
        List.remove(index);
    }
		
    @Override
    public void Clear() {
        List.clear();
    }
		
    @Override
    public int indexOf(double value) {
        return List.indexOf(value);
    }

    public void Allocate(int New_size) {
        List.ensureCapacity(New_size);
    	while (Count() < New_size) List.add(0.0);
    	while (Count() > New_size) List.remove(Count()-1);
    }
}

--save: ArrayBool.java

public class ArrayBool extends ArrayAny {

   public boolean Get_item(int index) { return false; }
   public void Set_item(int index, boolean value) { }
   public void Dispose() { }
    public int Count() { return 0; }
    public void Add(boolean value) { }
    public void Insert(int index, boolean value) { }
    public void Delete(int index) { }
    public void Delete_range(int i, int count) throws Exception {
    	if (i <= 0 && i + count >= Count()) Clear();
    	else
    	for (int j = i + count-1; j >= i; j--) Delete(j); 
    }

    public void Clear() { }
    public int indexOf(boolean value) { return -1; }
    public boolean Contains(boolean value) {
        return indexOf(value) >= 0;
    }
    public void Swap(int i, int j) {
    	boolean x = Get_item(i);
    	boolean y = Get_item(j);
    	Set_item(i, y);
    	Set_item(j, x);
    }
}

--save: DynABool.java

import java.util.ArrayList;

public class DynABool extends ArrayBool {

   protected ArrayList<Boolean> List;

   public DynABool() {
          List = new ArrayList<Boolean>();
   }

    @Override
    public ArrayAny Clone_array() { 
    	DynABool result = new DynABool();
    	for (int i = 0; i < Count(); i++)
    		result.Add(Get_item(i));
    	return result;
    }

   @Override
   public boolean Get_item(int index) {
        if (index < 0 || index >= Count())
            return false;
        return List.get(index);
   }

   @Override
   public void Set_item(int index, boolean value) {
        if (index < 0 || index >= Count())
            return;
        List.set(index, value);
   }

   @Override
   public void Dispose() {
       List.clear();
   }

    @Override
    public int Count() {
        return List.size();
    }
	
	@Override
    public void Add(boolean value) {
        List.add(value);
    }
		
    @Override
    public void Insert(int index, boolean value) {
        List.add(index, value);
    }
		
    @Override
    public void Delete(int index) {
        if (index < 0 || index >= Count()) return;
        List.remove(index);
    }
		
    @Override
    public void Clear() {
        List.clear();
    }

    @Override
    public int indexOf(boolean value) {
        return List.indexOf(value);
    }

    public void Allocate(int New_size) {
        List.ensureCapacity(New_size);
    	while (Count() < New_size) List.add(false);
    	while (Count() > New_size) List.remove(Count()-1);
    }
}

--save: ArrayByte.java

public class ArrayByte extends ArrayAny {

   public byte Get_item(int index) { return 0; }
   public void Set_item(int index, int value) { 
        Set_item(index, (byte)value);
   }
   public void Set_item(int index, byte value) { }
   public void Dispose() { }
    public int Count() { return 0; }
    public void Add(byte value) { }
    public void Insert(int index, byte value) { }
    public void Delete(int index) { }
    public void Delete_range(int i, int count) throws Exception {
    	if (i <= 0 && i + count >= Count()) Clear();
    	else
    	for (int j = i + count-1; j >= i; j--) Delete(j); 
    }

    public void Clear() { }
    public byte[] ToArray() {
        byte[] Result = new byte[Count()];
        for (int i = 0; i < Count(); i++) {
            Result[i] = Get_item(i);
        }
        return Result;
    }
    public int indexOf(byte value) { return -1; }
    public int indexOf(int value) {
        return indexOf((byte)(value & 0xff));
    }
    public boolean Contains(byte value) {
        return indexOf(value) >= 0;
    }
    public void Swap(int i, int j) {
    	byte x = Get_item(i);
    	byte y = Get_item(j);
    	Set_item(i, y);
    	Set_item(j, x);
    }    
}


--save: DynAByte.java

import java.util.ArrayList;

public class DynAByte extends ArrayByte {

   protected ArrayList<Byte> List;

   public DynAByte() {
          List = new ArrayList<Byte>();
   }

    @Override
    public ArrayAny Clone_array() { 
    	DynAByte result = new DynAByte();
    	for (int i = 0; i < Count(); i++)
    		result.Add(Get_item(i));
    	return result;
    }

   @Override
   public byte Get_item(int index) {
        if (index < 0 || index >= Count())
            return 0;
        return List.get(index);
   }

   @Override
   public void Set_item(int index, byte value) {
        if (index < 0 || index >= Count())
            return;
        List.set(index, (byte)value);
   }

   @Override
   public void Dispose() {
        List.clear();
   }
	   
    @Override
    public int Count() {
        return List.size();
    }
		
    @Override
    public void Add(byte value) {
        List.add(value);
    }
		
    @Override
    public void Insert(int index, byte value) {
        List.add(index, value);
    }
		
    @Override
    public void Delete(int index) {
        if (index < 0 || index >= Count()) return;
        List.remove(index);
    }
		
    @Override
    public void Clear() {
        List.clear();
    }
	   
    public void Reallocate(int New_size) {
        if (Count() >= New_size) return;
        List.ensureCapacity(New_size);
        while (Count() < New_size)
            Add((byte)0);
    }
    
    @Override
    public int indexOf(byte value) {
        return List.indexOf(value);
    }

    @Override
    public boolean Contains(byte value) {
        return indexOf(value) >= 0;
    }
    
    public boolean Contains(int value) {
        return indexOf((byte)(value&0xff)) >= 0;
    }
    
    public void Allocate(int New_size) {
        List.ensureCapacity(New_size);
    	while (Count() < New_size) List.add((byte)0);
    	while (Count() > New_size) List.remove(Count()-1);
    }
}


--save: FixAByte_OnArray.java

public class FixAByte_OnArray extends ArrayByte {

   public byte[] Array;
   public int Starting;
   public int Length;

    @Override
    public ArrayAny Clone_array() { 
    	FixAByte_OnArray result = new FixAByte_OnArray(Array, 0, Count()-1);
    	return result;
    }

   public FixAByte_OnArray(byte[] array, int start, int len) {
        Array = array;
        Starting = start;
        Length = len;
   }

   @Override
   public byte Get_item(int index) {
        if (index < 0 || index >= Count())
            return 0;
        return Array[index];
   }

   @Override
   public void Set_item(int index, byte value) {
        if (index < 0 || index >= Count())
            return;
        Array[index] = value;
   }

    @Override
    public int Count() {
        return Length;
    }

    @Override
    public void Clear() {
        Array = null;
        Starting = 0;
        Length = 0;
    }
	   
    @Override
    public byte[] ToArray() {
        byte[] Result = Array;
        return Result;
    }

    @Override
    public int indexOf(byte value) {
        for (int i= Starting; i < Starting + Length; i++)
            if (Array[i] == value) return i - Starting;
        return -1;
    }

    @Override
    public int indexOf(int value) {
        return indexOf((byte)value);
    }

}

--save: FixAByte.java

public class FixAByte extends ArrayByte {
    protected ArrayByte BaseList;
    public int Starting;
    public int Count_items;
    public boolean Is_slice;

    @Override
    public ArrayAny Clone_array() { 
    	FixAByte result = new FixAByte(this, 0, Count()-1);
    	return result;
    }

    public FixAByte(int N)
    {
        BaseList = new DynAByte();
        ((DynAByte)BaseList).List.ensureCapacity(N);
        for (byte i = 0; i < N; i++)
            BaseList.Add((byte)0);
        Count_items = BaseList.Count();
    }

    public FixAByte(byte[] A)
    {
        BaseList = new FixAByte_OnArray(A, 0, A.length);
        Count_items = BaseList.Count();
    }

    public FixAByte(byte[] A, int start, int len)
    {
        BaseList = new FixAByte_OnArray(A, start, len);
        Count_items = BaseList.Count();
    }

    public FixAByte(DynAByte base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx;
    }

    public FixAByte(FixAByte base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list.BaseList;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx + base_list.Starting;
    }

    @Override
    public byte Get_item(int index) {
        if (index < 0 || index >= Count_items)
            return 0;
        return BaseList.Get_item(index + Starting);
    }
        
    @Override public void Set_item(int index, byte value) {
        if (index < 0 || index >= Count_items)
            return;
        BaseList.Set_item(index + Starting, value);
    }

    public void finalizy() {
        if (!Is_slice) BaseList.Clear();
    }

    @Override
    public int Count() { 
        return Count_items; 
    }

    @Override
    public int indexOf(byte Value)
    {
        for (int i = Starting; i < Starting + Count_items; i++)
            if (BaseList.Get_item(i) == Value) return i;
        return -1;
    }


    @Override
    public void Dispose() {
        if (!Is_slice)
            BaseList.Dispose();
        Count_items = 0;
    }
    
	public FixAByte copy()
	{
		FixAByte result = new FixAByte(Count());
        for (int i = 0; i < Count(); i++)
            result.Set_item(i, Get_item(i));
        return result;
	}
	
}

--save: ArrayStr.java

public class ArrayStr extends ArrayAny {

   public String Get_item(int index) { return ""; }
   public void Set_item(int index, String value) { }
   public void Dispose() { }
    public int Count() { return 0; }
    public void Add(String value) { }
    public void Insert(int index, String value) { }
    public void Delete(int index) { }
    public void Delete_range(int i, int count) throws Exception {
    	if (i <= 0 && i + count >= Count()) Clear();
    	else
    	for (int j = i + count-1; j >= i; j--) Delete(j); 
    }

    public void Remove(String value) { }
    public void Clear() { }
    public int indexOf(String value) { return -1; }
    public boolean Contains(String value) {
        return indexOf(value) >= 0;
    }
    public void Swap(int i, int j) {
    	String x = Get_item(i);
    	String y = Get_item(j);
    	Set_item(i, y);
    	Set_item(j, x);
    }	   
}

--save: DynAStr.java

import java.util.ArrayList;

public class DynAStr extends ArrayStr {

   protected ArrayList<String> List;

   public DynAStr() {
          List = new ArrayList<String>();
   }

    @Override
    public ArrayAny Clone_array() { 
    	DynAStr result = new DynAStr();
    	for (int i = 0; i < Count(); i++)
    		result.Add(Get_item(i));
    	return result;
    }

   @Override
   public String Get_item(int index) {
        if (index < 0 || index >= Count())
            return "";
        return List.get(index);
   }

   @Override
   public void Set_item(int index, String value) {
        if (index < 0 || index >= Count())
            return;
        List.set(index, value);
   }

   @Override
   public void Dispose() {
        List.clear();
   }
	   
    @Override
    public int Count() {
        return List.size();
    }
		
    @Override
    public void Add(String value) {
        List.add(value);
    }
		
    @Override
    public void Insert(int index, String value) {
        List.add(index, value);
    }
		
    @Override
    public void Delete(int index) {
        if (index < 0 || index >= Count()) return;
        List.remove(index);
    }
		
    @Override
    public void Remove(String Value) {
        int index = indexOf(Value);
        if (index >= 0)
            List.remove(index);
    }
		
    @Override
    public void Clear() {
        List.clear();
    }

    @Override
    public int indexOf(String value) {
        return List.indexOf(value);
    }
    
    public void Allocate(int New_size) {
        List.ensureCapacity(New_size);
    	while (Count() < New_size) List.add("");
    	while (Count() > New_size) List.remove(Count()-1);
    }
    
}

--save: FixAObj.java

public class FixAObj extends ArrayObjHard {

    protected DynAObjHard BaseList;
    public int Starting;
    public int Count_items;
    public boolean Is_slice;

    @Override
    public ArrayAny Clone_array() { 
    	FixAObj result = new FixAObj(BaseList, Starting, Count_items);
    	return result;
    }

    public FixAObj(Ref_obj none) {
        super(none);
        BaseList = new DynAObjHard(none);
    }

    public FixAObj(DynAObjHard base_list, int From_idx, int To_idx)  {
        super(base_list.none_obj);
        Is_slice = true;
        BaseList = base_list;
        Starting = From_idx;
        Count_items = To_idx + 1 - From_idx;
    }

    public void finalizy() throws Exception {
        if (!Is_slice) BaseList.Clear();
        BaseList = null;
    }

    @Override
    public Ref_obj Get_item(int index) {
        if (index < 0 || index >= Count_items)
            return none_obj;
        return BaseList.Get_item(index + Starting);
    }
    
    @Override
    public void Set_item(int index, Ref_obj value) {
        if (index < 0 || index >= Count_items)
            return;
        BaseList.Set_item(index + Starting, value);
    }

    @Override
    public int Count() { 
        return Count_items; }

    @Override
    public int indexOf(Ref_obj Obj) {
        for (int i = Starting; i < Starting + Count_items; i++)
            if (BaseList.Get_item(i) == Obj) return i;
        return -1;
    }

    @Override
    public void Dispose() throws Exception {
        if (!Is_slice)
            BaseList.Dispose();
        Count_items = 0;
    }
}

--save: FixAInt.java

public class FixAInt extends ArrayInt {

    protected DynAInt BaseList;
    public int Starting;
    public int Count_items;
    public boolean Is_slice;

    @Override
    public ArrayAny Clone_array() { 
    	FixAInt result = new FixAInt(this, 0, Count()-1);
    	return result;
    }

    public FixAInt(int N) {
        BaseList = new DynAInt();
        BaseList.List.ensureCapacity(N);
        for (int i = 0; i < N; i++)
            BaseList.Add(0);
        Count_items = BaseList.Count();
    }

    public FixAInt(int[] A) {
        BaseList = new DynAInt();
        BaseList.List.ensureCapacity(A.length);
        for (int i : A)
            BaseList.Add(i);
        Count_items = BaseList.Count();
    }

    public FixAInt(DynAInt base_list, int From_idx, int To_idx) {
        Is_slice = true;
        BaseList = base_list;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx;
    }

    public FixAInt(FixAInt base_list, int From_idx, int To_idx) {
        Is_slice = true;
        BaseList = base_list.BaseList;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx + base_list.Starting;
    }

    @Override
    public int Get_item(int index) {
        if (index < 0 || index >= Count_items)
            return 0;
        return BaseList.Get_item(index + Starting);
    }
    
    @Override
    public void Set_item(int index, int value) {
        if (index < 0 || index >= Count_items)
            return;
        BaseList.Set_item(index + Starting, value);
    }

    public void finalizy() {
        if (!Is_slice) BaseList.Clear();
    }

    @Override
    public int Count() { 
        return Count_items; 
    }

    @Override
    public int indexOf(int Value)
    {
        for (int i = Starting; i < Starting + Count_items; i++)
            if (BaseList.Get_item(i) == Value) return i;
        return -1;
    }

    @Override
    public void Dispose() {
        if (!Is_slice)
            BaseList.Dispose();
        Count_items = 0;
    }
    
	public FixAInt copy()
	{
		FixAInt result = new FixAInt(Count());
        for (int i = 0; i < Count(); i++)
            result.Set_item(i, Get_item(i));
        return result;
	}
	
}

--save: FixAReal.java

public class FixAReal extends ArrayReal {
	
    protected DynAReal BaseList;
    public int Starting;
    public int Count_items;
    public boolean Is_slice;

    @Override
    public ArrayAny Clone_array() { 
    	FixAReal result = new FixAReal(this, 0, Count()-1);
    	return result;
    }

    public FixAReal(int N)
    {
        BaseList = new DynAReal();
        BaseList.List.ensureCapacity(N);
        for (int i = 0; i < N; i++)
            BaseList.Add(0);
        Count_items = BaseList.Count();
    }

    public FixAReal(double[] A)
    {
        BaseList = new DynAReal();
        BaseList.List.ensureCapacity(A.length);
        for (double i : A)
            BaseList.Add(i);
        Count_items = BaseList.Count();
    }

    public FixAReal(DynAReal base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx;
    }

    public FixAReal(FixAReal base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list.BaseList;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx + base_list.Starting;
    }

    @Override
    public double Get_item(int index) {
        if (index < 0 || index >= Count_items)
            return 0;
        return BaseList.Get_item(index + Starting);
    }
    
    @Override
    public void Set_item(int index, double value) {
        if (index < 0 || index >= Count_items)
            return;
        BaseList.Set_item(index + Starting, value);
    }

    public void finalizy() {
        if (!Is_slice) BaseList.Clear();
    }

    @Override
    public int Count() { 
        return Count_items; 
    }

    @Override
    public int indexOf(double Value)
    {
        for (int i = Starting; i < Starting + Count_items; i++)
            if (BaseList.Get_item(i) == Value) return i;
        return -1;
    }

    @Override
    public void Dispose() {
        if (!Is_slice)
            BaseList.Dispose();
        Count_items = 0;
    }

	public FixAReal copy()
	{
		FixAReal result = new FixAReal(Count());
        for (int i = 0; i < Count(); i++)
            result.Set_item(i, Get_item(i));
        return result;
	}
	
}

--save: FixABool.java

public class FixABool extends ArrayBool {
    protected DynABool BaseList;
    public int Starting;
    public int Count_items;
    public boolean Is_slice;

    @Override
    public ArrayAny Clone_array() { 
    	FixABool result = new FixABool(this, 0, Count()-1);
    	return result;
    }

    public FixABool(int N)
    {
        BaseList = new DynABool();
        BaseList.List.ensureCapacity(N);
        for (int i = 0; i < N; i++)
            BaseList.Add(false);
        Count_items = BaseList.Count();
    }

    public FixABool(boolean[] A) {
        BaseList = new DynABool();
        BaseList.List.ensureCapacity(A.length);
        for (boolean i : A)
            BaseList.Add(i);
        Count_items = BaseList.Count();
    }

    public FixABool(DynABool base_list, int From_idx, int To_idx) {
        Is_slice = true;
        BaseList = base_list;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx;
    }

    public FixABool(FixABool base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list.BaseList;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx + base_list.Starting;
    }

    @Override
    public boolean Get_item(int index) {
        if (index < 0 || index >= Count_items)
            return false;
        return BaseList.Get_item(index + Starting);
    }

    @Override
    public void Set_item(int index, boolean value) {
        if (index < 0 || index >= Count_items)
            return;
        BaseList.Set_item(index + Starting, value);
    }

    public void finalizy() {
        if (!Is_slice) BaseList.Clear();
    }

    @Override
    public int Count() { 
        return Count_items; 
    }

    @Override
    public int indexOf(boolean Value) {
        for (int i = Starting; i < Starting + Count_items; i++)
            if (BaseList.Get_item(i) == Value) return i;
        return -1;
    }

    @Override
    public void Dispose() {
        if (!Is_slice)
            BaseList.Dispose();
        Count_items = 0;
    }
    
	public FixABool copy()
	{
		FixABool result = new FixABool(Count());
        for (int i = 0; i < Count(); i++)
            result.Set_item(i, Get_item(i));
        return result;
	}
	
}

--save: FixAStr.java

public class FixAStr extends ArrayStr {
    protected DynAStr BaseList;
    public int Starting;
    public int Count_items;
    public boolean Is_slice;

    @Override
    public ArrayAny Clone_array() { 
    	FixAStr result = new FixAStr(this, 0, Count()-1);
    	return result;
    }

    public FixAStr(int N)
    {
        BaseList = new DynAStr();
        BaseList.List.ensureCapacity(N);
        for (int i = 0; i < N; i++)
            BaseList.Add("");
        Count_items = BaseList.Count();
    }

    public FixAStr(String[] A)
    {
        BaseList = new DynAStr();
        BaseList.List.ensureCapacity(A.length);
        for (String i : A)
            BaseList.Add(i);
        Count_items = BaseList.Count();
    }

    public FixAStr(DynAStr base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx;
    }

    public FixAStr(FixAStr base_list, int From_idx, int To_idx)
    {
        Is_slice = true;
        BaseList = base_list.BaseList;
        Count_items = To_idx + 1 - From_idx;
        Starting = From_idx + base_list.Starting;
    }

    @Override
    public String Get_item(int index) {
        if (index < 0 || index >= Count_items)
            return "";
        return BaseList.Get_item(index + Starting);
    }
        
    @Override
    public void Set_item(int index, String value) {
        if (index < 0 || index >= Count_items)
            return;
        BaseList.Set_item(index + Starting, value);
    }
        
    public void finalizy() {
        if (!Is_slice) BaseList.Clear();
    }

    @Override
    public int Count() { 
        return Count_items; 
    }

    @Override
    public int indexOf(String Value)
    {
        for (int i = Starting; i < Starting + Count_items; i++)
            if (BaseList.Get_item(i).equals(Value)) return i;
        return -1;
    }

    @Override
    public void Dispose() {
        if (!Is_slice)
            BaseList.Dispose();
        Count_items = 0;
    }
    
	public FixAStr copy()
	{
		FixAStr result = new FixAStr(Count());
        for (int i = 0; i < Count(); i++)
            result.Set_item(i, Get_item(i));
        return result;
	}
	
}

--save: AL4_Exception.java

public class AL4_Exception extends Exception {
	
}

--save: AL4StopException.java

public class AL4StopException extends AL4_Exception {
    public String Stop_message;

    public AL4StopException(String message)
    {
        Stop_message = message;
    }
}

--save: TooDeepRecursionException.java

class TooDeepRecursionException extends AL4_Exception {
}

--save:
*/

