mirror of
				https://github.com/irmen/prog8.git
				synced 2025-11-03 19:16:13 +00:00 
			
		
		
		
	Compare commits
	
		
			951 Commits
		
	
	
		
			v10.4.2
			...
			v12.0-beta
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 
						 | 
					513ee25432 | ||
| 
						 | 
					be74290ddc | ||
| 
						 | 
					a36501a9ed | ||
| 
						 | 
					ee5d33a230 | ||
| 
						 | 
					a8fd66cfdb | ||
| 
						 | 
					f5ce744748 | ||
| 
						 | 
					68066acdec | ||
| 
						 | 
					6286035d89 | ||
| 
						 | 
					9a37eb9146 | ||
| 
						 | 
					307796f115 | ||
| 
						 | 
					e962431139 | ||
| 
						 | 
					b7620abc9a | ||
| 
						 | 
					d2719d23f5 | ||
| 
						 | 
					d69eead6d8 | ||
| 
						 | 
					6db3611d93 | ||
| 
						 | 
					a84320c7e2 | ||
| 
						 | 
					dfc720557c | ||
| 
						 | 
					32149d073a | ||
| 
						 | 
					fc38be6376 | ||
| 
						 | 
					13f6efc1d1 | ||
| 
						 | 
					8296002887 | ||
| 
						 | 
					424b89f357 | ||
| 
						 | 
					4f5590fbff | ||
| 
						 | 
					598e70c49a | ||
| 
						 | 
					a6d051b496 | ||
| 
						 | 
					796d3242e1 | ||
| 
						 | 
					1e8ff6f82a | ||
| 
						 | 
					07bb5c36bd | ||
| 
						 | 
					7e26ecb0b6 | ||
| 
						 | 
					0c59ad70d4 | ||
| 
						 | 
					53ce688cc5 | ||
| 
						 | 
					bb8b44d9d0 | ||
| 
						 | 
					51ae32d23e | ||
| 
						 | 
					c873fac0dc | ||
| 
						 | 
					f0a67fff8a | ||
| 
						 | 
					f85ccd837d | ||
| 
						 | 
					396fcbc927 | ||
| 
						 | 
					0f564b301d | ||
| 
						 | 
					f4f34fc2ed | ||
| 
						 | 
					f7639cb78f | ||
| 
						 | 
					f5f5aef722 | ||
| 
						 | 
					d6e30d8468 | ||
| 
						 | 
					37afdf5a18 | ||
| 
						 | 
					5eb7074172 | ||
| 
						 | 
					9aff280d10 | ||
| 
						 | 
					44741a8e32 | ||
| 
						 | 
					37535f2913 | ||
| 
						 | 
					ec9475c308 | ||
| 
						 | 
					b961ce97d6 | ||
| 
						 | 
					4ed92d71a7 | ||
| 
						 | 
					3e1386a987 | ||
| 
						 | 
					4195e3968a | ||
| 
						 | 
					961095bfec | ||
| 
						 | 
					3ea8ca59b7 | ||
| 
						 | 
					71ffbe2ba7 | ||
| 
						 | 
					e63921009c | ||
| 
						 | 
					db1aa3f257 | ||
| 
						 | 
					8abdb837b2 | ||
| 
						 | 
					cdeabd4b66 | ||
| 
						 | 
					efff74c0f1 | ||
| 
						 | 
					0e177cb531 | ||
| 
						 | 
					35b921b062 | ||
| 
						 | 
					a7d98e43b8 | ||
| 
						 | 
					845ee2dd83 | ||
| 
						 | 
					f9b0bfe31b | ||
| 
						 | 
					f303d15628 | ||
| 
						 | 
					67f7ffa52d | ||
| 
						 | 
					88c5d9783a | ||
| 
						 | 
					e7fc0360ad | ||
| 
						 | 
					cd1862dd9f | ||
| 
						 | 
					045c4909a8 | ||
| 
						 | 
					f1bfe619b2 | ||
| 
						 | 
					e0107bacbd | ||
| 
						 | 
					b3bd2a6a09 | ||
| 
						 | 
					ff1f58e022 | ||
| 
						 | 
					557b12668d | ||
| 
						 | 
					b058f1c7c2 | ||
| 
						 | 
					3e07b6ca70 | ||
| 
						 | 
					d66dc664de | ||
| 
						 | 
					a2b9d78cf3 | ||
| 
						 | 
					44f70da113 | ||
| 
						 | 
					c87eaf576d | ||
| 
						 | 
					c09b1395f6 | ||
| 
						 | 
					d6a8201291 | ||
| 
						 | 
					4187f97f7a | ||
| 
						 | 
					9d3b2f12fd | ||
| 
						 | 
					87c1bbbf40 | ||
| 
						 | 
					a7ad6abdb9 | ||
| 
						 | 
					a611406020 | ||
| 
						 | 
					75da38224d | ||
| 
						 | 
					8d6f3301c8 | ||
| 
						 | 
					86b52a1c5e | ||
| 
						 | 
					2c8b1c2022 | ||
| 
						 | 
					ab1f065752 | ||
| 
						 | 
					2c7256a443 | ||
| 
						 | 
					97420b28e5 | ||
| 
						 | 
					1467c7039d | ||
| 
						 | 
					d319badc6c | ||
| 
						 | 
					65d6c1c438 | ||
| 
						 | 
					abeefb5655 | ||
| 
						 | 
					50fecbcebe | ||
| 
						 | 
					4fe8b72d42 | ||
| 
						 | 
					f3b060df51 | ||
| 
						 | 
					09d1cb6925 | ||
| 
						 | 
					54fa72fa98 | ||
| 
						 | 
					fd62fe7511 | ||
| 
						 | 
					bfb34dff62 | ||
| 
						 | 
					817b623596 | ||
| 
						 | 
					f6dbeb1f63 | ||
| 
						 | 
					c4b9bdd33f | ||
| 
						 | 
					68e0d5f1b5 | ||
| 
						 | 
					4939e3df55 | ||
| 
						 | 
					19f19f3880 | ||
| 
						 | 
					ad0c767ea8 | ||
| 
						 | 
					ed5f4d5855 | ||
| 
						 | 
					c2f5d37486 | ||
| 
						 | 
					231b50dacb | ||
| 
						 | 
					a71895cbe8 | ||
| 
						 | 
					a8bede17b2 | ||
| 
						 | 
					f6c8e693a5 | ||
| 
						 | 
					9461e4088c | ||
| 
						 | 
					efd73fd10d | ||
| 
						 | 
					ddf6e84a1a | ||
| 
						 | 
					633d6c34e2 | ||
| 
						 | 
					6e7fbc6683 | ||
| 
						 | 
					124ea1230b | ||
| 
						 | 
					8b48a295b6 | ||
| 
						 | 
					d285d37fdb | ||
| 
						 | 
					8bb927b483 | ||
| 
						 | 
					1af4cd0d63 | ||
| 
						 | 
					db2f28c4cd | ||
| 
						 | 
					5d9fbd2ccc | ||
| 
						 | 
					7efc709538 | ||
| 
						 | 
					79419a98d0 | ||
| 
						 | 
					1c77d5d5e7 | ||
| 
						 | 
					c6854e22a3 | ||
| 
						 | 
					83acc2f285 | ||
| 
						 | 
					6de95f7a3b | ||
| 
						 | 
					82839a2d82 | ||
| 
						 | 
					e5fc9b3132 | ||
| 
						 | 
					ced4c5944a | ||
| 
						 | 
					d4c460072b | ||
| 
						 | 
					0b9384b556 | ||
| 
						 | 
					6c3277e3e3 | ||
| 
						 | 
					d9ff1eb38a | ||
| 
						 | 
					e178097735 | ||
| 
						 | 
					a1ab8ed208 | ||
| 
						 | 
					6ababbf8f4 | ||
| 
						 | 
					79629befc1 | ||
| 
						 | 
					8022c0772a | ||
| 
						 | 
					8ad2b4638b | ||
| 
						 | 
					3a0392df8a | ||
| 
						 | 
					beb28b061d | ||
| 
						 | 
					c39acc5031 | ||
| 
						 | 
					f54a29c415 | ||
| 
						 | 
					783b111059 | ||
| 
						 | 
					fb286f8b54 | ||
| 
						 | 
					5999110e3f | ||
| 
						 | 
					52a757ea78 | ||
| 
						 | 
					28df08eea8 | ||
| 
						 | 
					79505308ba | ||
| 
						 | 
					a7e9d8e14b | ||
| 
						 | 
					08f3abe5bf | ||
| 
						 | 
					3ef09d7d9a | ||
| 
						 | 
					a9142b9ce5 | ||
| 
						 | 
					13e6f64d3b | ||
| 
						 | 
					4a1256c772 | ||
| 
						 | 
					ff9bec90ec | ||
| 
						 | 
					a6fee1e510 | ||
| 
						 | 
					80538f101e | ||
| 
						 | 
					aee53b14c7 | ||
| 
						 | 
					5eb2fc8d86 | ||
| 
						 | 
					98f91bbf88 | ||
| 
						 | 
					b48b36ef18 | ||
| 
						 | 
					221a093e5f | ||
| 
						 | 
					2ca1820d4e | ||
| 
						 | 
					d58737d5be | ||
| 
						 | 
					b52cee3154 | ||
| 
						 | 
					9a76941e10 | ||
| 
						 | 
					0285a4cce1 | ||
| 
						 | 
					5a3aa1bd25 | ||
| 
						 | 
					0f79351de9 | ||
| 
						 | 
					3cdb25ce8e | ||
| 
						 | 
					b7193bd0c6 | ||
| 
						 | 
					10ff6a0095 | ||
| 
						 | 
					d30f58004e | ||
| 
						 | 
					17bdb22e4f | ||
| 
						 | 
					a68209be37 | ||
| 
						 | 
					7b40eade44 | ||
| 
						 | 
					8a717c74b9 | ||
| 
						 | 
					aa72ded21e | ||
| 
						 | 
					8e53c83844 | ||
| 
						 | 
					e2a2db1256 | ||
| 
						 | 
					2afd2d4dae | ||
| 
						 | 
					fad17cc094 | ||
| 
						 | 
					f93d957999 | ||
| 
						 | 
					8db0344cee | ||
| 
						 | 
					32e531f951 | ||
| 
						 | 
					a4769702f9 | ||
| 
						 | 
					cf19fb8df1 | ||
| 
						 | 
					79b8bb5c9f | ||
| 
						 | 
					fc5889ec0b | ||
| 
						 | 
					369303c46d | ||
| 
						 | 
					d65670cc7b | ||
| 
						 | 
					f74eeaee0f | ||
| 
						 | 
					826fb3e9c2 | ||
| 
						 | 
					a3d7b8a899 | ||
| 
						 | 
					0cc36ed6e4 | ||
| 
						 | 
					976bd52972 | ||
| 
						 | 
					4a8d5def84 | ||
| 
						 | 
					2f60716082 | ||
| 
						 | 
					729efb04e1 | ||
| 
						 | 
					4ea8b4d445 | ||
| 
						 | 
					e800c165f9 | ||
| 
						 | 
					fd9bd23449 | ||
| 
						 | 
					8880ed1393 | ||
| 
						 | 
					f7fde070ca | ||
| 
						 | 
					5ada80779d | ||
| 
						 | 
					8972235a0e | ||
| 
						 | 
					e56f533e38 | ||
| 
						 | 
					324fb7dbf7 | ||
| 
						 | 
					44285b9b5d | ||
| 
						 | 
					a68f477d61 | ||
| 
						 | 
					ae9f99448e | ||
| 
						 | 
					7c0fb10197 | ||
| 
						 | 
					9e85571a7b | ||
| 
						 | 
					9e10c15e2e | ||
| 
						 | 
					6bd7752bac | ||
| 
						 | 
					83ec437e8a | ||
| 
						 | 
					4a1d05dd46 | ||
| 
						 | 
					aa324e355a | ||
| 
						 | 
					5cb8bcead7 | ||
| 
						 | 
					bbd06c0c99 | ||
| 
						 | 
					651830ea82 | ||
| 
						 | 
					c70146f1dc | ||
| 
						 | 
					d4e83b28bb | ||
| 
						 | 
					bc58a25765 | ||
| 
						 | 
					38645022c9 | ||
| 
						 | 
					647cd0fbe1 | ||
| 
						 | 
					ea8935a346 | ||
| 
						 | 
					7ea80babfc | ||
| 
						 | 
					dee761a99e | ||
| 
						 | 
					88ee7a8187 | ||
| 
						 | 
					eb8b408b82 | ||
| 
						 | 
					3d10882f57 | ||
| 
						 | 
					1988496512 | ||
| 
						 | 
					88b074c208 | ||
| 
						 | 
					c4c5636a81 | ||
| 
						 | 
					c39d570b72 | ||
| 
						 | 
					4ccd7f9f3a | ||
| 
						 | 
					1c9c5aeef7 | ||
| 
						 | 
					23ad540aa5 | ||
| 
						 | 
					08810c2749 | ||
| 
						 | 
					a52966f327 | ||
| 
						 | 
					624220e9a3 | ||
| 
						 | 
					842b11ed9e | ||
| 
						 | 
					82267b3f56 | ||
| 
						 | 
					67fb45a55b | ||
| 
						 | 
					11186f1dbe | ||
| 
						 | 
					0116fac201 | ||
| 
						 | 
					817f4f8e7c | ||
| 
						 | 
					866313209b | ||
| 
						 | 
					28e351daab | ||
| 
						 | 
					893e16d814 | ||
| 
						 | 
					33470c47fc | ||
| 
						 | 
					63f7b87572 | ||
| 
						 | 
					e2901cca1b | ||
| 
						 | 
					ce8006992a | ||
| 
						 | 
					0b5413ad83 | ||
| 
						 | 
					dd7adde387 | ||
| 
						 | 
					23058b51a1 | ||
| 
						 | 
					2f90c53ad0 | ||
| 
						 | 
					c3be7ab4b3 | ||
| 
						 | 
					a9b8fbc6c6 | ||
| 
						 | 
					720988ae72 | ||
| 
						 | 
					b0981a5fae | ||
| 
						 | 
					ea5deeefbd | ||
| 
						 | 
					054c98da7c | ||
| 
						 | 
					dc434d034a | ||
| 
						 | 
					a4a1b563aa | ||
| 
						 | 
					3f34b83e0d | ||
| 
						 | 
					9c63ef39c7 | ||
| 
						 | 
					9f6106452e | ||
| 
						 | 
					f9fbfe30e3 | ||
| 
						 | 
					9a9bf170c6 | ||
| 
						 | 
					7dd64b4f13 | ||
| 
						 | 
					b6c0bac96f | ||
| 
						 | 
					8ede098154 | ||
| 
						 | 
					2a4a3b786e | ||
| 
						 | 
					b4e0a2019e | ||
| 
						 | 
					e14c3f8b59 | ||
| 
						 | 
					c81f76226d | ||
| 
						 | 
					edc353cc24 | ||
| 
						 | 
					dcce519c69 | ||
| 
						 | 
					0a16dcafc0 | ||
| 
						 | 
					54d41b7f6f | ||
| 
						 | 
					0541b84d09 | ||
| 
						 | 
					1b420f7fe7 | ||
| 
						 | 
					6a9a82ff9d | ||
| 
						 | 
					aa36e6b19f | ||
| 
						 | 
					51cb6aad50 | ||
| 
						 | 
					b5ce409592 | ||
| 
						 | 
					2119817e4a | ||
| 
						 | 
					1efdfe8ea1 | ||
| 
						 | 
					67d4180825 | ||
| 
						 | 
					be31e190d2 | ||
| 
						 | 
					a68cf3c812 | ||
| 
						 | 
					c2bf9024f8 | ||
| 
						 | 
					bd72eaad4c | ||
| 
						 | 
					b5d1575823 | ||
| 
						 | 
					1d306e5cdc | ||
| 
						 | 
					b137164fe6 | ||
| 
						 | 
					67d4ad50e1 | ||
| 
						 | 
					c71066af4c | ||
| 
						 | 
					6f0a0981bd | ||
| 
						 | 
					49a4d9ba37 | ||
| 
						 | 
					fcdfa741b9 | ||
| 
						 | 
					e3e395836d | ||
| 
						 | 
					3bab177d50 | ||
| 
						 | 
					12abafb917 | ||
| 
						 | 
					8dc2e47507 | ||
| 
						 | 
					0be90dedf2 | ||
| 
						 | 
					daf7c3357c | ||
| 
						 | 
					e6bab3ceeb | ||
| 
						 | 
					59387b2ae8 | ||
| 
						 | 
					e8795859c5 | ||
| 
						 | 
					bebe60b687 | ||
| 
						 | 
					ddceec364e | ||
| 
						 | 
					f8f20440d3 | ||
| 
						 | 
					f8722faa4e | ||
| 
						 | 
					d067fa4b73 | ||
| 
						 | 
					26fbbf48a4 | ||
| 
						 | 
					d5cc414221 | ||
| 
						 | 
					b5e51ab937 | ||
| 
						 | 
					552e55c29f | ||
| 
						 | 
					a228908c1a | ||
| 
						 | 
					15fc3b6c04 | ||
| 
						 | 
					0456badd02 | ||
| 
						 | 
					d28f154f1c | ||
| 
						 | 
					399cf5118d | ||
| 
						 | 
					a87f2640d3 | ||
| 
						 | 
					a90ef274d7 | ||
| 
						 | 
					1c02179c5c | ||
| 
						 | 
					77584493fd | ||
| 
						 | 
					a36709e638 | ||
| 
						 | 
					341778ba67 | ||
| 
						 | 
					8d63cce749 | ||
| 
						 | 
					ec50b5a007 | ||
| 
						 | 
					8e7bbcdbe0 | ||
| 
						 | 
					37ecdc47b3 | ||
| 
						 | 
					112ca3cc53 | ||
| 
						 | 
					33b3a1664c | ||
| 
						 | 
					8a0c02e264 | ||
| 
						 | 
					31d84c8921 | ||
| 
						 | 
					34bedbeef1 | ||
| 
						 | 
					3b1b0985c1 | ||
| 
						 | 
					e40ace9dea | ||
| 
						 | 
					4c0e6e2640 | ||
| 
						 | 
					08b314c37d | ||
| 
						 | 
					86da9d3c7e | ||
| 
						 | 
					4e61e25c02 | ||
| 
						 | 
					5097d52d99 | ||
| 
						 | 
					368387e1a7 | ||
| 
						 | 
					09d2185bb1 | ||
| 
						 | 
					5c02e2bd71 | ||
| 
						 | 
					fb01389b3d | ||
| 
						 | 
					aaa81210ce | ||
| 
						 | 
					51269257ea | ||
| 
						 | 
					23a853db1e | ||
| 
						 | 
					9da430ffeb | ||
| 
						 | 
					cc063124cf | ||
| 
						 | 
					3b37b89951 | ||
| 
						 | 
					844b537d1e | ||
| 
						 | 
					caf1d4a22a | ||
| 
						 | 
					d8e244df99 | ||
| 
						 | 
					548e421e27 | ||
| 
						 | 
					322fa7ea69 | ||
| 
						 | 
					db6c887795 | ||
| 
						 | 
					cf7bea0985 | ||
| 
						 | 
					61fe55168a | ||
| 
						 | 
					25d7f8808f | ||
| 
						 | 
					1c4999ec87 | ||
| 
						 | 
					c726d3f937 | ||
| 
						 | 
					f70341df1b | ||
| 
						 | 
					f0b791452e | ||
| 
						 | 
					adf5600a9b | ||
| 
						 | 
					6d4ccc5feb | ||
| 
						 | 
					5f3829d5cc | ||
| 
						 | 
					770ebdcd4a | ||
| 
						 | 
					96f690e749 | ||
| 
						 | 
					eabdd3a8f3 | ||
| 
						 | 
					50650b966b | ||
| 
						 | 
					65e34d4989 | ||
| 
						 | 
					05dad5ab5f | ||
| 
						 | 
					1a69a2f1bc | ||
| 
						 | 
					435faafaad | ||
| 
						 | 
					686b32dc29 | ||
| 
						 | 
					0e64a22910 | ||
| 
						 | 
					4f0839f27e | ||
| 
						 | 
					bb1953267d | ||
| 
						 | 
					acc630972a | ||
| 
						 | 
					6a33be3fd8 | ||
| 
						 | 
					cd8aae4681 | ||
| 
						 | 
					11456496bd | ||
| 
						 | 
					f5fc4e345c | ||
| 
						 | 
					86eef7039f | ||
| 
						 | 
					f4b2264fcf | ||
| 
						 | 
					9b36ae2277 | ||
| 
						 | 
					913ab03963 | ||
| 
						 | 
					38448e471c | ||
| 
						 | 
					67231af623 | ||
| 
						 | 
					e31ef6f06f | ||
| 
						 | 
					09d188106a | ||
| 
						 | 
					d8e2116481 | ||
| 
						 | 
					435dfbb932 | ||
| 
						 | 
					ba93966474 | ||
| 
						 | 
					ea8d17cdb2 | ||
| 
						 | 
					082265fb25 | ||
| 
						 | 
					d138a7a567 | ||
| 
						 | 
					ea27d732ab | ||
| 
						 | 
					9e557ce8ac | ||
| 
						 | 
					924e28e9b3 | ||
| 
						 | 
					e5d9af75de | ||
| 
						 | 
					31c1bf8bc5 | ||
| 
						 | 
					37d4055036 | ||
| 
						 | 
					78b1076110 | ||
| 
						 | 
					0a3c748e41 | ||
| 
						 | 
					ebf79ef9e2 | ||
| 
						 | 
					60a73248cd | ||
| 
						 | 
					abbb7d7ba3 | ||
| 
						 | 
					59c378089e | ||
| 
						 | 
					0b789b5f0b | ||
| 
						 | 
					4382b96a9a | ||
| 
						 | 
					246e4f35a6 | ||
| 
						 | 
					99b9370178 | ||
| 
						 | 
					506062c6b6 | ||
| 
						 | 
					d634061cd9 | ||
| 
						 | 
					8353c689ca | ||
| 
						 | 
					d59d8ff1fe | ||
| 
						 | 
					e98e6f70ac | ||
| 
						 | 
					53e442d509 | ||
| 
						 | 
					134352ed7c | ||
| 
						 | 
					f7cbfdff06 | ||
| 
						 | 
					b28ee0819f | ||
| 
						 | 
					5de626aab8 | ||
| 
						 | 
					7aad5d486e | ||
| 
						 | 
					701f155951 | ||
| 
						 | 
					8c324d7514 | ||
| 
						 | 
					522958e0e9 | ||
| 
						 | 
					97390db5f5 | ||
| 
						 | 
					af920d1427 | ||
| 
						 | 
					779ebc0537 | ||
| 
						 | 
					38949b82c3 | ||
| 
						 | 
					d11386ef26 | ||
| 
						 | 
					0e0377d1f0 | ||
| 
						 | 
					55e0dbab27 | ||
| 
						 | 
					4dc82f2c83 | ||
| 
						 | 
					1ba5587404 | ||
| 
						 | 
					835c4b6da3 | ||
| 
						 | 
					dbd955b61e | ||
| 
						 | 
					d20e2fd88c | ||
| 
						 | 
					e0dea89477 | ||
| 
						 | 
					ccc6b56e35 | ||
| 
						 | 
					6fc2902895 | ||
| 
						 | 
					c96e4b40d4 | ||
| 
						 | 
					37da3e2170 | ||
| 
						 | 
					2661d3c489 | ||
| 
						 | 
					b89bbb9281 | ||
| 
						 | 
					696bf636ed | ||
| 
						 | 
					40952a788a | ||
| 
						 | 
					0162e7a0c1 | ||
| 
						 | 
					6ce099f176 | ||
| 
						 | 
					476a4bac8e | ||
| 
						 | 
					63a410a6df | ||
| 
						 | 
					cca27faa3b | ||
| 
						 | 
					803e6bd81a | ||
| 
						 | 
					88269628a2 | ||
| 
						 | 
					b920d553a0 | ||
| 
						 | 
					5e2d0d0dfc | ||
| 
						 | 
					2ae3bd68eb | ||
| 
						 | 
					9c183f27eb | ||
| 
						 | 
					8046023e82 | ||
| 
						 | 
					e328520588 | ||
| 
						 | 
					7eb079050c | ||
| 
						 | 
					2fdd5543b2 | ||
| 
						 | 
					d04164c0a6 | ||
| 
						 | 
					b047731f82 | ||
| 
						 | 
					4d91f92a2e | ||
| 
						 | 
					98505d27b1 | ||
| 
						 | 
					cd63a58ad9 | ||
| 
						 | 
					170f8dd092 | ||
| 
						 | 
					619dcb6a84 | ||
| 
						 | 
					99ae8ea52e | ||
| 
						 | 
					dc031c30eb | ||
| 
						 | 
					1e702439b7 | ||
| 
						 | 
					8debc42381 | ||
| 
						 | 
					532d719089 | ||
| 
						 | 
					b40860aca4 | ||
| 
						 | 
					2cbe6b5f7f | ||
| 
						 | 
					d2cc7ccdfa | ||
| 
						 | 
					2cb183c6d8 | ||
| 
						 | 
					84026b105f | ||
| 
						 | 
					a4d0589f10 | ||
| 
						 | 
					e375f6afce | ||
| 
						 | 
					5a7bc04816 | ||
| 
						 | 
					bd1894580e | ||
| 
						 | 
					9e694c0337 | ||
| 
						 | 
					c82586db28 | ||
| 
						 | 
					dd2d466350 | ||
| 
						 | 
					830da8de0a | ||
| 
						 | 
					4e5ee333c8 | ||
| 
						 | 
					9df899eb63 | ||
| 
						 | 
					ca7491a702 | ||
| 
						 | 
					1a07129865 | ||
| 
						 | 
					4fbd67ff99 | ||
| 
						 | 
					5bc6c50f42 | ||
| 
						 | 
					063de3801d | ||
| 
						 | 
					ae65266a4a | ||
| 
						 | 
					8ed2401e0b | ||
| 
						 | 
					d2e8ee8269 | ||
| 
						 | 
					1f996e3b8b | ||
| 
						 | 
					7108b74105 | ||
| 
						 | 
					801fe1b604 | ||
| 
						 | 
					fb44c87597 | ||
| 
						 | 
					6b9cdbd482 | ||
| 
						 | 
					0ab98033b5 | ||
| 
						 | 
					14a2b96609 | ||
| 
						 | 
					f829b689db | ||
| 
						 | 
					dfda8b7ed5 | ||
| 
						 | 
					4388466451 | ||
| 
						 | 
					5c2f509a52 | ||
| 
						 | 
					59582f5210 | ||
| 
						 | 
					e2a8bdbdfb | ||
| 
						 | 
					0916b943da | ||
| 
						 | 
					9c7ebc883c | ||
| 
						 | 
					0ee42b9aa0 | ||
| 
						 | 
					37b3868ca3 | ||
| 
						 | 
					a6835ce3f0 | ||
| 
						 | 
					69c96ad99b | ||
| 
						 | 
					b72877d59d | ||
| 
						 | 
					05eb15d4f7 | ||
| 
						 | 
					f1fec37c79 | ||
| 
						 | 
					73f6880ff8 | ||
| 
						 | 
					8a53742f31 | ||
| 
						 | 
					9be40e85ff | ||
| 
						 | 
					61079c1eb7 | ||
| 
						 | 
					1075ee8fc3 | ||
| 
						 | 
					a28b265197 | ||
| 
						 | 
					20e534c468 | ||
| 
						 | 
					da7aa5dc49 | ||
| 
						 | 
					8f2a43ca0a | ||
| 
						 | 
					d0909d7810 | ||
| 
						 | 
					1641999d20 | ||
| 
						 | 
					e16452037c | ||
| 
						 | 
					344d79684a | ||
| 
						 | 
					573a1d9b7b | ||
| 
						 | 
					25ab57580c | ||
| 
						 | 
					a332e0e3d1 | ||
| 
						 | 
					376f1cb139 | ||
| 
						 | 
					90f80558d7 | ||
| 
						 | 
					e281994898 | ||
| 
						 | 
					29fac122e1 | ||
| 
						 | 
					1dc412eb90 | ||
| 
						 | 
					3770a4fe0c | ||
| 
						 | 
					79cda544c8 | ||
| 
						 | 
					f04b97d890 | ||
| 
						 | 
					3e9b4ccc45 | ||
| 
						 | 
					2c3d838dd8 | ||
| 
						 | 
					7668a3c660 | ||
| 
						 | 
					5dd45b714a | ||
| 
						 | 
					8b08895d0f | ||
| 
						 | 
					8f8d99e3ed | ||
| 
						 | 
					23474360ec | ||
| 
						 | 
					81c255c450 | ||
| 
						 | 
					ef23d52ed7 | ||
| 
						 | 
					220ab773aa | ||
| 
						 | 
					e3e5bff7bb | ||
| 
						 | 
					7b9a841b2a | ||
| 
						 | 
					40423911ef | ||
| 
						 | 
					582a70b046 | ||
| 
						 | 
					5b63590ebf | ||
| 
						 | 
					2b6510dc19 | ||
| 
						 | 
					9d49589d73 | ||
| 
						 | 
					125b66c929 | ||
| 
						 | 
					5255f1c052 | ||
| 
						 | 
					a6ba05d60c | ||
| 
						 | 
					41e963b04b | ||
| 
						 | 
					6ff75bef29 | ||
| 
						 | 
					72c16d0d32 | ||
| 
						 | 
					94653e5c8c | ||
| 
						 | 
					3e2b2a698d | ||
| 
						 | 
					ae04f5aee8 | ||
| 
						 | 
					5c56267662 | ||
| 
						 | 
					e55ce5504e | ||
| 
						 | 
					fb1e89d9ef | ||
| 
						 | 
					bc550a4549 | ||
| 
						 | 
					ebdea9cf76 | ||
| 
						 | 
					09ec508f82 | ||
| 
						 | 
					d06e9ea7f6 | ||
| 
						 | 
					a36bdc54fd | ||
| 
						 | 
					0814ea9711 | ||
| 
						 | 
					daefe839d8 | ||
| 
						 | 
					e6088dd315 | ||
| 
						 | 
					fc03d6f332 | ||
| 
						 | 
					2aeb7a838e | ||
| 
						 | 
					99ff5dd078 | ||
| 
						 | 
					49982b49b6 | ||
| 
						 | 
					fd39c22616 | ||
| 
						 | 
					9e79722a7f | ||
| 
						 | 
					17334a1c58 | ||
| 
						 | 
					c7f0ff11ac | ||
| 
						 | 
					cd2cc89e6a | ||
| 
						 | 
					069143092d | ||
| 
						 | 
					efd41260f2 | ||
| 
						 | 
					8d2410622c | ||
| 
						 | 
					60554389b3 | ||
| 
						 | 
					a940dc7d43 | ||
| 
						 | 
					06ca68a625 | ||
| 
						 | 
					5b58e5b158 | ||
| 
						 | 
					74dd8fe80b | ||
| 
						 | 
					75ddcda5f3 | ||
| 
						 | 
					216825b98a | ||
| 
						 | 
					a96defab86 | ||
| 
						 | 
					0864b0a1b7 | ||
| 
						 | 
					8b158d9240 | ||
| 
						 | 
					f335251c2b | ||
| 
						 | 
					67bc0b6931 | ||
| 
						 | 
					e646dd1ed1 | ||
| 
						 | 
					2b7947f9b0 | ||
| 
						 | 
					ec0cfb4b3f | ||
| 
						 | 
					9cdf53019c | ||
| 
						 | 
					1a04a3eb3a | ||
| 
						 | 
					105d3995e0 | ||
| 
						 | 
					8ce3204f93 | ||
| 
						 | 
					d0f15f1285 | ||
| 
						 | 
					66d6f67120 | ||
| 
						 | 
					a106c88054 | ||
| 
						 | 
					ee784e1ccc | ||
| 
						 | 
					bb75be0b44 | ||
| 
						 | 
					2478aea316 | ||
| 
						 | 
					1e17df5296 | ||
| 
						 | 
					8583a96519 | ||
| 
						 | 
					d0c184c7de | ||
| 
						 | 
					0191acb2b3 | ||
| 
						 | 
					277a1a32b2 | ||
| 
						 | 
					7a13f57ab0 | ||
| 
						 | 
					0c882836d9 | ||
| 
						 | 
					228be5cd04 | ||
| 
						 | 
					08cd2fd6e8 | ||
| 
						 | 
					bc7b086f0f | ||
| 
						 | 
					e8f3af6981 | ||
| 
						 | 
					f9c7c7dab7 | ||
| 
						 | 
					09a17743ad | ||
| 
						 | 
					4f096a7511 | ||
| 
						 | 
					2ab2130000 | ||
| 
						 | 
					66558f7638 | ||
| 
						 | 
					a6f9ed07e7 | ||
| 
						 | 
					7268a8736f | ||
| 
						 | 
					8f6b5676d7 | ||
| 
						 | 
					ca9422bbe9 | ||
| 
						 | 
					35d9412559 | ||
| 
						 | 
					f071c07dd9 | ||
| 
						 | 
					e5ff3c1ff3 | ||
| 
						 | 
					f0e8ff0326 | ||
| 
						 | 
					3b5cda85ff | ||
| 
						 | 
					420793f9e2 | ||
| 
						 | 
					cf1dbaf0d8 | ||
| 
						 | 
					d187cef6b7 | ||
| 
						 | 
					3b3616afda | ||
| 
						 | 
					0ffebc25d0 | ||
| 
						 | 
					478e2b4ebd | ||
| 
						 | 
					a56ae7539a | ||
| 
						 | 
					407773bda2 | ||
| 
						 | 
					823eaa8918 | ||
| 
						 | 
					a2be42c5ca | ||
| 
						 | 
					a76b8d66ff | ||
| 
						 | 
					b7f47d354f | ||
| 
						 | 
					5d33c93af9 | ||
| 
						 | 
					4db6859f3f | ||
| 
						 | 
					45fe1bb16e | ||
| 
						 | 
					b014facbd3 | ||
| 
						 | 
					3b4b37f16b | ||
| 
						 | 
					68d5983a14 | ||
| 
						 | 
					f2cfcfdf31 | ||
| 
						 | 
					10b9162dc5 | ||
| 
						 | 
					c84cc8f8c9 | ||
| 
						 | 
					78c71bbf0e | ||
| 
						 | 
					37c2c1bf0b | ||
| 
						 | 
					c8996418da | ||
| 
						 | 
					76b29aa629 | ||
| 
						 | 
					ee521793f8 | ||
| 
						 | 
					f42e12bc13 | ||
| 
						 | 
					427451a23f | ||
| 
						 | 
					af7930d494 | ||
| 
						 | 
					e2882d37bf | ||
| 
						 | 
					942d3ee640 | ||
| 
						 | 
					7b4a82b91a | ||
| 
						 | 
					056c0a24d9 | ||
| 
						 | 
					827df04b32 | ||
| 
						 | 
					e174b31344 | ||
| 
						 | 
					49959af752 | ||
| 
						 | 
					c86c0912f8 | ||
| 
						 | 
					268b0c9365 | ||
| 
						 | 
					099fe280ba | ||
| 
						 | 
					f786f60e9c | ||
| 
						 | 
					f40e1eb1f2 | ||
| 
						 | 
					8b9da65357 | ||
| 
						 | 
					2cbbe0d48a | ||
| 
						 | 
					b6e1fb3ba8 | ||
| 
						 | 
					bdccffbb8e | ||
| 
						 | 
					5a85474712 | ||
| 
						 | 
					f50899c6fa | ||
| 
						 | 
					4daa909f32 | ||
| 
						 | 
					4555edf369 | ||
| 
						 | 
					529ea5bf58 | ||
| 
						 | 
					fe011de934 | ||
| 
						 | 
					0653d430a7 | ||
| 
						 | 
					a587f6e9a0 | ||
| 
						 | 
					3850e1dbb5 | ||
| 
						 | 
					91cde072e0 | ||
| 
						 | 
					2ca4aed566 | ||
| 
						 | 
					5071da6784 | ||
| 
						 | 
					4c1e2f3110 | ||
| 
						 | 
					2727a4dcb3 | ||
| 
						 | 
					126d4c69e6 | ||
| 
						 | 
					7657edcb7d | ||
| 
						 | 
					580e786952 | ||
| 
						 | 
					c0ae35b3a3 | ||
| 
						 | 
					c3dc74788a | ||
| 
						 | 
					379d241a0d | ||
| 
						 | 
					1f49e8fe75 | ||
| 
						 | 
					d70cfbb661 | ||
| 
						 | 
					5482ac0302 | ||
| 
						 | 
					131d5ceb4f | ||
| 
						 | 
					512ddd1694 | ||
| 
						 | 
					14a213bff9 | ||
| 
						 | 
					d586846bc5 | ||
| 
						 | 
					ef4efcb112 | ||
| 
						 | 
					b01555d75e | ||
| 
						 | 
					3804fba0f1 | ||
| 
						 | 
					f93b7e3303 | ||
| 
						 | 
					73baaeff1f | ||
| 
						 | 
					7c79cdbd2f | ||
| 
						 | 
					8ea032ed66 | ||
| 
						 | 
					e7a0cb636c | ||
| 
						 | 
					02f3f5d0f5 | ||
| 
						 | 
					1e9bbd662b | ||
| 
						 | 
					8644a4ae91 | ||
| 
						 | 
					1e85f7812f | ||
| 
						 | 
					80d88b3c61 | ||
| 
						 | 
					d2827a7431 | ||
| 
						 | 
					28c721fa7d | ||
| 
						 | 
					8f799567cf | ||
| 
						 | 
					9e8cc8b54d | ||
| 
						 | 
					cc59069876 | ||
| 
						 | 
					697d54e10a | ||
| 
						 | 
					1679ca79b4 | ||
| 
						 | 
					124ec77b58 | ||
| 
						 | 
					3675d7961b | ||
| 
						 | 
					f8aaa2d13c | ||
| 
						 | 
					b7afda781a | ||
| 
						 | 
					535ec13072 | ||
| 
						 | 
					26d0a174db | ||
| 
						 | 
					b2e821755c | ||
| 
						 | 
					2e303041c1 | ||
| 
						 | 
					96bed8f57f | ||
| 
						 | 
					86d4a4309f | ||
| 
						 | 
					1a1ab0dac6 | ||
| 
						 | 
					ba8c3d14f7 | ||
| 
						 | 
					617ea15c3a | ||
| 
						 | 
					ef192a5778 | ||
| 
						 | 
					565973c520 | ||
| 
						 | 
					25b1043572 | ||
| 
						 | 
					1ebfff7c7b | ||
| 
						 | 
					8341f9c066 | ||
| 
						 | 
					28cac291de | ||
| 
						 | 
					8fa14a10e2 | ||
| 
						 | 
					55dbd095ed | ||
| 
						 | 
					31ad8bdd8d | ||
| 
						 | 
					181f3e9eb1 | ||
| 
						 | 
					50c3d809dc | ||
| 
						 | 
					58f696d00a | ||
| 
						 | 
					f603c543d3 | ||
| 
						 | 
					6aaa0f928e | ||
| 
						 | 
					feb8aa435e | ||
| 
						 | 
					310e8f15cd | ||
| 
						 | 
					da03941582 | ||
| 
						 | 
					dcbb36a3bd | ||
| 
						 | 
					53558f5c1d | ||
| 
						 | 
					189399d5f8 | ||
| 
						 | 
					5406a992f5 | ||
| 
						 | 
					bc9683cc54 | ||
| 
						 | 
					2eed75f602 | ||
| 
						 | 
					d58f9f56c4 | ||
| 
						 | 
					2e35f3c3a3 | ||
| 
						 | 
					5c6bd9c091 | ||
| 
						 | 
					857d2eefca | ||
| 
						 | 
					90f1e7fd6a | ||
| 
						 | 
					18e37accf9 | ||
| 
						 | 
					cc53d698bf | ||
| 
						 | 
					cb86206698 | ||
| 
						 | 
					d77b1944fb | ||
| 
						 | 
					a58cb43c4a | ||
| 
						 | 
					88574c87c4 | ||
| 
						 | 
					3a7a7091c0 | ||
| 
						 | 
					906b137a7c | ||
| 
						 | 
					42e2c5f605 | ||
| 
						 | 
					cc13a51493 | ||
| 
						 | 
					f569ce6141 | ||
| 
						 | 
					4958463e75 | ||
| 
						 | 
					2360625927 | ||
| 
						 | 
					8badc40883 | ||
| 
						 | 
					844c97930f | ||
| 
						 | 
					5c09dc10ae | ||
| 
						 | 
					9fd9e9ab5f | ||
| 
						 | 
					35c477b5a6 | ||
| 
						 | 
					ae0cadb383 | ||
| 
						 | 
					984230e8fa | ||
| 
						 | 
					a874aec6a1 | ||
| 
						 | 
					ea1daa97d3 | ||
| 
						 | 
					fb0d9b46b0 | ||
| 
						 | 
					9da70bdf05 | ||
| 
						 | 
					d640cfbe13 | ||
| 
						 | 
					51a05ec4b7 | ||
| 
						 | 
					1f5706bbeb | ||
| 
						 | 
					25c9b2fea4 | ||
| 
						 | 
					154f9b300f | ||
| 
						 | 
					d78ce77536 | ||
| 
						 | 
					b4fb43bc80 | ||
| 
						 | 
					e0e01f794e | ||
| 
						 | 
					08865dbb4e | ||
| 
						 | 
					b9ad7e0e55 | ||
| 
						 | 
					07158a6f1a | ||
| 
						 | 
					957c42bc1d | ||
| 
						 | 
					f784da2da6 | ||
| 
						 | 
					c080fbe59a | ||
| 
						 | 
					d70b8303b1 | ||
| 
						 | 
					1d38c3582a | ||
| 
						 | 
					9438e996d7 | ||
| 
						 | 
					3b4a5e27f7 | ||
| 
						 | 
					648d9fc269 | ||
| 
						 | 
					54fccec7d7 | ||
| 
						 | 
					4f9693055e | ||
| 
						 | 
					555c50ee10 | ||
| 
						 | 
					bf98ceca2c | ||
| 
						 | 
					573cecb087 | ||
| 
						 | 
					1b528491c2 | ||
| 
						 | 
					4bdabe1961 | ||
| 
						 | 
					a3fa527378 | ||
| 
						 | 
					84f5ffa426 | ||
| 
						 | 
					25d2b42283 | ||
| 
						 | 
					300d1a871c | ||
| 
						 | 
					2fcb83a39f | ||
| 
						 | 
					3ba1d00a7c | ||
| 
						 | 
					64164c1c72 | ||
| 
						 | 
					3ee6058524 | ||
| 
						 | 
					93a0a41e73 | ||
| 
						 | 
					e7ab7b6d7a | ||
| 
						 | 
					7d4dc3c063 | ||
| 
						 | 
					a50400b7d1 | ||
| 
						 | 
					f89f1a84d0 | ||
| 
						 | 
					688dce6145 | ||
| 
						 | 
					b88f550c5b | ||
| 
						 | 
					9864abd393 | ||
| 
						 | 
					c702c4a6df | ||
| 
						 | 
					77e376f6bf | ||
| 
						 | 
					491e5dbcfb | ||
| 
						 | 
					a5c7393561 | ||
| 
						 | 
					7fd3e9bb7d | ||
| 
						 | 
					459e9f8f3b | ||
| 
						 | 
					5b1143bcb3 | ||
| 
						 | 
					fddd390d31 | ||
| 
						 | 
					e514eeba17 | ||
| 
						 | 
					c11a52b278 | ||
| 
						 | 
					85e87dfe2e | ||
| 
						 | 
					cb47e2c149 | ||
| 
						 | 
					0fc9aa6b2d | ||
| 
						 | 
					155896c4c7 | ||
| 
						 | 
					178e60bba0 | ||
| 
						 | 
					9f84aa5fb2 | ||
| 
						 | 
					66fc109ce5 | ||
| 
						 | 
					a231872821 | ||
| 
						 | 
					7cfb33a448 | ||
| 
						 | 
					3b798097b9 | ||
| 
						 | 
					6fb05bdefc | ||
| 
						 | 
					64ea72ed4d | ||
| 
						 | 
					89425088ce | ||
| 
						 | 
					925b9d845d | ||
| 
						 | 
					ad074076c2 | ||
| 
						 | 
					a2194c43a6 | ||
| 
						 | 
					4b23b1dc86 | ||
| 
						 | 
					9005c7994a | ||
| 
						 | 
					4a47e15b1c | ||
| 
						 | 
					09cbdf410a | ||
| 
						 | 
					df6a43c7f0 | ||
| 
						 | 
					4ce130dc8b | ||
| 
						 | 
					94d76aa82c | ||
| 
						 | 
					73609636c5 | ||
| 
						 | 
					66b06d6c40 | ||
| 
						 | 
					eeeb8d81f4 | ||
| 
						 | 
					6f727aff88 | ||
| 
						 | 
					518e5a30c2 | ||
| 
						 | 
					bbba4b3d60 | ||
| 
						 | 
					967adb9a87 | ||
| 
						 | 
					040a6c62de | ||
| 
						 | 
					483d193ced | ||
| 
						 | 
					62458216c9 | ||
| 
						 | 
					76b05cb5fd | ||
| 
						 | 
					570b574b93 | ||
| 
						 | 
					a82f211f9a | ||
| 
						 | 
					504c80cddf | ||
| 
						 | 
					4b4af9b527 | ||
| 
						 | 
					28b383f888 | ||
| 
						 | 
					40ce7725a1 | ||
| 
						 | 
					1f2d46628e | ||
| 
						 | 
					c9535049c8 | ||
| 
						 | 
					9317cf8a35 | ||
| 
						 | 
					1cd754f05d | ||
| 
						 | 
					97b8cb748d | ||
| 
						 | 
					84d9040b57 | ||
| 
						 | 
					fdd18c615c | ||
| 
						 | 
					c14f6cfc2b | ||
| 
						 | 
					326eab3dd1 | ||
| 
						 | 
					6da1f7eb4c | ||
| 
						 | 
					1e82483152 | ||
| 
						 | 
					6e2fd41a8b | ||
| 
						 | 
					9927af1095 | ||
| 
						 | 
					7585b6ef6f | ||
| 
						 | 
					a6159702da | ||
| 
						 | 
					0247fb0d84 | ||
| 
						 | 
					6de760885f | ||
| 
						 | 
					9851d14fb9 | ||
| 
						 | 
					d5fc69d3e4 | ||
| 
						 | 
					a40d120f2a | ||
| 
						 | 
					fcdd9414d9 | ||
| 
						 | 
					272a1001a8 | ||
| 
						 | 
					2a52241f1c | ||
| 
						 | 
					d8f1822c12 | ||
| 
						 | 
					ce7d094adb | ||
| 
						 | 
					a0cf1889a3 | ||
| 
						 | 
					38ef394e15 | ||
| 
						 | 
					abbf7c7cb0 | ||
| 
						 | 
					ca5f7ae32f | ||
| 
						 | 
					cbc4b75e50 | ||
| 
						 | 
					65ddcf91d0 | ||
| 
						 | 
					5280e1b449 | ||
| 
						 | 
					b6ffb81909 | ||
| 
						 | 
					e9edffa9f0 | ||
| 
						 | 
					aef211e5f3 | ||
| 
						 | 
					66829203d8 | ||
| 
						 | 
					7a0eaf3148 | 
							
								
								
									
										17
									
								
								.aiignore
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								.aiignore
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					# An .aiignore file follows the same syntax as a .gitignore file.
 | 
				
			||||||
 | 
					# .gitignore documentation: https://git-scm.com/docs/gitignore
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# you can ignore files
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					*.tmp
 | 
				
			||||||
 | 
					*.bin
 | 
				
			||||||
 | 
					*.prg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# or folders
 | 
				
			||||||
 | 
					dist/
 | 
				
			||||||
 | 
					build/
 | 
				
			||||||
 | 
					out/
 | 
				
			||||||
 | 
					output/
 | 
				
			||||||
 | 
					.gradle/
 | 
				
			||||||
 | 
					.kotlin/
 | 
				
			||||||
							
								
								
									
										3
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.github/FUNDING.yml
									
									
									
									
										vendored
									
									
								
							@@ -2,7 +2,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
 | 
					#github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
 | 
				
			||||||
#patreon: # Replace with a single Patreon username
 | 
					#patreon: # Replace with a single Patreon username
 | 
				
			||||||
open_collective: # Replace with a single Open Collective username
 | 
					#open_collective: # Replace with a single Open Collective username
 | 
				
			||||||
ko_fi: irmen
 | 
					ko_fi: irmen
 | 
				
			||||||
#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
 | 
					#tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
 | 
				
			||||||
#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
 | 
					#community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
 | 
				
			||||||
@@ -11,3 +11,4 @@ ko_fi: irmen
 | 
				
			|||||||
#otechie: # Replace with a single Otechie username
 | 
					#otechie: # Replace with a single Otechie username
 | 
				
			||||||
#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
 | 
					#lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
 | 
				
			||||||
#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
 | 
					#custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
 | 
				
			||||||
 | 
					custom: ['https://paypal.me/irmendejong']
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								.github/workflows/all-ci.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/all-ci.yml
									
									
									
									
										vendored
									
									
								
							@@ -20,10 +20,10 @@ jobs:
 | 
				
			|||||||
          make -j4
 | 
					          make -j4
 | 
				
			||||||
          sudo make install          
 | 
					          sudo make install          
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Set up JDK 11
 | 
					      - name: Set up JDK 17
 | 
				
			||||||
        uses: actions/setup-java@v4
 | 
					        uses: actions/setup-java@v4
 | 
				
			||||||
        with:
 | 
					        with:
 | 
				
			||||||
          java-version: 11
 | 
					          java-version: 17
 | 
				
			||||||
          distribution: temurin
 | 
					          distribution: temurin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      - name: Build and test with Gradle
 | 
					      - name: Build and test with Gradle
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										9
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,18 +1,23 @@
 | 
				
			|||||||
.idea/workspace.xml
 | 
					.idea/workspace.xml
 | 
				
			||||||
.idea/discord.xml
 | 
					.idea/discord.xml
 | 
				
			||||||
.idea/developer-tools.xml
 | 
					.idea/developer-tools.xml
 | 
				
			||||||
 | 
					.idea/usage.statistics.xml
 | 
				
			||||||
 | 
					.idea/shelf/
 | 
				
			||||||
build/
 | 
					build/
 | 
				
			||||||
dist/
 | 
					dist/
 | 
				
			||||||
output/
 | 
					output/
 | 
				
			||||||
 | 
					out/
 | 
				
			||||||
 | 
					out-new/
 | 
				
			||||||
 | 
					out-old/
 | 
				
			||||||
.*cache/
 | 
					.*cache/
 | 
				
			||||||
*.directory
 | 
					*.directory
 | 
				
			||||||
*.prg
 | 
					*.prg
 | 
				
			||||||
*.bin
 | 
					*.bin
 | 
				
			||||||
 | 
					*.p8ir
 | 
				
			||||||
*.labels.txt
 | 
					*.labels.txt
 | 
				
			||||||
*.vm.txt
 | 
					*.vm.txt
 | 
				
			||||||
*.vice-mon-list
 | 
					*.vice-mon-list
 | 
				
			||||||
docs/build
 | 
					docs/build
 | 
				
			||||||
out/
 | 
					 | 
				
			||||||
parser/**/*.interp
 | 
					parser/**/*.interp
 | 
				
			||||||
parser/**/*.tokens
 | 
					parser/**/*.tokens
 | 
				
			||||||
parser/**/*.java
 | 
					parser/**/*.java
 | 
				
			||||||
@@ -23,6 +28,7 @@ compiler/src/prog8/buildversion/*
 | 
				
			|||||||
.eggs/
 | 
					.eggs/
 | 
				
			||||||
/MANIFEST
 | 
					/MANIFEST
 | 
				
			||||||
.tox/
 | 
					.tox/
 | 
				
			||||||
 | 
					.kotlin/
 | 
				
			||||||
__pycache__/
 | 
					__pycache__/
 | 
				
			||||||
parser.out
 | 
					parser.out
 | 
				
			||||||
parsetab.py
 | 
					parsetab.py
 | 
				
			||||||
@@ -31,7 +37,6 @@ parsetab.py
 | 
				
			|||||||
compiler/lib/
 | 
					compiler/lib/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.gradle
 | 
					.gradle
 | 
				
			||||||
/prog8compiler.jar
 | 
					 | 
				
			||||||
sd*.img
 | 
					sd*.img
 | 
				
			||||||
*.d64
 | 
					*.d64
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										1582
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1582
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										12
									
								
								.idea/kotlinc.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										12
									
								
								.idea/kotlinc.xml
									
									
									
										generated
									
									
									
								
							@@ -1,9 +1,19 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
<project version="4">
 | 
					<project version="4">
 | 
				
			||||||
 | 
					  <component name="Kotlin2JsCompilerArguments">
 | 
				
			||||||
 | 
					    <option name="moduleKind" value="plain" />
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
  <component name="Kotlin2JvmCompilerArguments">
 | 
					  <component name="Kotlin2JvmCompilerArguments">
 | 
				
			||||||
    <option name="jvmTarget" value="11" />
 | 
					    <option name="jvmTarget" value="11" />
 | 
				
			||||||
  </component>
 | 
					  </component>
 | 
				
			||||||
 | 
					  <component name="KotlinCommonCompilerArguments">
 | 
				
			||||||
 | 
					    <option name="apiVersion" value="2.2" />
 | 
				
			||||||
 | 
					    <option name="languageVersion" value="2.2" />
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
 | 
					  <component name="KotlinCompilerSettings">
 | 
				
			||||||
 | 
					    <option name="additionalArguments" value="-Xwhen-guards -jvm-default=no-compatibility" />
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
  <component name="KotlinJpsPluginSettings">
 | 
					  <component name="KotlinJpsPluginSettings">
 | 
				
			||||||
    <option name="version" value="1.9.24" />
 | 
					    <option name="version" value="2.2.0" />
 | 
				
			||||||
  </component>
 | 
					  </component>
 | 
				
			||||||
</project>
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										20
									
								
								.idea/libraries/KotlinJavaRuntime.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										20
									
								
								.idea/libraries/KotlinJavaRuntime.xml
									
									
									
										generated
									
									
									
								
							@@ -1,23 +1,23 @@
 | 
				
			|||||||
<component name="libraryTable">
 | 
					<component name="libraryTable">
 | 
				
			||||||
  <library name="KotlinJavaRuntime" type="repository">
 | 
					  <library name="KotlinJavaRuntime" type="repository">
 | 
				
			||||||
    <properties maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.20" />
 | 
					    <properties maven-id="org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.2.20" />
 | 
				
			||||||
    <CLASSES>
 | 
					    <CLASSES>
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.0.20/kotlin-stdlib-jdk8-2.0.20.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.2.20/kotlin-stdlib-jdk8-2.2.20.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.20/kotlin-stdlib-2.0.20.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.2.20/kotlin-stdlib-2.2.20.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.0.20/kotlin-stdlib-jdk7-2.0.20.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.2.20/kotlin-stdlib-jdk7-2.2.20.jar!/" />
 | 
				
			||||||
    </CLASSES>
 | 
					    </CLASSES>
 | 
				
			||||||
    <JAVADOC>
 | 
					    <JAVADOC>
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.0.20/kotlin-stdlib-jdk8-2.0.20-javadoc.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.2.20/kotlin-stdlib-jdk8-2.2.20-javadoc.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.20/kotlin-stdlib-2.0.20-javadoc.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.2.20/kotlin-stdlib-2.2.20-javadoc.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.0.20/kotlin-stdlib-jdk7-2.0.20-javadoc.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.2.20/kotlin-stdlib-jdk7-2.2.20-javadoc.jar!/" />
 | 
				
			||||||
    </JAVADOC>
 | 
					    </JAVADOC>
 | 
				
			||||||
    <SOURCES>
 | 
					    <SOURCES>
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.0.20/kotlin-stdlib-jdk8-2.0.20-sources.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk8/2.2.20/kotlin-stdlib-jdk8-2.2.20-sources.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.0.20/kotlin-stdlib-2.0.20-sources.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.2.20/kotlin-stdlib-2.2.20-sources.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.0.20/kotlin-stdlib-jdk7-2.0.20-sources.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib-jdk7/2.2.20/kotlin-stdlib-jdk7-2.2.20-sources.jar!/" />
 | 
				
			||||||
    </SOURCES>
 | 
					    </SOURCES>
 | 
				
			||||||
  </library>
 | 
					  </library>
 | 
				
			||||||
</component>
 | 
					</component>
 | 
				
			||||||
							
								
								
									
										13
									
								
								.idea/libraries/eclipse_lsp4j.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								.idea/libraries/eclipse_lsp4j.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					<component name="libraryTable">
 | 
				
			||||||
 | 
					  <library name="eclipse.lsp4j" type="repository">
 | 
				
			||||||
 | 
					    <properties maven-id="org.eclipse.lsp4j:org.eclipse.lsp4j:0.24.0" />
 | 
				
			||||||
 | 
					    <CLASSES>
 | 
				
			||||||
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/eclipse/lsp4j/org.eclipse.lsp4j/0.24.0/org.eclipse.lsp4j-0.24.0.jar!/" />
 | 
				
			||||||
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/eclipse/lsp4j/org.eclipse.lsp4j.jsonrpc/0.24.0/org.eclipse.lsp4j.jsonrpc-0.24.0.jar!/" />
 | 
				
			||||||
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/com/google/code/gson/gson/2.13.1/gson-2.13.1.jar!/" />
 | 
				
			||||||
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/com/google/errorprone/error_prone_annotations/2.38.0/error_prone_annotations-2.38.0.jar!/" />
 | 
				
			||||||
 | 
					    </CLASSES>
 | 
				
			||||||
 | 
					    <JAVADOC />
 | 
				
			||||||
 | 
					    <SOURCES />
 | 
				
			||||||
 | 
					  </library>
 | 
				
			||||||
 | 
					</component>
 | 
				
			||||||
							
								
								
									
										20
									
								
								.idea/libraries/io_kotest_assertions_core_jvm.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										20
									
								
								.idea/libraries/io_kotest_assertions_core_jvm.xml
									
									
									
										generated
									
									
									
								
							@@ -1,20 +0,0 @@
 | 
				
			|||||||
<component name="libraryTable">
 | 
					 | 
				
			||||||
  <library name="io.kotest.assertions.core.jvm" type="repository">
 | 
					 | 
				
			||||||
    <properties maven-id="io.kotest:kotest-assertions-core-jvm:5.9.1" />
 | 
					 | 
				
			||||||
    <CLASSES>
 | 
					 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-core-jvm/5.9.1/kotest-assertions-core-jvm-5.9.1.jar!/" />
 | 
					 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-shared-jvm/5.9.1/kotest-assertions-shared-jvm-5.9.1.jar!/" />
 | 
					 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/io/github/java-diff-utils/java-diff-utils/4.12/java-diff-utils-4.12.jar!/" />
 | 
					 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar!/" />
 | 
					 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.23/kotlin-stdlib-1.9.23.jar!/" />
 | 
					 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
 | 
					 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-jdk8/1.8.0/kotlinx-coroutines-jdk8-1.8.0.jar!/" />
 | 
					 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-reflect/1.9.23/kotlin-reflect-1.9.23.jar!/" />
 | 
					 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-common-jvm/5.9.1/kotest-common-jvm-5.9.1.jar!/" />
 | 
					 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/io/kotest/kotest-assertions-api-jvm/5.9.1/kotest-assertions-api-jvm-5.9.1.jar!/" />
 | 
					 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlinx/kotlinx-coroutines-core-jvm/1.8.0/kotlinx-coroutines-core-jvm-1.8.0.jar!/" />
 | 
					 | 
				
			||||||
    </CLASSES>
 | 
					 | 
				
			||||||
    <JAVADOC />
 | 
					 | 
				
			||||||
    <SOURCES />
 | 
					 | 
				
			||||||
  </library>
 | 
					 | 
				
			||||||
</component>
 | 
					 | 
				
			||||||
							
								
								
									
										14
									
								
								.idea/libraries/michael_bull_kotlin_result_jvm.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										14
									
								
								.idea/libraries/michael_bull_kotlin_result_jvm.xml
									
									
									
										generated
									
									
									
								
							@@ -1,19 +1,19 @@
 | 
				
			|||||||
<component name="libraryTable">
 | 
					<component name="libraryTable">
 | 
				
			||||||
  <library name="michael.bull.kotlin.result.jvm" type="repository">
 | 
					  <library name="michael.bull.kotlin.result.jvm" type="repository">
 | 
				
			||||||
    <properties maven-id="com.michael-bull.kotlin-result:kotlin-result-jvm:2.0.0" />
 | 
					    <properties maven-id="com.michael-bull.kotlin-result:kotlin-result-jvm:2.1.0" />
 | 
				
			||||||
    <CLASSES>
 | 
					    <CLASSES>
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.1.0/kotlin-result-jvm-2.1.0.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.2.0/kotlin-stdlib-2.2.0.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0.jar!/" />
 | 
				
			||||||
    </CLASSES>
 | 
					    </CLASSES>
 | 
				
			||||||
    <JAVADOC>
 | 
					    <JAVADOC>
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0-javadoc.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.1.0/kotlin-result-jvm-2.1.0-javadoc.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22-javadoc.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.2.0/kotlin-stdlib-2.2.0-javadoc.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-javadoc.jar!/" />
 | 
				
			||||||
    </JAVADOC>
 | 
					    </JAVADOC>
 | 
				
			||||||
    <SOURCES>
 | 
					    <SOURCES>
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.0.0/kotlin-result-jvm-2.0.0-sources.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/com/michael-bull/kotlin-result/kotlin-result-jvm/2.1.0/kotlin-result-jvm-2.1.0-sources.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/1.9.22/kotlin-stdlib-1.9.22-sources.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-stdlib/2.2.0/kotlin-stdlib-2.2.0-sources.jar!/" />
 | 
				
			||||||
      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
 | 
					      <root url="jar://$MAVEN_REPOSITORY$/org/jetbrains/annotations/13.0/annotations-13.0-sources.jar!/" />
 | 
				
			||||||
    </SOURCES>
 | 
					    </SOURCES>
 | 
				
			||||||
  </library>
 | 
					  </library>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										10
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							@@ -4,14 +4,15 @@
 | 
				
			|||||||
    <option name="perGrammarGenerationSettings">
 | 
					    <option name="perGrammarGenerationSettings">
 | 
				
			||||||
      <list>
 | 
					      <list>
 | 
				
			||||||
        <PerGrammarGenerationSettings>
 | 
					        <PerGrammarGenerationSettings>
 | 
				
			||||||
          <option name="fileName" value="$PROJECT_DIR$/parser/antlr/Prog8ANTLR.g4" />
 | 
					          <option name="fileName" value="$PROJECT_DIR$/parser/src/main/antlr/Prog8ANTLR.g4" />
 | 
				
			||||||
          <option name="autoGen" value="true" />
 | 
					          <option name="autoGen" value="true" />
 | 
				
			||||||
          <option name="outputDir" value="$PROJECT_DIR$/parser/src/prog8/parser" />
 | 
					          <option name="outputDir" value="$PROJECT_DIR$/parser/src/prog8/parser" />
 | 
				
			||||||
          <option name="libDir" value="" />
 | 
					          <option name="libDir" value="" />
 | 
				
			||||||
          <option name="encoding" value="" />
 | 
					          <option name="encoding" value="" />
 | 
				
			||||||
          <option name="pkg" value="" />
 | 
					          <option name="pkg" value="" />
 | 
				
			||||||
          <option name="language" value="" />
 | 
					          <option name="language" value="Java" />
 | 
				
			||||||
          <option name="generateListener" value="false" />
 | 
					          <option name="generateListener" value="false" />
 | 
				
			||||||
 | 
					          <option name="generateVisitor" value="true" />
 | 
				
			||||||
        </PerGrammarGenerationSettings>
 | 
					        </PerGrammarGenerationSettings>
 | 
				
			||||||
      </list>
 | 
					      </list>
 | 
				
			||||||
    </option>
 | 
					    </option>
 | 
				
			||||||
@@ -22,7 +23,10 @@
 | 
				
			|||||||
  <component name="FrameworkDetectionExcludesConfiguration">
 | 
					  <component name="FrameworkDetectionExcludesConfiguration">
 | 
				
			||||||
    <type id="Python" />
 | 
					    <type id="Python" />
 | 
				
			||||||
  </component>
 | 
					  </component>
 | 
				
			||||||
  <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="openjdk-17" project-jdk-type="JavaSDK">
 | 
					  <component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="openjdk-21" project-jdk-type="JavaSDK">
 | 
				
			||||||
    <output url="file://$PROJECT_DIR$/out" />
 | 
					    <output url="file://$PROJECT_DIR$/out" />
 | 
				
			||||||
  </component>
 | 
					  </component>
 | 
				
			||||||
 | 
					  <component name="PythonCompatibilityInspectionAdvertiser">
 | 
				
			||||||
 | 
					    <option name="version" value="3" />
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
</project>
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										6
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										6
									
								
								.idea/modules.xml
									
									
									
										generated
									
									
									
								
							@@ -2,6 +2,8 @@
 | 
				
			|||||||
<project version="4">
 | 
					<project version="4">
 | 
				
			||||||
  <component name="ProjectModuleManager">
 | 
					  <component name="ProjectModuleManager">
 | 
				
			||||||
    <modules>
 | 
					    <modules>
 | 
				
			||||||
 | 
					      <module fileurl="file://$PROJECT_DIR$/beanshell/beanshell.iml" filepath="$PROJECT_DIR$/beanshell/beanshell.iml" />
 | 
				
			||||||
 | 
					      <module fileurl="file://$PROJECT_DIR$/benchmark-program/benchmark-program.iml" filepath="$PROJECT_DIR$/benchmark-program/benchmark-program.iml" />
 | 
				
			||||||
      <module fileurl="file://$PROJECT_DIR$/codeCore/codeCore.iml" filepath="$PROJECT_DIR$/codeCore/codeCore.iml" />
 | 
					      <module fileurl="file://$PROJECT_DIR$/codeCore/codeCore.iml" filepath="$PROJECT_DIR$/codeCore/codeCore.iml" />
 | 
				
			||||||
      <module fileurl="file://$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" filepath="$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" />
 | 
					      <module fileurl="file://$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" filepath="$PROJECT_DIR$/codeGenCpu6502/codeGenCpu6502.iml" />
 | 
				
			||||||
      <module fileurl="file://$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" filepath="$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" />
 | 
					      <module fileurl="file://$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" filepath="$PROJECT_DIR$/codeGenExperimental/codeGenExperimental.iml" />
 | 
				
			||||||
@@ -12,9 +14,11 @@
 | 
				
			|||||||
      <module fileurl="file://$PROJECT_DIR$/compilerAst/compilerAst.iml" filepath="$PROJECT_DIR$/compilerAst/compilerAst.iml" />
 | 
					      <module fileurl="file://$PROJECT_DIR$/compilerAst/compilerAst.iml" filepath="$PROJECT_DIR$/compilerAst/compilerAst.iml" />
 | 
				
			||||||
      <module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" />
 | 
					      <module fileurl="file://$PROJECT_DIR$/docs/docs.iml" filepath="$PROJECT_DIR$/docs/docs.iml" />
 | 
				
			||||||
      <module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
 | 
					      <module fileurl="file://$PROJECT_DIR$/examples/examples.iml" filepath="$PROJECT_DIR$/examples/examples.iml" />
 | 
				
			||||||
      <module fileurl="file://$PROJECT_DIR$/benchmark-program/benchmark-program.iml" filepath="$PROJECT_DIR$/benchmark-program/benchmark-program.iml" />
 | 
					 | 
				
			||||||
      <module fileurl="file://$PROJECT_DIR$/intermediate/intermediate.iml" filepath="$PROJECT_DIR$/intermediate/intermediate.iml" />
 | 
					      <module fileurl="file://$PROJECT_DIR$/intermediate/intermediate.iml" filepath="$PROJECT_DIR$/intermediate/intermediate.iml" />
 | 
				
			||||||
 | 
					      <module fileurl="file://$PROJECT_DIR$/languageServer/languageServer.iml" filepath="$PROJECT_DIR$/languageServer/languageServer.iml" />
 | 
				
			||||||
      <module fileurl="file://$PROJECT_DIR$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" />
 | 
					      <module fileurl="file://$PROJECT_DIR$/parser/parser.iml" filepath="$PROJECT_DIR$/parser/parser.iml" />
 | 
				
			||||||
 | 
					      <module fileurl="file://$PROJECT_DIR$/.idea/modules/prog8.iml" filepath="$PROJECT_DIR$/.idea/modules/prog8.iml" />
 | 
				
			||||||
 | 
					      <module fileurl="file://$PROJECT_DIR$/simpleAst/simpleAst.iml" filepath="$PROJECT_DIR$/simpleAst/simpleAst.iml" />
 | 
				
			||||||
      <module fileurl="file://$PROJECT_DIR$/virtualmachine/virtualmachine.iml" filepath="$PROJECT_DIR$/virtualmachine/virtualmachine.iml" />
 | 
					      <module fileurl="file://$PROJECT_DIR$/virtualmachine/virtualmachine.iml" filepath="$PROJECT_DIR$/virtualmachine/virtualmachine.iml" />
 | 
				
			||||||
    </modules>
 | 
					    </modules>
 | 
				
			||||||
  </component>
 | 
					  </component>
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										4
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								Makefile
									
									
									
									
									
								
							@@ -4,9 +4,9 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
all:
 | 
					all:
 | 
				
			||||||
	gradle installdist installshadowdist
 | 
						gradle installdist installshadowdist
 | 
				
			||||||
	@echo "compiler launch script can be found here: compiler/build/install/compiler-shadow/bin/p8compile"
 | 
						@echo "compiler launch script can be found here: compiler/build/install/compiler-shadow/bin/prog8c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
test:
 | 
					test:
 | 
				
			||||||
	gradle build
 | 
						gradle build
 | 
				
			||||||
	@echo "compiler launch script can be found here: compiler/build/install/compiler-shadow/bin/p8compile"
 | 
						@echo "compiler launch script can be found here: compiler/build/install/compiler-shadow/bin/prog8c"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										31
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								README.md
									
									
									
									
									
								
							@@ -1,4 +1,7 @@
 | 
				
			|||||||
[](https://ko-fi.com/H2H6S0FFF)
 | 
					[](https://ko-fi.com/H2H6S0FFF)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PayPal: [](https://paypal.me/irmendejong)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[](https://prog8.readthedocs.io/)
 | 
					[](https://prog8.readthedocs.io/)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Prog8 - Structured Programming Language for 8-bit 6502/65c02 microprocessors
 | 
					Prog8 - Structured Programming Language for 8-bit 6502/65c02 microprocessors
 | 
				
			||||||
@@ -14,7 +17,7 @@ which aims to provide many conveniences over raw assembly code (even when using
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
This project was created over the last couple of years by dedicating thousands of hours of my free time to it, to make it the best I possibly can.
 | 
					This project was created over the last couple of years by dedicating thousands of hours of my free time to it, to make it the best I possibly can.
 | 
				
			||||||
If you like Prog8, and think it's worth a nice cup of hot coffee or a delicious pizza, 
 | 
					If you like Prog8, and think it's worth a nice cup of hot coffee or a delicious pizza, 
 | 
				
			||||||
you can help me out a little bit over at [ko-fi.com/irmen](https://ko-fi.com/irmen). 
 | 
					you can help me out a little bit over at [ko-fi.com/irmen](https://ko-fi.com/irmen) or [PayPal](https://paypal.me/irmendejong)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Documentation
 | 
					Documentation
 | 
				
			||||||
@@ -58,19 +61,28 @@ What does Prog8 provide?
 | 
				
			|||||||
- code often is smaller and faster than equivalent C code compiled with CC65 or even LLVM-MOS
 | 
					- code often is smaller and faster than equivalent C code compiled with CC65 or even LLVM-MOS
 | 
				
			||||||
- modularity, symbol scoping, subroutines. No need for forward declarations.
 | 
					- modularity, symbol scoping, subroutines. No need for forward declarations.
 | 
				
			||||||
- various data types other than just bytes (16-bit words, floats, strings)
 | 
					- various data types other than just bytes (16-bit words, floats, strings)
 | 
				
			||||||
 | 
					- Structs and typed pointers
 | 
				
			||||||
- floating point math is supported on certain targets
 | 
					- floating point math is supported on certain targets
 | 
				
			||||||
 | 
					- access to most Kernal ROM routines as external subroutine definitions you can call normally
 | 
				
			||||||
 | 
					- tight control over Zeropage usage
 | 
				
			||||||
 | 
					- programs can be run multiple times without reloading because of automatic variable (re)initializations.
 | 
				
			||||||
 | 
					- programs can be configured to execute in ROM
 | 
				
			||||||
- strings can contain escaped characters but also many symbols directly if they have a petscii equivalent, such as "♠♥♣♦π▚●○╳". Characters like ^, _, \, {, } and | are also accepted and converted to the closest petscii equivalents.
 | 
					- strings can contain escaped characters but also many symbols directly if they have a petscii equivalent, such as "♠♥♣♦π▚●○╳". Characters like ^, _, \, {, } and | are also accepted and converted to the closest petscii equivalents.
 | 
				
			||||||
- automatic static variable allocations, automatic string and array variables and string sharing
 | 
					- automatic static variable allocations, automatic string and array variables and string sharing
 | 
				
			||||||
- high-level program optimizations
 | 
					- high-level program optimizations
 | 
				
			||||||
- programs can be run multiple times without reloading because of automatic variable (re)initializations.
 | 
					 | 
				
			||||||
- conditional branches that map 1:1 to cpu status flags
 | 
					- conditional branches that map 1:1 to cpu status flags
 | 
				
			||||||
- ``when`` statement to provide a concise jump table alternative to if/elseif chains
 | 
					- ``when`` statement to provide a concise jump table alternative to if/elseif chains
 | 
				
			||||||
 | 
					- ``on .. goto`` statement for fast jump tables
 | 
				
			||||||
- ``in`` expression for concise and efficient multi-value/containment check 
 | 
					- ``in`` expression for concise and efficient multi-value/containment check 
 | 
				
			||||||
 | 
					- ``defer`` statement to help write concise and robust subroutine cleanup logic
 | 
				
			||||||
- several specialized built-in functions such as ``lsb``, ``msb``, ``min``, ``max``, ``rol``, ``ror``
 | 
					- several specialized built-in functions such as ``lsb``, ``msb``, ``min``, ``max``, ``rol``, ``ror``
 | 
				
			||||||
- various powerful built-in libraries to do I/O, number conversions, graphics and more  
 | 
					- various powerful built-in libraries to do I/O, number conversions, graphics and more  
 | 
				
			||||||
 | 
					- subroutines can return more than one result value
 | 
				
			||||||
- inline assembly allows you to have full control when every cycle or byte matters
 | 
					- inline assembly allows you to have full control when every cycle or byte matters
 | 
				
			||||||
- supports the sixteen 'virtual' 16-bit registers R0 - R15 from the Commander X16 (also available on other targets)
 | 
					- supports the sixteen 'virtual' 16-bit registers R0 - R15 from the Commander X16 (also available on other targets)
 | 
				
			||||||
- encode strings and characters into petscii or screencodes or even other encodings
 | 
					- encode strings and characters into petscii or screencodes or even other encodings
 | 
				
			||||||
 | 
					- Automatic ROM/RAM bank switching on certain compiler targets when calling routines in other banks
 | 
				
			||||||
 | 
					- 50 Kb of available program RAM size on the C64 by default; because Basic ROM is banked out altogether 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
*Rapid edit-compile-run-debug cycle:*
 | 
					*Rapid edit-compile-run-debug cycle:*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -81,11 +93,11 @@ What does Prog8 provide?
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
*Multiple supported compiler targets* (contributions to improve these or to add support for other machines are welcome!):
 | 
					*Multiple supported compiler targets* (contributions to improve these or to add support for other machines are welcome!):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- "cx16": [CommanderX16](https://www.commanderx16.com)  (65c02 CPU)
 | 
				
			||||||
- "c64": Commodore-64  (6502 like CPU)
 | 
					- "c64": Commodore-64  (6502 like CPU)
 | 
				
			||||||
- "c128": Commodore-128  (6502 like CPU - the Z80 cpu mode is not supported)
 | 
					- "c128": Commodore-128  (6502 like CPU - the Z80 cpu mode is not supported)
 | 
				
			||||||
- "cx16": [CommanderX16](https://www.commanderx16.com)  (65c02 CPU)
 | 
					- "pet32": Commodore PET (limited support)
 | 
				
			||||||
- "pet32": Commodore PET (experimental)
 | 
					- via external configurable targets: Atari 800 XL, Neo6502, NES, C64 OS, Foenix F256, ...
 | 
				
			||||||
- "atari": Atari 8 bit such as 800XL (experimental)
 | 
					 | 
				
			||||||
- If you only use standard kernal and prog8 library routines, it is possible to compile the *exact same program* for different machines (just change the compiler target flag)
 | 
					- If you only use standard kernal and prog8 library routines, it is possible to compile the *exact same program* for different machines (just change the compiler target flag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -181,3 +193,12 @@ For instance here's a well known space ship animated in 3D with hidden line remo
 | 
				
			|||||||
in the CommanderX16 emulator:
 | 
					in the CommanderX16 emulator:
 | 
				
			||||||
 | 
					
 | 
				
			||||||

 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Performance comparison with various C compilers
 | 
				
			||||||
 | 
					-----------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here is a performance comparison with various C compilers for the 6502/C64 so you can get
 | 
				
			||||||
 | 
					an idea of how Prog8 stacks up.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[comparison](benchmark-c/benchmark.md)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										24
									
								
								beanshell/beanshell.iml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								beanshell/beanshell.iml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<module type="JAVA_MODULE" version="4">
 | 
				
			||||||
 | 
					  <component name="NewModuleRootManager" inherit-compiler-output="true">
 | 
				
			||||||
 | 
					    <exclude-output />
 | 
				
			||||||
 | 
					    <content url="file://$MODULE_DIR$">
 | 
				
			||||||
 | 
					      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
 | 
				
			||||||
 | 
					      <excludeFolder url="file://$MODULE_DIR$/build" />
 | 
				
			||||||
 | 
					    </content>
 | 
				
			||||||
 | 
					    <orderEntry type="inheritedJdk" />
 | 
				
			||||||
 | 
					    <orderEntry type="sourceFolder" forTests="false" />
 | 
				
			||||||
 | 
					    <orderEntry type="library" name="KotlinJavaRuntime" level="project" />
 | 
				
			||||||
 | 
					    <orderEntry type="library" name="jetbrains.kotlinx.cli.jvm" level="project" />
 | 
				
			||||||
 | 
					    <orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
 | 
				
			||||||
 | 
					    <orderEntry type="module-library">
 | 
				
			||||||
 | 
					      <library>
 | 
				
			||||||
 | 
					        <CLASSES>
 | 
				
			||||||
 | 
					          <root url="jar://$MODULE_DIR$/lib/bsh-3.0.0-SNAPSHOT.jar!/" />
 | 
				
			||||||
 | 
					        </CLASSES>
 | 
				
			||||||
 | 
					        <JAVADOC />
 | 
				
			||||||
 | 
					        <SOURCES />
 | 
				
			||||||
 | 
					      </library>
 | 
				
			||||||
 | 
					    </orderEntry>
 | 
				
			||||||
 | 
					  </component>
 | 
				
			||||||
 | 
					</module>
 | 
				
			||||||
							
								
								
									
										65
									
								
								beanshell/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								beanshell/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					import org.jetbrains.kotlin.gradle.dsl.JvmTarget
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					    id("application")
 | 
				
			||||||
 | 
					    kotlin("jvm")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					val serverMainClassName = "prog8lsp.MainKt"
 | 
				
			||||||
 | 
					val applicationName = "prog8-beanshell"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					application {
 | 
				
			||||||
 | 
					    mainClass.set(serverMainClassName)
 | 
				
			||||||
 | 
					    description = "Code completions, diagnostics and more for Prog8"
 | 
				
			||||||
 | 
					    // applicationDefaultJvmArgs = listOf("-DkotlinLanguageServer.version=$version")
 | 
				
			||||||
 | 
					    applicationDistribution.into("bin") {
 | 
				
			||||||
 | 
					        filePermissions {
 | 
				
			||||||
 | 
					            user {
 | 
				
			||||||
 | 
					                read=true
 | 
				
			||||||
 | 
					                execute=true
 | 
				
			||||||
 | 
					                write=true
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            other.execute = true
 | 
				
			||||||
 | 
					            group.execute = true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					repositories {
 | 
				
			||||||
 | 
					    mavenCentral()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dependencies {
 | 
				
			||||||
 | 
					    implementation(files("lib/bsh-3.0.0-SNAPSHOT.jar"))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					configurations.forEach { config ->
 | 
				
			||||||
 | 
					    config.resolutionStrategy {
 | 
				
			||||||
 | 
					        preferProjectModules()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sourceSets.main {
 | 
				
			||||||
 | 
					    java.srcDir("src")
 | 
				
			||||||
 | 
					    resources.srcDir("resources")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tasks.startScripts {
 | 
				
			||||||
 | 
					    applicationName = "prog8-beanshell"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tasks.register<Exec>("fixFilePermissions") {
 | 
				
			||||||
 | 
					    // When running on macOS or Linux the start script
 | 
				
			||||||
 | 
					    // needs executable permissions to run.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    onlyIf { !System.getProperty("os.name").lowercase().contains("windows") }
 | 
				
			||||||
 | 
					    commandLine("chmod", "+x", "${tasks.installDist.get().destinationDir}/bin/prog8-beanshell")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tasks.installDist {
 | 
				
			||||||
 | 
					    finalizedBy("fixFilePermissions")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tasks.build {
 | 
				
			||||||
 | 
					    finalizedBy("installDist")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								beanshell/lib/bsh-3.0.0-SNAPSHOT.jar
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								beanshell/lib/bsh-3.0.0-SNAPSHOT.jar
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										48
									
								
								beanshell/src/prog8beanshell/CommandLineReader.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								beanshell/src/prog8beanshell/CommandLineReader.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,48 @@
 | 
				
			|||||||
 | 
					package prog8beanshell
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.FilterReader
 | 
				
			||||||
 | 
					import java.io.Reader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CommandLineReader(val input: Reader): FilterReader(input)  {
 | 
				
			||||||
 | 
					    private val normal = 0
 | 
				
			||||||
 | 
					    private val lastCharNL = 1
 | 
				
			||||||
 | 
					    private val sentSemi = 2
 | 
				
			||||||
 | 
					    private var state = lastCharNL
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun read(): Int {
 | 
				
			||||||
 | 
					        if (state == sentSemi) {
 | 
				
			||||||
 | 
					            this.state = lastCharNL
 | 
				
			||||||
 | 
					            return 10
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            var b = input.read()
 | 
				
			||||||
 | 
					            while(b==13) b = input.read()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if (b == 10) {
 | 
				
			||||||
 | 
					                if (this.state == lastCharNL) {
 | 
				
			||||||
 | 
					                    b = 59
 | 
				
			||||||
 | 
					                    this.state = sentSemi
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    this.state = lastCharNL
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                this.state = normal
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return b
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun read(buff: CharArray, off: Int, len: Int): Int {
 | 
				
			||||||
 | 
					        val b = read()
 | 
				
			||||||
 | 
					        if (b == -1) {
 | 
				
			||||||
 | 
					            return -1
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            buff[off] = b.toChar()
 | 
				
			||||||
 | 
					            return 1
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										23
									
								
								beanshell/src/prog8beanshell/Main.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								beanshell/src/prog8beanshell/Main.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					package prog8beanshell
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import bsh.FileReader
 | 
				
			||||||
 | 
					import bsh.Interpreter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class BeanshellInterpreter {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun run(symbols: Map<String, Any>) {
 | 
				
			||||||
 | 
					        val interpreter = Interpreter(CommandLineReader(FileReader(System.`in`)), System.out, System.err, true)
 | 
				
			||||||
 | 
					        interpreter.setExitOnEOF(false)
 | 
				
			||||||
 | 
					        symbols.forEach { (name, value) -> interpreter.set(name, value) }
 | 
				
			||||||
 | 
					        interpreter.run()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fun main(args: Array<String>) {
 | 
				
			||||||
 | 
					    val i = BeanshellInterpreter()
 | 
				
			||||||
 | 
					    i.run(mapOf(
 | 
				
			||||||
 | 
					        "env" to System.getenv(),
 | 
				
			||||||
 | 
					        "args" to args
 | 
				
			||||||
 | 
					    ))
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										26
									
								
								benchmark-c/benchmark.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								benchmark-c/benchmark.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					# C-Bench-64 comparison
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Several benchmarks of https://thred.github.io/c-bench-64/
 | 
				
			||||||
 | 
					have been ported to equivalent Prog8 code and the benchmark results have been penciled in in the graphs below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Maybe one day I'll try to integrate the prog8 data properly but their benchmark site is comparing C compilers, which Prog8 clearly is not.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					However conclusions so far (note: these are micro benchmarks so interpret the results as you will!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Prog8 program size is consistently the smallest by a fair bit.
 | 
				
			||||||
 | 
					* Prog8 execution speed places it more or less in the middle of the stack.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Measured with Prog8 V12.0 .
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										71
									
								
								benchmark-c/crc16.p8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								benchmark-c/crc16.p8
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,71 @@
 | 
				
			|||||||
 | 
					%import textio
 | 
				
			||||||
 | 
					%import floats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; note: Prog8 has a complete CRC16 routine in its library: math.crc16
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main {
 | 
				
			||||||
 | 
					    sub start() {
 | 
				
			||||||
 | 
					        txt.lowercase()
 | 
				
			||||||
 | 
					        test.benchmark_name()
 | 
				
			||||||
 | 
					        cbm.SETTIM(0,0,0)
 | 
				
			||||||
 | 
					        test.benchmark()
 | 
				
			||||||
 | 
					        txt.print_f(floats.time() / 60)
 | 
				
			||||||
 | 
					        txt.print(" seconds\n")
 | 
				
			||||||
 | 
					        void test.benchmark_check()
 | 
				
			||||||
 | 
					        repeat {}
 | 
				
			||||||
 | 
					    }    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const uword EXPECTED = $ffd0
 | 
				
			||||||
 | 
					    uword crc_result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark_name()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        txt.print("crc16.p8\n")
 | 
				
			||||||
 | 
					        txt.print("Calculates the CRC16 of the C64 Kernal\n")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        crc_result = CRC16($e000, $2000)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    sub benchmark_check() -> bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        txt.print("CRC=")
 | 
				
			||||||
 | 
					        txt.print_uwhex(crc_result, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if crc_result == EXPECTED
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            txt.print(" [OK]")
 | 
				
			||||||
 | 
					            return false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        txt.print(" [FAIL] - expected ")
 | 
				
			||||||
 | 
					        txt.print_uwhex(EXPECTED, true)
 | 
				
			||||||
 | 
					        return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    sub CRC16(^^ubyte data, uword length) -> uword {
 | 
				
			||||||
 | 
					        ; CRC-16/XMODEM
 | 
				
			||||||
 | 
					        uword crc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        repeat length
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            crc ^= mkword(@(data),0)     ; currently there's no easy way to affect only the MSB of the variable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            repeat 8
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                crc <<=1
 | 
				
			||||||
 | 
					                if_cs
 | 
				
			||||||
 | 
					                    crc ^= $1021
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            data++
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return crc
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										72
									
								
								benchmark-c/crc32.p8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								benchmark-c/crc32.p8
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					%import textio
 | 
				
			||||||
 | 
					%import floats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					; note: Prog8 has a complete CRC32 routine in its library: math.crc32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main {
 | 
				
			||||||
 | 
					    sub start() {
 | 
				
			||||||
 | 
					        txt.lowercase()
 | 
				
			||||||
 | 
					        test.benchmark_name()
 | 
				
			||||||
 | 
					        cbm.SETTIM(0,0,0)
 | 
				
			||||||
 | 
					        test.benchmark()
 | 
				
			||||||
 | 
					        txt.print_f(floats.time() / 60)
 | 
				
			||||||
 | 
					        txt.print(" seconds\n")
 | 
				
			||||||
 | 
					        void test.benchmark_check()
 | 
				
			||||||
 | 
					        repeat {}
 | 
				
			||||||
 | 
					    }    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const long EXPECTED = $e1fa84c6
 | 
				
			||||||
 | 
					    long crc_result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark_name()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        txt.print("crc32.p8\n")
 | 
				
			||||||
 | 
					        txt.print("Calculates the CRC32 of the C64 Kernal\n")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        crc_result = CRC32($e000, $2000)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    sub benchmark_check() -> bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        txt.print("CRC=")
 | 
				
			||||||
 | 
					        txt.print_ulhex(crc_result, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if crc_result == EXPECTED
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            txt.print(" [OK]")
 | 
				
			||||||
 | 
					            return false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        txt.print(" [FAIL] - expected ")
 | 
				
			||||||
 | 
					        txt.print_ulhex(EXPECTED, true)
 | 
				
			||||||
 | 
					        return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    sub CRC32(^^ubyte data, uword length) -> long {
 | 
				
			||||||
 | 
					        ; CRC-32/CKSUM
 | 
				
			||||||
 | 
					        long crc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        repeat length
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            crc ^= (@(data) as long)<<24     ; currently there's no easy way to affect only the MSB of the variable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            repeat 8
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                crc <<=1
 | 
				
			||||||
 | 
					                if_cs
 | 
				
			||||||
 | 
					                    crc ^= $04c11db7
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            data++
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        crc ^= $ffffffff
 | 
				
			||||||
 | 
					        return crc
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										72
									
								
								benchmark-c/crc8.p8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								benchmark-c/crc8.p8
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					%import textio
 | 
				
			||||||
 | 
					%import floats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main {
 | 
				
			||||||
 | 
					    sub start() {
 | 
				
			||||||
 | 
					        txt.lowercase()
 | 
				
			||||||
 | 
					        test.benchmark_name()
 | 
				
			||||||
 | 
					        cbm.SETTIM(0,0,0)
 | 
				
			||||||
 | 
					        test.benchmark()
 | 
				
			||||||
 | 
					        txt.print_f(floats.time() / 60)
 | 
				
			||||||
 | 
					        txt.print(" seconds\n")
 | 
				
			||||||
 | 
					        void test.benchmark_check()
 | 
				
			||||||
 | 
					        repeat {}
 | 
				
			||||||
 | 
					    }    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark_name()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        txt.print("crc8.p8\n")
 | 
				
			||||||
 | 
					        txt.print("Calculates the CRC8 of the C64 Kernal\n")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        crc_result = CRC8($e000, $2000)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    sub benchmark_check() -> bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        txt.print("CRC=")
 | 
				
			||||||
 | 
					        txt.print_ubhex(crc_result, true)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if crc_result == EXPECTED
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            txt.print(" [OK]")
 | 
				
			||||||
 | 
					            return false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        txt.print(" [FAIL] - expected ")
 | 
				
			||||||
 | 
					        txt.print_ubhex(EXPECTED, true)
 | 
				
			||||||
 | 
					        return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const ubyte EXPECTED = $a2
 | 
				
			||||||
 | 
					    ubyte crc_result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub CRC8(^^ubyte data, uword length) -> ubyte
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ; CRC-8/GSM-A
 | 
				
			||||||
 | 
					        ubyte crc
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        repeat length
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            crc ^= @(data)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            repeat 8
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                if (crc & $80) != 0
 | 
				
			||||||
 | 
					                    crc = (crc << 1) ^ $1d
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    crc <<= 1
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            data++
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return crc
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										93
									
								
								benchmark-c/pow.p8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								benchmark-c/pow.p8
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,93 @@
 | 
				
			|||||||
 | 
					%import textio
 | 
				
			||||||
 | 
					%import floats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main {
 | 
				
			||||||
 | 
					    sub start() {
 | 
				
			||||||
 | 
					        txt.lowercase()
 | 
				
			||||||
 | 
					        test.benchmark_name()
 | 
				
			||||||
 | 
					        cbm.SETTIM(0,0,0)
 | 
				
			||||||
 | 
					        test.benchmark()
 | 
				
			||||||
 | 
					        txt.print_f(floats.time() / 60)
 | 
				
			||||||
 | 
					        txt.print(" seconds\n")
 | 
				
			||||||
 | 
					        void test.benchmark_check()
 | 
				
			||||||
 | 
					        repeat {}
 | 
				
			||||||
 | 
					    }    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const ubyte N_ITER = 10
 | 
				
			||||||
 | 
					    const ubyte SIZE = 32
 | 
				
			||||||
 | 
					    float[SIZE] array
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const float expected = 3614007361536.000000
 | 
				
			||||||
 | 
					    const float epsilon = 10000000
 | 
				
			||||||
 | 
					    float res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark_name()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        txt.print("pow.p8\n")
 | 
				
			||||||
 | 
					        txt.print("Calculates floating point exponential (")
 | 
				
			||||||
 | 
					        txt.print_uw(N_ITER)
 | 
				
			||||||
 | 
					        txt.print(" iterations)\n")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        ubyte i,j
 | 
				
			||||||
 | 
					        res = 0
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for j in 0 to SIZE-1 {
 | 
				
			||||||
 | 
					            array[j]=0
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for i in 0 to N_ITER-1 {
 | 
				
			||||||
 | 
					            for j in 0 to SIZE-1 {
 | 
				
			||||||
 | 
					                array[j] += testpow(2.5 / ((i + 1) as float), j)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for j in 0 to SIZE-1 {
 | 
				
			||||||
 | 
					            res += array[j]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub testpow(float x, ubyte y) -> float
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        float tmp = x
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        if y == 0
 | 
				
			||||||
 | 
					            return 1
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        repeat y-1
 | 
				
			||||||
 | 
					            tmp *= x
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        return tmp
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark_check() -> bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        txt.print("res      = ")
 | 
				
			||||||
 | 
					        txt.print_f(res)
 | 
				
			||||||
 | 
					        float diff = expected - res;
 | 
				
			||||||
 | 
					        txt.print("\nexpected = ")
 | 
				
			||||||
 | 
					        txt.print_f(expected)
 | 
				
			||||||
 | 
					        txt.print("\nepsilon  = ")
 | 
				
			||||||
 | 
					        txt.print_f(epsilon)
 | 
				
			||||||
 | 
					        txt.print("\ndiff     = ")
 | 
				
			||||||
 | 
					        txt.print_f(diff)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (diff < epsilon and diff > -epsilon)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            txt.print(" [OK]\n")
 | 
				
			||||||
 | 
					            return false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        txt.print("[FAIL]\n")
 | 
				
			||||||
 | 
					        return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								benchmark-c/result-crc16.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								benchmark-c/result-crc16.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 78 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								benchmark-c/result-crc32.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								benchmark-c/result-crc32.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 80 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								benchmark-c/result-crc8.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								benchmark-c/result-crc8.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 79 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								benchmark-c/result-pow.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								benchmark-c/result-pow.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 74 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								benchmark-c/result-sieve-bit.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								benchmark-c/result-sieve-bit.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 85 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								benchmark-c/result-sieve.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								benchmark-c/result-sieve.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 82 KiB  | 
							
								
								
									
										85
									
								
								benchmark-c/sieve.p8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								benchmark-c/sieve.p8
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,85 @@
 | 
				
			|||||||
 | 
					%import textio
 | 
				
			||||||
 | 
					%import floats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main {
 | 
				
			||||||
 | 
					    sub start() {
 | 
				
			||||||
 | 
					        txt.lowercase()
 | 
				
			||||||
 | 
					        test.benchmark_name()
 | 
				
			||||||
 | 
					        cbm.SETTIM(0,0,0)
 | 
				
			||||||
 | 
					        test.benchmark()
 | 
				
			||||||
 | 
					        txt.print_f(floats.time() / 60)
 | 
				
			||||||
 | 
					        txt.print(" seconds\n")
 | 
				
			||||||
 | 
					        void test.benchmark_check()
 | 
				
			||||||
 | 
					        repeat {}
 | 
				
			||||||
 | 
					    }    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test {
 | 
				
			||||||
 | 
					    const ubyte N_ITER = 10
 | 
				
			||||||
 | 
					    const uword SIZE = 8191
 | 
				
			||||||
 | 
					    const uword EXPECTED = 1900
 | 
				
			||||||
 | 
					    uword prime_count
 | 
				
			||||||
 | 
					    ^^bool @zp flags = memory("flags", SIZE, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark_name()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        txt.print("sieve.c\n")
 | 
				
			||||||
 | 
					        txt.print("Calculates the primes from 1 to ")
 | 
				
			||||||
 | 
					        txt.print_uw(SIZE * 2 + 2)
 | 
				
			||||||
 | 
					        txt.print(" (")
 | 
				
			||||||
 | 
					        txt.print_ub(N_ITER)
 | 
				
			||||||
 | 
					        txt.print(" iterations)\n")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        repeat N_ITER
 | 
				
			||||||
 | 
					            prime_count = sieve(SIZE)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    sub benchmark_check() -> bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        txt.print("count=")
 | 
				
			||||||
 | 
					        txt.print_uw(prime_count)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if prime_count == EXPECTED
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            txt.print(" [OK]")
 | 
				
			||||||
 | 
					            return false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        txt.print(" [FAIL] - expected ")
 | 
				
			||||||
 | 
					        txt.print_uw(EXPECTED)
 | 
				
			||||||
 | 
					        return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    sub sieve(uword size) -> uword 
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        uword i, prime, k
 | 
				
			||||||
 | 
					        uword count = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for i in 0 to size-1
 | 
				
			||||||
 | 
					            flags[i] = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for i in 0 to size-1 
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if flags[i]
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                prime = i + i + 3
 | 
				
			||||||
 | 
					                k = i + prime
 | 
				
			||||||
 | 
					                while k < size
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    flags[k] = false
 | 
				
			||||||
 | 
					                    k += prime
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                count++
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        return count
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										107
									
								
								benchmark-c/sieve_bit.p8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								benchmark-c/sieve_bit.p8
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					%import textio
 | 
				
			||||||
 | 
					%import floats
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main {
 | 
				
			||||||
 | 
					    sub start() {
 | 
				
			||||||
 | 
					        txt.lowercase()
 | 
				
			||||||
 | 
					        test.benchmark_name()
 | 
				
			||||||
 | 
					        cbm.SETTIM(0,0,0)
 | 
				
			||||||
 | 
					        test.benchmark()
 | 
				
			||||||
 | 
					        txt.print_f(floats.time() / 60)
 | 
				
			||||||
 | 
					        txt.print(" seconds\n")
 | 
				
			||||||
 | 
					        void test.benchmark_check()
 | 
				
			||||||
 | 
					        repeat {}
 | 
				
			||||||
 | 
					    }    
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test {
 | 
				
			||||||
 | 
					    const ubyte N_ITER = 4
 | 
				
			||||||
 | 
					    const uword SIZE = 16000
 | 
				
			||||||
 | 
					    const uword EXPECTED = 3432
 | 
				
			||||||
 | 
					    uword prime_count
 | 
				
			||||||
 | 
					    ^^ubyte @zp flags = memory("flags", SIZE/8+1, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark_name()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        txt.print("sieve_bit.p8\n")
 | 
				
			||||||
 | 
					        txt.print("Calculates the primes from 1 to ")
 | 
				
			||||||
 | 
					        txt.print_uw(SIZE * 2 + 2)
 | 
				
			||||||
 | 
					        txt.print(" (")
 | 
				
			||||||
 | 
					        txt.print_ub(N_ITER)
 | 
				
			||||||
 | 
					        txt.print(" iterations)\n")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        repeat N_ITER
 | 
				
			||||||
 | 
					            prime_count = sieve(SIZE)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    sub benchmark_check() -> bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        txt.print("count=")
 | 
				
			||||||
 | 
					        txt.print_uw(prime_count)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if prime_count == EXPECTED
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            txt.print(" [OK]")
 | 
				
			||||||
 | 
					            return false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        txt.print(" [FAIL] - expected ")
 | 
				
			||||||
 | 
					        txt.print_uw(EXPECTED)
 | 
				
			||||||
 | 
					        return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ubyte[] bitv = [
 | 
				
			||||||
 | 
					        $01,    
 | 
				
			||||||
 | 
					        $02,
 | 
				
			||||||
 | 
					        $04,
 | 
				
			||||||
 | 
					        $08,
 | 
				
			||||||
 | 
					        $10,
 | 
				
			||||||
 | 
					        $20,
 | 
				
			||||||
 | 
					        $40,
 | 
				
			||||||
 | 
					        $80
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub check_flag(uword idx) -> bool
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return flags[idx / 8] & bitv[lsb(idx) & 7] != 0
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub clear_flag(uword idx)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        flags[idx / 8] &= ~(bitv[lsb(idx) & 7])
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    sub sieve(uword size) -> uword 
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        uword i, prime, k
 | 
				
			||||||
 | 
					        uword count=1
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        for i in 0 to (size / 8)
 | 
				
			||||||
 | 
					            flags[i] = $ff
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for i in 0 to size-1
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if check_flag(i)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                prime = i + i + 3
 | 
				
			||||||
 | 
					                k = i + prime;
 | 
				
			||||||
 | 
					                while k < size
 | 
				
			||||||
 | 
					                {
 | 
				
			||||||
 | 
					                    clear_flag(k)
 | 
				
			||||||
 | 
					                    k += prime
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                count++
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					        return count
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,12 +1,10 @@
 | 
				
			|||||||
.PHONY:  all clean emu
 | 
					.PHONY:  clean run
 | 
				
			||||||
 | 
					
 | 
				
			||||||
all:  benchmark.prg
 | 
					run:
 | 
				
			||||||
 | 
						prog8c -target cx16 benchmark.p8
 | 
				
			||||||
 | 
						x16emu -run -prg benchmark.prg -warp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean:
 | 
					clean:
 | 
				
			||||||
	rm -f *.prg *.PRG *.asm *.vice-* *.BIN *.PAL *.zip *.7z
 | 
						rm -f *.prg *.PRG *.asm *.vice-* *.BIN *.PAL *.zip *.7z
 | 
				
			||||||
 | 
					
 | 
				
			||||||
emu:  benchmark.prg
 | 
					 | 
				
			||||||
	x16emu -run -prg $< -warp
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
benchmark.prg: benchmark.p8 b_3d.p8 b_adpcm.p8 b_circles.p8 b_life.p8 b_mandelbrot.p8 b_maze.p8 b_queens.p8 b_textelite.p8
 | 
					 | 
				
			||||||
	p8compile $< -target cx16 
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,14 +64,14 @@ rotate3d {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
matrix_math {
 | 
					matrix_math {
 | 
				
			||||||
    ; vertices
 | 
					    ; vertices
 | 
				
			||||||
    word[] @split xcoor = [ -40, -40, -40, -40,  40,  40,  40, 40 ]
 | 
					    word[] xcoor = [ -40, -40, -40, -40,  40,  40,  40, 40 ]
 | 
				
			||||||
    word[] @split ycoor = [ -40, -40,  40,  40, -40, -40,  40, 40 ]
 | 
					    word[] ycoor = [ -40, -40,  40,  40, -40, -40,  40, 40 ]
 | 
				
			||||||
    word[] @split zcoor = [ -40,  40, -40,  40, -40,  40, -40, 40 ]
 | 
					    word[] zcoor = [ -40,  40, -40,  40, -40,  40, -40, 40 ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ; storage for rotated coordinates
 | 
					    ; storage for rotated coordinates
 | 
				
			||||||
    word[len(xcoor)] @split rotatedx
 | 
					    word[len(xcoor)] rotatedx
 | 
				
			||||||
    word[len(ycoor)] @split rotatedy
 | 
					    word[len(ycoor)] rotatedy
 | 
				
			||||||
    word[len(zcoor)] @split rotatedz
 | 
					    word[len(zcoor)] rotatedz
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sub rotate_vertices(ubyte ax, ubyte ay, ubyte az) {
 | 
					    sub rotate_vertices(ubyte ax, ubyte ay, ubyte az) {
 | 
				
			||||||
        ; rotate around origin (0,0,0)
 | 
					        ; rotate around origin (0,0,0)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -25,8 +25,8 @@ adpcm {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    ; IMA ADPCM decoder.  Supports mono and stereo streams.
 | 
					    ; IMA ADPCM decoder.  Supports mono and stereo streams.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ubyte[] t_index = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8]
 | 
					    byte[] t_index = [ -1, -1, -1, -1, 2, 4, 6, 8, -1, -1, -1, -1, 2, 4, 6, 8]
 | 
				
			||||||
    uword[] @split t_step = [
 | 
					    uword[] t_step = [
 | 
				
			||||||
            7, 8, 9, 10, 11, 12, 13, 14,
 | 
					            7, 8, 9, 10, 11, 12, 13, 14,
 | 
				
			||||||
            16, 17, 19, 21, 23, 25, 28, 31,
 | 
					            16, 17, 19, 21, 23, 25, 28, 31,
 | 
				
			||||||
            34, 37, 41, 45, 50, 55, 60, 66,
 | 
					            34, 37, 41, 45, 50, 55, 60, 66,
 | 
				
			||||||
@@ -79,7 +79,7 @@ adpcm {
 | 
				
			|||||||
        ; elif predicted < -32767:
 | 
					        ; elif predicted < -32767:
 | 
				
			||||||
        ;    predicted = - 32767
 | 
					        ;    predicted = - 32767
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        index += t_index[nibble]
 | 
					        index += t_index[nibble] as ubyte
 | 
				
			||||||
        if_neg
 | 
					        if_neg
 | 
				
			||||||
            index = 0
 | 
					            index = 0
 | 
				
			||||||
        else if index >= len(t_step)-1
 | 
					        else if index >= len(t_step)-1
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										234
									
								
								benchmark-program/b_btree.p8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								benchmark-program/b_btree.p8
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,234 @@
 | 
				
			|||||||
 | 
					; Binary Search Tree.
 | 
				
			||||||
 | 
					; It's a simple implementation for test/demonstration purposes of the pointer support;
 | 
				
			||||||
 | 
					; no balancing is done and memory is not freed when elements are removed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					%import textio
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					btree {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark(uword max_time) -> uword {
 | 
				
			||||||
 | 
					        txt.nl()
 | 
				
			||||||
 | 
					        cbm.SETTIM(0,0,0)
 | 
				
			||||||
 | 
					        uword score
 | 
				
			||||||
 | 
					        while cbm.RDTIM16() < max_time {
 | 
				
			||||||
 | 
					            bench_operations()
 | 
				
			||||||
 | 
					            txt.chrout('.')
 | 
				
			||||||
 | 
					            score++
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        txt.nl()
 | 
				
			||||||
 | 
					        return score
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub bench_operations() {
 | 
				
			||||||
 | 
					        arena.freeall()
 | 
				
			||||||
 | 
					        btree.root = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for cx16.r0 in [321, 719, 194, 550, 187, 203, 520, 562, 221, 676, 97, 852, 273, 326, 589, 606, 275, 794, 63, 716]
 | 
				
			||||||
 | 
					            btree.add(cx16.r0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cx16.r0L = btree.size()
 | 
				
			||||||
 | 
					        btree.process_tree_inorder()
 | 
				
			||||||
 | 
					        btree.process_tree_preorder()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        void btree.contains(203)
 | 
				
			||||||
 | 
					        void btree.contains(204)
 | 
				
			||||||
 | 
					        void btree.contains(605)
 | 
				
			||||||
 | 
					        void btree.contains(606)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        btree.remove(9999)
 | 
				
			||||||
 | 
					        btree.remove(97)
 | 
				
			||||||
 | 
					        btree.remove(187)
 | 
				
			||||||
 | 
					        btree.remove(203)
 | 
				
			||||||
 | 
					        btree.remove(275)
 | 
				
			||||||
 | 
					        btree.remove(321)
 | 
				
			||||||
 | 
					        btree.remove(520)
 | 
				
			||||||
 | 
					        btree.remove(562)
 | 
				
			||||||
 | 
					        btree.remove(606)
 | 
				
			||||||
 | 
					        btree.remove(719)
 | 
				
			||||||
 | 
					        btree.remove(794)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cx16.r0L = btree.size()
 | 
				
			||||||
 | 
					        btree.process_tree_inorder()
 | 
				
			||||||
 | 
					        btree.process_tree_preorder()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    struct Node {
 | 
				
			||||||
 | 
					        ^^Node left
 | 
				
			||||||
 | 
					        ^^Node right
 | 
				
			||||||
 | 
					        uword value
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ^^Node root = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub add(uword value) {
 | 
				
			||||||
 | 
					        ^^Node node = arena.alloc(sizeof(Node))
 | 
				
			||||||
 | 
					        node.value = value
 | 
				
			||||||
 | 
					        node.left = node.right = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if root==0
 | 
				
			||||||
 | 
					            root=node
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            ^^Node parent = root
 | 
				
			||||||
 | 
					            repeat {
 | 
				
			||||||
 | 
					                if parent.value >= value {
 | 
				
			||||||
 | 
					                    if parent.left!=0
 | 
				
			||||||
 | 
					                        parent = parent.left
 | 
				
			||||||
 | 
					                    else {
 | 
				
			||||||
 | 
					                        parent.left = node
 | 
				
			||||||
 | 
					                        return
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    if parent.right!=0
 | 
				
			||||||
 | 
					                        parent = parent.right
 | 
				
			||||||
 | 
					                    else {
 | 
				
			||||||
 | 
					                        parent.right = node
 | 
				
			||||||
 | 
					                        return
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub contains(uword value) -> bool {
 | 
				
			||||||
 | 
					        ^^Node r = root
 | 
				
			||||||
 | 
					        while r!=0 {
 | 
				
			||||||
 | 
					            if r.value==value
 | 
				
			||||||
 | 
					                return true
 | 
				
			||||||
 | 
					            if r.value>value
 | 
				
			||||||
 | 
					                r = r.left
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                r = r.right
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub size() -> ubyte {
 | 
				
			||||||
 | 
					        ubyte count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if root!=0
 | 
				
			||||||
 | 
					            count_node(root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return count
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sub count_node(^^Node r) {
 | 
				
			||||||
 | 
					            count++
 | 
				
			||||||
 | 
					            if r.left!=0 {
 | 
				
			||||||
 | 
					                sys.pushw(r)
 | 
				
			||||||
 | 
					                count_node(r.left)
 | 
				
			||||||
 | 
					                r = sys.popw()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if r.right!=0 {
 | 
				
			||||||
 | 
					                sys.pushw(r)
 | 
				
			||||||
 | 
					                count_node(r.right)
 | 
				
			||||||
 | 
					                r = sys.popw()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub remove(uword value) {
 | 
				
			||||||
 | 
					        ; note: we don't deallocate the memory from the node, for simplicity sake
 | 
				
			||||||
 | 
					        ^^Node n = root
 | 
				
			||||||
 | 
					        ^^Node parent = 0
 | 
				
			||||||
 | 
					        while n!=0 {
 | 
				
			||||||
 | 
					            if n.value==value {
 | 
				
			||||||
 | 
					                if n.left==0
 | 
				
			||||||
 | 
					                    replacechild(parent, n, n.right)
 | 
				
			||||||
 | 
					                else if n.right==0
 | 
				
			||||||
 | 
					                    replacechild(parent, n, n.left)
 | 
				
			||||||
 | 
					                else {
 | 
				
			||||||
 | 
					                    ; Both left & right subtrees are present.
 | 
				
			||||||
 | 
					                    ; N = node to delete.
 | 
				
			||||||
 | 
					                    ;    Find N's successor S. (N's right subtree's minimum element)
 | 
				
			||||||
 | 
					                    ;    Attach N's left subtree to S.left (S doesn't have a left child)
 | 
				
			||||||
 | 
					                    ;    Attach N's right subtree to Parent in place of N.
 | 
				
			||||||
 | 
					                    ^^Node successor = find_successor(n)
 | 
				
			||||||
 | 
					                    successor.left = n.left
 | 
				
			||||||
 | 
					                    replacechild(parent, n, n.right)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            parent = n
 | 
				
			||||||
 | 
					            if n.value>value
 | 
				
			||||||
 | 
					                n = n.left
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                n = n.right
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sub find_successor(^^Node p) -> ^^Node {
 | 
				
			||||||
 | 
					            ^^Node succ = p
 | 
				
			||||||
 | 
					            p = p.right
 | 
				
			||||||
 | 
					            while p!=0 {
 | 
				
			||||||
 | 
					                succ = p
 | 
				
			||||||
 | 
					                p = p.left
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return succ
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sub replacechild(^^Node p, ^^Node child, ^^Node newchild) {
 | 
				
			||||||
 | 
					            if p.left==child
 | 
				
			||||||
 | 
					                p.left = newchild
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                p.right = newchild
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub process_tree_inorder() {
 | 
				
			||||||
 | 
					        if root!=0
 | 
				
			||||||
 | 
					            process_tree(root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sub process_tree(^^Node r) {
 | 
				
			||||||
 | 
					            if r.left!=0 {
 | 
				
			||||||
 | 
					                sys.pushw(r)
 | 
				
			||||||
 | 
					                process_tree(r.left)
 | 
				
			||||||
 | 
					                r = sys.popw()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            cx16.r0 = r.value
 | 
				
			||||||
 | 
					            if r.right!=0 {
 | 
				
			||||||
 | 
					                sys.pushw(r)
 | 
				
			||||||
 | 
					                process_tree(r.right)
 | 
				
			||||||
 | 
					                r = sys.popw()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub process_tree_preorder() {
 | 
				
			||||||
 | 
					        if root!=0
 | 
				
			||||||
 | 
					            process_tree(root,0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sub process_tree(^^Node r, ubyte depth) {
 | 
				
			||||||
 | 
					            cx16.r0 = r.value
 | 
				
			||||||
 | 
					            if r.left!=0 {
 | 
				
			||||||
 | 
					                sys.pushw(r)
 | 
				
			||||||
 | 
					                sys.push(depth)
 | 
				
			||||||
 | 
					                process_tree(r.left, depth+1)
 | 
				
			||||||
 | 
					                depth = sys.pop()
 | 
				
			||||||
 | 
					                r = sys.popw()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if r.right!=0 {
 | 
				
			||||||
 | 
					                sys.pushw(r)
 | 
				
			||||||
 | 
					                sys.push(depth)
 | 
				
			||||||
 | 
					                process_tree(r.right, depth+1)
 | 
				
			||||||
 | 
					                depth = sys.pop()
 | 
				
			||||||
 | 
					                r = sys.popw()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					arena {
 | 
				
			||||||
 | 
					    ; extremely trivial arena allocator (that never frees)
 | 
				
			||||||
 | 
					    uword buffer = memory("arena", 2000, 0)
 | 
				
			||||||
 | 
					    uword next = buffer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub alloc(ubyte size) -> uword {
 | 
				
			||||||
 | 
					        defer next += size
 | 
				
			||||||
 | 
					        return next
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub freeall() {
 | 
				
			||||||
 | 
					        next = buffer
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,20 +1,20 @@
 | 
				
			|||||||
%import gfx2
 | 
					%import gfx_lores
 | 
				
			||||||
%import math
 | 
					%import math
 | 
				
			||||||
 | 
					
 | 
				
			||||||
circles {
 | 
					circles {
 | 
				
			||||||
    const ubyte MAX_NUM_CIRCLES = 80
 | 
					    const ubyte MAX_NUM_CIRCLES = 80
 | 
				
			||||||
    const ubyte GROWTH_RATE = 4
 | 
					    const ubyte GROWTH_RATE = 4
 | 
				
			||||||
    uword[MAX_NUM_CIRCLES] @split circle_x
 | 
					    uword[MAX_NUM_CIRCLES] circle_x
 | 
				
			||||||
    uword[MAX_NUM_CIRCLES] @split circle_y
 | 
					    uword[MAX_NUM_CIRCLES] circle_y
 | 
				
			||||||
    ubyte[MAX_NUM_CIRCLES] circle_radius
 | 
					    ubyte[MAX_NUM_CIRCLES] circle_radius
 | 
				
			||||||
    ubyte color
 | 
					    ubyte color
 | 
				
			||||||
    uword total_num_circles
 | 
					    uword total_num_circles
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    sub draw(bool use_kernal, uword max_time) -> uword {
 | 
					    sub draw(bool use_kernal, uword max_time) -> uword {
 | 
				
			||||||
        if use_kernal
 | 
					        if use_kernal
 | 
				
			||||||
            void cx16.set_screen_mode(128)
 | 
					            cx16.set_screen_mode(128)
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            gfx2.screen_mode(1)
 | 
					            gfx_lores.graphics_mode()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        math.rndseed(12345,6789)
 | 
					        math.rndseed(12345,6789)
 | 
				
			||||||
        cbm.SETTIM(0,0,0)
 | 
					        cbm.SETTIM(0,0,0)
 | 
				
			||||||
@@ -28,14 +28,14 @@ circles {
 | 
				
			|||||||
                cx16.GRAPH_clear()
 | 
					                cx16.GRAPH_clear()
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                gfx2.clear_screen(0)
 | 
					                gfx_lores.clear_screen(0)
 | 
				
			||||||
            total_num_circles += draw_circles(use_kernal, max_time)
 | 
					            total_num_circles += draw_circles(use_kernal, max_time)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if use_kernal
 | 
					        if use_kernal
 | 
				
			||||||
            void cx16.set_screen_mode(3)
 | 
					            cx16.set_screen_mode(3)
 | 
				
			||||||
        else {
 | 
					        else {
 | 
				
			||||||
            gfx2.screen_mode(0)
 | 
					            gfx_lores.text_mode()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return total_num_circles
 | 
					        return total_num_circles
 | 
				
			||||||
@@ -66,7 +66,7 @@ circles {
 | 
				
			|||||||
                        cx16.GRAPH_draw_oval(x-radius, y-radius, radius*2, radius*2, true)
 | 
					                        cx16.GRAPH_draw_oval(x-radius, y-radius, radius*2, radius*2, true)
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    else
 | 
					                    else
 | 
				
			||||||
                        gfx2.disc(x, y as ubyte, radius, color)
 | 
					                        gfx_lores.disc(x, y as ubyte, radius, color)
 | 
				
			||||||
                    circle_x[num_circles] = x
 | 
					                    circle_x[num_circles] = x
 | 
				
			||||||
                    circle_y[num_circles] = y
 | 
					                    circle_y[num_circles] = y
 | 
				
			||||||
                    circle_radius[num_circles] = radius
 | 
					                    circle_radius[num_circles] = radius
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										69
									
								
								benchmark-program/b_sprites.p8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								benchmark-program/b_sprites.p8
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,69 @@
 | 
				
			|||||||
 | 
					%import sprites
 | 
				
			||||||
 | 
					%import coroutines
 | 
				
			||||||
 | 
					%import math
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					animsprites {
 | 
				
			||||||
 | 
					    uword num_iterations
 | 
				
			||||||
 | 
					    ubyte[64] sx
 | 
				
			||||||
 | 
					    ubyte[64] sy
 | 
				
			||||||
 | 
					    ubyte[64] sc
 | 
				
			||||||
 | 
					    ubyte[64] dx
 | 
				
			||||||
 | 
					    ubyte[64] dy
 | 
				
			||||||
 | 
					    uword maximum_duration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub benchmark(uword max_duration) -> uword {
 | 
				
			||||||
 | 
					        maximum_duration = max_duration
 | 
				
			||||||
 | 
					        math.rndseed(1122,9876)
 | 
				
			||||||
 | 
					        cx16.set_screen_mode(3)
 | 
				
			||||||
 | 
					        cx16.mouse_config2(1)
 | 
				
			||||||
 | 
					        sprites.set_mousepointer_hand()
 | 
				
			||||||
 | 
					        repeat 64
 | 
				
			||||||
 | 
					            void coroutines.add(animsprite, 0)
 | 
				
			||||||
 | 
					        cx16.mouse_config2(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        cbm.SETTIM(0,0,0)
 | 
				
			||||||
 | 
					        coroutines.run(supervisor)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sprites.reset(0, 64)
 | 
				
			||||||
 | 
					        return num_iterations
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub supervisor() -> bool {
 | 
				
			||||||
 | 
					        if cbm.RDTIM16() >= maximum_duration {
 | 
				
			||||||
 | 
					            coroutines.killall()
 | 
				
			||||||
 | 
					            return false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sub animsprite() {
 | 
				
			||||||
 | 
					        num_iterations++
 | 
				
			||||||
 | 
					        ; set up the sprite
 | 
				
			||||||
 | 
					        ubyte sprnum = coroutines.current()
 | 
				
			||||||
 | 
					        cx16.r6L, cx16.r7 = sprites.get_data_ptr(0)
 | 
				
			||||||
 | 
					        sprites.init(sprnum, cx16.r6L, cx16.r7, sprites.SIZE_16, sprites.SIZE_16, sprites.COLORS_256, 0)
 | 
				
			||||||
 | 
					        sx[sprnum] = math.rnd()
 | 
				
			||||||
 | 
					        sy[sprnum] = math.rnd()
 | 
				
			||||||
 | 
					        sc[sprnum] = math.rnd()
 | 
				
			||||||
 | 
					        dx[sprnum] = if math.rnd()&1 == 1  1 else 255
 | 
				
			||||||
 | 
					        dy[sprnum] = if math.rnd()&1 == 1  1 else 255
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ; move the sprite around
 | 
				
			||||||
 | 
					        while sc[sprnum]!=0 {
 | 
				
			||||||
 | 
					            animate(sprnum)
 | 
				
			||||||
 | 
					            void coroutines.yield()
 | 
				
			||||||
 | 
					            sprnum = coroutines.current()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sub animate(ubyte spr) {
 | 
				
			||||||
 | 
					            defer sc[spr]--
 | 
				
			||||||
 | 
					            sprites.pos(spr, sx[spr], sy[spr])
 | 
				
			||||||
 | 
					            sx[spr] += dx[spr]
 | 
				
			||||||
 | 
					            sy[spr] += dy[spr]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ; end the task but replace it with a fresh animated sprite task
 | 
				
			||||||
 | 
					        void coroutines.add(animsprite, 0)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,7 +1,6 @@
 | 
				
			|||||||
%import textio
 | 
					%import textio
 | 
				
			||||||
%import conv
 | 
					%import conv
 | 
				
			||||||
%import string
 | 
					%import strings
 | 
				
			||||||
%import string
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
textelite {
 | 
					textelite {
 | 
				
			||||||
@@ -172,7 +171,7 @@ textelite {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    sub next_input(str buffer) -> ubyte {
 | 
					    sub next_input(str buffer) -> ubyte {
 | 
				
			||||||
        input_index++
 | 
					        input_index++
 | 
				
			||||||
        return string.copy(inputs[input_index], buffer)
 | 
					        return strings.copy(inputs[input_index], buffer)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -571,7 +570,7 @@ elite_galaxy {
 | 
				
			|||||||
            ubyte distance = elite_planet.distance(px, py)
 | 
					            ubyte distance = elite_planet.distance(px, py)
 | 
				
			||||||
            if distance <= max_distance {
 | 
					            if distance <= max_distance {
 | 
				
			||||||
                elite_planet.name = make_current_planet_name()
 | 
					                elite_planet.name = make_current_planet_name()
 | 
				
			||||||
                elite_planet.name[0] = string.upperchar(elite_planet.name[0])
 | 
					                elite_planet.name[0] = strings.upperchar(elite_planet.name[0])
 | 
				
			||||||
                uword tx = elite_planet.x
 | 
					                uword tx = elite_planet.x
 | 
				
			||||||
                uword ty = elite_planet.y
 | 
					                uword ty = elite_planet.y
 | 
				
			||||||
                if local {
 | 
					                if local {
 | 
				
			||||||
@@ -743,42 +742,42 @@ elite_galaxy {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
elite_planet {
 | 
					elite_planet {
 | 
				
			||||||
    str[] words81 = ["fabled", "notable", "well known", "famous", "noted"]
 | 
					    str[] @nosplit words81 = ["fabled", "notable", "well known", "famous", "noted"]
 | 
				
			||||||
    str[] words82 = ["very", "mildly", "most", "reasonably", ""]
 | 
					    str[] @nosplit words82 = ["very", "mildly", "most", "reasonably", ""]
 | 
				
			||||||
    str[] words83 = ["ancient", "\x95", "great", "vast", "pink"]
 | 
					    str[] @nosplit words83 = ["ancient", "\x95", "great", "vast", "pink"]
 | 
				
			||||||
    str[] words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
 | 
					    str[] @nosplit words84 = ["\x9E \x9D plantations", "mountains", "\x9C", "\x94 forests", "oceans"]
 | 
				
			||||||
    str[] words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
 | 
					    str[] @nosplit words85 = ["shyness", "silliness", "mating traditions", "loathing of \x86", "love for \x86"]
 | 
				
			||||||
    str[] words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
 | 
					    str[] @nosplit words86 = ["food blenders", "tourists", "poetry", "discos", "\x8E"]
 | 
				
			||||||
    str[] words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
 | 
					    str[] @nosplit words87 = ["talking tree", "crab", "bat", "lobst", "\xB2"]
 | 
				
			||||||
    str[] words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
 | 
					    str[] @nosplit words88 = ["beset", "plagued", "ravaged", "cursed", "scourged"]
 | 
				
			||||||
    str[] words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
 | 
					    str[] @nosplit words89 = ["\x96 civil war", "\x9B \x98 \x99s", "a \x9B disease", "\x96 earthquakes", "\x96 solar activity"]
 | 
				
			||||||
    str[] words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
 | 
					    str[] @nosplit words8A = ["its \x83 \x84", "the \xB1 \x98 \x99", "its inhabitants' \x9A \x85", "\xA1", "its \x8D \x8E"]
 | 
				
			||||||
    str[] words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
 | 
					    str[] @nosplit words8B = ["juice", "brandy", "water", "brew", "gargle blasters"]
 | 
				
			||||||
    str[] words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
 | 
					    str[] @nosplit words8C = ["\xB2", "\xB1 \x99", "\xB1 \xB2", "\xB1 \x9B", "\x9B \xB2"]
 | 
				
			||||||
    str[] words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
 | 
					    str[] @nosplit words8D = ["fabulous", "exotic", "hoopy", "unusual", "exciting"]
 | 
				
			||||||
    str[] words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
 | 
					    str[] @nosplit words8E = ["cuisine", "night life", "casinos", "sit coms", " \xA1 "]
 | 
				
			||||||
    str[] words8F = ["\xB0", "The planet \xB0", "The world \xB0", "This planet", "This world"]
 | 
					    str[] @nosplit words8F = ["\xB0", "The planet \xB0", "The world \xB0", "This planet", "This world"]
 | 
				
			||||||
    str[] words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
 | 
					    str[] @nosplit words90 = ["n unremarkable", " boring", " dull", " tedious", " revolting"]
 | 
				
			||||||
    str[] words91 = ["planet", "world", "place", "little planet", "dump"]
 | 
					    str[] @nosplit words91 = ["planet", "world", "place", "little planet", "dump"]
 | 
				
			||||||
    str[] words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
 | 
					    str[] @nosplit words92 = ["wasp", "moth", "grub", "ant", "\xB2"]
 | 
				
			||||||
    str[] words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
 | 
					    str[] @nosplit words93 = ["poet", "arts graduate", "yak", "snail", "slug"]
 | 
				
			||||||
    str[] words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
 | 
					    str[] @nosplit words94 = ["tropical", "dense", "rain", "impenetrable", "exuberant"]
 | 
				
			||||||
    str[] words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
 | 
					    str[] @nosplit words95 = ["funny", "wierd", "unusual", "strange", "peculiar"]
 | 
				
			||||||
    str[] words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
 | 
					    str[] @nosplit words96 = ["frequent", "occasional", "unpredictable", "dreadful", "deadly"]
 | 
				
			||||||
    str[] words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
 | 
					    str[] @nosplit words97 = ["\x82 \x81 for \x8A", "\x82 \x81 for \x8A and \x8A", "\x88 by \x89", "\x82 \x81 for \x8A but \x88 by \x89", "a\x90 \x91"]
 | 
				
			||||||
    str[] words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
 | 
					    str[] @nosplit words98 = ["\x9B", "mountain", "edible", "tree", "spotted"]
 | 
				
			||||||
    str[] words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
 | 
					    str[] @nosplit words99 = ["\x9F", "\xA0", "\x87oid", "\x93", "\x92"]
 | 
				
			||||||
    str[] words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
 | 
					    str[] @nosplit words9A = ["ancient", "exceptional", "eccentric", "ingrained", "\x95"]
 | 
				
			||||||
    str[] words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
 | 
					    str[] @nosplit words9B = ["killer", "deadly", "evil", "lethal", "vicious"]
 | 
				
			||||||
    str[] words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
 | 
					    str[] @nosplit words9C = ["parking meters", "dust clouds", "ice bergs", "rock formations", "volcanoes"]
 | 
				
			||||||
    str[] words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
 | 
					    str[] @nosplit words9D = ["plant", "tulip", "banana", "corn", "\xB2weed"]
 | 
				
			||||||
    str[] words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
 | 
					    str[] @nosplit words9E = ["\xB2", "\xB1 \xB2", "\xB1 \x9B", "inhabitant", "\xB1 \xB2"]
 | 
				
			||||||
    str[] words9F = ["shrew", "beast", "bison", "snake", "wolf"]
 | 
					    str[] @nosplit words9F = ["shrew", "beast", "bison", "snake", "wolf"]
 | 
				
			||||||
    str[] wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
 | 
					    str[] @nosplit wordsA0 = ["leopard", "cat", "monkey", "goat", "fish"]
 | 
				
			||||||
    str[] wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
 | 
					    str[] @nosplit wordsA1 = ["\x8C \x8B", "\xB1 \x9F \xA2", "its \x8D \xA0 \xA2", "\xA3 \xA4", "\x8C \x8B"]
 | 
				
			||||||
    str[] wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
 | 
					    str[] @nosplit wordsA2 = ["meat", "cutlet", "steak", "burgers", "soup"]
 | 
				
			||||||
    str[] wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
 | 
					    str[] @nosplit wordsA3 = ["ice", "mud", "Zero-G", "vacuum", "\xB1 ultra"]
 | 
				
			||||||
    str[] wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
 | 
					    str[] @nosplit wordsA4 = ["hockey", "cricket", "karate", "polo", "tennis"]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uword[] @shared wordlists = [
 | 
					    uword[] @shared wordlists = [
 | 
				
			||||||
        words81, words82, words83, words84, words85, words86, words87, words88,
 | 
					        words81, words82, words83, words84, words85, words86, words87, words88,
 | 
				
			||||||
@@ -840,7 +839,7 @@ elite_planet {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        randname[nx] = 0
 | 
					        randname[nx] = 0
 | 
				
			||||||
        randname[0] = string.upperchar(randname[0])
 | 
					        randname[0] = strings.upperchar(randname[0])
 | 
				
			||||||
        return randname
 | 
					        return randname
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -912,12 +911,12 @@ elite_planet {
 | 
				
			|||||||
                        source_ptr = source_stack[stack_ptr]
 | 
					                        source_ptr = source_stack[stack_ptr]
 | 
				
			||||||
                    } else {
 | 
					                    } else {
 | 
				
			||||||
                        if c == $b0 {
 | 
					                        if c == $b0 {
 | 
				
			||||||
                            @(result_ptr) = string.upperchar(name[0])
 | 
					                            @(result_ptr) = strings.upperchar(name[0])
 | 
				
			||||||
                            result_ptr++
 | 
					                            result_ptr++
 | 
				
			||||||
                            concat_string(&name + 1)
 | 
					                            concat_string(&name + 1)
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        else if c == $b1 {
 | 
					                        else if c == $b1 {
 | 
				
			||||||
                            @(result_ptr) = string.upperchar(name[0])
 | 
					                            @(result_ptr) = strings.upperchar(name[0])
 | 
				
			||||||
                            result_ptr++
 | 
					                            result_ptr++
 | 
				
			||||||
                            ubyte ni
 | 
					                            ubyte ni
 | 
				
			||||||
                            for ni in 1 to len(name) {
 | 
					                            for ni in 1 to len(name) {
 | 
				
			||||||
@@ -981,7 +980,7 @@ elite_util {
 | 
				
			|||||||
            if pc == 0
 | 
					            if pc == 0
 | 
				
			||||||
                return true
 | 
					                return true
 | 
				
			||||||
            ; to lowercase for case insensitive compare:
 | 
					            ; to lowercase for case insensitive compare:
 | 
				
			||||||
            if string.lowerchar(pc)!=string.lowerchar(sc)
 | 
					            if strings.lowerchar(pc)!=strings.lowerchar(sc)
 | 
				
			||||||
                return false
 | 
					                return false
 | 
				
			||||||
            prefixptr++
 | 
					            prefixptr++
 | 
				
			||||||
            stringptr++
 | 
					            stringptr++
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +0,0 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					 | 
				
			||||||
<module type="WEB_MODULE" version="4">
 | 
					 | 
				
			||||||
  <component name="NewModuleRootManager" inherit-compiler-output="true">
 | 
					 | 
				
			||||||
    <exclude-output />
 | 
					 | 
				
			||||||
    <content url="file://$MODULE_DIR$">
 | 
					 | 
				
			||||||
      <excludeFolder url="file://$MODULE_DIR$/compiled" />
 | 
					 | 
				
			||||||
    </content>
 | 
					 | 
				
			||||||
    <orderEntry type="sourceFolder" forTests="false" />
 | 
					 | 
				
			||||||
  </component>
 | 
					 | 
				
			||||||
</module>
 | 
					 | 
				
			||||||
@@ -15,6 +15,8 @@
 | 
				
			|||||||
%import b_queens
 | 
					%import b_queens
 | 
				
			||||||
%import b_textelite
 | 
					%import b_textelite
 | 
				
			||||||
%import b_maze
 | 
					%import b_maze
 | 
				
			||||||
 | 
					%import b_sprites
 | 
				
			||||||
 | 
					%import b_btree
 | 
				
			||||||
 | 
					
 | 
				
			||||||
%zeropage basicsafe
 | 
					%zeropage basicsafe
 | 
				
			||||||
%option no_sysinit
 | 
					%option no_sysinit
 | 
				
			||||||
@@ -29,11 +31,11 @@ main {
 | 
				
			|||||||
    sub start() {
 | 
					    sub start() {
 | 
				
			||||||
        ubyte benchmark_number
 | 
					        ubyte benchmark_number
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void cx16.set_screen_mode(3)
 | 
					        cx16.set_screen_mode(3)
 | 
				
			||||||
        txt.color2(1, 6)
 | 
					        txt.color2(1, 6)
 | 
				
			||||||
        txt.clear_screen()
 | 
					        txt.clear_screen()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        txt.print("\n\n\n  prog8 compiler benchmark tests.\n")
 | 
					        txt.print("\n\n\n  prog8 compiler benchmark tests.\n\n  benchmark version v12\n\n")
 | 
				
			||||||
        sys.wait(60)
 | 
					        sys.wait(60)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        benchmark_number = 0
 | 
					        benchmark_number = 0
 | 
				
			||||||
@@ -62,44 +64,48 @@ main {
 | 
				
			|||||||
        benchmark_score[benchmark_number]  = adpcm.decode_benchmark(300)
 | 
					        benchmark_score[benchmark_number]  = adpcm.decode_benchmark(300)
 | 
				
			||||||
        benchmark_number++
 | 
					        benchmark_number++
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        announce_benchmark("circles with gfx2")
 | 
					        announce_benchmark("circles with gfx_lores")
 | 
				
			||||||
        benchmark_score[benchmark_number]  = circles.draw(false, 300)
 | 
					        benchmark_score[benchmark_number]  = circles.draw(false, 400)
 | 
				
			||||||
        benchmark_number++
 | 
					        benchmark_number++
 | 
				
			||||||
 | 
					
 | 
				
			||||||
;        announce_benchmark("circles with kernal")
 | 
					 | 
				
			||||||
;        benchmark_score[benchmark_number]  = circles.draw(true, 300)
 | 
					 | 
				
			||||||
;        benchmark_number++
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        announce_benchmark("text-elite")
 | 
					        announce_benchmark("text-elite")
 | 
				
			||||||
        benchmark_score[benchmark_number]  = textelite.bench(120)
 | 
					        benchmark_score[benchmark_number]  = textelite.bench(120)
 | 
				
			||||||
        benchmark_number++
 | 
					        benchmark_number++
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        announce_benchmark("sprites-coroutines-defer")
 | 
				
			||||||
 | 
					        benchmark_score[benchmark_number]  = animsprites.benchmark(300)
 | 
				
			||||||
 | 
					        benchmark_number++
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        announce_benchmark("btree-struct-pointers")
 | 
				
			||||||
 | 
					        benchmark_score[benchmark_number]  = btree.benchmark(200)
 | 
				
			||||||
 | 
					        benchmark_number++
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        benchmark_names[benchmark_number] = 0
 | 
					        benchmark_names[benchmark_number] = 0
 | 
				
			||||||
        benchmark_score[benchmark_number] = 0
 | 
					        benchmark_score[benchmark_number] = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        void cx16.set_screen_mode(3)
 | 
					        cx16.set_screen_mode(3)
 | 
				
			||||||
        txt.uppercase()
 | 
					        txt.uppercase()
 | 
				
			||||||
        txt.color2(1, 6)
 | 
					        txt.color2(1, 6)
 | 
				
			||||||
        uword final_score
 | 
					        uword total_score
 | 
				
			||||||
        benchmark_number = 0
 | 
					        benchmark_number = 0
 | 
				
			||||||
        txt.print("\nscore benchmark\n\n")
 | 
					        txt.print("\nscore benchmark (v12)\n\n")
 | 
				
			||||||
        do {
 | 
					        do {
 | 
				
			||||||
            txt.spc()
 | 
					            txt.spc()
 | 
				
			||||||
            txt.print_uw(benchmark_score[benchmark_number])
 | 
					            txt.print_uw(benchmark_score[benchmark_number])
 | 
				
			||||||
            txt.column(6)
 | 
					            txt.column(6)
 | 
				
			||||||
            txt.print(benchmark_names[benchmark_number])
 | 
					            txt.print(benchmark_names[benchmark_number])
 | 
				
			||||||
            final_score += benchmark_score[benchmark_number]
 | 
					            total_score += benchmark_score[benchmark_number]
 | 
				
			||||||
            txt.nl()
 | 
					            txt.nl()
 | 
				
			||||||
            benchmark_number++
 | 
					            benchmark_number++
 | 
				
			||||||
        } until benchmark_names[benchmark_number]==0
 | 
					        } until benchmark_names[benchmark_number]==0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        txt.print("\n\nfinal score : ")
 | 
					        txt.print("\n\ntotal score : ")
 | 
				
			||||||
        txt.print_uw(final_score)
 | 
					        txt.print_uw(total_score)
 | 
				
			||||||
        txt.nl()
 | 
					        txt.print(" (higher=better)\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        sub announce_benchmark(str name) {
 | 
					        sub announce_benchmark(str name) {
 | 
				
			||||||
            benchmark_names[benchmark_number] = name
 | 
					            benchmark_names[benchmark_number] = name
 | 
				
			||||||
            void cx16.set_screen_mode(3)
 | 
					            cx16.set_screen_mode(3)
 | 
				
			||||||
            txt.uppercase()
 | 
					            txt.uppercase()
 | 
				
			||||||
            txt.color2(1, 6)
 | 
					            txt.color2(1, 6)
 | 
				
			||||||
            txt.clear_screen()
 | 
					            txt.clear_screen()
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										10
									
								
								build.gradle
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								build.gradle
									
									
									
									
									
								
							@@ -1,10 +0,0 @@
 | 
				
			|||||||
plugins {
 | 
					 | 
				
			||||||
    id "org.jetbrains.kotlin.jvm" version "$kotlinVersion" apply false
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
allprojects {
 | 
					 | 
				
			||||||
    repositories {
 | 
					 | 
				
			||||||
        mavenLocal()
 | 
					 | 
				
			||||||
        mavenCentral()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										38
									
								
								build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					import org.jetbrains.kotlin.gradle.dsl.JvmTarget
 | 
				
			||||||
 | 
					import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode
 | 
				
			||||||
 | 
					import org.jetbrains.kotlin.gradle.internal.config.LanguageFeature
 | 
				
			||||||
 | 
					import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					    kotlin("jvm") version "2.2.20"
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					allprojects {
 | 
				
			||||||
 | 
					    apply(plugin="kotlin")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    repositories {
 | 
				
			||||||
 | 
					        mavenLocal()
 | 
				
			||||||
 | 
					        mavenCentral()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    kotlin {
 | 
				
			||||||
 | 
					        compilerOptions {
 | 
				
			||||||
 | 
					            freeCompilerArgs = listOf("-Xwhen-guards")
 | 
				
			||||||
 | 
					            jvmTarget = JvmTarget.JVM_11
 | 
				
			||||||
 | 
					            jvmDefault = JvmDefaultMode.NO_COMPATIBILITY
 | 
				
			||||||
 | 
					            // languageVersion.set(KotlinVersion.KOTLIN_2_3)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        sourceSets.all {
 | 
				
			||||||
 | 
					            languageSettings {
 | 
				
			||||||
 | 
					                // enable language features like so:
 | 
				
			||||||
 | 
					                // enableLanguageFeature(LanguageFeature.WhenGuards.name)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    java {
 | 
				
			||||||
 | 
					        targetCompatibility = JavaVersion.VERSION_11
 | 
				
			||||||
 | 
					        sourceCompatibility = JavaVersion.VERSION_11
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,42 +0,0 @@
 | 
				
			|||||||
 | 
					 | 
				
			||||||
plugins {
 | 
					 | 
				
			||||||
    id 'java'
 | 
					 | 
				
			||||||
    id 'application'
 | 
					 | 
				
			||||||
    id "org.jetbrains.kotlin.jvm"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
java {
 | 
					 | 
				
			||||||
    targetCompatibility = JavaLanguageVersion.of(javaVersion)
 | 
					 | 
				
			||||||
    sourceCompatibility = JavaLanguageVersion.of(javaVersion)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
compileKotlin {
 | 
					 | 
				
			||||||
    kotlinOptions {
 | 
					 | 
				
			||||||
        jvmTarget = javaVersion
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
compileTestKotlin {
 | 
					 | 
				
			||||||
    kotlinOptions {
 | 
					 | 
				
			||||||
        jvmTarget = javaVersion
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dependencies {
 | 
					 | 
				
			||||||
    // should have no dependencies to other modules
 | 
					 | 
				
			||||||
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
 | 
					 | 
				
			||||||
    implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:2.0.0"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sourceSets {
 | 
					 | 
				
			||||||
    main {
 | 
					 | 
				
			||||||
        java {
 | 
					 | 
				
			||||||
            srcDir "${project.projectDir}/src"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        resources {
 | 
					 | 
				
			||||||
            srcDir "${project.projectDir}/res"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
// note: there are no unit tests in this module!
 | 
					 | 
				
			||||||
							
								
								
									
										22
									
								
								codeCore/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								codeCore/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					    kotlin("jvm")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dependencies {
 | 
				
			||||||
 | 
					    // should have no dependencies to other modules
 | 
				
			||||||
 | 
					    // implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
 | 
				
			||||||
 | 
					    implementation("com.michael-bull.kotlin-result:kotlin-result-jvm:2.1.0")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sourceSets {
 | 
				
			||||||
 | 
					    main {
 | 
				
			||||||
 | 
					        java {
 | 
				
			||||||
 | 
					            srcDir("${project.projectDir}/src")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        resources {
 | 
				
			||||||
 | 
					            srcDir("${project.projectDir}/res")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// note: there are no unit tests in this module!
 | 
				
			||||||
							
								
								
									
										32
									
								
								codeCore/src/prog8/code/Globals.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								codeCore/src/prog8/code/Globals.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					package prog8.code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.IOException
 | 
				
			||||||
 | 
					import java.nio.file.Path
 | 
				
			||||||
 | 
					import kotlin.io.path.absolute
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const val INTERNED_STRINGS_MODULENAME = "prog8_interned_strings"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					val PROG8_CONTAINER_MODULES = arrayOf(INTERNED_STRINGS_MODULENAME)      // option to add more if needed one day
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// all automatically generated labels everywhere need to have the same label name prefix:
 | 
				
			||||||
 | 
					const val GENERATED_LABEL_PREFIX = "p8_label_gen_"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Returns the absolute path of the given path,
 | 
				
			||||||
 | 
					 * where links are replaced by the actual directories,
 | 
				
			||||||
 | 
					 * and containing no redundant path elements.
 | 
				
			||||||
 | 
					 * If the path doesn't refer to an existing directory or file on the file system,
 | 
				
			||||||
 | 
					 * it is returned unchanged.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					fun Path.sanitize(): Path {
 | 
				
			||||||
 | 
					    return try {
 | 
				
			||||||
 | 
					        this.toRealPath().normalize()
 | 
				
			||||||
 | 
					    } catch (_: java.nio.file.NoSuchFileException) {
 | 
				
			||||||
 | 
					        this.absolute().normalize()
 | 
				
			||||||
 | 
					        //throw NoSuchFileException(this.toFile(), null, nx.reason).also { it.initCause(nx) }
 | 
				
			||||||
 | 
					    } catch (iox: IOException) {
 | 
				
			||||||
 | 
					        throw FileSystemException(this.toFile()).also { it.initCause(iox) }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,256 +0,0 @@
 | 
				
			|||||||
package prog8.code
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import prog8.code.ast.PtNode
 | 
					 | 
				
			||||||
import prog8.code.ast.PtProgram
 | 
					 | 
				
			||||||
import prog8.code.core.*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Tree structure containing all symbol definitions in the program
 | 
					 | 
				
			||||||
 * (blocks, subroutines, variables (all types), memoryslabs, and labels).
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
class SymbolTable(astProgram: PtProgram) : StNode(astProgram.name, StNodeType.GLOBAL, astProgram) {
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * The table as a flat mapping of scoped names to the StNode.
 | 
					 | 
				
			||||||
     * This gives the fastest lookup possible (no need to traverse tree nodes)
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private var cachedFlat: Map<String, StNode>? = null
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val flat: Map<String, StNode> get()  {
 | 
					 | 
				
			||||||
        if(cachedFlat!=null)
 | 
					 | 
				
			||||||
            return cachedFlat!!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        val result = mutableMapOf<String, StNode>()
 | 
					 | 
				
			||||||
        fun collect(node: StNode) {
 | 
					 | 
				
			||||||
            for(child in node.children) {
 | 
					 | 
				
			||||||
                result[child.value.scopedName] = child.value
 | 
					 | 
				
			||||||
                collect(child.value)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        collect(this)
 | 
					 | 
				
			||||||
        cachedFlat = result
 | 
					 | 
				
			||||||
        return result
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun resetCachedFlat() {
 | 
					 | 
				
			||||||
        cachedFlat = null
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val allVariables: Collection<StStaticVariable> by lazy {
 | 
					 | 
				
			||||||
        val vars = mutableListOf<StStaticVariable>()
 | 
					 | 
				
			||||||
        fun collect(node: StNode) {
 | 
					 | 
				
			||||||
            for(child in node.children) {
 | 
					 | 
				
			||||||
                if(child.value.type== StNodeType.STATICVAR)
 | 
					 | 
				
			||||||
                    vars.add(child.value as StStaticVariable)
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                    collect(child.value)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        collect(this)
 | 
					 | 
				
			||||||
        vars
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val allMemMappedVariables: Collection<StMemVar> by lazy {
 | 
					 | 
				
			||||||
        val vars = mutableListOf<StMemVar>()
 | 
					 | 
				
			||||||
        fun collect(node: StNode) {
 | 
					 | 
				
			||||||
            for(child in node.children) {
 | 
					 | 
				
			||||||
                if(child.value.type== StNodeType.MEMVAR)
 | 
					 | 
				
			||||||
                    vars.add(child.value as StMemVar)
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                    collect(child.value)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        collect(this)
 | 
					 | 
				
			||||||
        vars
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val allMemorySlabs: Collection<StMemorySlab> by lazy {
 | 
					 | 
				
			||||||
        val vars = mutableListOf<StMemorySlab>()
 | 
					 | 
				
			||||||
        fun collect(node: StNode) {
 | 
					 | 
				
			||||||
            for(child in node.children) {
 | 
					 | 
				
			||||||
                if(child.value.type== StNodeType.MEMORYSLAB)
 | 
					 | 
				
			||||||
                    vars.add(child.value as StMemorySlab)
 | 
					 | 
				
			||||||
                else
 | 
					 | 
				
			||||||
                    collect(child.value)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        collect(this)
 | 
					 | 
				
			||||||
        vars
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun lookup(scopedName: String) = flat[scopedName]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun getLength(name: String): Int? {
 | 
					 | 
				
			||||||
        return when(val node = flat[name]) {
 | 
					 | 
				
			||||||
            is StMemVar -> node.length
 | 
					 | 
				
			||||||
            is StMemorySlab -> node.size.toInt()
 | 
					 | 
				
			||||||
            is StStaticVariable -> node.length
 | 
					 | 
				
			||||||
            else -> null
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum class StNodeType {
 | 
					 | 
				
			||||||
    GLOBAL,
 | 
					 | 
				
			||||||
    // MODULE,     // not used with current scoping rules
 | 
					 | 
				
			||||||
    BLOCK,
 | 
					 | 
				
			||||||
    SUBROUTINE,
 | 
					 | 
				
			||||||
    ROMSUB,
 | 
					 | 
				
			||||||
    LABEL,
 | 
					 | 
				
			||||||
    STATICVAR,
 | 
					 | 
				
			||||||
    MEMVAR,
 | 
					 | 
				
			||||||
    CONSTANT,
 | 
					 | 
				
			||||||
    BUILTINFUNC,
 | 
					 | 
				
			||||||
    MEMORYSLAB
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
open class StNode(val name: String,
 | 
					 | 
				
			||||||
                  val type: StNodeType,
 | 
					 | 
				
			||||||
                  val astNode: PtNode,
 | 
					 | 
				
			||||||
                  val children: MutableMap<String, StNode> = mutableMapOf()
 | 
					 | 
				
			||||||
) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    lateinit var parent: StNode
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val scopedName: String by lazy { scopedNameList.joinToString(".") }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    open fun lookup(scopedName: String) =
 | 
					 | 
				
			||||||
        lookup(scopedName.split('.'))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun lookupUnscopedOrElse(name: String, default: () -> StNode) =
 | 
					 | 
				
			||||||
        lookupUnscoped(name) ?: default()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun lookupOrElse(scopedName: String, default: () -> StNode): StNode =
 | 
					 | 
				
			||||||
        lookup(scopedName.split('.')) ?: default()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun lookupUnscoped(name: String): StNode? {
 | 
					 | 
				
			||||||
        // first consider the builtin functions
 | 
					 | 
				
			||||||
        var globalscope = this
 | 
					 | 
				
			||||||
        while(globalscope.type!= StNodeType.GLOBAL)
 | 
					 | 
				
			||||||
            globalscope = globalscope.parent
 | 
					 | 
				
			||||||
        val globalNode = globalscope.children[name]
 | 
					 | 
				
			||||||
        if(globalNode!=null && globalNode.type== StNodeType.BUILTINFUNC)
 | 
					 | 
				
			||||||
            return globalNode
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // search for the unqualified name in the current scope or its parent scopes
 | 
					 | 
				
			||||||
        var scope=this
 | 
					 | 
				
			||||||
        while(true) {
 | 
					 | 
				
			||||||
            val node = scope.children[name]
 | 
					 | 
				
			||||||
            if(node!=null)
 | 
					 | 
				
			||||||
                return node
 | 
					 | 
				
			||||||
            if(scope.type== StNodeType.GLOBAL)
 | 
					 | 
				
			||||||
                return null
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                scope = scope.parent
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun add(child: StNode) {
 | 
					 | 
				
			||||||
        children[child.name] = child
 | 
					 | 
				
			||||||
        child.parent = this
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private val scopedNameList: List<String> by lazy {
 | 
					 | 
				
			||||||
        if(type==StNodeType.GLOBAL)
 | 
					 | 
				
			||||||
            emptyList()
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            parent.scopedNameList + name
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private fun lookup(scopedName: List<String>): StNode? {
 | 
					 | 
				
			||||||
        // a scoped name refers to a name in another namespace, and always stars from the root.
 | 
					 | 
				
			||||||
        var node = this
 | 
					 | 
				
			||||||
        while(node.type!=StNodeType.GLOBAL)
 | 
					 | 
				
			||||||
            node = node.parent
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for(name in scopedName) {
 | 
					 | 
				
			||||||
            if(name in node.children)
 | 
					 | 
				
			||||||
                node = node.children.getValue(name)
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                return null
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return node
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class StStaticVariable(name: String,
 | 
					 | 
				
			||||||
                       val dt: DataType,
 | 
					 | 
				
			||||||
                       val onetimeInitializationNumericValue: Double?,      // regular (every-run-time) initialization is done via regular assignments
 | 
					 | 
				
			||||||
                       val onetimeInitializationStringValue: StString?,
 | 
					 | 
				
			||||||
                       val onetimeInitializationArrayValue: StArray?,
 | 
					 | 
				
			||||||
                       val length: Int?,            // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
 | 
					 | 
				
			||||||
                       val zpwish: ZeropageWish,    // used in the variable allocator
 | 
					 | 
				
			||||||
                       astNode: PtNode) : StNode(name, StNodeType.STATICVAR, astNode) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val uninitialized = onetimeInitializationArrayValue==null && onetimeInitializationStringValue==null && onetimeInitializationNumericValue==null
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    init {
 | 
					 | 
				
			||||||
        if(length!=null) {
 | 
					 | 
				
			||||||
            require(onetimeInitializationNumericValue == null)
 | 
					 | 
				
			||||||
            if(onetimeInitializationArrayValue!=null)
 | 
					 | 
				
			||||||
                require(onetimeInitializationArrayValue.isEmpty() ||onetimeInitializationArrayValue.size==length)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(onetimeInitializationNumericValue!=null) {
 | 
					 | 
				
			||||||
            require(dt in NumericDatatypes || dt==DataType.BOOL)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(onetimeInitializationArrayValue!=null) {
 | 
					 | 
				
			||||||
            require(dt in ArrayDatatypes)
 | 
					 | 
				
			||||||
            require(length==onetimeInitializationArrayValue.size)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if(onetimeInitializationStringValue!=null) {
 | 
					 | 
				
			||||||
            require(dt == DataType.STR)
 | 
					 | 
				
			||||||
            require(length == onetimeInitializationStringValue.first.length+1)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class StConstant(name: String, val dt: DataType, val value: Double, astNode: PtNode) :
 | 
					 | 
				
			||||||
    StNode(name, StNodeType.CONSTANT, astNode)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class StMemVar(name: String,
 | 
					 | 
				
			||||||
               val dt: DataType,
 | 
					 | 
				
			||||||
               val address: UInt,
 | 
					 | 
				
			||||||
               val length: Int?,             // for arrays: the number of elements, for strings: number of characters *including* the terminating 0-byte
 | 
					 | 
				
			||||||
               astNode: PtNode) :
 | 
					 | 
				
			||||||
    StNode(name, StNodeType.MEMVAR, astNode) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    init{
 | 
					 | 
				
			||||||
        require(dt!=DataType.BOOL && dt!=DataType.ARRAY_BOOL)
 | 
					 | 
				
			||||||
        if(dt in ArrayDatatypes || dt == DataType.STR)
 | 
					 | 
				
			||||||
            requireNotNull(length)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class StMemorySlab(
 | 
					 | 
				
			||||||
    name: String,
 | 
					 | 
				
			||||||
    val size: UInt,
 | 
					 | 
				
			||||||
    val align: UInt,
 | 
					 | 
				
			||||||
    astNode: PtNode
 | 
					 | 
				
			||||||
):
 | 
					 | 
				
			||||||
    StNode(name, StNodeType.MEMORYSLAB, astNode)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class StSub(name: String, val parameters: List<StSubroutineParameter>, val returnType: DataType?, astNode: PtNode) :
 | 
					 | 
				
			||||||
        StNode(name, StNodeType.SUBROUTINE, astNode)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class StRomSub(name: String,
 | 
					 | 
				
			||||||
               val address: UInt?,      // null in case of asmsub, specified in case of romsub
 | 
					 | 
				
			||||||
               val parameters: List<StRomSubParameter>,
 | 
					 | 
				
			||||||
               val returns: List<StRomSubParameter>,
 | 
					 | 
				
			||||||
               astNode: PtNode) :
 | 
					 | 
				
			||||||
    StNode(name, StNodeType.ROMSUB, astNode)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class StSubroutineParameter(val name: String, val type: DataType)
 | 
					 | 
				
			||||||
class StRomSubParameter(val register: RegisterOrStatusflag, val type: DataType)
 | 
					 | 
				
			||||||
class StArrayElement(val number: Double?, val addressOfSymbol: String?, val boolean: Boolean?)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
typealias StString = Pair<String, Encoding>
 | 
					 | 
				
			||||||
typealias StArray = List<StArrayElement>
 | 
					 | 
				
			||||||
@@ -1,181 +0,0 @@
 | 
				
			|||||||
package prog8.code.ast
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import prog8.code.core.*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sealed interface IPtSubroutine {
 | 
					 | 
				
			||||||
    val name: String
 | 
					 | 
				
			||||||
    val scopedName: String
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtAsmSub(
 | 
					 | 
				
			||||||
    name: String,
 | 
					 | 
				
			||||||
    val address: UInt?,
 | 
					 | 
				
			||||||
    val clobbers: Set<CpuRegister>,
 | 
					 | 
				
			||||||
    val parameters: List<Pair<RegisterOrStatusflag, PtSubroutineParameter>>,
 | 
					 | 
				
			||||||
    val returns: List<Pair<RegisterOrStatusflag, DataType>>,
 | 
					 | 
				
			||||||
    val inline: Boolean,
 | 
					 | 
				
			||||||
    position: Position
 | 
					 | 
				
			||||||
) : PtNamedNode(name, position), IPtSubroutine
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtSub(
 | 
					 | 
				
			||||||
    name: String,
 | 
					 | 
				
			||||||
    val parameters: List<PtSubroutineParameter>,
 | 
					 | 
				
			||||||
    val returntype: DataType?,
 | 
					 | 
				
			||||||
    position: Position
 | 
					 | 
				
			||||||
) : PtNamedNode(name, position), IPtSubroutine, IPtStatementContainer {
 | 
					 | 
				
			||||||
    init {
 | 
					 | 
				
			||||||
        // params and return value should not be str
 | 
					 | 
				
			||||||
        if(parameters.any{ it.type !in NumericDatatypes && it.type!=DataType.BOOL })
 | 
					 | 
				
			||||||
            throw AssemblyError("non-numeric/non-bool parameter")
 | 
					 | 
				
			||||||
        if(returntype!=null && returntype !in NumericDatatypes && returntype!=DataType.BOOL)
 | 
					 | 
				
			||||||
            throw AssemblyError("non-numeric/non-bool returntype $returntype")
 | 
					 | 
				
			||||||
        parameters.forEach { it.parent=this }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtSubroutineParameter(name: String, val type: DataType, position: Position): PtNamedNode(name, position)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sealed interface IPtAssignment {
 | 
					 | 
				
			||||||
    val children: MutableList<PtNode>
 | 
					 | 
				
			||||||
    val target: PtAssignTarget
 | 
					 | 
				
			||||||
        get() {
 | 
					 | 
				
			||||||
            if(children.size==2)
 | 
					 | 
				
			||||||
                return children[0] as PtAssignTarget
 | 
					 | 
				
			||||||
            else if(children.size<2)
 | 
					 | 
				
			||||||
                throw AssemblyError("incomplete node")
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                throw AssemblyError("no singular target")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    val value: PtExpression
 | 
					 | 
				
			||||||
        get() = children.last() as PtExpression
 | 
					 | 
				
			||||||
    val multiTarget: Boolean
 | 
					 | 
				
			||||||
        get() = children.size>2
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtAssignment(position: Position) : PtNode(position), IPtAssignment
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtAugmentedAssign(val operator: String, position: Position) : PtNode(position), IPtAssignment
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtAssignTarget(val void: Boolean, position: Position) : PtNode(position) {
 | 
					 | 
				
			||||||
    val identifier: PtIdentifier?
 | 
					 | 
				
			||||||
        get() = children.single() as? PtIdentifier
 | 
					 | 
				
			||||||
    val array: PtArrayIndexer?
 | 
					 | 
				
			||||||
        get() = children.single() as? PtArrayIndexer
 | 
					 | 
				
			||||||
    val memory: PtMemoryByte?
 | 
					 | 
				
			||||||
        get() = children.single() as? PtMemoryByte
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val type: DataType
 | 
					 | 
				
			||||||
        get() {
 | 
					 | 
				
			||||||
            return when(val tgt = children.single()) {
 | 
					 | 
				
			||||||
                is PtIdentifier -> tgt.type
 | 
					 | 
				
			||||||
                is PtArrayIndexer -> tgt.type
 | 
					 | 
				
			||||||
                is PtMemoryByte -> tgt.type
 | 
					 | 
				
			||||||
                else -> throw AssemblyError("weird target $tgt")
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    infix fun isSameAs(expression: PtExpression): Boolean = !void && expression.isSameAs(this)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtConditionalBranch(val condition: BranchCondition, position: Position) : PtNode(position) {
 | 
					 | 
				
			||||||
    val trueScope: PtNodeGroup
 | 
					 | 
				
			||||||
        get() = children[0] as PtNodeGroup
 | 
					 | 
				
			||||||
    val falseScope: PtNodeGroup
 | 
					 | 
				
			||||||
        get() = children[1] as PtNodeGroup
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtForLoop(position: Position) : PtNode(position) {
 | 
					 | 
				
			||||||
    val variable: PtIdentifier
 | 
					 | 
				
			||||||
        get() = children[0] as PtIdentifier
 | 
					 | 
				
			||||||
    val iterable: PtExpression
 | 
					 | 
				
			||||||
        get() = children[1] as PtExpression
 | 
					 | 
				
			||||||
    val statements: PtNodeGroup
 | 
					 | 
				
			||||||
        get() = children[2] as PtNodeGroup
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtIfElse(position: Position) : PtNode(position) {
 | 
					 | 
				
			||||||
    val condition: PtExpression
 | 
					 | 
				
			||||||
        get() = children[0] as PtExpression
 | 
					 | 
				
			||||||
    val ifScope: PtNodeGroup
 | 
					 | 
				
			||||||
        get() = children[1] as PtNodeGroup
 | 
					 | 
				
			||||||
    val elseScope: PtNodeGroup
 | 
					 | 
				
			||||||
        get() = children[2] as PtNodeGroup
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun hasElse(): Boolean = children.size==3 && elseScope.children.isNotEmpty()
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtJump(val identifier: PtIdentifier?,     // note: even ad-hoc labels are wrapped as an Identifier to simplify code. Just use dummy type and position.
 | 
					 | 
				
			||||||
             val address: UInt?,
 | 
					 | 
				
			||||||
             position: Position) : PtNode(position) {
 | 
					 | 
				
			||||||
    init {
 | 
					 | 
				
			||||||
        identifier?.let {it.parent = this }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtRepeatLoop(position: Position) : PtNode(position) {
 | 
					 | 
				
			||||||
    val count: PtExpression
 | 
					 | 
				
			||||||
        get() = children[0] as PtExpression
 | 
					 | 
				
			||||||
    val statements: PtNodeGroup
 | 
					 | 
				
			||||||
        get() = children[1] as PtNodeGroup
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtReturn(position: Position) : PtNode(position) {
 | 
					 | 
				
			||||||
    val hasValue = children.any()
 | 
					 | 
				
			||||||
    val value: PtExpression?
 | 
					 | 
				
			||||||
        get() {
 | 
					 | 
				
			||||||
            return if(children.any())
 | 
					 | 
				
			||||||
                children.single() as PtExpression
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                null
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sealed interface IPtVariable {
 | 
					 | 
				
			||||||
    val name: String
 | 
					 | 
				
			||||||
    val type: DataType
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtVariable(name: String, override val type: DataType, val zeropage: ZeropageWish, val value: PtExpression?, val arraySize: UInt?, position: Position) : PtNamedNode(name, position), IPtVariable {
 | 
					 | 
				
			||||||
    init {
 | 
					 | 
				
			||||||
        value?.let {it.parent=this}
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtConstant(name: String, override val type: DataType, val value: Double, position: Position) : PtNamedNode(name, position), IPtVariable
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtMemMapped(name: String, override val type: DataType, val address: UInt, val arraySize: UInt?, position: Position) : PtNamedNode(name, position), IPtVariable {
 | 
					 | 
				
			||||||
    init {
 | 
					 | 
				
			||||||
        require(type!=DataType.BOOL && type!=DataType.ARRAY_BOOL)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtWhen(position: Position) : PtNode(position) {
 | 
					 | 
				
			||||||
    val value: PtExpression
 | 
					 | 
				
			||||||
        get() = children[0] as PtExpression
 | 
					 | 
				
			||||||
    val choices: PtNodeGroup
 | 
					 | 
				
			||||||
        get() = children[1] as PtNodeGroup
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PtWhenChoice(val isElse: Boolean, position: Position) : PtNode(position) {
 | 
					 | 
				
			||||||
    val values: PtNodeGroup
 | 
					 | 
				
			||||||
        get() = children[0] as PtNodeGroup
 | 
					 | 
				
			||||||
    val statements: PtNodeGroup
 | 
					 | 
				
			||||||
        get() = children[1] as PtNodeGroup
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
package prog8.code.core
 | 
					package prog8.code.core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ReturnConvention(val dt: DataType?, val reg: RegisterOrPair?, val floatFac1: Boolean)
 | 
					class ReturnConvention(val dt: BaseDataType?, val reg: RegisterOrPair?)
 | 
				
			||||||
class ParamConvention(val dt: DataType, val reg: RegisterOrPair?, val variable: Boolean)
 | 
					class ParamConvention(val dt: BaseDataType, val reg: RegisterOrPair?, val variable: Boolean)
 | 
				
			||||||
class CallConvention(val params: List<ParamConvention>, val returns: ReturnConvention) {
 | 
					class CallConvention(val params: List<ParamConvention>, val returns: ReturnConvention) {
 | 
				
			||||||
    override fun toString(): String {
 | 
					    override fun toString(): String {
 | 
				
			||||||
        val paramConvs =  params.mapIndexed { index, it ->
 | 
					        val paramConvs =  params.mapIndexed { index, it ->
 | 
				
			||||||
@@ -13,35 +13,43 @@ class CallConvention(val params: List<ParamConvention>, val returns: ReturnConve
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        val returnConv =
 | 
					        val returnConv =
 | 
				
			||||||
            when {
 | 
					            when {
 | 
				
			||||||
                returns.reg!=null -> returns.reg.toString()
 | 
					                returns.reg == RegisterOrPair.FAC1 -> "floatFAC1"
 | 
				
			||||||
                returns.floatFac1 -> "floatFAC1"
 | 
					                returns.reg != null -> returns.reg.toString()
 | 
				
			||||||
                else -> "<no returnvalue>"
 | 
					                else -> "<no returnvalue>"
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        return "CallConvention[" + paramConvs.joinToString() + " ; returns: $returnConv]"
 | 
					        return "CallConvention[" + paramConvs.joinToString() + " ; returns: $returnConv]"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FParam(val name: String, val possibleDatatypes: Array<DataType>)
 | 
					class FParam(val name: String, vararg val possibleDatatypes: BaseDataType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private val IterableDatatypes = arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW)
 | 
				
			||||||
 | 
					private val IntegerDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)
 | 
				
			||||||
 | 
					private val NumericDatatypes = arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FSignature(val pure: Boolean,      // does it have side effects?
 | 
					class FSignature(val pure: Boolean,      // does it have side effects?
 | 
				
			||||||
                      val parameters: List<FParam>,
 | 
					                 val returnType: BaseDataType?,
 | 
				
			||||||
                      val returnType: DataType?) {
 | 
					                 vararg val parameters: FParam) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun callConvention(actualParamTypes: List<DataType>): CallConvention {
 | 
					    fun callConvention(actualParamTypes: List<BaseDataType>): CallConvention {
 | 
				
			||||||
        val returns: ReturnConvention = when (returnType) {
 | 
					        val returns: ReturnConvention = when (returnType) {
 | 
				
			||||||
            DataType.UBYTE, DataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A, false)
 | 
					            BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(returnType, RegisterOrPair.A)
 | 
				
			||||||
            DataType.UWORD, DataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY, false)
 | 
					            BaseDataType.UWORD, BaseDataType.WORD -> ReturnConvention(returnType, RegisterOrPair.AY)
 | 
				
			||||||
            DataType.FLOAT -> ReturnConvention(returnType, null, true)
 | 
					            BaseDataType.LONG -> ReturnConvention(returnType, RegisterOrPair.R14R15_32)
 | 
				
			||||||
            in PassByReferenceDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY, false)
 | 
					            BaseDataType.FLOAT -> ReturnConvention(returnType, RegisterOrPair.FAC1)
 | 
				
			||||||
            null -> ReturnConvention(null, null, false)
 | 
					            in IterableDatatypes -> ReturnConvention(returnType!!, RegisterOrPair.AY)
 | 
				
			||||||
 | 
					            null -> ReturnConvention(null, null)
 | 
				
			||||||
            else -> {
 | 
					            else -> {
 | 
				
			||||||
                // return type depends on arg type
 | 
					                // return type depends on arg type
 | 
				
			||||||
                when (val paramType = actualParamTypes.first()) {
 | 
					                when (val paramType = actualParamTypes.first()) {
 | 
				
			||||||
                    DataType.UBYTE, DataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A, false)
 | 
					                    BaseDataType.UBYTE, BaseDataType.BYTE -> ReturnConvention(paramType, RegisterOrPair.A)
 | 
				
			||||||
                    DataType.UWORD, DataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY, false)
 | 
					                    BaseDataType.UWORD, BaseDataType.WORD -> ReturnConvention(paramType, RegisterOrPair.AY)
 | 
				
			||||||
                    DataType.FLOAT -> ReturnConvention(paramType, null, true)
 | 
					                    BaseDataType.LONG -> ReturnConvention(returnType, RegisterOrPair.R14R15_32)
 | 
				
			||||||
                    in PassByReferenceDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY, false)
 | 
					                    BaseDataType.FLOAT -> ReturnConvention(paramType, RegisterOrPair.FAC1)
 | 
				
			||||||
                    else -> ReturnConvention(paramType, null, false)
 | 
					                    in IterableDatatypes -> ReturnConvention(paramType, RegisterOrPair.AY)
 | 
				
			||||||
 | 
					                    else -> ReturnConvention(paramType, null)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -49,16 +57,28 @@ class FSignature(val pure: Boolean,      // does it have side effects?
 | 
				
			|||||||
        return when {
 | 
					        return when {
 | 
				
			||||||
            actualParamTypes.isEmpty() -> CallConvention(emptyList(), returns)
 | 
					            actualParamTypes.isEmpty() -> CallConvention(emptyList(), returns)
 | 
				
			||||||
            actualParamTypes.size==1 -> {
 | 
					            actualParamTypes.size==1 -> {
 | 
				
			||||||
                // one parameter goes via register/registerpair
 | 
					                // One parameter goes via register/registerpair.
 | 
				
			||||||
 | 
					                // this avoids repeated code for every caller to store the value in the subroutine's argument variable.
 | 
				
			||||||
 | 
					                // (that store is still done, but only coded once at the start at the subroutine itself rather than at every call site).
 | 
				
			||||||
                val paramConv = when(val paramType = actualParamTypes[0]) {
 | 
					                val paramConv = when(val paramType = actualParamTypes[0]) {
 | 
				
			||||||
                    DataType.UBYTE, DataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false)
 | 
					                    BaseDataType.UBYTE, BaseDataType.BYTE -> ParamConvention(paramType, RegisterOrPair.A, false)
 | 
				
			||||||
                    DataType.UWORD, DataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false)
 | 
					                    BaseDataType.UWORD, BaseDataType.WORD -> ParamConvention(paramType, RegisterOrPair.AY, false)
 | 
				
			||||||
                    DataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false)
 | 
					                    BaseDataType.LONG -> ParamConvention(paramType, RegisterOrPair.R14R15_32, false)
 | 
				
			||||||
                    in PassByReferenceDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false)
 | 
					                    BaseDataType.FLOAT -> ParamConvention(paramType, RegisterOrPair.AY, false)      // NOTE: for builtin functions, floating point arguments are passed by reference (so you get a pointer in AY)
 | 
				
			||||||
 | 
					                    in IterableDatatypes -> ParamConvention(paramType, RegisterOrPair.AY, false)
 | 
				
			||||||
                    else -> ParamConvention(paramType, null, false)
 | 
					                    else -> ParamConvention(paramType, null, false)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                CallConvention(listOf(paramConv), returns)
 | 
					                CallConvention(listOf(paramConv), returns)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            actualParamTypes.size==2 && (actualParamTypes[0].isByte && actualParamTypes[1].isWord) -> {
 | 
				
			||||||
 | 
					                TODO("opportunity to pass word+byte arguments in A,Y and X registers but not implemented yet")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            actualParamTypes.size==2 && (actualParamTypes[0].isWord && actualParamTypes[1].isByte) -> {
 | 
				
			||||||
 | 
					                TODO("opportunity to pass word+byte arguments in A,Y and X registers but not implemented yet")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            actualParamTypes.size==3 && actualParamTypes.all { it.isByte } -> {
 | 
				
			||||||
 | 
					                TODO("opportunity to pass 3 byte arguments in A,Y and X registers but not implemented yet")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            else -> {
 | 
					            else -> {
 | 
				
			||||||
                // multiple parameters go via variables
 | 
					                // multiple parameters go via variables
 | 
				
			||||||
                val paramConvs = actualParamTypes.map { ParamConvention(it, null, true) }
 | 
					                val paramConvs = actualParamTypes.map { ParamConvention(it, null, true) }
 | 
				
			||||||
@@ -69,67 +89,78 @@ class FSignature(val pure: Boolean,      // does it have side effects?
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val BuiltinFunctions: Map<String, FSignature> = mapOf(
 | 
					val BuiltinFunctions: Map<String, FSignature> = mapOf(
 | 
				
			||||||
    // this set of function have no return value and operate in-place:
 | 
					    "setlsb"  to FSignature(false, null, FParam("variable", BaseDataType.WORD, BaseDataType.UWORD), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
 | 
				
			||||||
    "setlsb"    to FSignature(false, listOf(FParam("variable", arrayOf(DataType.WORD, DataType.UWORD)), FParam("value", arrayOf(DataType.BYTE, DataType.UBYTE))), null),
 | 
					    "setmsb"  to FSignature(false, null, FParam("variable", BaseDataType.WORD, BaseDataType.UWORD), FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
 | 
				
			||||||
    "setmsb"    to FSignature(false, listOf(FParam("variable", arrayOf(DataType.WORD, DataType.UWORD)), FParam("value", arrayOf(DataType.BYTE, DataType.UBYTE))), null),
 | 
					    "rol"     to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.LONG)),
 | 
				
			||||||
    "rol"       to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
 | 
					    "ror"     to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.LONG)),
 | 
				
			||||||
    "ror"       to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
 | 
					    "rol2"    to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.LONG)),
 | 
				
			||||||
    "rol2"      to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
 | 
					    "ror2"    to FSignature(false, null, FParam("item", BaseDataType.UBYTE, BaseDataType.UWORD, BaseDataType.LONG)),
 | 
				
			||||||
    "ror2"      to FSignature(false, listOf(FParam("item", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
 | 
					    "cmp"     to FSignature(false, null, FParam("value1", *IntegerDatatypes), FParam("value2", *NumericDatatypes)),  // cmp returns result in the cpu status flags, but not asa proper return value
 | 
				
			||||||
    // cmp returns a status in the carry flag, but not a proper return value
 | 
					    "prog8_lib_stringcompare"     to FSignature(true, BaseDataType.BYTE, FParam("str1", BaseDataType.STR), FParam("str2", BaseDataType.STR)),
 | 
				
			||||||
    "cmp"       to FSignature(false, listOf(FParam("value1", IntegerDatatypes), FParam("value2", NumericDatatypes)), null),
 | 
					    "prog8_lib_square_byte"       to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.BYTE, BaseDataType.UBYTE)),
 | 
				
			||||||
    "prog8_lib_stringcompare"     to FSignature(true, listOf(FParam("str1", arrayOf(DataType.STR)), FParam("str2", arrayOf(DataType.STR))), DataType.BYTE),
 | 
					    "prog8_lib_square_word"       to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.WORD, BaseDataType.UWORD)),
 | 
				
			||||||
    "prog8_lib_arraycopy"         to FSignature(false, listOf(FParam("source", ArrayDatatypes), FParam("target", ArrayDatatypes)), null),
 | 
					    "prog8_lib_structalloc"       to FSignature(true, BaseDataType.UWORD),
 | 
				
			||||||
    "prog8_lib_square_byte"       to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE, DataType.UBYTE))), DataType.UBYTE),
 | 
					    "abs"           to FSignature(true, null, FParam("value", *NumericDatatypes)),
 | 
				
			||||||
    "prog8_lib_square_word"       to FSignature(true, listOf(FParam("value", arrayOf(DataType.WORD, DataType.UWORD))), DataType.UWORD),
 | 
					    "abs__byte"     to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.BYTE)),
 | 
				
			||||||
    "prog8_ifelse_bittest_set"    to FSignature(true, listOf(FParam("variable", ByteDatatypes), FParam("bitnumber", arrayOf(DataType.UBYTE))), DataType.BOOL),
 | 
					    "abs__word"     to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.WORD)),
 | 
				
			||||||
    "prog8_ifelse_bittest_notset" to FSignature(true, listOf(FParam("variable", ByteDatatypes), FParam("bitnumber", arrayOf(DataType.UBYTE))), DataType.BOOL),
 | 
					    "abs__long"     to FSignature(true, BaseDataType.LONG, FParam("value", BaseDataType.LONG)),
 | 
				
			||||||
    "abs"       to FSignature(true, listOf(FParam("value", NumericDatatypes)), null),
 | 
					    "abs__float"    to FSignature(true, BaseDataType.FLOAT, FParam("value", BaseDataType.FLOAT)),
 | 
				
			||||||
    "abs__byte"  to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE))), DataType.BYTE),
 | 
					    "len"           to FSignature(true, BaseDataType.UWORD, FParam("values", *IterableDatatypes)),
 | 
				
			||||||
    "abs__word"  to FSignature(true, listOf(FParam("value", arrayOf(DataType.WORD))), DataType.WORD),
 | 
					    "sizeof"        to FSignature(true, BaseDataType.UBYTE, FParam("object", *(BaseDataType.entries - BaseDataType.STRUCT_INSTANCE).toTypedArray())),
 | 
				
			||||||
    "abs__float" to FSignature(true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT),
 | 
					    "offsetof"      to FSignature(true, BaseDataType.UBYTE, FParam("field", BaseDataType.UBYTE)),
 | 
				
			||||||
    "len"       to FSignature(true, listOf(FParam("values", IterableDatatypes)), DataType.UWORD),
 | 
					    "sgn"           to FSignature(true, BaseDataType.BYTE, FParam("value", *NumericDatatypes)),
 | 
				
			||||||
    // normal functions follow:
 | 
					    "sqrt"          to FSignature(true, null, FParam("value", *NumericDatatypes)),
 | 
				
			||||||
    "sizeof"    to FSignature(true, listOf(FParam("object", DataType.entries.toTypedArray())), DataType.UBYTE),
 | 
					    "sqrt__ubyte"   to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UBYTE)),
 | 
				
			||||||
    "sgn"       to FSignature(true, listOf(FParam("value", NumericDatatypes)), DataType.BYTE),
 | 
					    "sqrt__uword"   to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD)),
 | 
				
			||||||
    "sqrt"        to FSignature(true, listOf(FParam("value", NumericDatatypes)), null),
 | 
					    "sqrt__float"   to FSignature(true, BaseDataType.FLOAT, FParam("value", BaseDataType.FLOAT)),
 | 
				
			||||||
    "sqrt__ubyte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UBYTE))), DataType.UBYTE),
 | 
					    "divmod"        to FSignature(false, null, FParam("dividend", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("divisor", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("quotient", BaseDataType.UBYTE, BaseDataType.UWORD), FParam("remainder", BaseDataType.UBYTE, BaseDataType.UWORD)),
 | 
				
			||||||
    "sqrt__uword" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD))), DataType.UBYTE),
 | 
					    "divmod__ubyte" to FSignature(false, null, FParam("dividend", BaseDataType.UBYTE), FParam("divisor", BaseDataType.UBYTE), FParam("quotient", BaseDataType.UBYTE), FParam("remainder", BaseDataType.UBYTE)),
 | 
				
			||||||
    "sqrt__float" to FSignature(true, listOf(FParam("value", arrayOf(DataType.FLOAT))), DataType.FLOAT),
 | 
					    "divmod__uword" to FSignature(false, null, FParam("dividend", BaseDataType.UWORD), FParam("divisor", BaseDataType.UWORD), FParam("quotient", BaseDataType.UWORD), FParam("remainder", BaseDataType.UWORD)),
 | 
				
			||||||
    "divmod"           to FSignature(false, listOf(FParam("dividend", arrayOf(DataType.UBYTE, DataType.UWORD)), FParam("divisor", arrayOf(DataType.UBYTE, DataType.UWORD)), FParam("quotient", arrayOf(DataType.UBYTE, DataType.UWORD)), FParam("remainder", arrayOf(DataType.UBYTE, DataType.UWORD))), null),
 | 
					    "lsb"           to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
 | 
				
			||||||
    "divmod__ubyte"    to FSignature(false, listOf(FParam("dividend", arrayOf(DataType.UBYTE)), FParam("divisor", arrayOf(DataType.UBYTE)), FParam("quotient", arrayOf(DataType.UBYTE)), FParam("remainder", arrayOf(DataType.UBYTE))), null),
 | 
					    "lsb__long"     to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.LONG)),
 | 
				
			||||||
    "divmod__uword"    to FSignature(false, listOf(FParam("dividend", arrayOf(DataType.UWORD)), FParam("divisor", arrayOf(DataType.UWORD)), FParam("quotient", arrayOf(DataType.UWORD)), FParam("remainder", arrayOf(DataType.UWORD))), null),
 | 
					    "msb"           to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
 | 
				
			||||||
    "lsb"       to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE),
 | 
					    "msb__long"     to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.LONG)),
 | 
				
			||||||
    "msb"       to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD, DataType.WORD))), DataType.UBYTE),
 | 
					    "lsw"           to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
 | 
				
			||||||
    "mkword"    to FSignature(true, listOf(FParam("msb", arrayOf(DataType.UBYTE)), FParam("lsb", arrayOf(DataType.UBYTE))), DataType.UWORD),
 | 
					    "msw"           to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)),
 | 
				
			||||||
    "clamp"     to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE)), FParam("minimum", arrayOf(DataType.BYTE)), FParam("maximum", arrayOf(DataType.BYTE))), null),
 | 
					    "mkword"        to FSignature(true, BaseDataType.UWORD, FParam("msb", BaseDataType.UBYTE), FParam("lsb", BaseDataType.UBYTE)),
 | 
				
			||||||
    "clamp__byte"  to FSignature(true, listOf(FParam("value", arrayOf(DataType.BYTE)), FParam("minimum", arrayOf(DataType.BYTE)), FParam("maximum", arrayOf(DataType.BYTE))), DataType.BYTE),
 | 
					    "mklong"        to FSignature(true, BaseDataType.LONG, FParam("msb", BaseDataType.UBYTE), FParam("b2", BaseDataType.UBYTE), FParam("b1", BaseDataType.UBYTE), FParam("lsb", BaseDataType.UBYTE)),
 | 
				
			||||||
    "clamp__ubyte" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UBYTE)), FParam("minimum", arrayOf(DataType.UBYTE)), FParam("maximum", arrayOf(DataType.UBYTE))), DataType.UBYTE),
 | 
					    "mklong2"       to FSignature(true, BaseDataType.LONG, FParam("msw", BaseDataType.UWORD), FParam("lsw", BaseDataType.UWORD)),
 | 
				
			||||||
    "clamp__word"  to FSignature(true, listOf(FParam("value", arrayOf(DataType.WORD)), FParam("minimum", arrayOf(DataType.WORD)), FParam("maximum", arrayOf(DataType.WORD))), DataType.WORD),
 | 
					    "clamp"         to FSignature(true, null, FParam("value", BaseDataType.BYTE), FParam("minimum", BaseDataType.BYTE), FParam("maximum", BaseDataType.BYTE)),
 | 
				
			||||||
    "clamp__uword" to FSignature(true, listOf(FParam("value", arrayOf(DataType.UWORD)), FParam("minimum", arrayOf(DataType.UWORD)), FParam("maximum", arrayOf(DataType.UWORD))), DataType.UWORD),
 | 
					    "clamp__byte"   to FSignature(true, BaseDataType.BYTE, FParam("value", BaseDataType.BYTE), FParam("minimum", BaseDataType.BYTE), FParam("maximum", BaseDataType.BYTE)),
 | 
				
			||||||
    "min"        to FSignature(true, listOf(FParam("val1", arrayOf(DataType.BYTE)), FParam("val2", arrayOf(DataType.BYTE))), null),
 | 
					    "clamp__ubyte"  to FSignature(true, BaseDataType.UBYTE, FParam("value", BaseDataType.UBYTE), FParam("minimum", BaseDataType.UBYTE), FParam("maximum", BaseDataType.UBYTE)),
 | 
				
			||||||
    "min__byte"  to FSignature(true, listOf(FParam("val1", arrayOf(DataType.BYTE)), FParam("val2", arrayOf(DataType.BYTE))), DataType.BYTE),
 | 
					    "clamp__word"   to FSignature(true, BaseDataType.WORD, FParam("value", BaseDataType.WORD), FParam("minimum", BaseDataType.WORD), FParam("maximum", BaseDataType.WORD)),
 | 
				
			||||||
    "min__ubyte" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.UBYTE)), FParam("val2", arrayOf(DataType.UBYTE))), DataType.UBYTE),
 | 
					    "clamp__uword"  to FSignature(true, BaseDataType.UWORD, FParam("value", BaseDataType.UWORD), FParam("minimum", BaseDataType.UWORD), FParam("maximum", BaseDataType.UWORD)),
 | 
				
			||||||
    "min__word"  to FSignature(true, listOf(FParam("val1", arrayOf(DataType.WORD)), FParam("val2", arrayOf(DataType.WORD))), DataType.WORD),
 | 
					    "clamp__long"   to FSignature(true, BaseDataType.LONG, FParam("value", BaseDataType.LONG), FParam("minimum", BaseDataType.LONG), FParam("maximum", BaseDataType.LONG)),
 | 
				
			||||||
    "min__uword" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.UWORD)), FParam("val2", arrayOf(DataType.UWORD))), DataType.UWORD),
 | 
					    "min"           to FSignature(true, null, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
 | 
				
			||||||
    "max"        to FSignature(true, listOf(FParam("val1", arrayOf(DataType.BYTE)), FParam("val2", arrayOf(DataType.BYTE))), null),
 | 
					    "min__byte"     to FSignature(true, BaseDataType.BYTE, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
 | 
				
			||||||
    "max__byte"  to FSignature(true, listOf(FParam("val1", arrayOf(DataType.BYTE)), FParam("val2", arrayOf(DataType.BYTE))), DataType.BYTE),
 | 
					    "min__ubyte"    to FSignature(true, BaseDataType.UBYTE, FParam("val1", BaseDataType.UBYTE), FParam("val2", BaseDataType.UBYTE)),
 | 
				
			||||||
    "max__ubyte" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.UBYTE)), FParam("val2", arrayOf(DataType.UBYTE))), DataType.UBYTE),
 | 
					    "min__word"     to FSignature(true, BaseDataType.WORD, FParam("val1", BaseDataType.WORD), FParam("val2", BaseDataType.WORD)),
 | 
				
			||||||
    "max__word"  to FSignature(true, listOf(FParam("val1", arrayOf(DataType.WORD)), FParam("val2", arrayOf(DataType.WORD))), DataType.WORD),
 | 
					    "min__uword"    to FSignature(true, BaseDataType.UWORD, FParam("val1", BaseDataType.UWORD), FParam("val2", BaseDataType.UWORD)),
 | 
				
			||||||
    "max__uword" to FSignature(true, listOf(FParam("val1", arrayOf(DataType.UWORD)), FParam("val2", arrayOf(DataType.UWORD))), DataType.UWORD),
 | 
					    "min__long"     to FSignature(true, BaseDataType.LONG, FParam("val1", BaseDataType.LONG), FParam("val2", BaseDataType.LONG)),
 | 
				
			||||||
    "peek"      to FSignature(true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UBYTE),
 | 
					    "max"           to FSignature(true, null, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
 | 
				
			||||||
    "peekw"     to FSignature(true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UWORD),
 | 
					    "max__byte"     to FSignature(true, BaseDataType.BYTE, FParam("val1", BaseDataType.BYTE), FParam("val2", BaseDataType.BYTE)),
 | 
				
			||||||
    "peekf"     to FSignature(true, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.FLOAT),
 | 
					    "max__ubyte"    to FSignature(true, BaseDataType.UBYTE, FParam("val1", BaseDataType.UBYTE), FParam("val2", BaseDataType.UBYTE)),
 | 
				
			||||||
    "poke"      to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), null),
 | 
					    "max__word"     to FSignature(true, BaseDataType.WORD, FParam("val1", BaseDataType.WORD), FParam("val2", BaseDataType.WORD)),
 | 
				
			||||||
    "pokew"     to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UWORD))), null),
 | 
					    "max__uword"    to FSignature(true, BaseDataType.UWORD, FParam("val1", BaseDataType.UWORD), FParam("val2", BaseDataType.UWORD)),
 | 
				
			||||||
    "pokef"     to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.FLOAT))), null),
 | 
					    "max__long"     to FSignature(true, BaseDataType.LONG, FParam("val1", BaseDataType.LONG), FParam("val2", BaseDataType.LONG)),
 | 
				
			||||||
    "pokemon"   to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD)), FParam("value", arrayOf(DataType.UBYTE))), DataType.UBYTE),
 | 
					    "peek"          to FSignature(true, BaseDataType.UBYTE, FParam("address", BaseDataType.UWORD)),
 | 
				
			||||||
    "rsave"     to FSignature(false, emptyList(), null),
 | 
					    "peekbool"      to FSignature(true, BaseDataType.BOOL, FParam("address", BaseDataType.UWORD)),
 | 
				
			||||||
    "rrestore"  to FSignature(false, emptyList(), null),
 | 
					    "peekw"         to FSignature(true, BaseDataType.UWORD, FParam("address", BaseDataType.UWORD)),
 | 
				
			||||||
    "memory"    to FSignature(true, listOf(FParam("name", arrayOf(DataType.STR)), FParam("size", arrayOf(DataType.UWORD)), FParam("alignment", arrayOf(DataType.UWORD))), DataType.UWORD),
 | 
					    "peekl"         to FSignature(true, BaseDataType.LONG, FParam("address", BaseDataType.UWORD)),
 | 
				
			||||||
    "callfar"   to FSignature(false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("arg", arrayOf(DataType.UWORD))), DataType.UWORD),
 | 
					    "peekf"         to FSignature(true, BaseDataType.FLOAT, FParam("address", BaseDataType.UWORD)),
 | 
				
			||||||
    "callfar2"  to FSignature(false, listOf(FParam("bank", arrayOf(DataType.UBYTE)), FParam("address", arrayOf(DataType.UWORD)), FParam("argA", arrayOf(DataType.UBYTE)), FParam("argX", arrayOf(DataType.UBYTE)), FParam("argY", arrayOf(DataType.UBYTE)), FParam("argC", arrayOf(DataType.BOOL))), DataType.UWORD),
 | 
					    "poke"          to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE, BaseDataType.BYTE)),
 | 
				
			||||||
    "call"      to FSignature(false, listOf(FParam("address", arrayOf(DataType.UWORD))), DataType.UWORD),
 | 
					    "pokebool"      to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.BOOL)),
 | 
				
			||||||
 | 
					    "pokebowl"      to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.BOOL)),
 | 
				
			||||||
 | 
					    "pokew"         to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UWORD, BaseDataType.WORD)),
 | 
				
			||||||
 | 
					    "pokel"         to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.LONG)),
 | 
				
			||||||
 | 
					    "pokef"         to FSignature(false, null, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.FLOAT)),
 | 
				
			||||||
 | 
					    "pokemon"       to FSignature(false, BaseDataType.UBYTE, FParam("address", BaseDataType.UWORD), FParam("value", BaseDataType.UBYTE)),
 | 
				
			||||||
 | 
					    "rsave"         to FSignature(false, null),
 | 
				
			||||||
 | 
					    "rrestore"      to FSignature(false, null),
 | 
				
			||||||
 | 
					    "memory"        to FSignature(true, BaseDataType.UWORD, FParam("name", BaseDataType.STR), FParam("size", BaseDataType.UWORD), FParam("alignment", BaseDataType.UWORD)),
 | 
				
			||||||
 | 
					    "callfar"       to FSignature(false, BaseDataType.UWORD, FParam("bank", BaseDataType.UBYTE), FParam("address", BaseDataType.UWORD), FParam("arg", BaseDataType.UWORD)),
 | 
				
			||||||
 | 
					    "callfar2"      to FSignature(false, BaseDataType.UWORD, FParam("bank", BaseDataType.UBYTE), FParam("address", BaseDataType.UWORD), FParam("argA", BaseDataType.UBYTE), FParam("argX", BaseDataType.UBYTE), FParam("argY", BaseDataType.UBYTE), FParam("argC", BaseDataType.BOOL)),
 | 
				
			||||||
 | 
					    "call"          to FSignature(false, BaseDataType.UWORD, FParam("address", BaseDataType.UWORD)),
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val InplaceModifyingBuiltinFunctions = setOf(
 | 
					val InplaceModifyingBuiltinFunctions = setOf(
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,9 +11,12 @@ class CompilationOptions(val output: OutputType,
 | 
				
			|||||||
                         val zpAllowed: List<UIntRange>,
 | 
					                         val zpAllowed: List<UIntRange>,
 | 
				
			||||||
                         val floats: Boolean,
 | 
					                         val floats: Boolean,
 | 
				
			||||||
                         val noSysInit: Boolean,
 | 
					                         val noSysInit: Boolean,
 | 
				
			||||||
 | 
					                         val romable: Boolean,
 | 
				
			||||||
                         val compTarget: ICompilationTarget,
 | 
					                         val compTarget: ICompilationTarget,
 | 
				
			||||||
 | 
					                         val compilerVersion: String,
 | 
				
			||||||
                         // these are set later, based on command line arguments or options in the source code:
 | 
					                         // these are set later, based on command line arguments or options in the source code:
 | 
				
			||||||
                         var loadAddress: UInt,
 | 
					                         var loadAddress: UInt,
 | 
				
			||||||
 | 
					                         var memtopAddress: UInt,
 | 
				
			||||||
                         var warnSymbolShadowing: Boolean = false,
 | 
					                         var warnSymbolShadowing: Boolean = false,
 | 
				
			||||||
                         var optimize: Boolean = false,
 | 
					                         var optimize: Boolean = false,
 | 
				
			||||||
                         var asmQuiet: Boolean = false,
 | 
					                         var asmQuiet: Boolean = false,
 | 
				
			||||||
@@ -26,13 +29,14 @@ class CompilationOptions(val output: OutputType,
 | 
				
			|||||||
                         var varsGolden: Boolean = false,
 | 
					                         var varsGolden: Boolean = false,
 | 
				
			||||||
                         var slabsHighBank: Int? = null,
 | 
					                         var slabsHighBank: Int? = null,
 | 
				
			||||||
                         var slabsGolden: Boolean = false,
 | 
					                         var slabsGolden: Boolean = false,
 | 
				
			||||||
                         var splitWordArrays: Boolean = false,
 | 
					 | 
				
			||||||
                         var breakpointCpuInstruction: String? = null,
 | 
					                         var breakpointCpuInstruction: String? = null,
 | 
				
			||||||
 | 
					                         var ignoreFootguns: Boolean = false,
 | 
				
			||||||
                         var outputDir: Path = Path(""),
 | 
					                         var outputDir: Path = Path(""),
 | 
				
			||||||
 | 
					                         var quiet: Boolean = false,
 | 
				
			||||||
                         var symbolDefs: Map<String, String> = emptyMap()
 | 
					                         var symbolDefs: Map<String, String> = emptyMap()
 | 
				
			||||||
) {
 | 
					) {
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
        compTarget.machine.initializeMemoryAreas(this)
 | 
					        compTarget.initializeMemoryAreas(this)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -11,15 +11,16 @@ fun Number.toHex(): String {
 | 
				
			|||||||
    //  0..15 -> "0".."15"
 | 
					    //  0..15 -> "0".."15"
 | 
				
			||||||
    //  16..255 -> "$10".."$ff"
 | 
					    //  16..255 -> "$10".."$ff"
 | 
				
			||||||
    //  256..65536 -> "$0100".."$ffff"
 | 
					    //  256..65536 -> "$0100".."$ffff"
 | 
				
			||||||
 | 
					    //  larger -> "$12345678"
 | 
				
			||||||
    // negative values are prefixed with '-'.
 | 
					    // negative values are prefixed with '-'.
 | 
				
			||||||
    val integer = this.toInt()
 | 
					    val integer = this.toLong()
 | 
				
			||||||
    if(integer<0)
 | 
					    if(integer<0)
 | 
				
			||||||
        return '-' + abs(integer).toHex()
 | 
					        return '-' + abs(integer).toHex()
 | 
				
			||||||
    return when (integer) {
 | 
					    return when (integer) {
 | 
				
			||||||
        in 0 until 16 -> integer.toString()
 | 
					        in 0 until 16 -> integer.toString()
 | 
				
			||||||
        in 0 until 0x100 -> "$"+integer.toString(16).padStart(2,'0')
 | 
					        in 0 until 0x100 -> "$"+integer.toString(16).padStart(2,'0')
 | 
				
			||||||
        in 0 until 0x10000 -> "$"+integer.toString(16).padStart(4,'0')
 | 
					        in 0 until 0x10000 -> "$"+integer.toString(16).padStart(4,'0')
 | 
				
			||||||
        else -> throw IllegalArgumentException("number too large for 16 bits $this")
 | 
					        else -> "$"+integer.toString(16).padStart(8,'0')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -27,11 +28,12 @@ fun UInt.toHex(): String {
 | 
				
			|||||||
    //  0..15 -> "0".."15"
 | 
					    //  0..15 -> "0".."15"
 | 
				
			||||||
    //  16..255 -> "$10".."$ff"
 | 
					    //  16..255 -> "$10".."$ff"
 | 
				
			||||||
    //  256..65536 -> "$0100".."$ffff"
 | 
					    //  256..65536 -> "$0100".."$ffff"
 | 
				
			||||||
 | 
					    //  larger -> "$12345678"
 | 
				
			||||||
    return when (this) {
 | 
					    return when (this) {
 | 
				
			||||||
        in 0u until 16u -> this.toString()
 | 
					        in 0u until 16u -> this.toString()
 | 
				
			||||||
        in 0u until 0x100u -> "$"+this.toString(16).padStart(2,'0')
 | 
					        in 0u until 0x100u -> "$"+this.toString(16).padStart(2,'0')
 | 
				
			||||||
        in 0u until 0x10000u -> "$"+this.toString(16).padStart(4,'0')
 | 
					        in 0u until 0x10000u -> "$"+this.toString(16).padStart(4,'0')
 | 
				
			||||||
        else -> throw IllegalArgumentException("number too large for 16 bits $this")
 | 
					        else -> "$"+this.toString(16).padStart(8,'0')
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,63 +1,388 @@
 | 
				
			|||||||
package prog8.code.core
 | 
					package prog8.code.core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class DataType {
 | 
					import java.util.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class BaseDataType {
 | 
				
			||||||
    UBYTE,              // pass by value            8 bits unsigned
 | 
					    UBYTE,              // pass by value            8 bits unsigned
 | 
				
			||||||
    BYTE,               // pass by value            8 bits signed
 | 
					    BYTE,               // pass by value            8 bits signed
 | 
				
			||||||
    UWORD,              // pass by value            16 bits unsigned
 | 
					    UWORD,              // pass by value            16 bits unsigned
 | 
				
			||||||
    WORD,               // pass by value            16 bits signed
 | 
					    WORD,               // pass by value            16 bits signed
 | 
				
			||||||
    LONG,               // pass by value            32 bits signed
 | 
					    LONG,               // pass by value            32 bits signed
 | 
				
			||||||
    FLOAT,              // pass by value            machine dependent
 | 
					    FLOAT,              // pass by value            machine dependent
 | 
				
			||||||
    BOOL,               // pass by value            bit 0 of a 8 bit byte
 | 
					    BOOL,               // pass by value            bit 0 of an 8-bit byte
 | 
				
			||||||
    STR,                // pass by reference
 | 
					    STR,                // pass by reference
 | 
				
			||||||
    ARRAY_UB,           // pass by reference
 | 
					    ARRAY,              // pass by reference, subtype is the element type
 | 
				
			||||||
    ARRAY_B,            // pass by reference
 | 
					    ARRAY_SPLITW,       // pass by reference, split word layout, subtype is the element type (restricted to word types)
 | 
				
			||||||
    ARRAY_UW,           // pass by reference
 | 
					    POINTER,            // typed pointer, subtype is whatever type is pointed to
 | 
				
			||||||
    ARRAY_UW_SPLIT,     // pass by reference, lo/hi byte split
 | 
					    STRUCT_INSTANCE,    // the actual instance of a struct (not directly supported in the language yet, but we need its type)
 | 
				
			||||||
    ARRAY_W,            // pass by reference
 | 
					    ARRAY_POINTER,      // array of pointers (uwords), subtype is whatever type each element points to
 | 
				
			||||||
    ARRAY_W_SPLIT,      // pass by reference, lo/hi byte split
 | 
					 | 
				
			||||||
    ARRAY_F,            // pass by reference
 | 
					 | 
				
			||||||
    ARRAY_BOOL,         // pass by reference
 | 
					 | 
				
			||||||
    UNDEFINED;
 | 
					    UNDEFINED;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * is the type assignable to the given other type (perhaps via a typecast) without loss of precision?
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    infix fun isAssignableTo(targetType: DataType) =
 | 
					 | 
				
			||||||
        when(this) {
 | 
					 | 
				
			||||||
            BOOL -> targetType == BOOL
 | 
					 | 
				
			||||||
            UBYTE -> targetType.oneOf(UBYTE, WORD, UWORD, LONG, FLOAT)
 | 
					 | 
				
			||||||
            BYTE -> targetType.oneOf(BYTE, WORD, LONG, FLOAT)
 | 
					 | 
				
			||||||
            UWORD -> targetType.oneOf(UWORD, LONG, FLOAT)
 | 
					 | 
				
			||||||
            WORD -> targetType.oneOf(WORD, LONG, FLOAT)
 | 
					 | 
				
			||||||
            LONG -> targetType.oneOf(LONG, FLOAT)
 | 
					 | 
				
			||||||
            FLOAT -> targetType.oneOf(FLOAT)
 | 
					 | 
				
			||||||
            STR -> targetType.oneOf(STR, UWORD)
 | 
					 | 
				
			||||||
            in ArrayDatatypes -> targetType == this
 | 
					 | 
				
			||||||
            else -> false
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun oneOf(vararg types: DataType) = this in types
 | 
					    fun largerSizeThan(other: BaseDataType) =
 | 
				
			||||||
 | 
					 | 
				
			||||||
    infix fun largerThan(other: DataType) =
 | 
					 | 
				
			||||||
        when {
 | 
					        when {
 | 
				
			||||||
            this == other -> false
 | 
					            this == other -> false
 | 
				
			||||||
            this in ByteDatatypesWithBoolean -> false
 | 
					            this.isByteOrBool -> false
 | 
				
			||||||
            this in WordDatatypes -> other in ByteDatatypesWithBoolean
 | 
					            this.isWord -> other.isByteOrBool
 | 
				
			||||||
            this == LONG -> other in ByteDatatypesWithBoolean+WordDatatypes
 | 
					            this == LONG -> other.isByteOrBool || other.isWord
 | 
				
			||||||
            this == STR && other == UWORD || this == UWORD && other == STR -> false
 | 
					            this == STR && other == UWORD || this == UWORD && other == STR -> false
 | 
				
			||||||
 | 
					            this.isArray && other.isArray -> false
 | 
				
			||||||
 | 
					            this.isArray -> other != FLOAT
 | 
				
			||||||
 | 
					            this == STR -> other != FLOAT
 | 
				
			||||||
 | 
					            this.isPointer -> other.isByteOrBool
 | 
				
			||||||
            else -> true
 | 
					            else -> true
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    infix fun equalsSize(other: DataType) =
 | 
					    fun equalsSize(other: BaseDataType) =
 | 
				
			||||||
        when {
 | 
					        when {
 | 
				
			||||||
            this == other -> true
 | 
					            this == other -> true
 | 
				
			||||||
            this in ByteDatatypesWithBoolean -> other in ByteDatatypesWithBoolean
 | 
					            this.isArray && other.isArray -> true
 | 
				
			||||||
            this in WordDatatypes -> other in WordDatatypes
 | 
					            this.isByteOrBool -> other.isByteOrBool
 | 
				
			||||||
            this== STR && other== UWORD || this== UWORD && other== STR -> true
 | 
					            this.isWord -> other.isWord || other.isPointer
 | 
				
			||||||
 | 
					            this.isPointer -> other.isWord
 | 
				
			||||||
 | 
					            this == STR && other== UWORD || this== UWORD && other== STR -> true
 | 
				
			||||||
 | 
					            this == STR && other.isArray -> true
 | 
				
			||||||
 | 
					            this.isArray && other == STR -> true
 | 
				
			||||||
            else -> false
 | 
					            else -> false
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					val BaseDataType.isByte get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE)
 | 
				
			||||||
 | 
					val BaseDataType.isByteOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.BOOL)
 | 
				
			||||||
 | 
					val BaseDataType.isWord get() = this in arrayOf(BaseDataType.UWORD, BaseDataType.WORD)
 | 
				
			||||||
 | 
					val BaseDataType.isLong get() = this == BaseDataType.LONG
 | 
				
			||||||
 | 
					val BaseDataType.isInteger get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG)
 | 
				
			||||||
 | 
					val BaseDataType.isIntegerOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.BOOL)
 | 
				
			||||||
 | 
					val BaseDataType.isWordOrByteOrBool get() = this in arrayOf(BaseDataType.UBYTE, BaseDataType.BYTE, BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.BOOL)
 | 
				
			||||||
 | 
					val BaseDataType.isNumeric get() = this == BaseDataType.FLOAT || this.isInteger
 | 
				
			||||||
 | 
					val BaseDataType.isNumericOrBool get() = this == BaseDataType.BOOL || this.isNumeric
 | 
				
			||||||
 | 
					val BaseDataType.isSigned get() = this in arrayOf(BaseDataType.BYTE, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
 | 
				
			||||||
 | 
					val BaseDataType.isArray get() = this == BaseDataType.ARRAY || this == BaseDataType.ARRAY_SPLITW || this == BaseDataType.ARRAY_POINTER
 | 
				
			||||||
 | 
					val BaseDataType.isPointer get() = this == BaseDataType.POINTER
 | 
				
			||||||
 | 
					val BaseDataType.isStructInstance get() = this == BaseDataType.STRUCT_INSTANCE
 | 
				
			||||||
 | 
					val BaseDataType.isPointerArray get() = this == BaseDataType.ARRAY_POINTER
 | 
				
			||||||
 | 
					val BaseDataType.isSplitWordArray get() = this == BaseDataType.ARRAY_SPLITW || this == BaseDataType.ARRAY_POINTER       // pointer arrays are also always stored as split uwords
 | 
				
			||||||
 | 
					val BaseDataType.isIterable get() =  this in arrayOf(BaseDataType.STR, BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW, BaseDataType.ARRAY_POINTER)
 | 
				
			||||||
 | 
					val BaseDataType.isPassByRef get() = this.isIterable && !this.isPointer
 | 
				
			||||||
 | 
					val BaseDataType.isPassByValue get() = !this.isIterable || this.isPointer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ISubType {
 | 
				
			||||||
 | 
					    val scopedNameString: String
 | 
				
			||||||
 | 
					    fun memsize(sizer: IMemSizer): Int
 | 
				
			||||||
 | 
					    fun sameas(other: ISubType): Boolean
 | 
				
			||||||
 | 
					    fun getFieldType(name: String): DataType?
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DataType private constructor(val base: BaseDataType, val sub: BaseDataType?, var subType: ISubType?, var subTypeFromAntlr: List<String>?=null) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    init {
 | 
				
			||||||
 | 
					        when {
 | 
				
			||||||
 | 
					            base.isPointerArray -> {
 | 
				
			||||||
 | 
					                require(sub!=null || subType!=null || subTypeFromAntlr!=null)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            base.isArray -> {
 | 
				
			||||||
 | 
					                require(sub != null && subType==null && subTypeFromAntlr==null)
 | 
				
			||||||
 | 
					                if(base.isSplitWordArray)
 | 
				
			||||||
 | 
					                    require(sub == BaseDataType.UWORD || sub == BaseDataType.WORD)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            base==BaseDataType.STR -> require(sub==BaseDataType.UBYTE) { "string subtype should be ubyte" }
 | 
				
			||||||
 | 
					            base!=BaseDataType.POINTER -> require(sub == null) { "only string, array and pointer base types can have a subtype"}
 | 
				
			||||||
 | 
					            else -> {
 | 
				
			||||||
 | 
					                require(sub == null || (subType == null && subTypeFromAntlr == null)) {
 | 
				
			||||||
 | 
					                    "sub and subtype can't both be set"
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun equals(other: Any?): Boolean {
 | 
				
			||||||
 | 
					        if (this === other) return true
 | 
				
			||||||
 | 
					        if (other !is DataType) return false
 | 
				
			||||||
 | 
					        return base == other.base && sub == other.sub && (subType==other.subType || subType!!.sameas(other.subType!!))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun hashCode(): Int = Objects.hash(base, sub, subType)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun setActualSubType(actualSubType: ISubType) {
 | 
				
			||||||
 | 
					        subType = actualSubType
 | 
				
			||||||
 | 
					        subTypeFromAntlr = null
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    companion object {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val UBYTE = DataType(BaseDataType.UBYTE, null, null)
 | 
				
			||||||
 | 
					        val BYTE = DataType(BaseDataType.BYTE, null, null)
 | 
				
			||||||
 | 
					        val UWORD = DataType(BaseDataType.UWORD, null, null)
 | 
				
			||||||
 | 
					        val WORD = DataType(BaseDataType.WORD, null, null)
 | 
				
			||||||
 | 
					        val LONG = DataType(BaseDataType.LONG, null, null)
 | 
				
			||||||
 | 
					        val FLOAT = DataType(BaseDataType.FLOAT, null, null)
 | 
				
			||||||
 | 
					        val BOOL = DataType(BaseDataType.BOOL, null, null)
 | 
				
			||||||
 | 
					        val STR = DataType(BaseDataType.STR, BaseDataType.UBYTE, null)
 | 
				
			||||||
 | 
					        val UNDEFINED = DataType(BaseDataType.UNDEFINED, null, null)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private val simpletypes = mapOf(
 | 
				
			||||||
 | 
					            BaseDataType.UBYTE to DataType(BaseDataType.UBYTE, null, null),
 | 
				
			||||||
 | 
					            BaseDataType.BYTE to DataType(BaseDataType.BYTE, null, null),
 | 
				
			||||||
 | 
					            BaseDataType.UWORD to DataType(BaseDataType.UWORD, null, null),
 | 
				
			||||||
 | 
					            BaseDataType.WORD to DataType(BaseDataType.WORD, null, null),
 | 
				
			||||||
 | 
					            BaseDataType.LONG to DataType(BaseDataType.LONG, null, null),
 | 
				
			||||||
 | 
					            BaseDataType.FLOAT to DataType(BaseDataType.FLOAT, null, null),
 | 
				
			||||||
 | 
					            BaseDataType.BOOL to DataType(BaseDataType.BOOL, null, null),
 | 
				
			||||||
 | 
					            BaseDataType.STR to DataType(BaseDataType.STR, BaseDataType.UBYTE, null),
 | 
				
			||||||
 | 
					            BaseDataType.UNDEFINED to DataType(BaseDataType.UNDEFINED, null, null)
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fun forDt(dt: BaseDataType): DataType {
 | 
				
			||||||
 | 
					            if(dt.isStructInstance)
 | 
				
			||||||
 | 
					                TODO("cannot use struct instance as a data type (yet) - use a pointer instead")
 | 
				
			||||||
 | 
					            return simpletypes.getValue(dt)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fun arrayFor(elementDt: BaseDataType, splitwordarray: Boolean=true): DataType {
 | 
				
			||||||
 | 
					            require(!elementDt.isPointer) { "use other array constructor for arrays of pointers" }
 | 
				
			||||||
 | 
					            val actualElementDt = if(elementDt==BaseDataType.STR) BaseDataType.UWORD else elementDt      // array of strings is actually just an array of UWORD pointers
 | 
				
			||||||
 | 
					            return if(splitwordarray && actualElementDt.isWord)
 | 
				
			||||||
 | 
					                DataType(BaseDataType.ARRAY_SPLITW, actualElementDt, null)
 | 
				
			||||||
 | 
					            else {
 | 
				
			||||||
 | 
					                if(actualElementDt.isNumericOrBool)
 | 
				
			||||||
 | 
					                    DataType(BaseDataType.ARRAY, actualElementDt, null)
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    throw NoSuchElementException("invalid basic element dt $elementDt")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fun arrayOfPointersTo(sub: BaseDataType): DataType = DataType(BaseDataType.ARRAY_POINTER, sub, null)
 | 
				
			||||||
 | 
					        fun arrayOfPointersTo(structType: ISubType?): DataType = DataType(BaseDataType.ARRAY_POINTER, null, structType)
 | 
				
			||||||
 | 
					        fun arrayOfPointersFromAntlrTo(sub: BaseDataType?, identifier: List<String>?): DataType =
 | 
				
			||||||
 | 
					            DataType(BaseDataType.ARRAY_POINTER, sub, null, identifier)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fun pointer(base: BaseDataType): DataType = DataType(BaseDataType.POINTER, base, null)
 | 
				
			||||||
 | 
					        fun pointer(dt: DataType): DataType = if(dt.isBasic)
 | 
				
			||||||
 | 
					                DataType(BaseDataType.POINTER, dt.base, null)
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                DataType(BaseDataType.POINTER, null, dt.subType, dt.subTypeFromAntlr)
 | 
				
			||||||
 | 
					        fun pointer(structType: ISubType): DataType = DataType(BaseDataType.POINTER, null, structType)
 | 
				
			||||||
 | 
					        fun pointerFromAntlr(identifier: List<String>): DataType = DataType(BaseDataType.POINTER, null, null, identifier)
 | 
				
			||||||
 | 
					        fun structInstance(type: ISubType?): DataType = DataType(BaseDataType.STRUCT_INSTANCE, sub=null, type)
 | 
				
			||||||
 | 
					        fun structInstanceFromAntlr(struct: List<String>): DataType = DataType(BaseDataType.STRUCT_INSTANCE, null, null, subTypeFromAntlr = struct)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun elementToArray(splitwords: Boolean = true): DataType {
 | 
				
			||||||
 | 
					        return if (base == BaseDataType.UWORD || base == BaseDataType.WORD || base == BaseDataType.STR) arrayFor(base, splitwords)
 | 
				
			||||||
 | 
					        else arrayFor(base, false)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun elementType(): DataType =
 | 
				
			||||||
 | 
					        when {
 | 
				
			||||||
 | 
					            isPointerArray -> DataType(BaseDataType.POINTER, sub, subType)
 | 
				
			||||||
 | 
					            base.isArray || base==BaseDataType.STR -> forDt(sub!!)
 | 
				
			||||||
 | 
					            else -> throw IllegalArgumentException("not an array")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun typeForAddressOf(msb: Boolean): DataType {
 | 
				
			||||||
 | 
					        if (isUndefined)
 | 
				
			||||||
 | 
					            return if(msb) pointer(BaseDataType.UBYTE) else UWORD
 | 
				
			||||||
 | 
					        else {
 | 
				
			||||||
 | 
					            if (isBasic)
 | 
				
			||||||
 | 
					                return pointer(base)
 | 
				
			||||||
 | 
					            if (isString)
 | 
				
			||||||
 | 
					                return pointer(BaseDataType.UBYTE)
 | 
				
			||||||
 | 
					            if (isPointer)
 | 
				
			||||||
 | 
					                return UWORD
 | 
				
			||||||
 | 
					            if (isArray) {
 | 
				
			||||||
 | 
					                if (msb || isSplitWordArray)
 | 
				
			||||||
 | 
					                    return pointer(BaseDataType.UBYTE)
 | 
				
			||||||
 | 
					                val elementDt = elementType()
 | 
				
			||||||
 | 
					                require(elementDt.isBasic)
 | 
				
			||||||
 | 
					                return pointer(elementDt)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (subType != null)
 | 
				
			||||||
 | 
					                return pointer(this)
 | 
				
			||||||
 | 
					            return UWORD
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun dereference(): DataType {
 | 
				
			||||||
 | 
					        require(isPointer || isUnsignedWord)
 | 
				
			||||||
 | 
					        return when {
 | 
				
			||||||
 | 
					            isUnsignedWord -> forDt(BaseDataType.UBYTE)
 | 
				
			||||||
 | 
					            sub!=null -> forDt(sub)
 | 
				
			||||||
 | 
					            subType!=null -> DataType(BaseDataType.STRUCT_INSTANCE, null, subType)
 | 
				
			||||||
 | 
					            subTypeFromAntlr!=null -> DataType(BaseDataType.STRUCT_INSTANCE, null, null, subTypeFromAntlr)
 | 
				
			||||||
 | 
					            else -> throw IllegalArgumentException("cannot dereference this pointer type")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun toString(): String = when(base) {
 | 
				
			||||||
 | 
					        BaseDataType.ARRAY -> {
 | 
				
			||||||
 | 
					            when(sub) {
 | 
				
			||||||
 | 
					                BaseDataType.BOOL -> "bool[]"
 | 
				
			||||||
 | 
					                BaseDataType.FLOAT -> "float[]"
 | 
				
			||||||
 | 
					                BaseDataType.BYTE -> "byte[]"
 | 
				
			||||||
 | 
					                BaseDataType.WORD -> "word[]"
 | 
				
			||||||
 | 
					                BaseDataType.UBYTE -> "ubyte[]"
 | 
				
			||||||
 | 
					                BaseDataType.UWORD -> "uword[]"
 | 
				
			||||||
 | 
					                BaseDataType.LONG -> "long[]"
 | 
				
			||||||
 | 
					                else -> throw IllegalArgumentException("invalid sub type")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        BaseDataType.ARRAY_SPLITW -> {
 | 
				
			||||||
 | 
					            when(sub) {
 | 
				
			||||||
 | 
					                BaseDataType.WORD -> "word[] (split)"
 | 
				
			||||||
 | 
					                BaseDataType.UWORD -> "uword[] (split)"
 | 
				
			||||||
 | 
					                else -> throw IllegalArgumentException("invalid sub type")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        BaseDataType.POINTER -> {
 | 
				
			||||||
 | 
					            if(sub!=null) "^^${sub.name.lowercase()}" else if(subType!=null) "^^${subType!!.scopedNameString}" else "^^${subTypeFromAntlr}"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        BaseDataType.ARRAY_POINTER -> {
 | 
				
			||||||
 | 
					            if(sub!=null) "^^${sub.name.lowercase()}[] (split)" else if (subType!=null) "^^${subType!!.scopedNameString}[] (split)" else "^^${subTypeFromAntlr}[] (split)"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        BaseDataType.STRUCT_INSTANCE -> {
 | 
				
			||||||
 | 
					            sub?.name?.lowercase() ?: if (subType!=null) subType!!.scopedNameString else "$subTypeFromAntlr"
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else -> base.name.lowercase()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun sourceString(): String = when (base) {
 | 
				
			||||||
 | 
					        BaseDataType.BOOL -> "bool"
 | 
				
			||||||
 | 
					        BaseDataType.UBYTE -> "ubyte"
 | 
				
			||||||
 | 
					        BaseDataType.BYTE -> "byte"
 | 
				
			||||||
 | 
					        BaseDataType.UWORD -> "uword"
 | 
				
			||||||
 | 
					        BaseDataType.WORD -> "word"
 | 
				
			||||||
 | 
					        BaseDataType.LONG -> "long"
 | 
				
			||||||
 | 
					        BaseDataType.FLOAT -> "float"
 | 
				
			||||||
 | 
					        BaseDataType.STR -> "str"
 | 
				
			||||||
 | 
					        BaseDataType.POINTER -> {
 | 
				
			||||||
 | 
					            when {
 | 
				
			||||||
 | 
					                sub!=null -> "^^${sub.name.lowercase()}"
 | 
				
			||||||
 | 
					                subType!=null -> "^^${subType!!.scopedNameString}"
 | 
				
			||||||
 | 
					                subTypeFromAntlr!=null -> "^^${subTypeFromAntlr!!.joinToString(".")}"
 | 
				
			||||||
 | 
					                else -> "?????"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        BaseDataType.STRUCT_INSTANCE -> {
 | 
				
			||||||
 | 
					            when {
 | 
				
			||||||
 | 
					                sub!=null -> sub.name.lowercase()
 | 
				
			||||||
 | 
					                subType!=null -> subType!!.scopedNameString
 | 
				
			||||||
 | 
					                subTypeFromAntlr!=null -> subTypeFromAntlr!!.joinToString(".")
 | 
				
			||||||
 | 
					                else -> "?????"
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        BaseDataType.ARRAY_POINTER -> {
 | 
				
			||||||
 | 
					            when {
 | 
				
			||||||
 | 
					                sub!=null -> "^^${sub.name.lowercase()}["
 | 
				
			||||||
 | 
					                subType!=null -> "^^${subType!!.scopedNameString}["
 | 
				
			||||||
 | 
					                subTypeFromAntlr!=null -> "^^${subTypeFromAntlr!!.joinToString(".")}["
 | 
				
			||||||
 | 
					                else -> "????? ["
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        BaseDataType.ARRAY -> {
 | 
				
			||||||
 | 
					            when(sub) {
 | 
				
			||||||
 | 
					                BaseDataType.UBYTE -> "ubyte["
 | 
				
			||||||
 | 
					                BaseDataType.UWORD -> "@nosplit uword["
 | 
				
			||||||
 | 
					                BaseDataType.BOOL -> "bool["
 | 
				
			||||||
 | 
					                BaseDataType.BYTE -> "byte["
 | 
				
			||||||
 | 
					                BaseDataType.WORD -> "@nosplit word["
 | 
				
			||||||
 | 
					                BaseDataType.LONG -> "long["
 | 
				
			||||||
 | 
					                BaseDataType.FLOAT -> "float["
 | 
				
			||||||
 | 
					                else -> throw IllegalArgumentException("invalid sub type")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        BaseDataType.ARRAY_SPLITW -> {
 | 
				
			||||||
 | 
					            when(sub) {
 | 
				
			||||||
 | 
					                BaseDataType.UWORD -> "uword["
 | 
				
			||||||
 | 
					                BaseDataType.WORD -> "word["
 | 
				
			||||||
 | 
					                else -> throw IllegalArgumentException("invalid sub type")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        BaseDataType.UNDEFINED -> throw IllegalArgumentException("wrong dt")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // is the type assignable to the given other type (perhaps via a typecast) without loss of precision?
 | 
				
			||||||
 | 
					    infix fun isAssignableTo(targetType: DataType) =
 | 
				
			||||||
 | 
					        when(base) {
 | 
				
			||||||
 | 
					            BaseDataType.BOOL -> targetType.base == BaseDataType.BOOL
 | 
				
			||||||
 | 
					            BaseDataType.UBYTE -> targetType.base in arrayOf(BaseDataType.UBYTE, BaseDataType.WORD, BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.FLOAT)
 | 
				
			||||||
 | 
					            BaseDataType.BYTE -> targetType.base in arrayOf(BaseDataType.BYTE, BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
 | 
				
			||||||
 | 
					            BaseDataType.UWORD -> targetType.base in arrayOf(BaseDataType.UWORD, BaseDataType.LONG, BaseDataType.FLOAT, BaseDataType.POINTER, BaseDataType.ARRAY_POINTER)
 | 
				
			||||||
 | 
					            BaseDataType.WORD -> targetType.base in arrayOf(BaseDataType.WORD, BaseDataType.LONG, BaseDataType.FLOAT)
 | 
				
			||||||
 | 
					            BaseDataType.LONG -> targetType.base in arrayOf(BaseDataType.LONG, BaseDataType.FLOAT)
 | 
				
			||||||
 | 
					            BaseDataType.FLOAT -> targetType.base in arrayOf(BaseDataType.FLOAT)
 | 
				
			||||||
 | 
					            BaseDataType.STR -> targetType.base in arrayOf(BaseDataType.STR, BaseDataType.UWORD) || (targetType.isPointer && targetType.sub==BaseDataType.UBYTE)
 | 
				
			||||||
 | 
					            BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW -> targetType.base in arrayOf(BaseDataType.ARRAY, BaseDataType.ARRAY_SPLITW) && targetType.sub == sub
 | 
				
			||||||
 | 
					            BaseDataType.POINTER -> {
 | 
				
			||||||
 | 
					                when {
 | 
				
			||||||
 | 
					                    targetType.base == BaseDataType.UWORD || targetType.base == BaseDataType.LONG -> true
 | 
				
			||||||
 | 
					                    targetType.isPointer -> this.isUnsignedWord || this == targetType
 | 
				
			||||||
 | 
					                    else -> false
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            BaseDataType.STRUCT_INSTANCE -> false        // we cannot deal with actual struct instances yet in any shape or form (only getting fields from it)
 | 
				
			||||||
 | 
					            BaseDataType.ARRAY_POINTER -> false
 | 
				
			||||||
 | 
					            BaseDataType.UNDEFINED -> false
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun largerSizeThan(other: DataType): Boolean = base.largerSizeThan(other.base)
 | 
				
			||||||
 | 
					    fun equalsSize(other: DataType): Boolean = base.equalsSize(other.base)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // note: for pointer types, size() doesn't return the size of the pointer itself but the size of the thing it points to
 | 
				
			||||||
 | 
					    fun size(memsizer: IMemSizer): Int = if(sub!=null) {
 | 
				
			||||||
 | 
					            memsizer.memorySize(sub)
 | 
				
			||||||
 | 
					        } else if(subType!=null) {
 | 
				
			||||||
 | 
					            subType!!.memsize(memsizer)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            memsizer.memorySize(base)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val isBasic = sub==null && subType==null && subTypeFromAntlr==null
 | 
				
			||||||
 | 
					    val isUndefined = base == BaseDataType.UNDEFINED
 | 
				
			||||||
 | 
					    val isByte = base.isByte
 | 
				
			||||||
 | 
					    val isUnsignedByte = base == BaseDataType.UBYTE
 | 
				
			||||||
 | 
					    val isSignedByte = base == BaseDataType.BYTE
 | 
				
			||||||
 | 
					    val isByteOrBool = base.isByteOrBool
 | 
				
			||||||
 | 
					    val isWord = base.isWord
 | 
				
			||||||
 | 
					    val isUnsignedWord =  base == BaseDataType.UWORD
 | 
				
			||||||
 | 
					    val isSignedWord =  base == BaseDataType.WORD
 | 
				
			||||||
 | 
					    val isInteger = base.isInteger
 | 
				
			||||||
 | 
					    val isWordOrByteOrBool = base.isWordOrByteOrBool
 | 
				
			||||||
 | 
					    val isIntegerOrBool = base.isIntegerOrBool
 | 
				
			||||||
 | 
					    val isNumeric = base.isNumeric
 | 
				
			||||||
 | 
					    val isNumericOrBool = base.isNumericOrBool
 | 
				
			||||||
 | 
					    val isSigned = base.isSigned
 | 
				
			||||||
 | 
					    val isUnsigned = !base.isSigned
 | 
				
			||||||
 | 
					    val isArray = base.isArray
 | 
				
			||||||
 | 
					    val isPointer = base.isPointer
 | 
				
			||||||
 | 
					    val isPointerToByte = base.isPointer && sub?.isByteOrBool==true
 | 
				
			||||||
 | 
					    val isPointerToWord = base.isPointer && sub?.isWord==true
 | 
				
			||||||
 | 
					    val isStructInstance = base.isStructInstance
 | 
				
			||||||
 | 
					    val isPointerArray = base.isPointerArray
 | 
				
			||||||
 | 
					    val isBoolArray = base.isArray && !base.isPointerArray && sub == BaseDataType.BOOL
 | 
				
			||||||
 | 
					    val isByteArray = base.isArray && !base.isPointerArray && (sub == BaseDataType.UBYTE || sub == BaseDataType.BYTE)
 | 
				
			||||||
 | 
					    val isUnsignedByteArray = base.isArray && !base.isPointerArray && sub == BaseDataType.UBYTE
 | 
				
			||||||
 | 
					    val isSignedByteArray = base.isArray && !base.isPointerArray && sub == BaseDataType.BYTE
 | 
				
			||||||
 | 
					    val isWordArray = base.isArray && !base.isPointerArray && (sub == BaseDataType.UWORD || sub == BaseDataType.WORD)
 | 
				
			||||||
 | 
					    val isUnsignedWordArray = base.isArray && !base.isPointerArray && sub == BaseDataType.UWORD
 | 
				
			||||||
 | 
					    val isSignedWordArray = base.isArray && !base.isPointerArray && sub == BaseDataType.WORD
 | 
				
			||||||
 | 
					    val isLongArray = base.isArray && sub == BaseDataType.LONG
 | 
				
			||||||
 | 
					    val isFloatArray = base.isArray && !base.isPointerArray && sub == BaseDataType.FLOAT
 | 
				
			||||||
 | 
					    val isString = base == BaseDataType.STR
 | 
				
			||||||
 | 
					    val isBool = base == BaseDataType.BOOL
 | 
				
			||||||
 | 
					    val isFloat = base == BaseDataType.FLOAT
 | 
				
			||||||
 | 
					    val isLong = base == BaseDataType.LONG
 | 
				
			||||||
 | 
					    val isStringly = base == BaseDataType.STR || base == BaseDataType.UWORD || (base == BaseDataType.ARRAY && (sub == BaseDataType.UBYTE || sub == BaseDataType.BYTE))
 | 
				
			||||||
 | 
					    val isSplitWordArray = base.isSplitWordArray
 | 
				
			||||||
 | 
					    val isSplitUnsignedWordArray = base.isSplitWordArray && !base.isPointerArray && sub == BaseDataType.UWORD
 | 
				
			||||||
 | 
					    val isSplitSignedWordArray = base.isSplitWordArray && !base.isPointerArray && sub == BaseDataType.WORD
 | 
				
			||||||
 | 
					    val isIterable =  base.isIterable
 | 
				
			||||||
 | 
					    val isPassByRef = base.isPassByRef
 | 
				
			||||||
 | 
					    val isPassByValue = base.isPassByValue
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class CpuRegister {
 | 
					enum class CpuRegister {
 | 
				
			||||||
    A,
 | 
					    A,
 | 
				
			||||||
    X,
 | 
					    X,
 | 
				
			||||||
@@ -75,7 +400,9 @@ enum class RegisterOrPair {
 | 
				
			|||||||
    FAC2,
 | 
					    FAC2,
 | 
				
			||||||
    // cx16 virtual registers:
 | 
					    // cx16 virtual registers:
 | 
				
			||||||
    R0, R1, R2, R3, R4, R5, R6, R7,
 | 
					    R0, R1, R2, R3, R4, R5, R6, R7,
 | 
				
			||||||
    R8, R9, R10, R11, R12, R13, R14, R15;
 | 
					    R8, R9, R10, R11, R12, R13, R14, R15,
 | 
				
			||||||
 | 
					    // combined virtual registers to store 32 bits longs:
 | 
				
			||||||
 | 
					    R0R1_32, R2R3_32, R4R5_32, R6R7_32, R8R9_32, R10R11_32, R12R13_32, R14R15_32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        val names by lazy { entries.map { it.toString()} }
 | 
					        val names by lazy { entries.map { it.toString()} }
 | 
				
			||||||
@@ -88,6 +415,18 @@ enum class RegisterOrPair {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun startregname() = when(this) {
 | 
				
			||||||
 | 
					        R0R1_32 -> "r0"
 | 
				
			||||||
 | 
					        R2R3_32 -> "r2"
 | 
				
			||||||
 | 
					        R4R5_32 -> "r4"
 | 
				
			||||||
 | 
					        R6R7_32 -> "r6"
 | 
				
			||||||
 | 
					        R8R9_32 -> "r8"
 | 
				
			||||||
 | 
					        R10R11_32 -> "r10"
 | 
				
			||||||
 | 
					        R12R13_32 -> "r12"
 | 
				
			||||||
 | 
					        R14R15_32 -> "r14"
 | 
				
			||||||
 | 
					        else -> throw IllegalArgumentException("must be a combined virtual register $this")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun asCpuRegister(): CpuRegister = when(this) {
 | 
					    fun asCpuRegister(): CpuRegister = when(this) {
 | 
				
			||||||
        A -> CpuRegister.A
 | 
					        A -> CpuRegister.A
 | 
				
			||||||
        X -> CpuRegister.X
 | 
					        X -> CpuRegister.X
 | 
				
			||||||
@@ -95,6 +434,21 @@ enum class RegisterOrPair {
 | 
				
			|||||||
        else -> throw IllegalArgumentException("no cpu hardware register for $this")
 | 
					        else -> throw IllegalArgumentException("no cpu hardware register for $this")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun asScopedNameVirtualReg(type: DataType?): List<String> {
 | 
				
			||||||
 | 
					        require(this in Cx16VirtualRegisters)
 | 
				
			||||||
 | 
					        val suffix = when(type?.base) {
 | 
				
			||||||
 | 
					            BaseDataType.UBYTE, BaseDataType.BOOL -> "L"
 | 
				
			||||||
 | 
					            BaseDataType.BYTE -> "sL"
 | 
				
			||||||
 | 
					            BaseDataType.WORD -> "s"
 | 
				
			||||||
 | 
					            BaseDataType.UWORD, BaseDataType.POINTER, null -> ""
 | 
				
			||||||
 | 
					            else -> throw IllegalArgumentException("invalid register param type for cx16 virtual reg")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return listOf("cx16", name.lowercase()+suffix)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun isWord() = this==AX || this == AY || this==XY || this in Cx16VirtualRegisters
 | 
				
			||||||
 | 
					    fun isLong() = this in combinedLongRegisters
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}       // only used in parameter and return value specs in asm subroutines
 | 
					}       // only used in parameter and return value specs in asm subroutines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class Statusflag {
 | 
					enum class Statusflag {
 | 
				
			||||||
@@ -123,48 +477,6 @@ enum class BranchCondition {
 | 
				
			|||||||
    VC
 | 
					    VC
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
val ByteDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE)
 | 
					 | 
				
			||||||
val ByteDatatypesWithBoolean = ByteDatatypes + DataType.BOOL
 | 
					 | 
				
			||||||
val WordDatatypes = arrayOf(DataType.UWORD, DataType.WORD)
 | 
					 | 
				
			||||||
val IntegerDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.LONG)
 | 
					 | 
				
			||||||
val IntegerDatatypesWithBoolean = IntegerDatatypes + DataType.BOOL
 | 
					 | 
				
			||||||
val NumericDatatypes = arrayOf(DataType.UBYTE, DataType.BYTE, DataType.UWORD, DataType.WORD, DataType.LONG, DataType.FLOAT)
 | 
					 | 
				
			||||||
val NumericDatatypesWithBoolean = NumericDatatypes + DataType.BOOL
 | 
					 | 
				
			||||||
val SignedDatatypes =  arrayOf(DataType.BYTE, DataType.WORD, DataType.LONG, DataType.FLOAT)
 | 
					 | 
				
			||||||
val ArrayDatatypes = arrayOf(DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_UW, DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W, DataType.ARRAY_W_SPLIT, DataType.ARRAY_F, DataType.ARRAY_BOOL)
 | 
					 | 
				
			||||||
val StringlyDatatypes = arrayOf(DataType.STR, DataType.ARRAY_UB, DataType.ARRAY_B, DataType.UWORD)
 | 
					 | 
				
			||||||
val SplitWordArrayTypes = arrayOf(DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT)
 | 
					 | 
				
			||||||
val IterableDatatypes = arrayOf(
 | 
					 | 
				
			||||||
    DataType.STR,
 | 
					 | 
				
			||||||
    DataType.ARRAY_UB, DataType.ARRAY_B,
 | 
					 | 
				
			||||||
    DataType.ARRAY_UW, DataType.ARRAY_W,
 | 
					 | 
				
			||||||
    DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT,
 | 
					 | 
				
			||||||
    DataType.ARRAY_F, DataType.ARRAY_BOOL
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
val PassByValueDatatypes = NumericDatatypesWithBoolean
 | 
					 | 
				
			||||||
val PassByReferenceDatatypes = IterableDatatypes
 | 
					 | 
				
			||||||
val ArrayToElementTypes = mapOf(
 | 
					 | 
				
			||||||
    DataType.STR to DataType.UBYTE,
 | 
					 | 
				
			||||||
    DataType.ARRAY_B to DataType.BYTE,
 | 
					 | 
				
			||||||
    DataType.ARRAY_UB to DataType.UBYTE,
 | 
					 | 
				
			||||||
    DataType.ARRAY_W to DataType.WORD,
 | 
					 | 
				
			||||||
    DataType.ARRAY_UW to DataType.UWORD,
 | 
					 | 
				
			||||||
    DataType.ARRAY_W_SPLIT to DataType.WORD,
 | 
					 | 
				
			||||||
    DataType.ARRAY_UW_SPLIT to DataType.UWORD,
 | 
					 | 
				
			||||||
    DataType.ARRAY_F to DataType.FLOAT,
 | 
					 | 
				
			||||||
    DataType.ARRAY_BOOL to DataType.BOOL
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
val ElementToArrayTypes = mapOf(
 | 
					 | 
				
			||||||
    DataType.BYTE to DataType.ARRAY_B,
 | 
					 | 
				
			||||||
    DataType.UBYTE to DataType.ARRAY_UB,
 | 
					 | 
				
			||||||
    DataType.WORD to DataType.ARRAY_W,
 | 
					 | 
				
			||||||
    DataType.UWORD to DataType.ARRAY_UW,
 | 
					 | 
				
			||||||
    DataType.FLOAT to DataType.ARRAY_F,
 | 
					 | 
				
			||||||
    DataType.BOOL to DataType.ARRAY_BOOL,
 | 
					 | 
				
			||||||
    DataType.STR to DataType.ARRAY_UW          // array of str is just an array of pointers
 | 
					 | 
				
			||||||
)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
val Cx16VirtualRegisters = arrayOf(
 | 
					val Cx16VirtualRegisters = arrayOf(
 | 
				
			||||||
    RegisterOrPair.R0, RegisterOrPair.R1, RegisterOrPair.R2, RegisterOrPair.R3,
 | 
					    RegisterOrPair.R0, RegisterOrPair.R1, RegisterOrPair.R2, RegisterOrPair.R3,
 | 
				
			||||||
    RegisterOrPair.R4, RegisterOrPair.R5, RegisterOrPair.R6, RegisterOrPair.R7,
 | 
					    RegisterOrPair.R4, RegisterOrPair.R5, RegisterOrPair.R6, RegisterOrPair.R7,
 | 
				
			||||||
@@ -172,7 +484,18 @@ val Cx16VirtualRegisters = arrayOf(
 | 
				
			|||||||
    RegisterOrPair.R12, RegisterOrPair.R13, RegisterOrPair.R14, RegisterOrPair.R15
 | 
					    RegisterOrPair.R12, RegisterOrPair.R13, RegisterOrPair.R14, RegisterOrPair.R15
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val CpuRegisters = setOf(
 | 
					val combinedLongRegisters = arrayOf(
 | 
				
			||||||
 | 
					    RegisterOrPair.R0R1_32,
 | 
				
			||||||
 | 
					    RegisterOrPair.R2R3_32,
 | 
				
			||||||
 | 
					    RegisterOrPair.R4R5_32,
 | 
				
			||||||
 | 
					    RegisterOrPair.R6R7_32,
 | 
				
			||||||
 | 
					    RegisterOrPair.R8R9_32,
 | 
				
			||||||
 | 
					    RegisterOrPair.R10R11_32,
 | 
				
			||||||
 | 
					    RegisterOrPair.R12R13_32,
 | 
				
			||||||
 | 
					    RegisterOrPair.R14R15_32
 | 
				
			||||||
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					val CpuRegisters = arrayOf(
 | 
				
			||||||
    RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y,
 | 
					    RegisterOrPair.A, RegisterOrPair.X, RegisterOrPair.Y,
 | 
				
			||||||
    RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY
 | 
					    RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
@@ -181,7 +504,8 @@ val CpuRegisters = setOf(
 | 
				
			|||||||
enum class OutputType {
 | 
					enum class OutputType {
 | 
				
			||||||
    RAW,
 | 
					    RAW,
 | 
				
			||||||
    PRG,
 | 
					    PRG,
 | 
				
			||||||
    XEX
 | 
					    XEX,
 | 
				
			||||||
 | 
					    LIBRARY
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
enum class CbmPrgLauncherType {
 | 
					enum class CbmPrgLauncherType {
 | 
				
			||||||
@@ -203,3 +527,8 @@ enum class ZeropageWish {
 | 
				
			|||||||
    DONTCARE,
 | 
					    DONTCARE,
 | 
				
			||||||
    NOT_IN_ZEROPAGE
 | 
					    NOT_IN_ZEROPAGE
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class SplitWish {
 | 
				
			||||||
 | 
					    DONTCARE,
 | 
				
			||||||
 | 
					    NOSPLIT
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,8 +1,43 @@
 | 
				
			|||||||
package prog8.code.core
 | 
					package prog8.code.core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.nio.file.Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum class CpuType {
 | 
				
			||||||
 | 
					    CPU6502,
 | 
				
			||||||
 | 
					    CPU65C02,
 | 
				
			||||||
 | 
					    VIRTUAL
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface ICompilationTarget: IStringEncoding, IMemSizer {
 | 
					interface ICompilationTarget: IStringEncoding, IMemSizer {
 | 
				
			||||||
    val name: String
 | 
					    val name: String
 | 
				
			||||||
    val machine: IMachineDefinition
 | 
					
 | 
				
			||||||
 | 
					    val FLOAT_MAX_NEGATIVE: Double
 | 
				
			||||||
 | 
					    val FLOAT_MAX_POSITIVE: Double
 | 
				
			||||||
 | 
					    val FLOAT_MEM_SIZE: Int
 | 
				
			||||||
 | 
					    val STARTUP_CODE_RESERVED_SIZE: UInt        // this is here, so that certain compiler targets are able to tune this
 | 
				
			||||||
 | 
					    val PROGRAM_LOAD_ADDRESS : UInt
 | 
				
			||||||
 | 
					    val PROGRAM_MEMTOP_ADDRESS: UInt
 | 
				
			||||||
 | 
					    val BSSHIGHRAM_START: UInt
 | 
				
			||||||
 | 
					    val BSSHIGHRAM_END: UInt
 | 
				
			||||||
 | 
					    val BSSGOLDENRAM_START: UInt
 | 
				
			||||||
 | 
					    val BSSGOLDENRAM_END: UInt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val cpu: CpuType
 | 
				
			||||||
 | 
					    var zeropage: Zeropage
 | 
				
			||||||
 | 
					    var golden: GoldenRam
 | 
				
			||||||
 | 
					    val libraryPath: Path?
 | 
				
			||||||
 | 
					    val customLauncher: List<String>
 | 
				
			||||||
 | 
					    val additionalAssemblerOptions: List<String>
 | 
				
			||||||
 | 
					    val defaultOutputType: OutputType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun initializeMemoryAreas(compilerOptions: CompilationOptions)
 | 
				
			||||||
 | 
					    fun getFloatAsmBytes(num: Number): String
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun convertFloatToBytes(num: Double): List<UByte>
 | 
				
			||||||
 | 
					    fun convertBytesToFloat(bytes: List<UByte>): Double
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path, quiet: Boolean)
 | 
				
			||||||
 | 
					    fun isIOAddress(address: UInt): Boolean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun encodeString(str: String, encoding: Encoding): List<UByte>
 | 
					    override fun encodeString(str: String, encoding: Encoding): List<UByte>
 | 
				
			||||||
    override fun decodeString(bytes: Iterable<UByte>, encoding: Encoding): String
 | 
					    override fun decodeString(bytes: Iterable<UByte>, encoding: Encoding): String
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,4 +13,6 @@ interface IErrorReporter {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun noErrorForLine(position: Position): Boolean
 | 
					    fun noErrorForLine(position: Position): Boolean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun printSingleError(errormessage: String)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,34 +0,0 @@
 | 
				
			|||||||
package prog8.code.core
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.nio.file.Path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
enum class CpuType {
 | 
					 | 
				
			||||||
    CPU6502,
 | 
					 | 
				
			||||||
    CPU65c02,
 | 
					 | 
				
			||||||
    VIRTUAL
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface IMachineDefinition {
 | 
					 | 
				
			||||||
    val FLOAT_MAX_NEGATIVE: Double
 | 
					 | 
				
			||||||
    val FLOAT_MAX_POSITIVE: Double
 | 
					 | 
				
			||||||
    val FLOAT_MEM_SIZE: Int
 | 
					 | 
				
			||||||
    val PROGRAM_LOAD_ADDRESS : UInt
 | 
					 | 
				
			||||||
    val BSSHIGHRAM_START: UInt
 | 
					 | 
				
			||||||
    val BSSHIGHRAM_END: UInt
 | 
					 | 
				
			||||||
    val BSSGOLDENRAM_START: UInt
 | 
					 | 
				
			||||||
    val BSSGOLDENRAM_END: UInt
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    val cpu: CpuType
 | 
					 | 
				
			||||||
    var zeropage: Zeropage
 | 
					 | 
				
			||||||
    var golden: GoldenRam
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun initializeMemoryAreas(compilerOptions: CompilationOptions)
 | 
					 | 
				
			||||||
    fun getFloatAsmBytes(num: Number): String
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun convertFloatToBytes(num: Double): List<UByte>
 | 
					 | 
				
			||||||
    fun convertBytesToFloat(bytes: List<UByte>): Double
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path)
 | 
					 | 
				
			||||||
    fun isIOAddress(address: UInt): Boolean
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,6 +1,15 @@
 | 
				
			|||||||
package prog8.code.core
 | 
					package prog8.code.core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IMemSizer {
 | 
					interface IMemSizer {
 | 
				
			||||||
    fun memorySize(dt: DataType): Int
 | 
					    fun memorySize(dt: DataType, numElements: Int?): Int
 | 
				
			||||||
    fun memorySize(arrayDt: DataType, numElements: Int): Int
 | 
					
 | 
				
			||||||
 | 
					    fun memorySize(dt: BaseDataType): Int {
 | 
				
			||||||
 | 
					        if(dt.isPassByRef)
 | 
				
			||||||
 | 
					            return memorySize(DataType.UWORD, null)      // a pointer size
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            return memorySize(DataType.forDt(dt), null)
 | 
				
			||||||
 | 
					        } catch (x: NoSuchElementException) {
 | 
				
			||||||
 | 
					            throw IllegalArgumentException(x.message)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,7 +9,8 @@ enum class Encoding(val prefix: String) {
 | 
				
			|||||||
    ISO5("iso5"),               // cx16  (iso-8859-5, cyrillic)
 | 
					    ISO5("iso5"),               // cx16  (iso-8859-5, cyrillic)
 | 
				
			||||||
    ISO16("iso16"),             // cx16  (iso-8859-16, eastern european)
 | 
					    ISO16("iso16"),             // cx16  (iso-8859-16, eastern european)
 | 
				
			||||||
    CP437("cp437"),             // cx16  (ibm pc, codepage 437)
 | 
					    CP437("cp437"),             // cx16  (ibm pc, codepage 437)
 | 
				
			||||||
    KATAKANA("kata")                 // cx16  (katakana)
 | 
					    KATAKANA("kata"),           // cx16  (katakana)
 | 
				
			||||||
 | 
					    C64OS("c64os")              // c64 (C64 OS)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IStringEncoding {
 | 
					interface IStringEncoding {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,9 +22,10 @@ abstract class MemoryAllocator(protected val options: CompilationOptions) {
 | 
				
			|||||||
abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
 | 
					abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    abstract val SCRATCH_B1 : UInt      // temp storage for a single byte
 | 
					    abstract val SCRATCH_B1 : UInt      // temp storage for a single byte
 | 
				
			||||||
    abstract val SCRATCH_REG : UInt     // temp storage for a register, must be B1+1
 | 
					    abstract val SCRATCH_REG : UInt     // temp storage for a register byte, must be B1+1
 | 
				
			||||||
    abstract val SCRATCH_W1 : UInt      // temp storage 1 for a word  $fb+$fc
 | 
					    abstract val SCRATCH_W1 : UInt      // temp storage 1 for a word
 | 
				
			||||||
    abstract val SCRATCH_W2 : UInt      // temp storage 2 for a word  $fb+$fc
 | 
					    abstract val SCRATCH_W2 : UInt      // temp storage 2 for a word
 | 
				
			||||||
 | 
					    abstract val SCRATCH_PTR : UInt     // temp storage for a pointer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // the variables allocated into Zeropage.
 | 
					    // the variables allocated into Zeropage.
 | 
				
			||||||
@@ -38,7 +39,7 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
 | 
				
			|||||||
            for (reserved in options.zpReserved)
 | 
					            for (reserved in options.zpReserved)
 | 
				
			||||||
                reserve(reserved)
 | 
					                reserve(reserved)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            free.removeAll(setOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1u, SCRATCH_W2, SCRATCH_W2 + 1u))
 | 
					            free.removeAll(arrayOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1 + 1u, SCRATCH_W2, SCRATCH_W2 + 1u, SCRATCH_PTR, SCRATCH_PTR+1u))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -70,9 +71,10 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
 | 
				
			|||||||
            return Err(MemAllocationError("zero page usage has been disabled"))
 | 
					            return Err(MemAllocationError("zero page usage has been disabled"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val size: Int =
 | 
					        val size: Int =
 | 
				
			||||||
                when (datatype) {
 | 
					                when {
 | 
				
			||||||
                    in IntegerDatatypesWithBoolean -> options.compTarget.memorySize(datatype)
 | 
					                    datatype.isIntegerOrBool -> options.compTarget.memorySize(datatype, null)
 | 
				
			||||||
                    DataType.STR, in ArrayDatatypes  -> {
 | 
					                    datatype.isPointer -> options.compTarget.memorySize(datatype, null)
 | 
				
			||||||
 | 
					                    datatype.isString || datatype.isArray -> {
 | 
				
			||||||
                        val memsize = options.compTarget.memorySize(datatype, numElements!!)
 | 
					                        val memsize = options.compTarget.memorySize(datatype, numElements!!)
 | 
				
			||||||
                        if(position!=null)
 | 
					                        if(position!=null)
 | 
				
			||||||
                            errors.warn("allocating a large value in zeropage; str/array $memsize bytes", position)
 | 
					                            errors.warn("allocating a large value in zeropage; str/array $memsize bytes", position)
 | 
				
			||||||
@@ -80,9 +82,9 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
 | 
				
			|||||||
                            errors.warn("$name: allocating a large value in zeropage; str/array $memsize bytes", Position.DUMMY)
 | 
					                            errors.warn("$name: allocating a large value in zeropage; str/array $memsize bytes", Position.DUMMY)
 | 
				
			||||||
                        memsize
 | 
					                        memsize
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
                    DataType.FLOAT -> {
 | 
					                    datatype.isFloat -> {
 | 
				
			||||||
                        if (options.floats) {
 | 
					                        if (options.floats) {
 | 
				
			||||||
                            val memsize = options.compTarget.memorySize(DataType.FLOAT)
 | 
					                            val memsize = options.compTarget.memorySize(DataType.FLOAT, null)
 | 
				
			||||||
                            if(position!=null)
 | 
					                            if(position!=null)
 | 
				
			||||||
                                errors.warn("allocating a large value in zeropage; float $memsize bytes", position)
 | 
					                                errors.warn("allocating a large value in zeropage; float $memsize bytes", position)
 | 
				
			||||||
                            else
 | 
					                            else
 | 
				
			||||||
@@ -94,7 +96,7 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        synchronized(this) {
 | 
					        synchronized(this) {
 | 
				
			||||||
            if(free.size > 0) {
 | 
					            if(free.isNotEmpty()) {
 | 
				
			||||||
                if(size==1) {
 | 
					                if(size==1) {
 | 
				
			||||||
                    for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
 | 
					                    for(candidate in free.minOrNull()!! .. free.maxOrNull()!!+1u) {
 | 
				
			||||||
                        if(oneSeparateByteFree(candidate))
 | 
					                        if(oneSeparateByteFree(candidate))
 | 
				
			||||||
@@ -118,10 +120,11 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
 | 
				
			|||||||
        require(size>=0)
 | 
					        require(size>=0)
 | 
				
			||||||
        free.removeAll(address until address+size.toUInt())
 | 
					        free.removeAll(address until address+size.toUInt())
 | 
				
			||||||
        if(name.isNotEmpty()) {
 | 
					        if(name.isNotEmpty()) {
 | 
				
			||||||
            allocatedVariables[name] = when(datatype) {
 | 
					            allocatedVariables[name] = when {
 | 
				
			||||||
                in NumericDatatypes, DataType.BOOL -> VarAllocation(address, datatype, size)        // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments
 | 
					                datatype.isNumericOrBool -> VarAllocation(address, datatype, size)        // numerical variables in zeropage never have an initial value here because they are set in separate initializer assignments
 | 
				
			||||||
                DataType.STR -> VarAllocation(address, datatype, size)
 | 
					                datatype.isString -> VarAllocation(address, datatype, size)
 | 
				
			||||||
                in ArrayDatatypes -> VarAllocation(address, datatype, size)
 | 
					                datatype.isArray -> VarAllocation(address, datatype, size)
 | 
				
			||||||
 | 
					                datatype.isPointer -> VarAllocation(address, datatype, size)
 | 
				
			||||||
                else -> throw AssemblyError("invalid dt")
 | 
					                else -> throw AssemblyError("invalid dt")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -133,8 +136,6 @@ abstract class Zeropage(options: CompilationOptions): MemoryAllocator(options) {
 | 
				
			|||||||
        require(size>0)
 | 
					        require(size>0)
 | 
				
			||||||
        return free.containsAll((address until address+size.toUInt()).toList())
 | 
					        return free.containsAll((address until address+size.toUInt()).toList())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    abstract fun allocateCx16VirtualRegisters()
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -150,14 +151,13 @@ class GoldenRam(options: CompilationOptions, val region: UIntRange): MemoryAlloc
 | 
				
			|||||||
        errors: IErrorReporter): Result<VarAllocation, MemAllocationError> {
 | 
					        errors: IErrorReporter): Result<VarAllocation, MemAllocationError> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val size: Int =
 | 
					        val size: Int =
 | 
				
			||||||
            when (datatype) {
 | 
					            when {
 | 
				
			||||||
                in IntegerDatatypesWithBoolean -> options.compTarget.memorySize(datatype)
 | 
					                datatype.isIntegerOrBool -> options.compTarget.memorySize(datatype, null)
 | 
				
			||||||
                DataType.STR, in ArrayDatatypes  -> {
 | 
					                datatype.isString -> numElements!!
 | 
				
			||||||
                    options.compTarget.memorySize(datatype, numElements!!)
 | 
					                datatype.isArray -> options.compTarget.memorySize(datatype, numElements!!)
 | 
				
			||||||
                }
 | 
					                datatype.isFloat -> {
 | 
				
			||||||
                DataType.FLOAT -> {
 | 
					 | 
				
			||||||
                    if (options.floats) {
 | 
					                    if (options.floats) {
 | 
				
			||||||
                        options.compTarget.memorySize(DataType.FLOAT)
 | 
					                        options.compTarget.memorySize(DataType.FLOAT, null)
 | 
				
			||||||
                    } else return Err(MemAllocationError("floating point option not enabled"))
 | 
					                    } else return Err(MemAllocationError("floating point option not enabled"))
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else -> throw MemAllocationError("weird dt")
 | 
					                else -> throw MemAllocationError("weird dt")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,10 @@
 | 
				
			|||||||
package prog8.code.core
 | 
					package prog8.code.core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
val AssociativeOperators = setOf("+", "*", "&", "|", "^", "==", "!=", "xor")       // note: and,or are no longer associative because of Shortcircuit/McCarthy evaluation
 | 
					val AssociativeOperators = arrayOf("+", "*", "&", "|", "^", "==", "!=", "xor")       // note: and,or are not associative because of Shortcircuit/McCarthy evaluation
 | 
				
			||||||
val ComparisonOperators = setOf("==", "!=", "<", ">", "<=", ">=")
 | 
					val ComparisonOperators = arrayOf("==", "!=", "<", ">", "<=", ">=")
 | 
				
			||||||
val LogicalOperators = setOf("and", "or", "xor", "not", "in")
 | 
					val LogicalOperators = arrayOf("and", "or", "xor", "not", "in")
 | 
				
			||||||
val BitwiseOperators = setOf("&", "|", "^", "~")
 | 
					val BitwiseOperators = arrayOf("&", "|", "^", "~")
 | 
				
			||||||
val PrefixOperators = setOf("+", "-", "~", "not")
 | 
					val PrefixOperators = arrayOf("+", "-", "~", "not")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fun invertedComparisonOperator(operator: String) =
 | 
					fun invertedComparisonOperator(operator: String) =
 | 
				
			||||||
    when (operator) {
 | 
					    when (operator) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,21 +1,21 @@
 | 
				
			|||||||
package prog8.code.core
 | 
					package prog8.code.core
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prog8.code.core.SourceCode.Companion.LIBRARYFILEPREFIX
 | 
					import prog8.code.sanitize
 | 
				
			||||||
 | 
					import prog8.code.source.SourceCode
 | 
				
			||||||
import java.nio.file.InvalidPathException
 | 
					import java.nio.file.InvalidPathException
 | 
				
			||||||
import kotlin.io.path.Path
 | 
					import kotlin.io.path.Path
 | 
				
			||||||
import kotlin.io.path.absolute
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
data class Position(val file: String, val line: Int, val startCol: Int, val endCol: Int) {
 | 
					data class Position(val file: String, val line: Int, val startCol: Int, val endCol: Int) {
 | 
				
			||||||
    override fun toString(): String = "[$file: line $line col ${startCol+1}-${endCol+1}]"
 | 
					    override fun toString(): String = "[$file: line $line col ${startCol+1}-${endCol+1}]"
 | 
				
			||||||
    fun toClickableStr(): String {
 | 
					    fun toClickableStr(): String {
 | 
				
			||||||
        if(this===DUMMY)
 | 
					        if(this===DUMMY)
 | 
				
			||||||
            return ""
 | 
					            return ""
 | 
				
			||||||
        if(file.startsWith(LIBRARYFILEPREFIX))
 | 
					        if(SourceCode.isLibraryResource(file))
 | 
				
			||||||
            return "$file:$line:$startCol:"
 | 
					            return "$file:$line:$startCol:"
 | 
				
			||||||
        return try {
 | 
					        return try {
 | 
				
			||||||
            val path = Path(file).absolute().normalize().toString()
 | 
					            val path = Path(file).sanitize().toString()
 | 
				
			||||||
            "file://$path:$line:$startCol:"
 | 
					            "file://$path:$line:$startCol:"
 | 
				
			||||||
        } catch(x: InvalidPathException) {
 | 
					        } catch(_: InvalidPathException) {
 | 
				
			||||||
            // this can occur on Windows when the source origin contains "invalid" characters such as ':'
 | 
					            // this can occur on Windows when the source origin contains "invalid" characters such as ':'
 | 
				
			||||||
            "file://$file:$line:$startCol:"
 | 
					            "file://$file:$line:$startCol:"
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										74
									
								
								codeCore/src/prog8/code/source/ImportFileSystem.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								codeCore/src/prog8/code/source/ImportFileSystem.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
				
			|||||||
 | 
					package prog8.code.source
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import prog8.code.core.Position
 | 
				
			||||||
 | 
					import prog8.code.sanitize
 | 
				
			||||||
 | 
					import java.nio.file.Path
 | 
				
			||||||
 | 
					import java.util.*
 | 
				
			||||||
 | 
					import kotlin.io.path.Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Resource caching "filesystem".
 | 
				
			||||||
 | 
					// Note that it leaves the decision to load a resource or an actual disk file to the caller.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object ImportFileSystem {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun expandTilde(path: String): String = if (path.startsWith("~")) {
 | 
				
			||||||
 | 
					        val userHome = System.getProperty("user.home")
 | 
				
			||||||
 | 
					        userHome + path.drop(1)
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        path
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun expandTilde(path: Path): Path = Path(expandTilde(path.toString()))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun getFile(path: Path, isLibrary: Boolean=false): SourceCode {
 | 
				
			||||||
 | 
					        val normalized = path.sanitize()
 | 
				
			||||||
 | 
					        val cached = cache[normalized.toString()]
 | 
				
			||||||
 | 
					        if (cached != null)
 | 
				
			||||||
 | 
					            return cached
 | 
				
			||||||
 | 
					        val file = SourceCode.File(normalized, isLibrary)
 | 
				
			||||||
 | 
					        cache[normalized.toString()] = file
 | 
				
			||||||
 | 
					        return file
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun getResource(name: String): SourceCode {
 | 
				
			||||||
 | 
					        val cached = cache[name]
 | 
				
			||||||
 | 
					        if (cached != null) return cached
 | 
				
			||||||
 | 
					        val resource = SourceCode.Resource(name)
 | 
				
			||||||
 | 
					        cache[name] = resource
 | 
				
			||||||
 | 
					        return resource
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun retrieveSourceLine(position: Position): String {
 | 
				
			||||||
 | 
					        if(SourceCode.isLibraryResource(position.file)) {
 | 
				
			||||||
 | 
					            val cached = cache[SourceCode.withoutPrefix(position.file)]
 | 
				
			||||||
 | 
					            if(cached != null)
 | 
				
			||||||
 | 
					                return getLine(cached, position.line)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        val cached = cache[position.file]
 | 
				
			||||||
 | 
					        if(cached != null)
 | 
				
			||||||
 | 
					            return getLine(cached, position.line)
 | 
				
			||||||
 | 
					        val path = Path(position.file).sanitize()
 | 
				
			||||||
 | 
					        val cached2 = cache[path.toString()]
 | 
				
			||||||
 | 
					        if(cached2 != null)
 | 
				
			||||||
 | 
					            return getLine(cached2, position.line)
 | 
				
			||||||
 | 
					        throw NoSuchElementException("cannot get source line $position, with path $path")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun getLine(code: SourceCode, lineIndex: Int): String {
 | 
				
			||||||
 | 
					        var spans = lineSpanCache[code]
 | 
				
			||||||
 | 
					        if(spans==null) {
 | 
				
			||||||
 | 
					            val lineSpans = Regex("^", RegexOption.MULTILINE).findAll(code.text).map { it.range.first }
 | 
				
			||||||
 | 
					            val ends = lineSpans.drop(1) + code.text.length
 | 
				
			||||||
 | 
					            spans = lineSpans.zip(ends).map { (start, end) -> LineSpan(start, end) }.toList().toTypedArray()
 | 
				
			||||||
 | 
					            lineSpanCache[code] = spans
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        val span = spans[lineIndex - 1]
 | 
				
			||||||
 | 
					        return code.text.substring(span.start, span.end).trim()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private class LineSpan(val start: Int, val end: Int)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val cache = TreeMap<String, SourceCode>(String.CASE_INSENSITIVE_ORDER)
 | 
				
			||||||
 | 
					    private val lineSpanCache = mutableMapOf<SourceCode, Array<LineSpan>>()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,16 +1,13 @@
 | 
				
			|||||||
package prog8.code.core
 | 
					package prog8.code.source
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.File
 | 
					import prog8.code.sanitize
 | 
				
			||||||
import java.io.IOException
 | 
					import java.io.IOException
 | 
				
			||||||
import java.nio.file.Path
 | 
					import java.nio.file.Path
 | 
				
			||||||
import java.text.Normalizer
 | 
					import java.text.Normalizer
 | 
				
			||||||
import kotlin.io.path.Path
 | 
					import kotlin.io.path.Path
 | 
				
			||||||
 | 
					import kotlin.io.path.absolute
 | 
				
			||||||
import kotlin.io.path.readText
 | 
					import kotlin.io.path.readText
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
const val internedStringsModuleName = "prog8_interned_strings"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Encapsulates - and ties together - actual source code (=text) and its [origin].
 | 
					 * Encapsulates - and ties together - actual source code (=text) and its [origin].
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
@@ -26,6 +23,11 @@ sealed class SourceCode {
 | 
				
			|||||||
     */
 | 
					     */
 | 
				
			||||||
    abstract val isFromFilesystem: Boolean
 | 
					    abstract val isFromFilesystem: Boolean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Whether this [SourceCode] instance was created from a library module file
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    abstract val isFromLibrary: Boolean
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * The logical name of the source code unit. Usually the module's name.
 | 
					     * The logical name of the source code unit. Usually the module's name.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
@@ -55,14 +57,21 @@ sealed class SourceCode {
 | 
				
			|||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * filename prefix to designate library files that will be retreived from internal resources rather than disk
 | 
					         * filename prefix to designate library files that will be retreived from internal resources rather than disk
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
        const val LIBRARYFILEPREFIX = "library:"
 | 
					        private const val LIBRARYFILEPREFIX = "library:"
 | 
				
			||||||
        const val STRINGSOURCEPREFIX = "string:"
 | 
					        private const val STRINGSOURCEPREFIX = "string:"
 | 
				
			||||||
        val curdir: Path = Path(".").toAbsolutePath()
 | 
					        val curdir: Path = Path(".").absolute()
 | 
				
			||||||
        fun relative(path: Path): Path = curdir.relativize(path.toAbsolutePath())
 | 
					        fun relative(path: Path): Path = curdir.relativize(path.sanitize())
 | 
				
			||||||
        fun isRegularFilesystemPath(pathString: String) =
 | 
					        fun isRegularFilesystemPath(pathString: String) = !isLibraryResource(pathString) && !isStringResource(pathString)
 | 
				
			||||||
            !(pathString.startsWith(LIBRARYFILEPREFIX) || pathString.startsWith(STRINGSOURCEPREFIX))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        fun isLibraryResource(path: String) = path.startsWith(LIBRARYFILEPREFIX)
 | 
					        fun isLibraryResource(path: String) = path.startsWith(LIBRARYFILEPREFIX)
 | 
				
			||||||
 | 
					        fun isStringResource(path: String) = path.startsWith(STRINGSOURCEPREFIX)
 | 
				
			||||||
 | 
					        fun withoutPrefix(path: String): String {
 | 
				
			||||||
 | 
					            return if(isLibraryResource(path))
 | 
				
			||||||
 | 
					                path.removePrefix(LIBRARYFILEPREFIX)
 | 
				
			||||||
 | 
					            else if(isStringResource(path))
 | 
				
			||||||
 | 
					                path.removePrefix(STRINGSOURCEPREFIX)
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                path
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
@@ -73,6 +82,7 @@ sealed class SourceCode {
 | 
				
			|||||||
        override val text = origText.replace("\\R".toRegex(), "\n")      // normalize line endings
 | 
					        override val text = origText.replace("\\R".toRegex(), "\n")      // normalize line endings
 | 
				
			||||||
        override val isFromResources = false
 | 
					        override val isFromResources = false
 | 
				
			||||||
        override val isFromFilesystem = false
 | 
					        override val isFromFilesystem = false
 | 
				
			||||||
 | 
					        override val isFromLibrary = false
 | 
				
			||||||
        override val origin = "$STRINGSOURCEPREFIX${System.identityHashCode(text).toString(16)}"
 | 
					        override val origin = "$STRINGSOURCEPREFIX${System.identityHashCode(text).toString(16)}"
 | 
				
			||||||
        override val name = "<unnamed-text>"
 | 
					        override val name = "<unnamed-text>"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -80,12 +90,13 @@ sealed class SourceCode {
 | 
				
			|||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * Get [SourceCode] from the file represented by the specified Path.
 | 
					     * Get [SourceCode] from the file represented by the specified Path.
 | 
				
			||||||
     * This immediately reads the file fully into memory.
 | 
					     * This immediately reads the file fully into memory.
 | 
				
			||||||
 | 
					     * You can only get an instance of this via the ImportFileSystem object.
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * [origin] will be the given path in absolute and normalized form.
 | 
					     * [origin] will be the given path in absolute and normalized form.
 | 
				
			||||||
     * @throws NoSuchFileException if the file does not exist
 | 
					     * @throws NoSuchFileException if the file does not exist
 | 
				
			||||||
     * @throws FileSystemException if the file cannot be read
 | 
					     * @throws FileSystemException if the file cannot be read
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    class File(path: Path): SourceCode() {
 | 
					    internal class File(path: Path, override val isFromLibrary: Boolean): SourceCode() {
 | 
				
			||||||
        override val text: String
 | 
					        override val text: String
 | 
				
			||||||
        override val origin: String
 | 
					        override val origin: String
 | 
				
			||||||
        override val name: String
 | 
					        override val name: String
 | 
				
			||||||
@@ -109,12 +120,14 @@ sealed class SourceCode {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * [origin]: `library:/x/y/z.p8` for a given `pathString` of "x/y/z.p8"
 | 
					     * [origin]: `library:/x/y/z.p8` for a given `pathString` of "x/y/z.p8"
 | 
				
			||||||
 | 
					     * You can only get an instance of this via the ImportFileSystem object.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    class Resource(pathString: String): SourceCode() {
 | 
					    internal class Resource(pathString: String): SourceCode() {
 | 
				
			||||||
        private val normalized = "/" + Path(pathString).normalize().toMutableList().joinToString("/")
 | 
					        private val normalized = "/" + Path(pathString).normalize().toMutableList().joinToString("/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        override val isFromResources = true
 | 
					        override val isFromResources = true
 | 
				
			||||||
        override val isFromFilesystem = false
 | 
					        override val isFromFilesystem = false
 | 
				
			||||||
 | 
					        override val isFromLibrary = true
 | 
				
			||||||
        override val origin = "$LIBRARYFILEPREFIX$normalized"
 | 
					        override val origin = "$LIBRARYFILEPREFIX$normalized"
 | 
				
			||||||
        override val text: String
 | 
					        override val text: String
 | 
				
			||||||
        override val name: String
 | 
					        override val name: String
 | 
				
			||||||
@@ -124,7 +137,7 @@ sealed class SourceCode {
 | 
				
			|||||||
            if (rscURL == null) {
 | 
					            if (rscURL == null) {
 | 
				
			||||||
                val rscRoot = object {}.javaClass.getResource("/")
 | 
					                val rscRoot = object {}.javaClass.getResource("/")
 | 
				
			||||||
                throw NoSuchFileException(
 | 
					                throw NoSuchFileException(
 | 
				
			||||||
                    File(normalized),
 | 
					                    java.io.File(normalized),
 | 
				
			||||||
                    reason = "looked in resources rooted at $rscRoot"
 | 
					                    reason = "looked in resources rooted at $rscRoot"
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -141,37 +154,8 @@ sealed class SourceCode {
 | 
				
			|||||||
    class Generated(override val name: String) : SourceCode() {
 | 
					    class Generated(override val name: String) : SourceCode() {
 | 
				
			||||||
        override val isFromResources: Boolean = false
 | 
					        override val isFromResources: Boolean = false
 | 
				
			||||||
        override val isFromFilesystem: Boolean = false
 | 
					        override val isFromFilesystem: Boolean = false
 | 
				
			||||||
 | 
					        override val isFromLibrary: Boolean = false
 | 
				
			||||||
        override val origin: String = name
 | 
					        override val origin: String = name
 | 
				
			||||||
        override val text: String = "<generated code node, no text representation>"
 | 
					        override val text: String = "<generated code node, no text representation>"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
object SourceLineCache {
 | 
					 | 
				
			||||||
    private val cache = mutableMapOf<String, List<String>>()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    private fun getCachedFile(file: String): List<String> {
 | 
					 | 
				
			||||||
        val existing = cache[file]
 | 
					 | 
				
			||||||
        if(existing!=null)
 | 
					 | 
				
			||||||
            return existing
 | 
					 | 
				
			||||||
        if (SourceCode.isRegularFilesystemPath(file)) {
 | 
					 | 
				
			||||||
            val source = SourceCode.File(Path(file))
 | 
					 | 
				
			||||||
            cache[file] = source.text.split('\n', '\r').map { it.trim() }
 | 
					 | 
				
			||||||
            return cache.getValue(file)
 | 
					 | 
				
			||||||
        } else if(file.startsWith(SourceCode.LIBRARYFILEPREFIX)) {
 | 
					 | 
				
			||||||
            val source = SourceCode.Resource(file.drop(SourceCode.LIBRARYFILEPREFIX.length))
 | 
					 | 
				
			||||||
            cache[file] = source.text.split('\n', '\r').map { it.trim()}
 | 
					 | 
				
			||||||
            return cache.getValue(file)
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return emptyList()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fun retrieveLine(position: Position): String? {
 | 
					 | 
				
			||||||
        if (position.line>0) {
 | 
					 | 
				
			||||||
            val lines = getCachedFile(position.file)
 | 
					 | 
				
			||||||
            if(lines.isNotEmpty())
 | 
					 | 
				
			||||||
                return lines[position.line-1]
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        return null
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,31 +0,0 @@
 | 
				
			|||||||
package prog8.code.target
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import prog8.code.core.*
 | 
					 | 
				
			||||||
import prog8.code.target.atari.AtariMachineDefinition
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AtariTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
 | 
					 | 
				
			||||||
    override val name = NAME
 | 
					 | 
				
			||||||
    override val machine = AtariMachineDefinition()
 | 
					 | 
				
			||||||
    override val defaultEncoding = Encoding.ATASCII
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    companion object {
 | 
					 | 
				
			||||||
        const val NAME = "atari"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun memorySize(dt: DataType): Int {
 | 
					 | 
				
			||||||
        return when(dt) {
 | 
					 | 
				
			||||||
            in ByteDatatypesWithBoolean -> 1
 | 
					 | 
				
			||||||
            in WordDatatypes, in PassByReferenceDatatypes -> 2
 | 
					 | 
				
			||||||
            DataType.FLOAT -> machine.FLOAT_MEM_SIZE
 | 
					 | 
				
			||||||
            else -> throw IllegalArgumentException("invalid datatype")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun memorySize(arrayDt: DataType, numElements: Int) =
 | 
					 | 
				
			||||||
        if(arrayDt==DataType.UWORD)
 | 
					 | 
				
			||||||
            numElements    // pointer to bytes.
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,19 +1,81 @@
 | 
				
			|||||||
package prog8.code.target
 | 
					package prog8.code.target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prog8.code.core.Encoding
 | 
					import prog8.code.core.*
 | 
				
			||||||
import prog8.code.core.ICompilationTarget
 | 
					import prog8.code.target.encodings.Encoder
 | 
				
			||||||
import prog8.code.core.IMemSizer
 | 
					import prog8.code.target.zp.C128Zeropage
 | 
				
			||||||
import prog8.code.core.IStringEncoding
 | 
					import java.nio.file.Path
 | 
				
			||||||
import prog8.code.target.c128.C128MachineDefinition
 | 
					 | 
				
			||||||
import prog8.code.target.cbm.CbmMemorySizer
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class C128Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
 | 
					class C128Target: ICompilationTarget,
 | 
				
			||||||
 | 
					    IStringEncoding by Encoder(true),
 | 
				
			||||||
 | 
					    IMemSizer by NormalMemSizer(Mflpt5.FLOAT_MEM_SIZE) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override val name = NAME
 | 
					    override val name = NAME
 | 
				
			||||||
    override val machine = C128MachineDefinition()
 | 
					 | 
				
			||||||
    override val defaultEncoding = Encoding.PETSCII
 | 
					    override val defaultEncoding = Encoding.PETSCII
 | 
				
			||||||
 | 
					    override val libraryPath = null
 | 
				
			||||||
 | 
					    override val customLauncher = emptyList<String>()
 | 
				
			||||||
 | 
					    override val additionalAssemblerOptions = emptyList<String>()
 | 
				
			||||||
 | 
					    override val defaultOutputType = OutputType.PRG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        const val NAME = "c128"
 | 
					        const val NAME = "c128"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val cpu = CpuType.CPU6502
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
 | 
				
			||||||
 | 
					    override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
 | 
				
			||||||
 | 
					    override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
 | 
				
			||||||
 | 
					    override val STARTUP_CODE_RESERVED_SIZE = 20u
 | 
				
			||||||
 | 
					    override val PROGRAM_LOAD_ADDRESS = 0x1c01u
 | 
				
			||||||
 | 
					    override val PROGRAM_MEMTOP_ADDRESS = 0xc000u
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val BSSHIGHRAM_START = 0u    // TODO address?
 | 
				
			||||||
 | 
					    override val BSSHIGHRAM_END = 0u      // TODO address?
 | 
				
			||||||
 | 
					    override val BSSGOLDENRAM_START = 0u  // TODO address?
 | 
				
			||||||
 | 
					    override val BSSGOLDENRAM_END = 0u    // TODO address?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override lateinit var zeropage: Zeropage
 | 
				
			||||||
 | 
					    override lateinit var golden: GoldenRam
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun convertFloatToBytes(num: Double): List<UByte> {
 | 
				
			||||||
 | 
					        val m5 = Mflpt5.fromNumber(num)
 | 
				
			||||||
 | 
					        return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun convertBytesToFloat(bytes: List<UByte>): Double {
 | 
				
			||||||
 | 
					        require(bytes.size==5) { "need 5 bytes" }
 | 
				
			||||||
 | 
					        val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
 | 
				
			||||||
 | 
					        return m5.toDouble()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path, quiet: Boolean) {
 | 
				
			||||||
 | 
					        if(selectedEmulator!=1) {
 | 
				
			||||||
 | 
					            System.err.println("The c128 target only supports the main emulator (Vice).")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!quiet)
 | 
				
			||||||
 | 
					            println("\nStarting C-128 emulator x128...")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString())
 | 
				
			||||||
 | 
					        val cmdline = listOf("x128", "-silent", "-moncommands", viceMonlist,
 | 
				
			||||||
 | 
					            "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
 | 
				
			||||||
 | 
					        val processb = ProcessBuilder(cmdline)
 | 
				
			||||||
 | 
					        if(!quiet)
 | 
				
			||||||
 | 
					            processb.inheritIO()
 | 
				
			||||||
 | 
					        val process: Process = processb.start()
 | 
				
			||||||
 | 
					        process.waitFor()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
 | 
				
			||||||
 | 
					        zeropage = C128Zeropage(compilerOptions)
 | 
				
			||||||
 | 
					        golden = GoldenRam(compilerOptions, UIntRange.EMPTY)    // TODO does the c128 have some of this somewhere?
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,23 +1,95 @@
 | 
				
			|||||||
package prog8.code.target
 | 
					package prog8.code.target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prog8.code.core.Encoding
 | 
					import prog8.code.core.*
 | 
				
			||||||
import prog8.code.core.ICompilationTarget
 | 
					import prog8.code.target.encodings.Encoder
 | 
				
			||||||
import prog8.code.core.IMemSizer
 | 
					import prog8.code.target.zp.C64Zeropage
 | 
				
			||||||
import prog8.code.core.IStringEncoding
 | 
					import java.io.IOException
 | 
				
			||||||
import prog8.code.target.c64.C64MachineDefinition
 | 
					import java.nio.file.Path
 | 
				
			||||||
import prog8.code.target.cbm.CbmMemorySizer
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class C64Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
 | 
					class C64Target: ICompilationTarget,
 | 
				
			||||||
 | 
					    IStringEncoding by Encoder(true),
 | 
				
			||||||
 | 
					    IMemSizer by NormalMemSizer(Mflpt5.FLOAT_MEM_SIZE) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override val name = NAME
 | 
					    override val name = NAME
 | 
				
			||||||
    override val machine = C64MachineDefinition()
 | 
					 | 
				
			||||||
    override val defaultEncoding = Encoding.PETSCII
 | 
					    override val defaultEncoding = Encoding.PETSCII
 | 
				
			||||||
 | 
					    override val libraryPath = null
 | 
				
			||||||
 | 
					    override val customLauncher = emptyList<String>()
 | 
				
			||||||
 | 
					    override val additionalAssemblerOptions = emptyList<String>()
 | 
				
			||||||
 | 
					    override val defaultOutputType = OutputType.PRG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        const val NAME = "c64"
 | 
					        const val NAME = "c64"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        fun viceMonListName(baseFilename: String) = "$baseFilename.vice-mon-list"
 | 
					        fun viceMonListName(baseFilename: String) = "$baseFilename.vice-mon-list"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val cpu = CpuType.CPU6502
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
 | 
				
			||||||
 | 
					    override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
 | 
				
			||||||
 | 
					    override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
 | 
				
			||||||
 | 
					    override val STARTUP_CODE_RESERVED_SIZE = 20u
 | 
				
			||||||
 | 
					    override val PROGRAM_LOAD_ADDRESS = 0x0801u
 | 
				
			||||||
 | 
					    override val PROGRAM_MEMTOP_ADDRESS = 0xcfe0u      // $a000  if floats are used
 | 
				
			||||||
 | 
					    // note that at $cfe0-$cfff are the 16 'virtual registers' R0-R15
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val BSSHIGHRAM_START = 0xc000u
 | 
				
			||||||
 | 
					    override val BSSHIGHRAM_END = 0xcfdfu
 | 
				
			||||||
 | 
					    override val BSSGOLDENRAM_START = 0u        // no golden ram on C64
 | 
				
			||||||
 | 
					    override val BSSGOLDENRAM_END = 0u
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override lateinit var zeropage: Zeropage
 | 
				
			||||||
 | 
					    override lateinit var golden: GoldenRam
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun convertFloatToBytes(num: Double): List<UByte> {
 | 
				
			||||||
 | 
					        val m5 = Mflpt5.fromNumber(num)
 | 
				
			||||||
 | 
					        return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun convertBytesToFloat(bytes: List<UByte>): Double {
 | 
				
			||||||
 | 
					        require(bytes.size==5) { "need 5 bytes" }
 | 
				
			||||||
 | 
					        val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
 | 
				
			||||||
 | 
					        return m5.toDouble()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path, quiet: Boolean) {
 | 
				
			||||||
 | 
					        if(selectedEmulator!=1) {
 | 
				
			||||||
 | 
					            System.err.println("The c64 target only supports the main emulator (Vice).")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for(emulator in listOf("x64sc", "x64")) {
 | 
				
			||||||
 | 
					            if(!quiet)
 | 
				
			||||||
 | 
					                println("\nStarting C-64 emulator $emulator...")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val viceMonlist = viceMonListName(programNameWithPath.toString())
 | 
				
			||||||
 | 
					            val cmdline = listOf(emulator, "-silent", "-moncommands", viceMonlist,
 | 
				
			||||||
 | 
					                "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
 | 
				
			||||||
 | 
					            val processb = ProcessBuilder(cmdline)
 | 
				
			||||||
 | 
					            if(!quiet)
 | 
				
			||||||
 | 
					                processb.inheritIO()
 | 
				
			||||||
 | 
					            val process: Process
 | 
				
			||||||
 | 
					            try {
 | 
				
			||||||
 | 
					                process=processb.start()
 | 
				
			||||||
 | 
					            } catch(_: IOException) {
 | 
				
			||||||
 | 
					                continue  // try the next emulator executable
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            process.waitFor()
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
 | 
				
			||||||
 | 
					        zeropage = C64Zeropage(compilerOptions)
 | 
				
			||||||
 | 
					        golden = GoldenRam(compilerOptions, UIntRange.EMPTY)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -26,7 +98,6 @@ val CompilationTargets = listOf(
 | 
				
			|||||||
    C128Target.NAME,
 | 
					    C128Target.NAME,
 | 
				
			||||||
    Cx16Target.NAME,
 | 
					    Cx16Target.NAME,
 | 
				
			||||||
    PETTarget.NAME,
 | 
					    PETTarget.NAME,
 | 
				
			||||||
    AtariTarget.NAME,
 | 
					 | 
				
			||||||
    VMTarget.NAME
 | 
					    VMTarget.NAME
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -35,7 +106,6 @@ fun getCompilationTargetByName(name: String) = when(name.lowercase()) {
 | 
				
			|||||||
    C128Target.NAME -> C128Target()
 | 
					    C128Target.NAME -> C128Target()
 | 
				
			||||||
    Cx16Target.NAME -> Cx16Target()
 | 
					    Cx16Target.NAME -> Cx16Target()
 | 
				
			||||||
    PETTarget.NAME -> PETTarget()
 | 
					    PETTarget.NAME -> PETTarget()
 | 
				
			||||||
    AtariTarget.NAME -> AtariTarget()
 | 
					 | 
				
			||||||
    VMTarget.NAME -> VMTarget()
 | 
					    VMTarget.NAME -> VMTarget()
 | 
				
			||||||
    else -> throw IllegalArgumentException("invalid compilation target")
 | 
					    else -> throw IllegalArgumentException("invalid compilation target")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
							
								
								
									
										173
									
								
								codeCore/src/prog8/code/target/ConfigFileTarget.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										173
									
								
								codeCore/src/prog8/code/target/ConfigFileTarget.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,173 @@
 | 
				
			|||||||
 | 
					package prog8.code.target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import prog8.code.core.*
 | 
				
			||||||
 | 
					import prog8.code.source.ImportFileSystem.expandTilde
 | 
				
			||||||
 | 
					import prog8.code.target.encodings.Encoder
 | 
				
			||||||
 | 
					import prog8.code.target.zp.ConfigurableZeropage
 | 
				
			||||||
 | 
					import java.io.IOException
 | 
				
			||||||
 | 
					import java.nio.file.Path
 | 
				
			||||||
 | 
					import java.util.*
 | 
				
			||||||
 | 
					import kotlin.io.path.Path
 | 
				
			||||||
 | 
					import kotlin.io.path.inputStream
 | 
				
			||||||
 | 
					import kotlin.io.path.isDirectory
 | 
				
			||||||
 | 
					import kotlin.io.path.nameWithoutExtension
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConfigFileTarget(
 | 
				
			||||||
 | 
					    override val name: String,
 | 
				
			||||||
 | 
					    override val defaultEncoding: Encoding,
 | 
				
			||||||
 | 
					    override val cpu: CpuType,
 | 
				
			||||||
 | 
					    override val PROGRAM_LOAD_ADDRESS: UInt,
 | 
				
			||||||
 | 
					    override val PROGRAM_MEMTOP_ADDRESS: UInt,
 | 
				
			||||||
 | 
					    override val STARTUP_CODE_RESERVED_SIZE: UInt,
 | 
				
			||||||
 | 
					    override val BSSHIGHRAM_START: UInt,
 | 
				
			||||||
 | 
					    override val BSSHIGHRAM_END: UInt,
 | 
				
			||||||
 | 
					    override val BSSGOLDENRAM_START: UInt,
 | 
				
			||||||
 | 
					    override val BSSGOLDENRAM_END: UInt,
 | 
				
			||||||
 | 
					    override val defaultOutputType: OutputType,
 | 
				
			||||||
 | 
					    override val libraryPath: Path,
 | 
				
			||||||
 | 
					    override val customLauncher: List<String>,
 | 
				
			||||||
 | 
					    override val additionalAssemblerOptions: List<String>,
 | 
				
			||||||
 | 
					    val ioAddresses: List<UIntRange>,
 | 
				
			||||||
 | 
					    val zpScratchB1: UInt,
 | 
				
			||||||
 | 
					    val zpScratchReg: UInt,
 | 
				
			||||||
 | 
					    val zpScratchW1: UInt,
 | 
				
			||||||
 | 
					    val zpScratchW2: UInt,
 | 
				
			||||||
 | 
					    val zpScratchPtr: UInt,
 | 
				
			||||||
 | 
					    val virtualregistersStart: UInt,
 | 
				
			||||||
 | 
					    val zpFullsafe: List<UIntRange>,
 | 
				
			||||||
 | 
					    val zpKernalsafe: List<UIntRange>,
 | 
				
			||||||
 | 
					    val zpBasicsafe: List<UIntRange>
 | 
				
			||||||
 | 
					): ICompilationTarget, IStringEncoding by Encoder(true), IMemSizer by NormalMemSizer(8) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    companion object {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private fun Properties.getString(property: String): String {
 | 
				
			||||||
 | 
					            val value = this.getProperty(property, null)
 | 
				
			||||||
 | 
					            if(value!=null)
 | 
				
			||||||
 | 
					                return value
 | 
				
			||||||
 | 
					            throw NoSuchElementException("string property '$property' not found in config file")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private fun Properties.getInteger(property: String): UInt {
 | 
				
			||||||
 | 
					            val value = this.getProperty(property, null)
 | 
				
			||||||
 | 
					            if(value!=null) return parseInt(value)
 | 
				
			||||||
 | 
					            throw NoSuchElementException("integer property '$property' not found in config file")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private fun parseInt(value: String): UInt {
 | 
				
			||||||
 | 
					            if(value.startsWith("0x"))
 | 
				
			||||||
 | 
					                return value.drop(2).toUInt(16)
 | 
				
			||||||
 | 
					            if(value.startsWith("$"))
 | 
				
			||||||
 | 
					                return value.drop(1).toUInt(16)
 | 
				
			||||||
 | 
					            if(value.startsWith("%"))
 | 
				
			||||||
 | 
					                return value.drop(1).toUInt(2)
 | 
				
			||||||
 | 
					            return value.toUInt()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private fun parseAddressRanges(key: String, props: Properties): List<UIntRange> {
 | 
				
			||||||
 | 
					            val rangesStr = props.getString(key)
 | 
				
			||||||
 | 
					            if(rangesStr.isBlank())
 | 
				
			||||||
 | 
					                return emptyList()
 | 
				
			||||||
 | 
					            val result = mutableListOf<UIntRange>()
 | 
				
			||||||
 | 
					            val ranges = rangesStr.split(",").map { it.trim() }
 | 
				
			||||||
 | 
					            for(r in ranges) {
 | 
				
			||||||
 | 
					                if ('-' in r) {
 | 
				
			||||||
 | 
					                    val (fromStr, toStr) = r.split("-")
 | 
				
			||||||
 | 
					                    val from = parseInt(fromStr.trim())
 | 
				
			||||||
 | 
					                    val to = parseInt(toStr.trim())
 | 
				
			||||||
 | 
					                    result.add(from..to)
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    val address = parseInt(r)
 | 
				
			||||||
 | 
					                    result.add(address..address)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return result
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fun fromConfigFile(configfile: Path): ConfigFileTarget {
 | 
				
			||||||
 | 
					            val props = Properties()
 | 
				
			||||||
 | 
					            props.load(configfile.inputStream())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val cpuString = props.getString("cpu").uppercase()
 | 
				
			||||||
 | 
					            val cpuType = try {
 | 
				
			||||||
 | 
					                CpuType.valueOf(cpuString)
 | 
				
			||||||
 | 
					            } catch (_: IllegalArgumentException) {
 | 
				
			||||||
 | 
					                CpuType.valueOf("CPU$cpuString")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            val ioAddresses = parseAddressRanges("io_regions", props)
 | 
				
			||||||
 | 
					            val zpFullsafe = parseAddressRanges("zp_fullsafe", props)
 | 
				
			||||||
 | 
					            val zpKernalsafe = parseAddressRanges("zp_kernalsafe", props)
 | 
				
			||||||
 | 
					            val zpBasicsafe = parseAddressRanges("zp_basicsafe", props)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val libraryPath = expandTilde(Path(props.getString("library")))
 | 
				
			||||||
 | 
					            if(!libraryPath.isDirectory())
 | 
				
			||||||
 | 
					                throw IOException("invalid library path: $libraryPath")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val customLauncherStr = props.getProperty("custom_launcher_code", null)
 | 
				
			||||||
 | 
					            val customLauncher =
 | 
				
			||||||
 | 
					                if(customLauncherStr?.isNotBlank()==true)
 | 
				
			||||||
 | 
					                    (customLauncherStr+"\n").lines().map { it.trimEnd() }
 | 
				
			||||||
 | 
					                else emptyList()
 | 
				
			||||||
 | 
					            val assemblerOptionsStr = props.getProperty("assembler_options", "").trim()
 | 
				
			||||||
 | 
					            val outputTypeString = props.getProperty("output_type", "PRG")
 | 
				
			||||||
 | 
					            val defaultOutputType = OutputType.valueOf(outputTypeString.uppercase())
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return ConfigFileTarget(
 | 
				
			||||||
 | 
					                configfile.nameWithoutExtension,
 | 
				
			||||||
 | 
					                Encoding.entries.first { it.prefix==props.getString("encoding") },
 | 
				
			||||||
 | 
					                cpuType,
 | 
				
			||||||
 | 
					                props.getInteger("load_address"),
 | 
				
			||||||
 | 
					                props.getInteger("memtop"),
 | 
				
			||||||
 | 
					                0u,         // used only in a very specific error condition check in a certain scenario...
 | 
				
			||||||
 | 
					                props.getInteger("bss_highram_start"),
 | 
				
			||||||
 | 
					                props.getInteger("bss_highram_end"),
 | 
				
			||||||
 | 
					                props.getInteger("bss_goldenram_start"),
 | 
				
			||||||
 | 
					                props.getInteger("bss_goldenram_end"),
 | 
				
			||||||
 | 
					                defaultOutputType,
 | 
				
			||||||
 | 
					                libraryPath,
 | 
				
			||||||
 | 
					                customLauncher,
 | 
				
			||||||
 | 
					                if(assemblerOptionsStr=="") emptyList() else assemblerOptionsStr.split(" "),
 | 
				
			||||||
 | 
					                ioAddresses,
 | 
				
			||||||
 | 
					                props.getInteger("zp_scratch_b1"),
 | 
				
			||||||
 | 
					                props.getInteger("zp_scratch_reg"),
 | 
				
			||||||
 | 
					                props.getInteger("zp_scratch_w1"),
 | 
				
			||||||
 | 
					                props.getInteger("zp_scratch_w2"),
 | 
				
			||||||
 | 
					                props.getInteger("zp_scratch_ptr"),
 | 
				
			||||||
 | 
					                props.getInteger("virtual_registers"),
 | 
				
			||||||
 | 
					                zpFullsafe,
 | 
				
			||||||
 | 
					                zpKernalsafe,
 | 
				
			||||||
 | 
					                zpBasicsafe,
 | 
				
			||||||
 | 
					            )
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO floats are not yet supported here, just enter some values
 | 
				
			||||||
 | 
					    override val FLOAT_MAX_POSITIVE = 9.999999999e97
 | 
				
			||||||
 | 
					    override val FLOAT_MAX_NEGATIVE = -9.999999999e97
 | 
				
			||||||
 | 
					    override val FLOAT_MEM_SIZE = 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override lateinit var zeropage: Zeropage
 | 
				
			||||||
 | 
					    override lateinit var golden: GoldenRam     // TODO this is not yet used
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun getFloatAsmBytes(num: Number) = TODO("floats")
 | 
				
			||||||
 | 
					    override fun convertFloatToBytes(num: Double): List<UByte> = TODO("floats")
 | 
				
			||||||
 | 
					    override fun convertBytesToFloat(bytes: List<UByte>): Double = TODO("floats")
 | 
				
			||||||
 | 
					    override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path, quiet: Boolean) {
 | 
				
			||||||
 | 
					        throw IllegalArgumentException("Custom compiler target cannot automatically launch an emulator. Do this manually.")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun isIOAddress(address: UInt): Boolean = ioAddresses.any { address in it }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
 | 
				
			||||||
 | 
					        zeropage = ConfigurableZeropage(
 | 
				
			||||||
 | 
					            zpScratchB1, zpScratchReg, zpScratchW1, zpScratchW2, zpScratchPtr,
 | 
				
			||||||
 | 
					            virtualregistersStart,
 | 
				
			||||||
 | 
					            zpBasicsafe,
 | 
				
			||||||
 | 
					            zpKernalsafe,
 | 
				
			||||||
 | 
					            zpFullsafe,
 | 
				
			||||||
 | 
					            compilerOptions
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					        // note: there's no golden ram yet
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,19 +1,94 @@
 | 
				
			|||||||
package prog8.code.target
 | 
					package prog8.code.target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prog8.code.core.Encoding
 | 
					import prog8.code.core.*
 | 
				
			||||||
import prog8.code.core.ICompilationTarget
 | 
					import prog8.code.target.encodings.Encoder
 | 
				
			||||||
import prog8.code.core.IMemSizer
 | 
					import prog8.code.target.zp.CX16Zeropage
 | 
				
			||||||
import prog8.code.core.IStringEncoding
 | 
					import java.nio.file.Path
 | 
				
			||||||
import prog8.code.target.cbm.CbmMemorySizer
 | 
					 | 
				
			||||||
import prog8.code.target.cx16.CX16MachineDefinition
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Cx16Target: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
 | 
					class Cx16Target: ICompilationTarget,
 | 
				
			||||||
 | 
					    IStringEncoding by Encoder(true),
 | 
				
			||||||
 | 
					    IMemSizer by NormalMemSizer(Mflpt5.FLOAT_MEM_SIZE) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override val name = NAME
 | 
					    override val name = NAME
 | 
				
			||||||
    override val machine = CX16MachineDefinition()
 | 
					 | 
				
			||||||
    override val defaultEncoding = Encoding.PETSCII
 | 
					    override val defaultEncoding = Encoding.PETSCII
 | 
				
			||||||
 | 
					    override val libraryPath = null
 | 
				
			||||||
 | 
					    override val customLauncher = emptyList<String>()
 | 
				
			||||||
 | 
					    override val additionalAssemblerOptions = emptyList<String>()
 | 
				
			||||||
 | 
					    override val defaultOutputType = OutputType.PRG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        const val NAME = "cx16"
 | 
					        const val NAME = "cx16"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val cpu = CpuType.CPU65C02
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
 | 
				
			||||||
 | 
					    override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
 | 
				
			||||||
 | 
					    override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
 | 
				
			||||||
 | 
					    override val STARTUP_CODE_RESERVED_SIZE = 20u
 | 
				
			||||||
 | 
					    override val PROGRAM_LOAD_ADDRESS = 0x0801u
 | 
				
			||||||
 | 
					    override val PROGRAM_MEMTOP_ADDRESS = 0x9f00u
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val BSSHIGHRAM_START = 0xa000u     // hiram bank 1, 8Kb, assumed to be active
 | 
				
			||||||
 | 
					    override val BSSHIGHRAM_END = 0xbfffu       // Rom starts at $c000
 | 
				
			||||||
 | 
					    override val BSSGOLDENRAM_START = 0x0400u
 | 
				
			||||||
 | 
					    override val BSSGOLDENRAM_END = 0x07ffu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override lateinit var zeropage: Zeropage
 | 
				
			||||||
 | 
					    override lateinit var golden: GoldenRam
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun convertFloatToBytes(num: Double): List<UByte> {
 | 
				
			||||||
 | 
					        val m5 = Mflpt5.fromNumber(num)
 | 
				
			||||||
 | 
					        return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun convertBytesToFloat(bytes: List<UByte>): Double {
 | 
				
			||||||
 | 
					        require(bytes.size==5) { "need 5 bytes" }
 | 
				
			||||||
 | 
					        val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
 | 
				
			||||||
 | 
					        return m5.toDouble()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path, quiet: Boolean) {
 | 
				
			||||||
 | 
					        val emulator: String
 | 
				
			||||||
 | 
					        val extraArgs: List<String>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        when(selectedEmulator) {
 | 
				
			||||||
 | 
					            1 -> {
 | 
				
			||||||
 | 
					                emulator = "x16emu"
 | 
				
			||||||
 | 
					                extraArgs = listOf("-debug")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            2 -> {
 | 
				
			||||||
 | 
					                emulator = "box16"
 | 
				
			||||||
 | 
					                extraArgs = listOf("-sym", C64Target.viceMonListName(programNameWithPath.toString()))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else -> {
 | 
				
			||||||
 | 
					                System.err.println("Cx16 target only supports x16emu and box16 emulators.")
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!quiet)
 | 
				
			||||||
 | 
					            println("\nStarting Commander X16 emulator $emulator...")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val cmdline = listOf(emulator, "-scale", "2", "-rtc", "-run", "-prg", "${programNameWithPath}.prg") + extraArgs
 | 
				
			||||||
 | 
					        val processb = ProcessBuilder(cmdline)
 | 
				
			||||||
 | 
					        if(!quiet)
 | 
				
			||||||
 | 
					            processb.inheritIO()
 | 
				
			||||||
 | 
					        processb.environment()["PULSE_LATENCY_MSEC"] = "10"
 | 
				
			||||||
 | 
					        val process: Process = processb.start()
 | 
				
			||||||
 | 
					        process.waitFor()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0x9f00u..0x9fffu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
 | 
				
			||||||
 | 
					        zeropage = CX16Zeropage(compilerOptions)
 | 
				
			||||||
 | 
					        golden = GoldenRam(compilerOptions, BSSGOLDENRAM_START..BSSGOLDENRAM_END)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,9 @@
 | 
				
			|||||||
package prog8.code.target.cbm
 | 
					package prog8.code.target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prog8.code.core.InternalCompilerException
 | 
					import prog8.code.core.InternalCompilerException
 | 
				
			||||||
import kotlin.math.absoluteValue
 | 
					import kotlin.math.absoluteValue
 | 
				
			||||||
import kotlin.math.pow
 | 
					import kotlin.math.pow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
data class Mflpt5(val b0: UByte, val b1: UByte, val b2: UByte, val b3: UByte, val b4: UByte) {
 | 
					data class Mflpt5(val b0: UByte, val b1: UByte, val b2: UByte, val b3: UByte, val b4: UByte) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
@@ -19,7 +18,7 @@ data class Mflpt5(val b0: UByte, val b1: UByte, val b2: UByte, val b3: UByte, va
 | 
				
			|||||||
            // and https://en.wikipedia.org/wiki/IEEE_754-1985
 | 
					            // and https://en.wikipedia.org/wiki/IEEE_754-1985
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            val flt = num.toDouble()
 | 
					            val flt = num.toDouble()
 | 
				
			||||||
            if (flt < FLOAT_MAX_NEGATIVE || flt > FLOAT_MAX_POSITIVE)
 | 
					            if (flt !in FLOAT_MAX_NEGATIVE..FLOAT_MAX_POSITIVE)
 | 
				
			||||||
                throw InternalCompilerException("floating point number out of 5-byte mflpt range: $this")
 | 
					                throw InternalCompilerException("floating point number out of 5-byte mflpt range: $this")
 | 
				
			||||||
            if (flt == 0.0)
 | 
					            if (flt == 0.0)
 | 
				
			||||||
                return zero
 | 
					                return zero
 | 
				
			||||||
							
								
								
									
										39
									
								
								codeCore/src/prog8/code/target/NormalMemSizer.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								codeCore/src/prog8/code/target/NormalMemSizer.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					package prog8.code.target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import prog8.code.core.BaseDataType
 | 
				
			||||||
 | 
					import prog8.code.core.DataType
 | 
				
			||||||
 | 
					import prog8.code.core.IMemSizer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					internal class NormalMemSizer(val floatsize: Int): IMemSizer {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun memorySize(dt: DataType, numElements: Int?): Int {
 | 
				
			||||||
 | 
					        if(dt.isPointerArray)
 | 
				
			||||||
 | 
					            return 2 * numElements!!        // array of pointers is just array of uwords
 | 
				
			||||||
 | 
					        else if(dt.isArray) {
 | 
				
			||||||
 | 
					            if(numElements==null) return 2      // treat it as a pointer size
 | 
				
			||||||
 | 
					            return when(dt.sub) {
 | 
				
			||||||
 | 
					                BaseDataType.BOOL, BaseDataType.UBYTE, BaseDataType.BYTE -> numElements
 | 
				
			||||||
 | 
					                BaseDataType.UWORD, BaseDataType.WORD, BaseDataType.STR -> numElements * 2
 | 
				
			||||||
 | 
					                BaseDataType.LONG -> numElements * 4
 | 
				
			||||||
 | 
					                BaseDataType.FLOAT-> numElements * floatsize
 | 
				
			||||||
 | 
					                BaseDataType.UNDEFINED -> throw IllegalArgumentException("undefined has no memory size")
 | 
				
			||||||
 | 
					                else -> throw IllegalArgumentException("invalid sub type")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else if (dt.isString) {
 | 
				
			||||||
 | 
					            return numElements        // treat it as the size of the given string with the length
 | 
				
			||||||
 | 
					                ?: 2    // treat it as the size to store a string pointer
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return when {
 | 
				
			||||||
 | 
					            dt.isByteOrBool -> 1 * (numElements ?: 1)
 | 
				
			||||||
 | 
					            dt.isFloat -> floatsize * (numElements ?: 1)
 | 
				
			||||||
 | 
					            dt.isLong -> 4 * (numElements ?: 1)
 | 
				
			||||||
 | 
					            dt.isPointer -> 2  // pointer is just a uword
 | 
				
			||||||
 | 
					            dt.isStructInstance -> dt.subType!!.memsize(this)
 | 
				
			||||||
 | 
					            dt.isUndefined -> throw IllegalArgumentException("undefined has no memory size")
 | 
				
			||||||
 | 
					            else -> 2 * (numElements ?: 1)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,19 +1,80 @@
 | 
				
			|||||||
package prog8.code.target
 | 
					package prog8.code.target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prog8.code.core.Encoding
 | 
					import prog8.code.core.*
 | 
				
			||||||
import prog8.code.core.ICompilationTarget
 | 
					import prog8.code.target.encodings.Encoder
 | 
				
			||||||
import prog8.code.core.IMemSizer
 | 
					import prog8.code.target.zp.PETZeropage
 | 
				
			||||||
import prog8.code.core.IStringEncoding
 | 
					import java.nio.file.Path
 | 
				
			||||||
import prog8.code.target.cbm.CbmMemorySizer
 | 
					 | 
				
			||||||
import prog8.code.target.pet.PETMachineDefinition
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PETTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer by CbmMemorySizer {
 | 
					class PETTarget: ICompilationTarget,
 | 
				
			||||||
 | 
					    IStringEncoding by Encoder(true),
 | 
				
			||||||
 | 
					    IMemSizer by NormalMemSizer(Mflpt5.FLOAT_MEM_SIZE) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override val name = NAME
 | 
					    override val name = NAME
 | 
				
			||||||
    override val machine = PETMachineDefinition()
 | 
					 | 
				
			||||||
    override val defaultEncoding = Encoding.PETSCII
 | 
					    override val defaultEncoding = Encoding.PETSCII
 | 
				
			||||||
 | 
					    override val libraryPath = null
 | 
				
			||||||
 | 
					    override val customLauncher = emptyList<String>()
 | 
				
			||||||
 | 
					    override val additionalAssemblerOptions = emptyList<String>()
 | 
				
			||||||
 | 
					    override val defaultOutputType = OutputType.PRG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        const val NAME = "pet32"
 | 
					        const val NAME = "pet32"
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val cpu = CpuType.CPU6502
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
 | 
				
			||||||
 | 
					    override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
 | 
				
			||||||
 | 
					    override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
 | 
				
			||||||
 | 
					    override val STARTUP_CODE_RESERVED_SIZE = 20u
 | 
				
			||||||
 | 
					    override val PROGRAM_LOAD_ADDRESS = 0x0401u
 | 
				
			||||||
 | 
					    override val PROGRAM_MEMTOP_ADDRESS = 0x8000u
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val BSSHIGHRAM_START = 0u
 | 
				
			||||||
 | 
					    override val BSSHIGHRAM_END = 0u
 | 
				
			||||||
 | 
					    override val BSSGOLDENRAM_START = 0u
 | 
				
			||||||
 | 
					    override val BSSGOLDENRAM_END = 0u
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override lateinit var zeropage: Zeropage
 | 
				
			||||||
 | 
					    override lateinit var golden: GoldenRam
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun convertFloatToBytes(num: Double): List<UByte> {
 | 
				
			||||||
 | 
					        val m5 = Mflpt5.fromNumber(num)
 | 
				
			||||||
 | 
					        return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun convertBytesToFloat(bytes: List<UByte>): Double {
 | 
				
			||||||
 | 
					        require(bytes.size==5) { "need 5 bytes" }
 | 
				
			||||||
 | 
					        val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
 | 
				
			||||||
 | 
					        return m5.toDouble()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path, quiet: Boolean) {
 | 
				
			||||||
 | 
					        if(selectedEmulator!=1) {
 | 
				
			||||||
 | 
					            System.err.println("The pet target only supports the main emulator (Vice).")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(!quiet)
 | 
				
			||||||
 | 
					            println("\nStarting PET emulator...")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString())
 | 
				
			||||||
 | 
					        val cmdline = listOf("xpet", "-model", "4032", "-ramsize", "32", "-videosize", "40", "-silent", "-moncommands", viceMonlist,
 | 
				
			||||||
 | 
					            "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
 | 
				
			||||||
 | 
					        val processb = ProcessBuilder(cmdline)
 | 
				
			||||||
 | 
					        if(!quiet)
 | 
				
			||||||
 | 
					            processb.inheritIO()
 | 
				
			||||||
 | 
					        val process=processb.start()
 | 
				
			||||||
 | 
					        process.waitFor()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun isIOAddress(address: UInt): Boolean = address in 0xe800u..0xe8ffu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
 | 
				
			||||||
 | 
					        zeropage = PETZeropage(compilerOptions)
 | 
				
			||||||
 | 
					        golden = GoldenRam(compilerOptions, UIntRange.EMPTY)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,29 +1,109 @@
 | 
				
			|||||||
package prog8.code.target
 | 
					package prog8.code.target
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prog8.code.core.*
 | 
					import prog8.code.core.*
 | 
				
			||||||
import prog8.code.target.virtual.VirtualMachineDefinition
 | 
					import prog8.code.target.encodings.Encoder
 | 
				
			||||||
 | 
					import java.nio.file.Path
 | 
				
			||||||
 | 
					import kotlin.io.path.extension
 | 
				
			||||||
 | 
					import kotlin.io.path.isReadable
 | 
				
			||||||
 | 
					import kotlin.io.path.name
 | 
				
			||||||
 | 
					import kotlin.io.path.readText
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VMTarget: ICompilationTarget,
 | 
				
			||||||
 | 
					    IStringEncoding by Encoder(false),
 | 
				
			||||||
 | 
					    IMemSizer by NormalMemSizer(FLOAT_MEM_SIZE) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class VMTarget: ICompilationTarget, IStringEncoding by Encoder, IMemSizer {
 | 
					 | 
				
			||||||
    override val name = NAME
 | 
					    override val name = NAME
 | 
				
			||||||
    override val machine = VirtualMachineDefinition()
 | 
					 | 
				
			||||||
    override val defaultEncoding = Encoding.ISO
 | 
					    override val defaultEncoding = Encoding.ISO
 | 
				
			||||||
 | 
					    override val libraryPath = null
 | 
				
			||||||
 | 
					    override val customLauncher = emptyList<String>()
 | 
				
			||||||
 | 
					    override val additionalAssemblerOptions = emptyList<String>()
 | 
				
			||||||
 | 
					    override val defaultOutputType = OutputType.PRG
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    companion object {
 | 
					    companion object {
 | 
				
			||||||
        const val NAME = "virtual"
 | 
					        const val NAME = "virtual"
 | 
				
			||||||
 | 
					        const val FLOAT_MEM_SIZE = 8             // 64-bits double
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun memorySize(dt: DataType): Int {
 | 
					    override val cpu = CpuType.VIRTUAL
 | 
				
			||||||
        return when(dt) {
 | 
					
 | 
				
			||||||
            in ByteDatatypesWithBoolean -> 1
 | 
					    override val FLOAT_MAX_POSITIVE = Double.MAX_VALUE
 | 
				
			||||||
            in WordDatatypes, in PassByReferenceDatatypes -> 2
 | 
					    override val FLOAT_MAX_NEGATIVE = -Double.MAX_VALUE
 | 
				
			||||||
            DataType.FLOAT -> machine.FLOAT_MEM_SIZE
 | 
					    override val FLOAT_MEM_SIZE = VMTarget.FLOAT_MEM_SIZE
 | 
				
			||||||
            else -> throw IllegalArgumentException("invalid datatype")
 | 
					    override val STARTUP_CODE_RESERVED_SIZE = 0u  // not actually used
 | 
				
			||||||
        }
 | 
					    override val PROGRAM_LOAD_ADDRESS = 0u      // not actually used
 | 
				
			||||||
 | 
					    override val PROGRAM_MEMTOP_ADDRESS = 0xffffu  // not actually used
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override val BSSHIGHRAM_START = 0u          // not actually used
 | 
				
			||||||
 | 
					    override val BSSHIGHRAM_END = 0u            // not actually used
 | 
				
			||||||
 | 
					    override val BSSGOLDENRAM_START = 0u        // not actually used
 | 
				
			||||||
 | 
					    override val BSSGOLDENRAM_END = 0u          // not actually used
 | 
				
			||||||
 | 
					    override lateinit var zeropage: Zeropage    // not actually used
 | 
				
			||||||
 | 
					    override lateinit var golden: GoldenRam     // not actually used
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun getFloatAsmBytes(num: Number): String {
 | 
				
			||||||
 | 
					        // little endian binary representation
 | 
				
			||||||
 | 
					        val bits = num.toDouble().toBits().toULong()
 | 
				
			||||||
 | 
					        val hexStr = bits.toString(16).padStart(16, '0')
 | 
				
			||||||
 | 
					        val parts = hexStr.chunked(2).map { "$$it" }
 | 
				
			||||||
 | 
					        return parts.joinToString(", ")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun memorySize(arrayDt: DataType, numElements: Int) =
 | 
					    override fun convertFloatToBytes(num: Double): List<UByte> {
 | 
				
			||||||
        if(arrayDt==DataType.UWORD)
 | 
					        val bits = num.toBits().toULong()
 | 
				
			||||||
            numElements    // pointer to bytes.
 | 
					        val hexStr = bits.toString(16).padStart(16, '0')
 | 
				
			||||||
 | 
					        val parts = hexStr.chunked(2).map { it.toInt(16).toUByte() }
 | 
				
			||||||
 | 
					        return parts
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun convertBytesToFloat(bytes: List<UByte>): Double {
 | 
				
			||||||
 | 
					        require(bytes.size==8) { "need 8 bytes" }
 | 
				
			||||||
 | 
					        val b0 = bytes[0].toLong() shl (8*7)
 | 
				
			||||||
 | 
					        val b1 = bytes[1].toLong() shl (8*6)
 | 
				
			||||||
 | 
					        val b2 = bytes[2].toLong() shl (8*5)
 | 
				
			||||||
 | 
					        val b3 = bytes[3].toLong() shl (8*4)
 | 
				
			||||||
 | 
					        val b4 = bytes[4].toLong() shl (8*3)
 | 
				
			||||||
 | 
					        val b5 = bytes[5].toLong() shl (8*2)
 | 
				
			||||||
 | 
					        val b6 = bytes[6].toLong() shl (8*1)
 | 
				
			||||||
 | 
					        val b7 = bytes[7].toLong() shl (8*0)
 | 
				
			||||||
 | 
					        return Double.fromBits(b0 or b1 or b2 or b3 or b4 or b5 or b6 or b7)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path, quiet: Boolean) {
 | 
				
			||||||
 | 
					        if(!quiet)
 | 
				
			||||||
 | 
					            println("\nStarting Virtual Machine...")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // to not have external module dependencies in our own module, we launch the virtual machine via reflection
 | 
				
			||||||
 | 
					        val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner
 | 
				
			||||||
 | 
					        val withExt = if(programNameWithPath.extension=="p8ir") programNameWithPath else programNameWithPath.resolveSibling("${programNameWithPath.name}.p8ir")
 | 
				
			||||||
 | 
					        if(withExt.isReadable())
 | 
				
			||||||
 | 
					            vm.runProgram(withExt.readText(), quiet)
 | 
				
			||||||
        else
 | 
					        else
 | 
				
			||||||
            memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements
 | 
					            throw java.nio.file.NoSuchFileException(withExt.name, null, "not a .p8ir file")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun isIOAddress(address: UInt): Boolean = false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
 | 
				
			||||||
 | 
					        zeropage = VirtualZeropage(compilerOptions)
 | 
				
			||||||
 | 
					        golden = GoldenRam(compilerOptions, UIntRange.EMPTY)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface IVirtualMachineRunner {
 | 
				
			||||||
 | 
					    fun runProgram(irSource: String, quiet: Boolean)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private class VirtualZeropage(options: CompilationOptions): Zeropage(options) {
 | 
				
			||||||
 | 
					    override val SCRATCH_B1: UInt
 | 
				
			||||||
 | 
					        get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
 | 
				
			||||||
 | 
					    override val SCRATCH_REG: UInt
 | 
				
			||||||
 | 
					        get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
 | 
				
			||||||
 | 
					    override val SCRATCH_W1: UInt
 | 
				
			||||||
 | 
					        get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
 | 
				
			||||||
 | 
					    override val SCRATCH_W2: UInt
 | 
				
			||||||
 | 
					        get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
 | 
				
			||||||
 | 
					    override val SCRATCH_PTR: UInt
 | 
				
			||||||
 | 
					        get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,60 +0,0 @@
 | 
				
			|||||||
package prog8.code.target.atari
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import prog8.code.core.*
 | 
					 | 
				
			||||||
import java.nio.file.Path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AtariMachineDefinition: IMachineDefinition {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val cpu = CpuType.CPU6502
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val FLOAT_MAX_POSITIVE = 9.999999999e97
 | 
					 | 
				
			||||||
    override val FLOAT_MAX_NEGATIVE = -9.999999999e97
 | 
					 | 
				
			||||||
    override val FLOAT_MEM_SIZE = 6
 | 
					 | 
				
			||||||
    override val PROGRAM_LOAD_ADDRESS = 0x2000u
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val BSSHIGHRAM_START = 0u    // TODO
 | 
					 | 
				
			||||||
    override val BSSHIGHRAM_END = 0u      // TODO
 | 
					 | 
				
			||||||
    override val BSSGOLDENRAM_START = 0u  // TODO
 | 
					 | 
				
			||||||
    override val BSSGOLDENRAM_END = 0u    // TODO
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override lateinit var zeropage: Zeropage
 | 
					 | 
				
			||||||
    override lateinit var golden: GoldenRam
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun getFloatAsmBytes(num: Number) = TODO("atari float asm bytes from number")
 | 
					 | 
				
			||||||
    override fun convertFloatToBytes(num: Double): List<UByte> = TODO("atari float to bytes")
 | 
					 | 
				
			||||||
    override fun convertBytesToFloat(bytes: List<UByte>): Double = TODO("atari bytes to float")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
 | 
					 | 
				
			||||||
        val emulatorName: String
 | 
					 | 
				
			||||||
        val cmdline: List<String>
 | 
					 | 
				
			||||||
        when(selectedEmulator) {
 | 
					 | 
				
			||||||
            1 -> {
 | 
					 | 
				
			||||||
                emulatorName = "atari800"
 | 
					 | 
				
			||||||
                cmdline = listOf(emulatorName, "-xl", "-xl-rev", "2", "-nobasic", "-run", "${programNameWithPath}.xex")
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            2 -> {
 | 
					 | 
				
			||||||
                emulatorName = "altirra"
 | 
					 | 
				
			||||||
                cmdline = listOf("Altirra64.exe", "${programNameWithPath.normalize()}.xex")
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else -> {
 | 
					 | 
				
			||||||
                System.err.println("Atari target only supports atari800 and altirra emulators.")
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // TODO monlist?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        println("\nStarting Atari800XL emulator $emulatorName...")
 | 
					 | 
				
			||||||
        val processb = ProcessBuilder(cmdline).inheritIO()
 | 
					 | 
				
			||||||
        val process: Process = processb.start()
 | 
					 | 
				
			||||||
        process.waitFor()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu        // TODO
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
 | 
					 | 
				
			||||||
        zeropage = AtariZeropage(compilerOptions)
 | 
					 | 
				
			||||||
        golden = GoldenRam(compilerOptions, UIntRange.EMPTY)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,57 +0,0 @@
 | 
				
			|||||||
package prog8.code.target.atari
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import prog8.code.core.CompilationOptions
 | 
					 | 
				
			||||||
import prog8.code.core.InternalCompilerException
 | 
					 | 
				
			||||||
import prog8.code.core.Zeropage
 | 
					 | 
				
			||||||
import prog8.code.core.ZeropageType
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class AtariZeropage(options: CompilationOptions) : Zeropage(options) {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val SCRATCH_B1 = 0xcbu      // temp storage for a single byte
 | 
					 | 
				
			||||||
    override val SCRATCH_REG = 0xccu     // temp storage for a register, must be B1+1
 | 
					 | 
				
			||||||
    override val SCRATCH_W1 = 0xcdu      // temp storage 1 for a word  $cd+$ce
 | 
					 | 
				
			||||||
    override val SCRATCH_W2 = 0xcfu      // temp storage 2 for a word  $cf+$d0        TODO is $d0 okay to use?
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    init {
 | 
					 | 
				
			||||||
        if (options.floats) {
 | 
					 | 
				
			||||||
            throw InternalCompilerException("Atari target doesn't yet support floating point routines")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (options.floats && options.zeropage !in arrayOf(
 | 
					 | 
				
			||||||
                ZeropageType.FLOATSAFE,
 | 
					 | 
				
			||||||
                ZeropageType.BASICSAFE,
 | 
					 | 
				
			||||||
                ZeropageType.DONTUSE
 | 
					 | 
				
			||||||
            ))
 | 
					 | 
				
			||||||
            throw InternalCompilerException("when floats are enabled, zero page type should be 'floatsafe' or 'basicsafe' or 'dontuse'")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        when (options.zeropage) {
 | 
					 | 
				
			||||||
            ZeropageType.FULL -> {
 | 
					 | 
				
			||||||
                // TODO all atari usable zero page locations, except the ones used by the system's IRQ routine
 | 
					 | 
				
			||||||
                free.addAll(0x00u..0xffu)
 | 
					 | 
				
			||||||
                // TODO atari  free.removeAll(setOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u))        // these are updated by IRQ
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            ZeropageType.KERNALSAFE -> {
 | 
					 | 
				
			||||||
                free.addAll(0x80u..0xffu)       // TODO
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            ZeropageType.BASICSAFE,
 | 
					 | 
				
			||||||
            ZeropageType.FLOATSAFE -> {
 | 
					 | 
				
			||||||
                free.addAll(0x80u..0xffu)       // TODO
 | 
					 | 
				
			||||||
                free.removeAll(0xd4u .. 0xefu)      // floating point storage
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            ZeropageType.DONTUSE -> {
 | 
					 | 
				
			||||||
                free.clear()  // don't use zeropage at all
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        val distinctFree = free.distinct()
 | 
					 | 
				
			||||||
        free.clear()
 | 
					 | 
				
			||||||
        free.addAll(distinctFree)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        removeReservedFromFreePool()
 | 
					 | 
				
			||||||
        retainAllowed()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun allocateCx16VirtualRegisters() {
 | 
					 | 
				
			||||||
        TODO("Not known if atari can put the virtual regs in ZP")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,60 +0,0 @@
 | 
				
			|||||||
package prog8.code.target.c128
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import prog8.code.core.*
 | 
					 | 
				
			||||||
import prog8.code.target.C64Target
 | 
					 | 
				
			||||||
import prog8.code.target.cbm.Mflpt5
 | 
					 | 
				
			||||||
import java.nio.file.Path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class C128MachineDefinition: IMachineDefinition {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val cpu = CpuType.CPU6502
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
 | 
					 | 
				
			||||||
    override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
 | 
					 | 
				
			||||||
    override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
 | 
					 | 
				
			||||||
    override val PROGRAM_LOAD_ADDRESS = 0x1c01u
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val BSSHIGHRAM_START = 0u    // TODO
 | 
					 | 
				
			||||||
    override val BSSHIGHRAM_END = 0u      // TODO
 | 
					 | 
				
			||||||
    override val BSSGOLDENRAM_START = 0u  // TODO
 | 
					 | 
				
			||||||
    override val BSSGOLDENRAM_END = 0u    // TODO
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override lateinit var zeropage: Zeropage
 | 
					 | 
				
			||||||
    override lateinit var golden: GoldenRam
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun convertFloatToBytes(num: Double): List<UByte> {
 | 
					 | 
				
			||||||
        val m5 = Mflpt5.fromNumber(num)
 | 
					 | 
				
			||||||
        return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun convertBytesToFloat(bytes: List<UByte>): Double {
 | 
					 | 
				
			||||||
        require(bytes.size==5) { "need 5 bytes" }
 | 
					 | 
				
			||||||
        val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
 | 
					 | 
				
			||||||
        return m5.toDouble()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
 | 
					 | 
				
			||||||
        if(selectedEmulator!=1) {
 | 
					 | 
				
			||||||
            System.err.println("The c128 target only supports the main emulator (Vice).")
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        println("\nStarting C-128 emulator x128...")
 | 
					 | 
				
			||||||
        val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString())
 | 
					 | 
				
			||||||
        val cmdline = listOf("x128", "-silent", "-moncommands", viceMonlist,
 | 
					 | 
				
			||||||
                "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
 | 
					 | 
				
			||||||
        val processb = ProcessBuilder(cmdline).inheritIO()
 | 
					 | 
				
			||||||
        val process: Process = processb.start()
 | 
					 | 
				
			||||||
        process.waitFor()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
 | 
					 | 
				
			||||||
        zeropage = C128Zeropage(compilerOptions)
 | 
					 | 
				
			||||||
        golden = GoldenRam(compilerOptions, UIntRange.EMPTY)    // TODO does the c128 have some of this somewhere?
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,70 +0,0 @@
 | 
				
			|||||||
package prog8.code.target.c64
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import prog8.code.core.*
 | 
					 | 
				
			||||||
import prog8.code.target.C64Target
 | 
					 | 
				
			||||||
import prog8.code.target.cbm.Mflpt5
 | 
					 | 
				
			||||||
import java.io.IOException
 | 
					 | 
				
			||||||
import java.nio.file.Path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class C64MachineDefinition: IMachineDefinition {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val cpu = CpuType.CPU6502
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
 | 
					 | 
				
			||||||
    override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
 | 
					 | 
				
			||||||
    override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
 | 
					 | 
				
			||||||
    override val PROGRAM_LOAD_ADDRESS = 0x0801u
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val BSSHIGHRAM_START = 0xc000u
 | 
					 | 
				
			||||||
    override val BSSHIGHRAM_END = 0xcfffu
 | 
					 | 
				
			||||||
    override val BSSGOLDENRAM_START = 0u
 | 
					 | 
				
			||||||
    override val BSSGOLDENRAM_END = 0u
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override lateinit var zeropage: Zeropage
 | 
					 | 
				
			||||||
    override lateinit var golden: GoldenRam
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun convertFloatToBytes(num: Double): List<UByte> {
 | 
					 | 
				
			||||||
        val m5 = Mflpt5.fromNumber(num)
 | 
					 | 
				
			||||||
        return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun convertBytesToFloat(bytes: List<UByte>): Double {
 | 
					 | 
				
			||||||
        require(bytes.size==5) { "need 5 bytes" }
 | 
					 | 
				
			||||||
        val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
 | 
					 | 
				
			||||||
        return m5.toDouble()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
 | 
					 | 
				
			||||||
        if(selectedEmulator!=1) {
 | 
					 | 
				
			||||||
            System.err.println("The c64 target only supports the main emulator (Vice).")
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        for(emulator in listOf("x64sc", "x64")) {
 | 
					 | 
				
			||||||
            println("\nStarting C-64 emulator $emulator...")
 | 
					 | 
				
			||||||
            val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString())
 | 
					 | 
				
			||||||
            val cmdline = listOf(emulator, "-silent", "-moncommands", viceMonlist,
 | 
					 | 
				
			||||||
                    "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
 | 
					 | 
				
			||||||
            val processb = ProcessBuilder(cmdline).inheritIO()
 | 
					 | 
				
			||||||
            val process: Process
 | 
					 | 
				
			||||||
            try {
 | 
					 | 
				
			||||||
                process=processb.start()
 | 
					 | 
				
			||||||
            } catch(x: IOException) {
 | 
					 | 
				
			||||||
                continue  // try the next emulator executable
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            process.waitFor()
 | 
					 | 
				
			||||||
            break
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0xd000u..0xdfffu
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
 | 
					 | 
				
			||||||
        zeropage = C64Zeropage(compilerOptions)
 | 
					 | 
				
			||||||
        golden = GoldenRam(compilerOptions, 0xc000u until 0xd000u)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,21 +0,0 @@
 | 
				
			|||||||
package prog8.code.target.cbm
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import prog8.code.core.*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
internal object CbmMemorySizer: IMemSizer {
 | 
					 | 
				
			||||||
    override fun memorySize(dt: DataType): Int {
 | 
					 | 
				
			||||||
        return when(dt) {
 | 
					 | 
				
			||||||
            in ByteDatatypesWithBoolean -> 1
 | 
					 | 
				
			||||||
            in WordDatatypes, in PassByReferenceDatatypes -> 2
 | 
					 | 
				
			||||||
            DataType.FLOAT -> Mflpt5.FLOAT_MEM_SIZE
 | 
					 | 
				
			||||||
            else -> throw IllegalArgumentException("invalid datatype")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun memorySize(arrayDt: DataType, numElements: Int) =
 | 
					 | 
				
			||||||
        if(arrayDt==DataType.UWORD)
 | 
					 | 
				
			||||||
            numElements    // pointer to bytes.
 | 
					 | 
				
			||||||
        else
 | 
					 | 
				
			||||||
            memorySize(ArrayToElementTypes.getValue(arrayDt)) * numElements
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,73 +0,0 @@
 | 
				
			|||||||
package prog8.code.target.cx16
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import prog8.code.core.*
 | 
					 | 
				
			||||||
import prog8.code.target.C64Target
 | 
					 | 
				
			||||||
import prog8.code.target.cbm.Mflpt5
 | 
					 | 
				
			||||||
import java.nio.file.Path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class CX16MachineDefinition: IMachineDefinition {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val cpu = CpuType.CPU65c02
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
 | 
					 | 
				
			||||||
    override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
 | 
					 | 
				
			||||||
    override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
 | 
					 | 
				
			||||||
    override val PROGRAM_LOAD_ADDRESS = 0x0801u
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val BSSHIGHRAM_START = 0xa000u     // hiram bank 1, 8Kb, assumed to be active
 | 
					 | 
				
			||||||
    override val BSSHIGHRAM_END = 0xbfffu       // Rom starts at $c000
 | 
					 | 
				
			||||||
    override val BSSGOLDENRAM_START = 0x0400u
 | 
					 | 
				
			||||||
    override val BSSGOLDENRAM_END = 0x07ffu
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override lateinit var zeropage: Zeropage
 | 
					 | 
				
			||||||
    override lateinit var golden: GoldenRam
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun convertFloatToBytes(num: Double): List<UByte> {
 | 
					 | 
				
			||||||
        val m5 = Mflpt5.fromNumber(num)
 | 
					 | 
				
			||||||
        return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun convertBytesToFloat(bytes: List<UByte>): Double {
 | 
					 | 
				
			||||||
        require(bytes.size==5) { "need 5 bytes" }
 | 
					 | 
				
			||||||
        val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
 | 
					 | 
				
			||||||
        return m5.toDouble()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
 | 
					 | 
				
			||||||
        val emulator: String
 | 
					 | 
				
			||||||
        val extraArgs: List<String>
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        when(selectedEmulator) {
 | 
					 | 
				
			||||||
            1 -> {
 | 
					 | 
				
			||||||
                emulator = "x16emu"
 | 
					 | 
				
			||||||
                extraArgs = listOf("-debug")
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            2 -> {
 | 
					 | 
				
			||||||
                emulator = "box16"
 | 
					 | 
				
			||||||
                extraArgs = listOf("-sym", C64Target.viceMonListName(programNameWithPath.toString()))
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else -> {
 | 
					 | 
				
			||||||
                System.err.println("Cx16 target only supports x16emu and box16 emulators.")
 | 
					 | 
				
			||||||
                return
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        println("\nStarting Commander X16 emulator $emulator...")
 | 
					 | 
				
			||||||
        val cmdline = listOf(emulator, "-scale", "2", "-rtc", "-run", "-prg", "${programNameWithPath}.prg") + extraArgs
 | 
					 | 
				
			||||||
        val processb = ProcessBuilder(cmdline).inheritIO()
 | 
					 | 
				
			||||||
        processb.environment()["PULSE_LATENCY_MSEC"] = "10"
 | 
					 | 
				
			||||||
        val process: Process = processb.start()
 | 
					 | 
				
			||||||
        process.waitFor()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun isIOAddress(address: UInt): Boolean = address==0u || address==1u || address in 0x9f00u..0x9fffu
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
 | 
					 | 
				
			||||||
        zeropage = CX16Zeropage(compilerOptions)
 | 
					 | 
				
			||||||
        golden = GoldenRam(compilerOptions, 0x0400u until 0x0800u)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -197,6 +197,7 @@ object AtasciiEncoding {
 | 
				
			|||||||
    fun encode(str: String): Result<List<UByte>, CharConversionException> {
 | 
					    fun encode(str: String): Result<List<UByte>, CharConversionException> {
 | 
				
			||||||
        val mapped = str.map { chr ->
 | 
					        val mapped = str.map { chr ->
 | 
				
			||||||
            when (chr) {
 | 
					            when (chr) {
 | 
				
			||||||
 | 
					                '\r' -> 0x9bu
 | 
				
			||||||
                '\u0000' -> 0u
 | 
					                '\u0000' -> 0u
 | 
				
			||||||
                in '\u8000'..'\u80ff' -> {
 | 
					                in '\u8000'..'\u80ff' -> {
 | 
				
			||||||
                    // special case: take the lower 8 bit hex value directly
 | 
					                    // special case: take the lower 8 bit hex value directly
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										327
									
								
								codeCore/src/prog8/code/target/encodings/C64osEncoding.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								codeCore/src/prog8/code/target/encodings/C64osEncoding.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,327 @@
 | 
				
			|||||||
 | 
					package prog8.code.target.encodings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import com.github.michaelbull.result.Err
 | 
				
			||||||
 | 
					import com.github.michaelbull.result.Ok
 | 
				
			||||||
 | 
					import com.github.michaelbull.result.Result
 | 
				
			||||||
 | 
					import java.io.CharConversionException
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					object C64osEncoding {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // decoding:  from C64 OS Screencodes (0-255) to unicode
 | 
				
			||||||
 | 
					    // character table from:
 | 
				
			||||||
 | 
					    // https://www.c64os.com/c64os/usersguide/appendices#charactersets
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private val decodingC64os = charArrayOf(
 | 
				
			||||||
 | 
					        '@'     ,    //  @    0x00 -> COMMERCIAL AT
 | 
				
			||||||
 | 
					        'a'     ,    //  a    0x01 -> LATIN SMALL LETTER A
 | 
				
			||||||
 | 
					        'b'     ,    //  b    0x02 -> LATIN SMALL LETTER B
 | 
				
			||||||
 | 
					        'c'     ,    //  c    0x03 -> LATIN SMALL LETTER C
 | 
				
			||||||
 | 
					        'd'     ,    //  d    0x04 -> LATIN SMALL LETTER D
 | 
				
			||||||
 | 
					        'e'     ,    //  e    0x05 -> LATIN SMALL LETTER E
 | 
				
			||||||
 | 
					        'f'     ,    //  f    0x06 -> LATIN SMALL LETTER F
 | 
				
			||||||
 | 
					        'g'     ,    //  g    0x07 -> LATIN SMALL LETTER G
 | 
				
			||||||
 | 
					        'h'     ,    //  h    0x08 -> LATIN SMALL LETTER H
 | 
				
			||||||
 | 
					        'i'     ,    //  i    0x09 -> LATIN SMALL LETTER I
 | 
				
			||||||
 | 
					        'j'     ,    //  j    0x0A -> LATIN SMALL LETTER J
 | 
				
			||||||
 | 
					        'k'     ,    //  k    0x0B -> LATIN SMALL LETTER K
 | 
				
			||||||
 | 
					        'l'     ,    //  l    0x0C -> LATIN SMALL LETTER L
 | 
				
			||||||
 | 
					        'm'     ,    //  m    0x0D -> LATIN SMALL LETTER M
 | 
				
			||||||
 | 
					        'n'     ,    //  n    0x0E -> LATIN SMALL LETTER N
 | 
				
			||||||
 | 
					        'o'     ,    //  o    0x0F -> LATIN SMALL LETTER O
 | 
				
			||||||
 | 
					        'p'     ,    //  p    0x10 -> LATIN SMALL LETTER P
 | 
				
			||||||
 | 
					        'q'     ,    //  q    0x11 -> LATIN SMALL LETTER Q
 | 
				
			||||||
 | 
					        'r'     ,    //  r    0x12 -> LATIN SMALL LETTER R
 | 
				
			||||||
 | 
					        's'     ,    //  s    0x13 -> LATIN SMALL LETTER S
 | 
				
			||||||
 | 
					        't'     ,    //  t    0x14 -> LATIN SMALL LETTER T
 | 
				
			||||||
 | 
					        'u'     ,    //  u    0x15 -> LATIN SMALL LETTER U
 | 
				
			||||||
 | 
					        'v'     ,    //  v    0x16 -> LATIN SMALL LETTER V
 | 
				
			||||||
 | 
					        'w'     ,    //  w    0x17 -> LATIN SMALL LETTER W
 | 
				
			||||||
 | 
					        'x'     ,    //  x    0x18 -> LATIN SMALL LETTER X
 | 
				
			||||||
 | 
					        'y'     ,    //  y    0x19 -> LATIN SMALL LETTER Y
 | 
				
			||||||
 | 
					        'z'     ,    //  z    0x1A -> LATIN SMALL LETTER Z
 | 
				
			||||||
 | 
					        '['     ,    //  [    0x1B -> LEFT SQUARE BRACKET
 | 
				
			||||||
 | 
					        '\\'    ,    //  \    0x1C -> REVERSE SOLIDUS
 | 
				
			||||||
 | 
					        ']'     ,    //  ]    0x1D -> RIGHT SQUARE BRACKET
 | 
				
			||||||
 | 
					        '^'     ,    //  ^    0x1E -> CIRCUMFLEX
 | 
				
			||||||
 | 
					        '_'     ,    //  _    0x1F -> UNDERSCORE
 | 
				
			||||||
 | 
					        ' '     ,    //       0x20 -> SPACE
 | 
				
			||||||
 | 
					        '!'     ,    //  !    0x21 -> EXCLAMATION MARK
 | 
				
			||||||
 | 
					        '"'     ,    //  "    0x22 -> QUOTATION MARK
 | 
				
			||||||
 | 
					        '#'     ,    //  #    0x23 -> NUMBER SIGN
 | 
				
			||||||
 | 
					        '$'     ,    //  $    0x24 -> DOLLAR SIGN
 | 
				
			||||||
 | 
					        '%'     ,    //  %    0x25 -> PERCENT SIGN
 | 
				
			||||||
 | 
					        '&'     ,    //  &    0x26 -> AMPERSAND
 | 
				
			||||||
 | 
					        '\''    ,    //  '    0x27 -> APOSTROPHE
 | 
				
			||||||
 | 
					        '('     ,    //  (    0x28 -> LEFT PARENTHESIS
 | 
				
			||||||
 | 
					        ')'     ,    //  )    0x29 -> RIGHT PARENTHESIS
 | 
				
			||||||
 | 
					        '*'     ,    //  *    0x2A -> ASTERISK
 | 
				
			||||||
 | 
					        '+'     ,    //  +    0x2B -> PLUS SIGN
 | 
				
			||||||
 | 
					        ','     ,    //  ,    0x2C -> COMMA
 | 
				
			||||||
 | 
					        '-'     ,    //  -    0x2D -> HYPHEN-MINUS
 | 
				
			||||||
 | 
					        '.'     ,    //  .    0x2E -> FULL STOP
 | 
				
			||||||
 | 
					        '/'     ,    //  /    0x2F -> SOLIDUS
 | 
				
			||||||
 | 
					        '0'     ,    //  0    0x30 -> DIGIT ZERO
 | 
				
			||||||
 | 
					        '1'     ,    //  1    0x31 -> DIGIT ONE
 | 
				
			||||||
 | 
					        '2'     ,    //  2    0x32 -> DIGIT TWO
 | 
				
			||||||
 | 
					        '3'     ,    //  3    0x33 -> DIGIT THREE
 | 
				
			||||||
 | 
					        '4'     ,    //  4    0x34 -> DIGIT FOUR
 | 
				
			||||||
 | 
					        '5'     ,    //  5    0x35 -> DIGIT FIVE
 | 
				
			||||||
 | 
					        '6'     ,    //  6    0x36 -> DIGIT SIX
 | 
				
			||||||
 | 
					        '7'     ,    //  7    0x37 -> DIGIT SEVEN
 | 
				
			||||||
 | 
					        '8'     ,    //  8    0x38 -> DIGIT EIGHT
 | 
				
			||||||
 | 
					        '9'     ,    //  9    0x39 -> DIGIT NINE
 | 
				
			||||||
 | 
					        ':'     ,    //  :    0x3A -> COLON
 | 
				
			||||||
 | 
					        ';'     ,    //  ;    0x3B -> SEMICOLON
 | 
				
			||||||
 | 
					        '<'     ,    //  <    0x3C -> LESS-THAN SIGN
 | 
				
			||||||
 | 
					        '='     ,    //  =    0x3D -> EQUALS SIGN
 | 
				
			||||||
 | 
					        '>'     ,    //  >    0x3E -> GREATER-THAN SIGN
 | 
				
			||||||
 | 
					        '?'     ,    //  ?    0x3F -> QUESTION MARK
 | 
				
			||||||
 | 
					        '`'     ,    //  `    0x40 -> GRAVE ACCENT
 | 
				
			||||||
 | 
					        'A'     ,    //  A    0x41 -> LATIN CAPITAL LETTER A
 | 
				
			||||||
 | 
					        'B'     ,    //  B    0x42 -> LATIN CAPITAL LETTER B
 | 
				
			||||||
 | 
					        'C'     ,    //  C    0x43 -> LATIN CAPITAL LETTER C
 | 
				
			||||||
 | 
					        'D'     ,    //  D    0x44 -> LATIN CAPITAL LETTER D
 | 
				
			||||||
 | 
					        'E'     ,    //  E    0x45 -> LATIN CAPITAL LETTER E
 | 
				
			||||||
 | 
					        'F'     ,    //  F    0x46 -> LATIN CAPITAL LETTER F
 | 
				
			||||||
 | 
					        'G'     ,    //  G    0x47 -> LATIN CAPITAL LETTER G
 | 
				
			||||||
 | 
					        'H'     ,    //  H    0x48 -> LATIN CAPITAL LETTER H
 | 
				
			||||||
 | 
					        'I'     ,    //  I    0x49 -> LATIN CAPITAL LETTER I
 | 
				
			||||||
 | 
					        'J'     ,    //  J    0x4A -> LATIN CAPITAL LETTER J
 | 
				
			||||||
 | 
					        'K'     ,    //  K    0x4B -> LATIN CAPITAL LETTER K
 | 
				
			||||||
 | 
					        'L'     ,    //  L    0x4C -> LATIN CAPITAL LETTER L
 | 
				
			||||||
 | 
					        'M'     ,    //  M    0x4D -> LATIN CAPITAL LETTER M
 | 
				
			||||||
 | 
					        'N'     ,    //  N    0x4E -> LATIN CAPITAL LETTER N
 | 
				
			||||||
 | 
					        'O'     ,    //  O    0x4F -> LATIN CAPITAL LETTER O
 | 
				
			||||||
 | 
					        'P'     ,    //  P    0x50 -> LATIN CAPITAL LETTER P
 | 
				
			||||||
 | 
					        'Q'     ,    //  Q    0x51 -> LATIN CAPITAL LETTER Q
 | 
				
			||||||
 | 
					        'R'     ,    //  R    0x52 -> LATIN CAPITAL LETTER R
 | 
				
			||||||
 | 
					        'S'     ,    //  S    0x53 -> LATIN CAPITAL LETTER S
 | 
				
			||||||
 | 
					        'T'     ,    //  T    0x54 -> LATIN CAPITAL LETTER T
 | 
				
			||||||
 | 
					        'U'     ,    //  U    0x55 -> LATIN CAPITAL LETTER U
 | 
				
			||||||
 | 
					        'V'     ,    //  V    0x56 -> LATIN CAPITAL LETTER V
 | 
				
			||||||
 | 
					        'W'     ,    //  W    0x57 -> LATIN CAPITAL LETTER W
 | 
				
			||||||
 | 
					        'X'     ,    //  X    0x58 -> LATIN CAPITAL LETTER X
 | 
				
			||||||
 | 
					        'Y'     ,    //  Y    0x59 -> LATIN CAPITAL LETTER Y
 | 
				
			||||||
 | 
					        'Z'     ,    //  Z    0x5A -> LATIN CAPITAL LETTER Z
 | 
				
			||||||
 | 
					        '{'     ,    //  {    0x5B -> LEFT BRACE
 | 
				
			||||||
 | 
					        '|'     ,    //  |    0x5C -> VERTICAL BAR
 | 
				
			||||||
 | 
					        '}'     ,    //  }    0x5D -> RIGHT BRACE
 | 
				
			||||||
 | 
					        '~'     ,    //  ~    0x5E -> TILDE
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x5F -> RESERVED
 | 
				
			||||||
 | 
					        '\u00a0',    //       0x60 -> NO-BREAK SPACE (TRANSPARENT)
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x61 -> COMMODORE SYMBOL
 | 
				
			||||||
 | 
					        '\u2191',    //  ↑    0x62 -> UP ARROW
 | 
				
			||||||
 | 
					        '\u2193',    //  ↓    0x63 -> DOWN ARROW
 | 
				
			||||||
 | 
					        '\u2190',    //  ←    0x64 -> LEFT ARROW
 | 
				
			||||||
 | 
					        '\u2192',    //  →    0x65 -> RIGHT ARROW
 | 
				
			||||||
 | 
					        '\u231A',    //  ⌚   0x66 -> WATCH (ANALOG CLOCKFACE)
 | 
				
			||||||
 | 
					        '\u21BB',    //  ↻    0x67 -> CYCLE ARROWS
 | 
				
			||||||
 | 
					        '\u2026',    //  …    0x68 -> ELLIPSIS
 | 
				
			||||||
 | 
					        '\u25a7',    //  ▧    0x69 -> DIAGNONAL STRIPES
 | 
				
			||||||
 | 
					        '\u2610',    //  ☐    0x6A -> CHECKBOX UNCHECKED
 | 
				
			||||||
 | 
					        '\u2611',    //  ☑    0x6B -> CHECKBOX CHECKED
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x6C -> RADIO BUTTON UNSELECTED
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x6D -> RADIO BUTTON SELECTED
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x6E -> UTILITY CLOSE BUTTON
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x6F -> UTILITY TITLE BAR
 | 
				
			||||||
 | 
					        '\u00a9',    //  ©    0x70 -> COPYRIGHT
 | 
				
			||||||
 | 
					        '\u2713',    //  ✓    0x71 -> CHECKMARK
 | 
				
			||||||
 | 
					        '\u2261',    //  ≡    0x72 -> THREE HORIZONTAL STRIPES
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x73 -> TICK TRACK
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x74 -> TICK TRACK NUB
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x75 -> TAB CORNER
 | 
				
			||||||
 | 
					        '\u2980',    //  ⦀    0x76 -> THREE VERTICAL STRIPES
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x77 -> CUSTOM 1
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x78 -> CUSTOM 2
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x79 -> CUSTOM 3
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x7A -> CUSTOM 4
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x7B -> CUSTOM 5
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x7C -> CUSTOM 6
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x7D -> CUSTOM 7
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x7E -> CUSTOM 8
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x7F -> CUSTOM 9
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x80 -> REVERSED COMMERCIAL AT
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x81 -> REVERSED LATIN SMALL LETTER A
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x82 -> REVERSED LATIN SMALL LETTER B
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x83 -> REVERSED LATIN SMALL LETTER C
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x84 -> REVERSED LATIN SMALL LETTER D
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x85 -> REVERSED LATIN SMALL LETTER E
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x86 -> REVERSED LATIN SMALL LETTER F
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x87 -> REVERSED LATIN SMALL LETTER G
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x88 -> REVERSED LATIN SMALL LETTER H
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x89 -> REVERSED LATIN SMALL LETTER I
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x8A -> REVERSED LATIN SMALL LETTER J
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x8B -> REVERSED LATIN SMALL LETTER K
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x8C -> REVERSED LATIN SMALL LETTER L
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x8D -> REVERSED LATIN SMALL LETTER M
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x8E -> REVERSED LATIN SMALL LETTER N
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x8F -> REVERSED LATIN SMALL LETTER O
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x90 -> REVERSED LATIN SMALL LETTER P
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x91 -> REVERSED LATIN SMALL LETTER Q
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x92 -> REVERSED LATIN SMALL LETTER R
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x93 -> REVERSED LATIN SMALL LETTER S
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x94 -> REVERSED LATIN SMALL LETTER T
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x95 -> REVERSED LATIN SMALL LETTER U
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x96 -> REVERSED LATIN SMALL LETTER V
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x97 -> REVERSED LATIN SMALL LETTER W
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x98 -> REVERSED LATIN SMALL LETTER X
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x99 -> REVERSED LATIN SMALL LETTER Y
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x9A -> REVERSED LATIN SMALL LETTER Z
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x9B -> REVERSED LEFT SQUARE BRACKET
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x9C -> REVERSED REVERSE SOLIDUS
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x9D -> REVERSED RIGHT SQUARE BRACKET
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x9E -> REVERSED CIRCUMFLEX
 | 
				
			||||||
 | 
					        '\ufffe',    //       0x9F -> REVERSED UNDERSCORE
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xA0 -> REVERSED SPACE
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xA1 -> REVERSED EXCLAMATION MARK
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xA2 -> REVERSED QUOTATION MARK
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xA3 -> REVERSED NUMBER SIGN
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xA4 -> REVERSED DOLLAR SIGN
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xA5 -> REVERSED PERCENT SIGN
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xA6 -> REVERSED AMPERSAND
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xA7 -> REVERSED APOSTROPHE
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xA8 -> REVERSED LEFT PARENTHESIS
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xA9 -> REVERSED RIGHT PARENTHESIS
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xAA -> REVERSED ASTERISK
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xAB -> REVERSED PLUS SIGN
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xAC -> REVERSED COMMA
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xAD -> REVERSED HYPHEN-MINUS
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xAE -> REVERSED FULL STOP
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xAF -> REVERSED SOLIDUS
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xB0 -> REVERSED DIGIT ZERO
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xB1 -> REVERSED DIGIT ONE
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xB2 -> REVERSED DIGIT TWO
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xB3 -> REVERSED DIGIT THREE
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xB4 -> REVERSED DIGIT FOUR
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xB5 -> REVERSED DIGIT FIVE
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xB6 -> REVERSED DIGIT SIX
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xB7 -> REVERSED DIGIT SEVEN
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xB8 -> REVERSED DIGIT EIGHT
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xB9 -> REVERSED DIGIT NINE
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xBA -> REVERSED COLON
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xBB -> REVERSED SEMICOLON
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xBC -> REVERSED LESS-THAN SIGN
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xBD -> REVERSED EQUALS SIGN
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xBE -> REVERSED GREATER-THAN SIGN
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xBF -> REVERSED QUESTION MARK
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xC0 -> REVERSED GRAVE ACCENT
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xC1 -> REVERSED LATIN CAPITAL LETTER A
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xC2 -> REVERSED LATIN CAPITAL LETTER B
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xC3 -> REVERSED LATIN CAPITAL LETTER C
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xC4 -> REVERSED LATIN CAPITAL LETTER D
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xC5 -> REVERSED LATIN CAPITAL LETTER E
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xC6 -> REVERSED LATIN CAPITAL LETTER F
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xC7 -> REVERSED LATIN CAPITAL LETTER G
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xC8 -> REVERSED LATIN CAPITAL LETTER H
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xC9 -> REVERSED LATIN CAPITAL LETTER I
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xCA -> REVERSED LATIN CAPITAL LETTER J
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xCB -> REVERSED LATIN CAPITAL LETTER K
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xCC -> REVERSED LATIN CAPITAL LETTER L
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xCD -> REVERSED LATIN CAPITAL LETTER M
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xCE -> REVERSED LATIN CAPITAL LETTER N
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xCF -> REVERSED LATIN CAPITAL LETTER O
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xD0 -> REVERSED LATIN CAPITAL LETTER P
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xD1 -> REVERSED LATIN CAPITAL LETTER Q
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xD2 -> REVERSED LATIN CAPITAL LETTER R
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xD3 -> REVERSED LATIN CAPITAL LETTER S
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xD4 -> REVERSED LATIN CAPITAL LETTER T
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xD5 -> REVERSED LATIN CAPITAL LETTER U
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xD6 -> REVERSED LATIN CAPITAL LETTER V
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xD7 -> REVERSED LATIN CAPITAL LETTER W
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xD8 -> REVERSED LATIN CAPITAL LETTER X
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xD9 -> REVERSED LATIN CAPITAL LETTER Y
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xDA -> REVERSED LATIN CAPITAL LETTER Z
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xDB -> REVERSED LEFT BRACE
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xDC -> REVERSED VERTICAL BAR
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xDD -> REVERSED RIGHT BRACE
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xDE -> REVERSED TILDE
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xDF -> RESERVED
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xE0 -> RESERVED
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xE1 -> REVERSED COMMODORE SYMBOL
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xE2 -> REVERSED UP ARROW
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xE3 -> REVERSED DOWN ARROW
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xE4 -> REVERSED LEFT ARROW
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xE5 -> REVERSED RIGHT ARROW
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xE6 -> REVERSED ANALOG CLOCKFACE
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xE7 -> REVERSED CYCLE ARROWS
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xE8 -> REVERSED ELLIPSIS
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xE9 -> REVERSED DIAGONAL STRIPES
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xEA -> REVERSED CHECKBOX UNCHECKED
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xEB -> REVERSED CHECKBOX CHECKED
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xEC -> REVERSED RADIO BUTTON UNSELECTED
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xED -> REVERSED RADIO BUTTON SELECTED
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xEE -> MEMORY CHIP ICON
 | 
				
			||||||
 | 
					        '\u21e7',    //  ⇧    0xEF -> SHIFT SYMBOL
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xF0 -> REVERSED COPYRIGHT SYMBOL
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xF1 -> REVERSED CHECKMARK
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xF2 -> REVERSED THREE HORIZONTAL STRIPES
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xF3 -> REVERSED TICK TRACK
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xF4 -> REVERSED TICK TRACK NUB
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xF5 -> REVERSED TAB CORNER
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xF6 -> REVERSED THREE VERTICAL STRIPES
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xF7 -> CUSTOM 10
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xF8 -> CUSTOM 11
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xF9 -> CUSTOM 12
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xFA -> CUSTOM 13
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xFB -> CUSTOM 14
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xFC -> CUSTOM 15
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xFD -> CUSTOM 16
 | 
				
			||||||
 | 
					        '\ufffe',    //       0xFE -> CUSTOM 17
 | 
				
			||||||
 | 
					        '\ufffe'     //       0xFF -> CUSTOM 18
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // encoding:  from unicode to C64 OS Screencodes (0-255)
 | 
				
			||||||
 | 
					    private val encodingC64os = decodingC64os.withIndex().associate{it.value to it.index}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun replaceSpecial(chr: Char): Char =
 | 
				
			||||||
 | 
					        when(chr) {
 | 
				
			||||||
 | 
					            '\r' -> '\n'        // to make \r (carriage returrn) equivalent to \n (line feed): RETURN ($0d)
 | 
				
			||||||
 | 
					            else -> chr
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    fun encode(text: String, lowercase: Boolean = false): Result<List<UByte>, CharConversionException> {
 | 
				
			||||||
 | 
					        fun encodeChar(chr3: Char, lowercase: Boolean): UByte {
 | 
				
			||||||
 | 
					            val chr = replaceSpecial(chr3)
 | 
				
			||||||
 | 
					            val screencode = encodingC64os[chr]
 | 
				
			||||||
 | 
					            return screencode?.toUByte() ?: when (chr) {
 | 
				
			||||||
 | 
					                '\u0000' -> 0u
 | 
				
			||||||
 | 
					                '\n' -> 13u
 | 
				
			||||||
 | 
					                in '\u8000'..'\u80ff' -> {
 | 
				
			||||||
 | 
					                    // special case: take the lower 8 bit hex value directly
 | 
				
			||||||
 | 
					                    (chr.code - 0x8000).toUByte()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else -> {
 | 
				
			||||||
 | 
					                    if(chr.isISOControl())
 | 
				
			||||||
 | 
					                        throw CharConversionException("no c64os character for char #${chr.code}")
 | 
				
			||||||
 | 
					                    else
 | 
				
			||||||
 | 
					                        throw CharConversionException("no c64os character for char #${chr.code} '${chr}'")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return try {
 | 
				
			||||||
 | 
					            Ok(text.map {
 | 
				
			||||||
 | 
					                try {
 | 
				
			||||||
 | 
					                    encodeChar(it, lowercase)
 | 
				
			||||||
 | 
					                } catch (x: CharConversionException) {
 | 
				
			||||||
 | 
					                    encodeChar(it, !lowercase)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        } catch(cx: CharConversionException) {
 | 
				
			||||||
 | 
					            Err(cx)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fun decode(screencode: Iterable<UByte>, lowercase: Boolean = false): Result<String, CharConversionException> {
 | 
				
			||||||
 | 
					        return try {
 | 
				
			||||||
 | 
					            Ok(screencode.map {
 | 
				
			||||||
 | 
					                val code = it.toInt()
 | 
				
			||||||
 | 
					                if(code<0 || code>= decodingC64os.size)
 | 
				
			||||||
 | 
					                    throw CharConversionException("c64os $code out of range 0..${decodingC64os.size-1}")
 | 
				
			||||||
 | 
					                decodingC64os[code]
 | 
				
			||||||
 | 
					            }.joinToString(""))
 | 
				
			||||||
 | 
					        } catch(ce: CharConversionException) {
 | 
				
			||||||
 | 
					            Err(ce)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,25 +1,24 @@
 | 
				
			|||||||
package prog8.code.target
 | 
					package prog8.code.target.encodings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import com.github.michaelbull.result.fold
 | 
					import com.github.michaelbull.result.fold
 | 
				
			||||||
import prog8.code.core.Encoding
 | 
					import prog8.code.core.Encoding
 | 
				
			||||||
import prog8.code.core.IStringEncoding
 | 
					import prog8.code.core.IStringEncoding
 | 
				
			||||||
import prog8.code.core.InternalCompilerException
 | 
					import prog8.code.core.InternalCompilerException
 | 
				
			||||||
import prog8.code.target.encodings.*
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Encoder(val newlineToCarriageReturn: Boolean): IStringEncoding {
 | 
				
			||||||
object Encoder: IStringEncoding {
 | 
					 | 
				
			||||||
    override val defaultEncoding: Encoding = Encoding.ISO
 | 
					    override val defaultEncoding: Encoding = Encoding.ISO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun encodeString(str: String, encoding: Encoding): List<UByte> {
 | 
					    override fun encodeString(str: String, encoding: Encoding): List<UByte> {
 | 
				
			||||||
        val coded = when(encoding) {
 | 
					        val coded = when(encoding) {
 | 
				
			||||||
            Encoding.PETSCII -> PetsciiEncoding.encodePetscii(str, true)
 | 
					            Encoding.PETSCII -> PetsciiEncoding.encodePetscii(str, true)
 | 
				
			||||||
            Encoding.SCREENCODES -> PetsciiEncoding.encodeScreencode(str, true)
 | 
					            Encoding.SCREENCODES -> PetsciiEncoding.encodeScreencode(str, true)
 | 
				
			||||||
            Encoding.ISO -> IsoEncoding.encode(str)
 | 
					            Encoding.ISO -> IsoEncoding.encode(str, newlineToCarriageReturn)
 | 
				
			||||||
            Encoding.ATASCII -> AtasciiEncoding.encode(str)
 | 
					            Encoding.ISO5 -> IsoCyrillicEncoding.encode(str, newlineToCarriageReturn)
 | 
				
			||||||
            Encoding.ISO5 -> IsoCyrillicEncoding.encode(str)
 | 
					            Encoding.ISO16 -> IsoEasternEncoding.encode(str, newlineToCarriageReturn)
 | 
				
			||||||
            Encoding.ISO16 -> IsoEasternEncoding.encode(str)
 | 
					 | 
				
			||||||
            Encoding.CP437 -> Cp437Encoding.encode(str)
 | 
					            Encoding.CP437 -> Cp437Encoding.encode(str)
 | 
				
			||||||
            Encoding.KATAKANA -> KatakanaEncoding.encode(str)
 | 
					            Encoding.KATAKANA -> KatakanaEncoding.encode(str, newlineToCarriageReturn)
 | 
				
			||||||
 | 
					            Encoding.ATASCII -> AtasciiEncoding.encode(str)
 | 
				
			||||||
 | 
					            Encoding.C64OS -> C64osEncoding.encode(str)
 | 
				
			||||||
            else -> throw InternalCompilerException("unsupported encoding $encoding")
 | 
					            else -> throw InternalCompilerException("unsupported encoding $encoding")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return coded.fold(
 | 
					        return coded.fold(
 | 
				
			||||||
@@ -31,12 +30,13 @@ object Encoder: IStringEncoding {
 | 
				
			|||||||
        val decoded = when(encoding) {
 | 
					        val decoded = when(encoding) {
 | 
				
			||||||
            Encoding.PETSCII -> PetsciiEncoding.decodePetscii(bytes, true)
 | 
					            Encoding.PETSCII -> PetsciiEncoding.decodePetscii(bytes, true)
 | 
				
			||||||
            Encoding.SCREENCODES -> PetsciiEncoding.decodeScreencode(bytes, true)
 | 
					            Encoding.SCREENCODES -> PetsciiEncoding.decodeScreencode(bytes, true)
 | 
				
			||||||
            Encoding.ISO -> IsoEncoding.decode(bytes)
 | 
					            Encoding.ISO -> IsoEncoding.decode(bytes, newlineToCarriageReturn)
 | 
				
			||||||
            Encoding.ATASCII -> AtasciiEncoding.decode(bytes)
 | 
					            Encoding.ISO5 -> IsoCyrillicEncoding.decode(bytes, newlineToCarriageReturn)
 | 
				
			||||||
            Encoding.ISO5 -> IsoCyrillicEncoding.decode(bytes)
 | 
					            Encoding.ISO16 -> IsoEasternEncoding.decode(bytes, newlineToCarriageReturn)
 | 
				
			||||||
            Encoding.ISO16 -> IsoEasternEncoding.decode(bytes)
 | 
					 | 
				
			||||||
            Encoding.CP437 -> Cp437Encoding.decode(bytes)
 | 
					            Encoding.CP437 -> Cp437Encoding.decode(bytes)
 | 
				
			||||||
            Encoding.KATAKANA -> KatakanaEncoding.decode(bytes)
 | 
					            Encoding.KATAKANA -> KatakanaEncoding.decode(bytes, newlineToCarriageReturn)
 | 
				
			||||||
 | 
					            Encoding.ATASCII -> AtasciiEncoding.decode(bytes)
 | 
				
			||||||
 | 
					            Encoding.C64OS -> C64osEncoding.decode(bytes)
 | 
				
			||||||
            else -> throw InternalCompilerException("unsupported encoding $encoding")
 | 
					            else -> throw InternalCompilerException("unsupported encoding $encoding")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return decoded.fold(
 | 
					        return decoded.fold(
 | 
				
			||||||
@@ -6,14 +6,16 @@ import com.github.michaelbull.result.Result
 | 
				
			|||||||
import java.io.CharConversionException
 | 
					import java.io.CharConversionException
 | 
				
			||||||
import java.nio.charset.Charset
 | 
					import java.nio.charset.Charset
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
open class IsoEncodingBase(charsetName: String) {
 | 
					open class IsoEncodingBase(charsetName: String) {
 | 
				
			||||||
    val charset: Charset = Charset.forName(charsetName)
 | 
					    val charset: Charset = Charset.forName(charsetName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun encode(str: String): Result<List<UByte>, CharConversionException> {
 | 
					    fun encode(str: String, newlineToCarriageReturn: Boolean): Result<List<UByte>, CharConversionException> {
 | 
				
			||||||
        return try {
 | 
					        return try {
 | 
				
			||||||
            val mapped = str.map { chr ->
 | 
					            val mapped = str.map { chr ->
 | 
				
			||||||
                when (chr) {
 | 
					                when (chr) {
 | 
				
			||||||
                    '\u0000' -> 0u
 | 
					                    '\u0000' -> 0u
 | 
				
			||||||
 | 
					                    '\n' -> if(newlineToCarriageReturn) 13u else 10u
 | 
				
			||||||
                    in '\u8000'..'\u80ff' -> {
 | 
					                    in '\u8000'..'\u80ff' -> {
 | 
				
			||||||
                        // special case: take the lower 8 bit hex value directly
 | 
					                        // special case: take the lower 8 bit hex value directly
 | 
				
			||||||
                        (chr.code - 0x8000).toUByte()
 | 
					                        (chr.code - 0x8000).toUByte()
 | 
				
			||||||
@@ -27,9 +29,14 @@ open class IsoEncodingBase(charsetName: String) {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun decode(bytes: Iterable<UByte>): Result<String, CharConversionException> {
 | 
					    fun decode(bytes: Iterable<UByte>, newlineToCarriageReturn: Boolean): Result<String, CharConversionException> {
 | 
				
			||||||
        return try {
 | 
					        return try {
 | 
				
			||||||
            Ok(String(bytes.map { it.toByte() }.toByteArray(), charset))
 | 
					            Ok(String(bytes.map {
 | 
				
			||||||
 | 
					                when(it) {
 | 
				
			||||||
 | 
					                    13u.toUByte() -> if(newlineToCarriageReturn) 10 else 13
 | 
				
			||||||
 | 
					                    else -> it.toByte()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }.toByteArray(), charset))
 | 
				
			||||||
        } catch (ce: CharConversionException) {
 | 
					        } catch (ce: CharConversionException) {
 | 
				
			||||||
            Err(ce)
 | 
					            Err(ce)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -64,10 +64,11 @@ object JapaneseCharacterConverter {
 | 
				
			|||||||
object KatakanaEncoding {
 | 
					object KatakanaEncoding {
 | 
				
			||||||
    val charset: Charset = Charset.forName("JIS_X0201")
 | 
					    val charset: Charset = Charset.forName("JIS_X0201")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun encode(str: String): Result<List<UByte>, CharConversionException> {
 | 
					    fun encode(str: String, newlineToCarriageReturn: Boolean): Result<List<UByte>, CharConversionException> {
 | 
				
			||||||
        return try {
 | 
					        return try {
 | 
				
			||||||
            val mapped = str.map { chr ->
 | 
					            val mapped = str.map { chr ->
 | 
				
			||||||
                when (chr) {
 | 
					                when (chr) {
 | 
				
			||||||
 | 
					                    '\n' -> if(newlineToCarriageReturn) 13u else 10u
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    '\u0000' -> 0u
 | 
					                    '\u0000' -> 0u
 | 
				
			||||||
                    '\u00a0' -> 0xa0u // $a0 isn't technically a part of JIS X 0201 spec, and so we need to handle this ourselves
 | 
					                    '\u00a0' -> 0xa0u // $a0 isn't technically a part of JIS X 0201 spec, and so we need to handle this ourselves
 | 
				
			||||||
@@ -112,9 +113,14 @@ object KatakanaEncoding {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun decode(bytes: Iterable<UByte>): Result<String, CharConversionException> {
 | 
					    fun decode(bytes: Iterable<UByte>, newlineToCarriageReturn: Boolean): Result<String, CharConversionException> {
 | 
				
			||||||
        return try {
 | 
					        return try {
 | 
				
			||||||
            Ok(String(bytes.map { it.toByte() }.toByteArray(), charset))
 | 
					            Ok(String(bytes.map {
 | 
				
			||||||
 | 
					                when(it) {
 | 
				
			||||||
 | 
					                    13u.toUByte() -> if(newlineToCarriageReturn) 10 else 13
 | 
				
			||||||
 | 
					                    else -> it.toByte()
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }.toByteArray(), charset))
 | 
				
			||||||
        } catch (ce: CharConversionException) {
 | 
					        } catch (ce: CharConversionException) {
 | 
				
			||||||
            Err(ce)
 | 
					            Err(ce)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ import java.io.CharConversionException
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
object PetsciiEncoding {
 | 
					object PetsciiEncoding {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // decoding:  from Petscii/Screencodes (0-255) to unicode
 | 
					    // decoding:  from Petscii/Screencodes (0-255) to Unicode
 | 
				
			||||||
    // character tables used from https://github.com/irmen/cbmcodecs2
 | 
					    // character tables used from https://github.com/irmen/cbmcodecs2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private val decodingPetsciiLowercase = charArrayOf(
 | 
					    private val decodingPetsciiLowercase = charArrayOf(
 | 
				
			||||||
@@ -21,7 +21,7 @@ object PetsciiEncoding {
 | 
				
			|||||||
        '\ufffe',    //       0x07 -> UNDEFINED
 | 
					        '\ufffe',    //       0x07 -> UNDEFINED
 | 
				
			||||||
        '\uf118',    //       0x08 -> DISABLE CHARACTER SET SWITCHING (CUS)
 | 
					        '\uf118',    //       0x08 -> DISABLE CHARACTER SET SWITCHING (CUS)
 | 
				
			||||||
        '\uf119',    //       0x09 -> ENABLE CHARACTER SET SWITCHING (CUS)
 | 
					        '\uf119',    //       0x09 -> ENABLE CHARACTER SET SWITCHING (CUS)
 | 
				
			||||||
        '\ufffe',    //       0x0A -> UNDEFINED
 | 
					        '\n',        //       0x0A -> LINE FEED (RETURN)
 | 
				
			||||||
        '\ufffe',    //       0x0B -> UNDEFINED
 | 
					        '\ufffe',    //       0x0B -> UNDEFINED
 | 
				
			||||||
        '\ufffe',    //       0x0C -> UNDEFINED
 | 
					        '\ufffe',    //       0x0C -> UNDEFINED
 | 
				
			||||||
        '\n'    ,    //       0x0D -> LINE FEED (RETURN)
 | 
					        '\n'    ,    //       0x0D -> LINE FEED (RETURN)
 | 
				
			||||||
@@ -1089,7 +1089,7 @@ object PetsciiEncoding {
 | 
				
			|||||||
            Ok(text.map {
 | 
					            Ok(text.map {
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    encodeChar(it, lowercase)
 | 
					                    encodeChar(it, lowercase)
 | 
				
			||||||
                } catch (x: CharConversionException) {
 | 
					                } catch (_: CharConversionException) {
 | 
				
			||||||
                    encodeChar(it, !lowercase)
 | 
					                    encodeChar(it, !lowercase)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
@@ -1117,6 +1117,8 @@ object PetsciiEncoding {
 | 
				
			|||||||
            val screencode = if(lowercase) encodingScreencodeLowercase[chr] else encodingScreencodeUppercase[chr]
 | 
					            val screencode = if(lowercase) encodingScreencodeLowercase[chr] else encodingScreencodeUppercase[chr]
 | 
				
			||||||
            return screencode?.toUByte() ?: when (chr) {
 | 
					            return screencode?.toUByte() ?: when (chr) {
 | 
				
			||||||
                '\u0000' -> 0u
 | 
					                '\u0000' -> 0u
 | 
				
			||||||
 | 
					                '\n' -> 141u
 | 
				
			||||||
 | 
					                '\r' -> 141u
 | 
				
			||||||
                in '\u8000'..'\u80ff' -> {
 | 
					                in '\u8000'..'\u80ff' -> {
 | 
				
			||||||
                    // special case: take the lower 8 bit hex value directly
 | 
					                    // special case: take the lower 8 bit hex value directly
 | 
				
			||||||
                    (chr.code - 0x8000).toUByte()
 | 
					                    (chr.code - 0x8000).toUByte()
 | 
				
			||||||
@@ -1135,7 +1137,7 @@ object PetsciiEncoding {
 | 
				
			|||||||
            Ok(text.map {
 | 
					            Ok(text.map {
 | 
				
			||||||
                try {
 | 
					                try {
 | 
				
			||||||
                    encodeChar(it, lowercase)
 | 
					                    encodeChar(it, lowercase)
 | 
				
			||||||
                } catch (x: CharConversionException) {
 | 
					                } catch (_: CharConversionException) {
 | 
				
			||||||
                    encodeChar(it, !lowercase)
 | 
					                    encodeChar(it, !lowercase)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            })
 | 
					            })
 | 
				
			||||||
@@ -1157,16 +1159,16 @@ object PetsciiEncoding {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fun petscii2scr(petscii_code: UByte, inverseVideo: Boolean): Result<UByte, CharConversionException> {
 | 
					    fun petscii2scr(petsciicode: UByte, inverseVideo: Boolean): Result<UByte, CharConversionException> {
 | 
				
			||||||
        val code: UInt = when {
 | 
					        val code: UInt = when {
 | 
				
			||||||
            petscii_code <= 0x1fu -> petscii_code + 128u
 | 
					            petsciicode <= 0x1fu -> petsciicode + 128u
 | 
				
			||||||
            petscii_code <= 0x3fu -> petscii_code.toUInt()
 | 
					            petsciicode <= 0x3fu -> petsciicode.toUInt()
 | 
				
			||||||
            petscii_code <= 0x5fu -> petscii_code - 64u
 | 
					            petsciicode <= 0x5fu -> petsciicode - 64u
 | 
				
			||||||
            petscii_code <= 0x7fu -> petscii_code - 32u
 | 
					            petsciicode <= 0x7fu -> petsciicode - 32u
 | 
				
			||||||
            petscii_code <= 0x9fu -> petscii_code + 64u
 | 
					            petsciicode <= 0x9fu -> petsciicode + 64u
 | 
				
			||||||
            petscii_code <= 0xbfu -> petscii_code - 64u
 | 
					            petsciicode <= 0xbfu -> petsciicode - 64u
 | 
				
			||||||
            petscii_code <= 0xfeu -> petscii_code - 128u
 | 
					            petsciicode <= 0xfeu -> petsciicode - 128u
 | 
				
			||||||
            petscii_code == 255.toUByte() -> 95u
 | 
					            petsciicode == 255.toUByte() -> 95u
 | 
				
			||||||
            else -> return Err(CharConversionException("petscii code out of range"))
 | 
					            else -> return Err(CharConversionException("petscii code out of range"))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if(inverseVideo) {
 | 
					        if(inverseVideo) {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,61 +0,0 @@
 | 
				
			|||||||
package prog8.code.target.pet
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import prog8.code.core.*
 | 
					 | 
				
			||||||
import prog8.code.target.C64Target
 | 
					 | 
				
			||||||
import prog8.code.target.cbm.Mflpt5
 | 
					 | 
				
			||||||
import java.nio.file.Path
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class PETMachineDefinition: IMachineDefinition {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val cpu = CpuType.CPU6502
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val FLOAT_MAX_POSITIVE = Mflpt5.FLOAT_MAX_POSITIVE
 | 
					 | 
				
			||||||
    override val FLOAT_MAX_NEGATIVE = Mflpt5.FLOAT_MAX_NEGATIVE
 | 
					 | 
				
			||||||
    override val FLOAT_MEM_SIZE = Mflpt5.FLOAT_MEM_SIZE
 | 
					 | 
				
			||||||
    override val PROGRAM_LOAD_ADDRESS = 0x0401u
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val BSSHIGHRAM_START = 0u
 | 
					 | 
				
			||||||
    override val BSSHIGHRAM_END = 0u
 | 
					 | 
				
			||||||
    override val BSSGOLDENRAM_START = 0u
 | 
					 | 
				
			||||||
    override val BSSGOLDENRAM_END = 0u
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override lateinit var zeropage: Zeropage
 | 
					 | 
				
			||||||
    override lateinit var golden: GoldenRam
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun getFloatAsmBytes(num: Number) = Mflpt5.fromNumber(num).makeFloatFillAsm()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun convertFloatToBytes(num: Double): List<UByte> {
 | 
					 | 
				
			||||||
        val m5 = Mflpt5.fromNumber(num)
 | 
					 | 
				
			||||||
        return listOf(m5.b0, m5.b1, m5.b2, m5.b3, m5.b4)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun convertBytesToFloat(bytes: List<UByte>): Double {
 | 
					 | 
				
			||||||
        require(bytes.size==5) { "need 5 bytes" }
 | 
					 | 
				
			||||||
        val m5 = Mflpt5(bytes[0], bytes[1], bytes[2], bytes[3], bytes[4])
 | 
					 | 
				
			||||||
        return m5.toDouble()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
 | 
					 | 
				
			||||||
        if(selectedEmulator!=1) {
 | 
					 | 
				
			||||||
            System.err.println("The pet target only supports the main emulator (Vice).")
 | 
					 | 
				
			||||||
            return
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        println("\nStarting PET emulator...")
 | 
					 | 
				
			||||||
        val viceMonlist = C64Target.viceMonListName(programNameWithPath.toString())
 | 
					 | 
				
			||||||
        val cmdline = listOf("xpet", "-model", "4032", "-ramsize", "32", "-videosize", "40", "-silent", "-moncommands", viceMonlist,
 | 
					 | 
				
			||||||
                "-autostartprgmode", "1", "-autostart-warp", "-autostart", "${programNameWithPath}.prg")
 | 
					 | 
				
			||||||
        val processb = ProcessBuilder(cmdline).inheritIO()
 | 
					 | 
				
			||||||
        val process=processb.start()
 | 
					 | 
				
			||||||
        process.waitFor()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun isIOAddress(address: UInt): Boolean = address in 0xe800u..0xe8ffu
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
 | 
					 | 
				
			||||||
        zeropage = PETZeropage(compilerOptions)
 | 
					 | 
				
			||||||
        // there's no golden ram.
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,91 +0,0 @@
 | 
				
			|||||||
package prog8.code.target.virtual
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import prog8.code.core.*
 | 
					 | 
				
			||||||
import java.nio.file.Path
 | 
					 | 
				
			||||||
import kotlin.io.path.isReadable
 | 
					 | 
				
			||||||
import kotlin.io.path.name
 | 
					 | 
				
			||||||
import kotlin.io.path.readText
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
class VirtualMachineDefinition: IMachineDefinition {
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val cpu = CpuType.VIRTUAL
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val FLOAT_MAX_POSITIVE = Float.MAX_VALUE.toDouble()
 | 
					 | 
				
			||||||
    override val FLOAT_MAX_NEGATIVE = -Float.MAX_VALUE.toDouble()
 | 
					 | 
				
			||||||
    override val FLOAT_MEM_SIZE = 8             // 64-bits double
 | 
					 | 
				
			||||||
    override val PROGRAM_LOAD_ADDRESS = 0u      // not actually used
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override val BSSHIGHRAM_START = 0u          // not actually used
 | 
					 | 
				
			||||||
    override val BSSHIGHRAM_END = 0u            // not actually used
 | 
					 | 
				
			||||||
    override val BSSGOLDENRAM_START = 0u        // not actually used
 | 
					 | 
				
			||||||
    override val BSSGOLDENRAM_END = 0u          // not actually used
 | 
					 | 
				
			||||||
    override lateinit var zeropage: Zeropage    // not actually used
 | 
					 | 
				
			||||||
    override lateinit var golden: GoldenRam     // not actually used
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun getFloatAsmBytes(num: Number): String {
 | 
					 | 
				
			||||||
        // little endian binary representation
 | 
					 | 
				
			||||||
        val bits = num.toDouble().toBits().toULong()
 | 
					 | 
				
			||||||
        val hexStr = bits.toString(16).padStart(16, '0')
 | 
					 | 
				
			||||||
        val parts = hexStr.chunked(2).map { "\$" + it }
 | 
					 | 
				
			||||||
        return parts.joinToString(", ")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun convertFloatToBytes(num: Double): List<UByte> {
 | 
					 | 
				
			||||||
        val bits = num.toBits().toULong()
 | 
					 | 
				
			||||||
        val hexStr = bits.toString(16).padStart(16, '0')
 | 
					 | 
				
			||||||
        val parts = hexStr.chunked(2).map { it.toInt(16).toUByte() }
 | 
					 | 
				
			||||||
        return parts
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun convertBytesToFloat(bytes: List<UByte>): Double {
 | 
					 | 
				
			||||||
        require(bytes.size==8) { "need 8 bytes" }
 | 
					 | 
				
			||||||
        val b0 = bytes[0].toLong() shl (8*7)
 | 
					 | 
				
			||||||
        val b1 = bytes[1].toLong() shl (8*6)
 | 
					 | 
				
			||||||
        val b2 = bytes[2].toLong() shl (8*5)
 | 
					 | 
				
			||||||
        val b3 = bytes[3].toLong() shl (8*4)
 | 
					 | 
				
			||||||
        val b4 = bytes[4].toLong() shl (8*3)
 | 
					 | 
				
			||||||
        val b5 = bytes[5].toLong() shl (8*2)
 | 
					 | 
				
			||||||
        val b6 = bytes[6].toLong() shl (8*1)
 | 
					 | 
				
			||||||
        val b7 = bytes[7].toLong() shl (8*0)
 | 
					 | 
				
			||||||
        return Double.fromBits(b0 or b1 or b2 or b3 or b4 or b5 or b6 or b7)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun launchEmulator(selectedEmulator: Int, programNameWithPath: Path) {
 | 
					 | 
				
			||||||
        println("\nStarting Virtual Machine...")
 | 
					 | 
				
			||||||
        // to not have external module dependencies in our own module, we launch the virtual machine via reflection
 | 
					 | 
				
			||||||
        val vm = Class.forName("prog8.vm.VmRunner").getDeclaredConstructor().newInstance() as IVirtualMachineRunner
 | 
					 | 
				
			||||||
        val filename = programNameWithPath.name
 | 
					 | 
				
			||||||
        if(programNameWithPath.isReadable()) {
 | 
					 | 
				
			||||||
            vm.runProgram(programNameWithPath.readText())
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            val withExt = programNameWithPath.resolveSibling("$filename.p8ir")
 | 
					 | 
				
			||||||
            if(withExt.isReadable())
 | 
					 | 
				
			||||||
                vm.runProgram(withExt.readText())
 | 
					 | 
				
			||||||
            else
 | 
					 | 
				
			||||||
                throw NoSuchFileException(withExt.toFile(), reason="not a .p8ir file")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun isIOAddress(address: UInt): Boolean = false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun initializeMemoryAreas(compilerOptions: CompilationOptions) {
 | 
					 | 
				
			||||||
        zeropage = VirtualZeropage(compilerOptions)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
interface IVirtualMachineRunner {
 | 
					 | 
				
			||||||
    fun runProgram(irSource: String)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
private class VirtualZeropage(options: CompilationOptions): Zeropage(options) {
 | 
					 | 
				
			||||||
    override val SCRATCH_B1: UInt
 | 
					 | 
				
			||||||
        get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
 | 
					 | 
				
			||||||
    override val SCRATCH_REG: UInt
 | 
					 | 
				
			||||||
        get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
 | 
					 | 
				
			||||||
    override val SCRATCH_W1: UInt
 | 
					 | 
				
			||||||
        get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
 | 
					 | 
				
			||||||
    override val SCRATCH_W2: UInt
 | 
					 | 
				
			||||||
        get() = throw IllegalStateException("virtual shouldn't use this zeropage variable")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun allocateCx16VirtualRegisters() { /* there is no actual zero page in this target to allocate thing in */ }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package prog8.code.target.c128
 | 
					package prog8.code.target.zp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prog8.code.core.CompilationOptions
 | 
					import prog8.code.core.CompilationOptions
 | 
				
			||||||
import prog8.code.core.InternalCompilerException
 | 
					import prog8.code.core.InternalCompilerException
 | 
				
			||||||
@@ -6,22 +6,17 @@ import prog8.code.core.Zeropage
 | 
				
			|||||||
import prog8.code.core.ZeropageType
 | 
					import prog8.code.core.ZeropageType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// reference: "Mapping the C128" zero page chapter.
 | 
					// reference: "Mapping the C128" zeropage chapter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class C128Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
					class C128Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override val SCRATCH_B1 = 0x74u      // temp storage for a single byte
 | 
					    override val SCRATCH_B1 = 0x74u      // temp storage for a single byte
 | 
				
			||||||
    override val SCRATCH_REG = 0x75u     // temp storage for a register, must be B1+1
 | 
					    override val SCRATCH_REG = 0x75u     // temp storage for a register byte, must be B1+1
 | 
				
			||||||
    override val SCRATCH_W1 = 0xfbu      // temp storage 1 for a word  $fb+$fc
 | 
					    override val SCRATCH_W1 = 0xfbu      // temp storage 1 for a word  $fb+$fc
 | 
				
			||||||
    override val SCRATCH_W2 = 0xfdu      // temp storage 2 for a word  $fd+$fe
 | 
					    override val SCRATCH_W2 = 0xfdu      // temp storage 2 for a word  $fd+$fe
 | 
				
			||||||
 | 
					    override val SCRATCH_PTR = 0x0bu     // temp storage for a pointer $0b+$0c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
        if (options.floats) {
 | 
					 | 
				
			||||||
            throw InternalCompilerException("C128 target doesn't yet support floating point routines")
 | 
					 | 
				
			||||||
            // note: in git commit labeled 'c128: remove floats module' the floats.p8 and floats.asm files are removed,
 | 
					 | 
				
			||||||
            //       they could be retrieved again at a later time if the compiler somehow *does* store the fp variables in bank1.
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (options.floats && options.zeropage !in arrayOf(
 | 
					        if (options.floats && options.zeropage !in arrayOf(
 | 
				
			||||||
                ZeropageType.FLOATSAFE,
 | 
					                ZeropageType.FLOATSAFE,
 | 
				
			||||||
                ZeropageType.BASICSAFE,
 | 
					                ZeropageType.BASICSAFE,
 | 
				
			||||||
@@ -33,18 +28,18 @@ class C128Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			|||||||
            ZeropageType.FULL -> {
 | 
					            ZeropageType.FULL -> {
 | 
				
			||||||
                // $00/$01 are data port IO registers, // $02-$09 are storage locations for JSRFAR and such
 | 
					                // $00/$01 are data port IO registers, // $02-$09 are storage locations for JSRFAR and such
 | 
				
			||||||
                free.addAll(0x0au..0xffu)
 | 
					                free.addAll(0x0au..0xffu)
 | 
				
			||||||
                free.removeAll(listOf(0x90u, 0x91u, 0xa0u, 0xa1u, 0xa2u, 0xc0u, 0xccu, 0xcdu, 0xd0u, 0xd1u, 0xd2u, 0xd3u, 0xd4u, 0xd5u, 0xf7u))        // these are updated/used by IRQ
 | 
					                free.removeAll(arrayOf(0x90u, 0x91u, 0xa0u, 0xa1u, 0xa2u, 0xc0u, 0xccu, 0xcdu, 0xd0u, 0xd1u, 0xd2u, 0xd3u, 0xd4u, 0xd5u, 0xf7u))        // these are updated/used by IRQ
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ZeropageType.KERNALSAFE -> {
 | 
					            ZeropageType.KERNALSAFE -> {
 | 
				
			||||||
                free.addAll(0x0au..0x8fu)       // BASIC variables
 | 
					                free.addAll(0x0au..0x8fu)       // BASIC variables
 | 
				
			||||||
                free.addAll(listOf(0x92u, 0x96u, 0x9bu, 0x9cu, 0x9eu, 0x9fu, 0xa4u, 0xa7u, 0xa8u, 0xa9u, 0xaau, 0xabu,
 | 
					                free.addAll(arrayOf(0x92u, 0x96u, 0x9bu, 0x9cu, 0x9eu, 0x9fu, 0xa4u, 0xa7u, 0xa8u, 0xa9u, 0xaau, 0xabu,
 | 
				
			||||||
                    0xb0u, 0xb1u, 0xb4u, 0xb5u, 0xb6u))
 | 
					                    0xb0u, 0xb1u, 0xb4u, 0xb5u, 0xb6u))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ZeropageType.FLOATSAFE,
 | 
					            ZeropageType.FLOATSAFE,
 | 
				
			||||||
            ZeropageType.BASICSAFE -> {
 | 
					            ZeropageType.BASICSAFE -> {
 | 
				
			||||||
                free.addAll(listOf(0x0bu, 0x0cu, 0x0du, 0x0eu, 0x0fu, 0x10u, 0x11u, 0x12u, 0x16u, 0x17u, 0x18u, 0x19u, 0x1au))
 | 
					                free.addAll(arrayOf(0x0bu, 0x0cu, 0x0du, 0x0eu, 0x0fu, 0x10u, 0x11u, 0x12u, 0x16u, 0x17u, 0x18u, 0x19u, 0x1au))
 | 
				
			||||||
                free.addAll(0x1bu..0x23u)
 | 
					                free.addAll(0x1bu..0x23u)
 | 
				
			||||||
                free.addAll(listOf(0x3fu, 0x40u, 0x41u, 0x42u, 0x43u, 0x44u, 0x47u, 0x48u, 0x49u, 0x4au, 0x4bu, 0x4cu, 0x4fu,
 | 
					                free.addAll(arrayOf(0x3fu, 0x40u, 0x41u, 0x42u, 0x43u, 0x44u, 0x47u, 0x48u, 0x49u, 0x4au, 0x4bu, 0x4cu, 0x4fu,
 | 
				
			||||||
                    0x55u, 0x56u, 0x57u, 0x58u,
 | 
					                    0x55u, 0x56u, 0x57u, 0x58u,
 | 
				
			||||||
                    0x74u, 0x75u, 0x78u, 0x80u, 0x83u, 0x87u, 0x88u, 0x89u, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu,
 | 
					                    0x74u, 0x75u, 0x78u, 0x80u, 0x83u, 0x87u, 0x88u, 0x89u, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu,
 | 
				
			||||||
                    0x92u, 0x96u, 0x9bu, 0x9cu, 0x9eu, 0x9fu, 0xa4u, 0xa7u, 0xa8u, 0xa9u, 0xaau, 0xabu,
 | 
					                    0x92u, 0x96u, 0x9bu, 0x9cu, 0x9eu, 0x9fu, 0xa4u, 0xa7u, 0xa8u, 0xa9u, 0xaau, 0xabu,
 | 
				
			||||||
@@ -53,7 +48,7 @@ class C128Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                // if(options.zeropage==ZeropageType.BASICSAFE) {
 | 
					                // if(options.zeropage==ZeropageType.BASICSAFE) {
 | 
				
			||||||
                    // can also clobber the FP locations (unconditionally, because the C128 target doesn't support floating point calculations in prog8 at this time0
 | 
					                    // can also clobber the FP locations (unconditionally, because the C128 target doesn't support floating point calculations in prog8 at this time0
 | 
				
			||||||
                    free.addAll(listOf(0x14u, 0x28u, 0x29u, 0x2au, 0x2bu, 0x2cu,
 | 
					                    free.addAll(arrayOf(0x14u, 0x28u, 0x29u, 0x2au, 0x2bu, 0x2cu,
 | 
				
			||||||
                        0x50u, 0x51u, 0x52u, 0x53u, 0x54u, 0x59u, 0x5au, 0x5bu, 0x5cu, 0x5du, 0x5eu, 0x5fu, 0x60u, 0x61u, 0x62u,
 | 
					                        0x50u, 0x51u, 0x52u, 0x53u, 0x54u, 0x59u, 0x5au, 0x5bu, 0x5cu, 0x5du, 0x5eu, 0x5fu, 0x60u, 0x61u, 0x62u,
 | 
				
			||||||
                        0x63u, 0x64u, 0x65u, 0x66u, 0x67u, 0x68u,
 | 
					                        0x63u, 0x64u, 0x65u, 0x66u, 0x67u, 0x68u,
 | 
				
			||||||
                        0x6au, 0x6bu, 0x6cu, 0x6du, 0x6eu, 0x6fu, 0x71u))
 | 
					                        0x6au, 0x6bu, 0x6cu, 0x6du, 0x6eu, 0x6fu, 0x71u))
 | 
				
			||||||
@@ -71,8 +66,4 @@ class C128Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			|||||||
        removeReservedFromFreePool()
 | 
					        removeReservedFromFreePool()
 | 
				
			||||||
        retainAllowed()
 | 
					        retainAllowed()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun allocateCx16VirtualRegisters() {
 | 
					 | 
				
			||||||
        TODO("Not known if C128 can put the virtual regs in ZP")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package prog8.code.target.c64
 | 
					package prog8.code.target.zp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prog8.code.core.*
 | 
					import prog8.code.core.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,9 +6,10 @@ import prog8.code.core.*
 | 
				
			|||||||
class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
					class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override val SCRATCH_B1 = 0x02u      // temp storage for a single byte
 | 
					    override val SCRATCH_B1 = 0x02u      // temp storage for a single byte
 | 
				
			||||||
    override val SCRATCH_REG = 0x03u     // temp storage for a register, must be B1+1
 | 
					    override val SCRATCH_REG = 0x03u     // temp storage for a register byte, must be B1+1
 | 
				
			||||||
    override val SCRATCH_W1 = 0xfbu      // temp storage 1 for a word  $fb+$fc
 | 
					    override val SCRATCH_W1 = 0xfbu      // temp storage 1 for a word  $fb+$fc
 | 
				
			||||||
    override val SCRATCH_W2 = 0xfdu      // temp storage 2 for a word  $fd+$fe
 | 
					    override val SCRATCH_W2 = 0xfdu      // temp storage 2 for a word  $fd+$fe
 | 
				
			||||||
 | 
					    override val SCRATCH_PTR = 0x9bu     // temp storage for a pointer $9b+$9c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
@@ -21,11 +22,10 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        if (options.zeropage == ZeropageType.FULL) {
 | 
					        if (options.zeropage == ZeropageType.FULL) {
 | 
				
			||||||
            free.addAll(0x02u..0xffu)
 | 
					            free.addAll(0x02u..0xffu)
 | 
				
			||||||
            free.removeAll(setOf(SCRATCH_B1, SCRATCH_REG, SCRATCH_W1, SCRATCH_W1+1u, SCRATCH_W2, SCRATCH_W2+1u))
 | 
					            free.removeAll(arrayOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u))        // these are updated by IRQ
 | 
				
			||||||
            free.removeAll(setOf(0xa0u, 0xa1u, 0xa2u, 0x91u, 0xc0u, 0xc5u, 0xcbu, 0xf5u, 0xf6u))        // these are updated by IRQ
 | 
					 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            if (options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) {
 | 
					            if (options.zeropage == ZeropageType.KERNALSAFE || options.zeropage == ZeropageType.FLOATSAFE) {
 | 
				
			||||||
                free.addAll(listOf(
 | 
					                free.addAll(arrayOf(
 | 
				
			||||||
                        0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
 | 
					                        0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
 | 
				
			||||||
                        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
 | 
					                        0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
 | 
				
			||||||
                        0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
 | 
					                        0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
 | 
				
			||||||
@@ -43,7 +43,7 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            if (options.zeropage == ZeropageType.FLOATSAFE) {
 | 
					            if (options.zeropage == ZeropageType.FLOATSAFE) {
 | 
				
			||||||
                // remove the zeropage locations used for floating point operations from the free list
 | 
					                // remove the zeropage locations used for floating point operations from the free list
 | 
				
			||||||
                free.removeAll(listOf(
 | 
					                free.removeAll(arrayOf(
 | 
				
			||||||
                        0x03, 0x04, 0x05, 0x06, 0x10, 0x11, 0x12,
 | 
					                        0x03, 0x04, 0x05, 0x06, 0x10, 0x11, 0x12,
 | 
				
			||||||
                        0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
 | 
					                        0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a,
 | 
				
			||||||
                        0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
 | 
					                        0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60,
 | 
				
			||||||
@@ -56,7 +56,7 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			|||||||
            if(options.zeropage != ZeropageType.DONTUSE) {
 | 
					            if(options.zeropage != ZeropageType.DONTUSE) {
 | 
				
			||||||
                // add the free Zp addresses
 | 
					                // add the free Zp addresses
 | 
				
			||||||
                // these are valid for the C-64 but allow BASIC to keep running fully *as long as you don't use tape I/O*
 | 
					                // these are valid for the C-64 but allow BASIC to keep running fully *as long as you don't use tape I/O*
 | 
				
			||||||
                free.addAll(listOf(0x02, 0x03, 0x04, 0x05, 0x06, 0x0a, 0x0e,
 | 
					                free.addAll(arrayOf(0x02, 0x03, 0x04, 0x05, 0x06, 0x0a, 0x0e,
 | 
				
			||||||
                        0x92, 0x96, 0x9b, 0x9c, 0x9e, 0x9f, 0xa6,
 | 
					                        0x92, 0x96, 0x9b, 0x9c, 0x9e, 0x9f, 0xa6,
 | 
				
			||||||
                        0xb0, 0xb1, 0xbe, 0xbf, 0xf9).map{it.toUInt()})
 | 
					                        0xb0, 0xb1, 0xbe, 0xbf, 0xf9).map{it.toUInt()})
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
@@ -79,9 +79,9 @@ class C64Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			|||||||
        retainAllowed()
 | 
					        retainAllowed()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun allocateCx16VirtualRegisters() {
 | 
					    private fun allocateCx16VirtualRegisters() {
 | 
				
			||||||
        // Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
 | 
					        // Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
 | 
				
			||||||
        // However, to be able for the compiler to "see" them as zero page variables, we have to register them here as well.
 | 
					        // However, to be able for the compiler to "see" them as zeropage variables, we have to register them here as well.
 | 
				
			||||||
        // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
 | 
					        // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
 | 
				
			||||||
        // The base addres is $04.  Unfortunately it cannot be the same as on the Commander X16 ($02).
 | 
					        // The base addres is $04.  Unfortunately it cannot be the same as on the Commander X16 ($02).
 | 
				
			||||||
        for(reg in 0..15) {
 | 
					        for(reg in 0..15) {
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package prog8.code.target.cx16
 | 
					package prog8.code.target.zp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prog8.code.core.*
 | 
					import prog8.code.core.*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6,9 +6,10 @@ import prog8.code.core.*
 | 
				
			|||||||
class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
					class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override val SCRATCH_B1 = 0x7au      // temp storage for a single byte
 | 
					    override val SCRATCH_B1 = 0x7au      // temp storage for a single byte
 | 
				
			||||||
    override val SCRATCH_REG = 0x7bu     // temp storage for a register, must be B1+1
 | 
					    override val SCRATCH_REG = 0x7bu     // temp storage for a register byte, must be B1+1
 | 
				
			||||||
    override val SCRATCH_W1 = 0x7cu      // temp storage 1 for a word  $7c+$7d
 | 
					    override val SCRATCH_W1 = 0x7cu      // temp storage 1 for a word  $7c+$7d
 | 
				
			||||||
    override val SCRATCH_W2 = 0x7eu      // temp storage 2 for a word  $7e+$7f
 | 
					    override val SCRATCH_W2 = 0x7eu      // temp storage 2 for a word  $7e+$7f
 | 
				
			||||||
 | 
					    override val SCRATCH_PTR = 0x22u     // temp storage for a pointer $22+$23
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
@@ -52,9 +53,9 @@ class CX16Zeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override fun allocateCx16VirtualRegisters() {
 | 
					    private fun allocateCx16VirtualRegisters() {
 | 
				
			||||||
        // Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
 | 
					        // Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
 | 
				
			||||||
        // However, to be able for the compiler to "see" them as zero page variables, we have to register them here as well.
 | 
					        // However, to be able for the compiler to "see" them as zeropage variables, we have to register them here as well.
 | 
				
			||||||
        // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
 | 
					        // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
 | 
				
			||||||
        for(reg in 0..15) {
 | 
					        for(reg in 0..15) {
 | 
				
			||||||
            allocatedVariables["cx16.r${reg}"]   = VarAllocation((2+reg*2).toUInt(), DataType.UWORD, 2)       // cx16.r0 .. cx16.r15
 | 
					            allocatedVariables["cx16.r${reg}"]   = VarAllocation((2+reg*2).toUInt(), DataType.UWORD, 2)       // cx16.r0 .. cx16.r15
 | 
				
			||||||
							
								
								
									
										63
									
								
								codeCore/src/prog8/code/target/zp/ConfigurableZeropage.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								codeCore/src/prog8/code/target/zp/ConfigurableZeropage.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,63 @@
 | 
				
			|||||||
 | 
					package prog8.code.target.zp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import prog8.code.core.CompilationOptions
 | 
				
			||||||
 | 
					import prog8.code.core.DataType
 | 
				
			||||||
 | 
					import prog8.code.core.Zeropage
 | 
				
			||||||
 | 
					import prog8.code.core.ZeropageType
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConfigurableZeropage(
 | 
				
			||||||
 | 
					    override val SCRATCH_B1: UInt,      // temp storage for a single byte
 | 
				
			||||||
 | 
					    override val SCRATCH_REG: UInt,     // temp storage for a register byte, must be B1+1
 | 
				
			||||||
 | 
					    override val SCRATCH_W1: UInt,      // temp storage 1 for a word
 | 
				
			||||||
 | 
					    override val SCRATCH_W2: UInt,      // temp storage 2 for a word
 | 
				
			||||||
 | 
					    override val SCRATCH_PTR: UInt,     // temp storage for a pointer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    val virtualRegistersStart: UInt,        // location of 32 bytes for the r0-r15 virtual registers
 | 
				
			||||||
 | 
					    basicsafe: List<UIntRange>,
 | 
				
			||||||
 | 
					    kernalsafe: List<UIntRange>,
 | 
				
			||||||
 | 
					    fullsafe: List<UIntRange>,
 | 
				
			||||||
 | 
					    options: CompilationOptions
 | 
				
			||||||
 | 
					) : Zeropage(options) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    init {
 | 
				
			||||||
 | 
					        if (options.floats) {
 | 
				
			||||||
 | 
					            TODO("floats in configurable target zp")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(SCRATCH_REG!=SCRATCH_B1+1u)
 | 
				
			||||||
 | 
					            throw IllegalArgumentException("Zero page scratch variable REG should be B1+1")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        when (options.zeropage) {
 | 
				
			||||||
 | 
					            ZeropageType.DONTUSE -> { /* don't use any zeropage at all */ }
 | 
				
			||||||
 | 
					            ZeropageType.FULL -> fullsafe.forEach { free.addAll(it) }
 | 
				
			||||||
 | 
					            ZeropageType.BASICSAFE -> basicsafe.forEach { free.addAll(it) }
 | 
				
			||||||
 | 
					            ZeropageType.KERNALSAFE -> kernalsafe.forEach { free.addAll(it) }
 | 
				
			||||||
 | 
					            ZeropageType.FLOATSAFE -> TODO("floatsafe in configurable target zp")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val distinctFree = free.distinct()
 | 
				
			||||||
 | 
					        free.clear()
 | 
				
			||||||
 | 
					        free.addAll(distinctFree)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        removeReservedFromFreePool()
 | 
				
			||||||
 | 
					        allocateCx16VirtualRegisters()
 | 
				
			||||||
 | 
					        retainAllowed()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun allocateCx16VirtualRegisters() {
 | 
				
			||||||
 | 
					        // Note: the 16 virtual registers R0-R15 are not regular allocated variables, they're *memory mapped* elsewhere to fixed addresses.
 | 
				
			||||||
 | 
					        // However, to be able for the compiler to "see" them as zeropage variables, we have to register them here as well.
 | 
				
			||||||
 | 
					        // This is important because the compiler sometimes treats ZP variables more efficiently (for example if it's a pointer)
 | 
				
			||||||
 | 
					        for(reg in 0..15) {
 | 
				
			||||||
 | 
					            val address = virtualRegistersStart + (2*reg).toUInt()
 | 
				
			||||||
 | 
					            if(address<=0xffu) {
 | 
				
			||||||
 | 
					                allocatedVariables["cx16.r${reg}"]   = VarAllocation(address, DataType.UWORD, 2)       // cx16.r0 .. cx16.r15
 | 
				
			||||||
 | 
					                allocatedVariables["cx16.r${reg}s"]  = VarAllocation(address, DataType.WORD, 2)        // cx16.r0s .. cx16.r15s
 | 
				
			||||||
 | 
					                allocatedVariables["cx16.r${reg}L"]  = VarAllocation(address, DataType.UBYTE, 1)       // cx16.r0L .. cx16.r15L
 | 
				
			||||||
 | 
					                allocatedVariables["cx16.r${reg}H"]  = VarAllocation(address+1u, DataType.UBYTE, 1)    // cx16.r0H .. cx16.r15H
 | 
				
			||||||
 | 
					                allocatedVariables["cx16.r${reg}sL"] = VarAllocation(address, DataType.BYTE, 1)        // cx16.r0sL .. cx16.r15sL
 | 
				
			||||||
 | 
					                allocatedVariables["cx16.r${reg}sH"] = VarAllocation(address+1u, DataType.BYTE, 1)     // cx16.r0sH .. cx16.r15sH
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -1,4 +1,4 @@
 | 
				
			|||||||
package prog8.code.target.pet
 | 
					package prog8.code.target.zp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prog8.code.core.CompilationOptions
 | 
					import prog8.code.core.CompilationOptions
 | 
				
			||||||
import prog8.code.core.InternalCompilerException
 | 
					import prog8.code.core.InternalCompilerException
 | 
				
			||||||
@@ -11,15 +11,12 @@ import prog8.code.core.ZeropageType
 | 
				
			|||||||
class PETZeropage(options: CompilationOptions) : Zeropage(options) {
 | 
					class PETZeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    override val SCRATCH_B1 = 0xb3u      // temp storage for a single byte
 | 
					    override val SCRATCH_B1 = 0xb3u      // temp storage for a single byte
 | 
				
			||||||
    override val SCRATCH_REG = 0xb4u     // temp storage for a register, must be B1+1
 | 
					    override val SCRATCH_REG = 0xb4u     // temp storage for a register byte, must be B1+1
 | 
				
			||||||
    override val SCRATCH_W1 = 0xb6u      // temp storage 1 for a word
 | 
					    override val SCRATCH_W1 = 0xb6u      // temp storage 1 for a word
 | 
				
			||||||
    override val SCRATCH_W2 = 0xb8u      // temp storage 2 for a word
 | 
					    override val SCRATCH_W2 = 0xb8u      // temp storage 2 for a word
 | 
				
			||||||
 | 
					    override val SCRATCH_PTR = 0xb1u     // temp storage for a pointer $b1+$b2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    init {
 | 
					    init {
 | 
				
			||||||
        if (options.floats) {
 | 
					 | 
				
			||||||
            throw InternalCompilerException("PET target doesn't yet support floating point routines")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (options.floats && options.zeropage !in arrayOf(
 | 
					        if (options.floats && options.zeropage !in arrayOf(
 | 
				
			||||||
                ZeropageType.FLOATSAFE,
 | 
					                ZeropageType.FLOATSAFE,
 | 
				
			||||||
                ZeropageType.BASICSAFE,
 | 
					                ZeropageType.BASICSAFE,
 | 
				
			||||||
@@ -38,7 +35,7 @@ class PETZeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            ZeropageType.FLOATSAFE,
 | 
					            ZeropageType.FLOATSAFE,
 | 
				
			||||||
            ZeropageType.BASICSAFE -> {
 | 
					            ZeropageType.BASICSAFE -> {
 | 
				
			||||||
                free.addAll(0xb3u..0xbau)       // TODO more?
 | 
					                free.addAll(0xb1u..0xbau)       // TODO more?
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            ZeropageType.DONTUSE -> {
 | 
					            ZeropageType.DONTUSE -> {
 | 
				
			||||||
                free.clear()  // don't use zeropage at all
 | 
					                free.clear()  // don't use zeropage at all
 | 
				
			||||||
@@ -52,8 +49,4 @@ class PETZeropage(options: CompilationOptions) : Zeropage(options) {
 | 
				
			|||||||
        removeReservedFromFreePool()
 | 
					        removeReservedFromFreePool()
 | 
				
			||||||
        retainAllowed()
 | 
					        retainAllowed()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					 | 
				
			||||||
    override fun allocateCx16VirtualRegisters() {
 | 
					 | 
				
			||||||
        TODO("Not known if PET can put the virtual regs in ZP")
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -1,63 +0,0 @@
 | 
				
			|||||||
plugins {
 | 
					 | 
				
			||||||
    id 'java'
 | 
					 | 
				
			||||||
    id 'application'
 | 
					 | 
				
			||||||
    id "org.jetbrains.kotlin.jvm"
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
java {
 | 
					 | 
				
			||||||
    targetCompatibility = JavaLanguageVersion.of(javaVersion)
 | 
					 | 
				
			||||||
    sourceCompatibility = JavaLanguageVersion.of(javaVersion)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
compileKotlin {
 | 
					 | 
				
			||||||
    kotlinOptions {
 | 
					 | 
				
			||||||
        jvmTarget = javaVersion
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
compileTestKotlin {
 | 
					 | 
				
			||||||
    kotlinOptions {
 | 
					 | 
				
			||||||
        jvmTarget = javaVersion
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
dependencies {
 | 
					 | 
				
			||||||
    implementation project(':codeCore')
 | 
					 | 
				
			||||||
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
 | 
					 | 
				
			||||||
    // implementation "org.jetbrains.kotlin:kotlin-reflect"
 | 
					 | 
				
			||||||
    implementation "com.michael-bull.kotlin-result:kotlin-result-jvm:2.0.0"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    testImplementation 'io.kotest:kotest-runner-junit5-jvm:5.9.1'
 | 
					 | 
				
			||||||
    testImplementation 'io.kotest:kotest-framework-datatest:5.9.1'
 | 
					 | 
				
			||||||
    testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2'
 | 
					 | 
				
			||||||
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
sourceSets {
 | 
					 | 
				
			||||||
    main {
 | 
					 | 
				
			||||||
        java {
 | 
					 | 
				
			||||||
            srcDir "${project.projectDir}/src"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        resources {
 | 
					 | 
				
			||||||
            srcDir "${project.projectDir}/res"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    test {
 | 
					 | 
				
			||||||
        java {
 | 
					 | 
				
			||||||
            srcDir "${project.projectDir}/test"
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
test {
 | 
					 | 
				
			||||||
    // Enable JUnit 5 (Gradle 4.6+).
 | 
					 | 
				
			||||||
    useJUnitPlatform()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Always run tests, even when nothing changed.
 | 
					 | 
				
			||||||
    dependsOn 'cleanTest'
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // Show test results.
 | 
					 | 
				
			||||||
    testLogging {
 | 
					 | 
				
			||||||
        events "skipped", "failed"
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
							
								
								
									
										43
									
								
								codeGenCpu6502/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								codeGenCpu6502/build.gradle.kts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					plugins {
 | 
				
			||||||
 | 
					    kotlin("jvm")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dependencies {
 | 
				
			||||||
 | 
					    implementation(project(":codeCore"))
 | 
				
			||||||
 | 
					    implementation(project(":simpleAst"))
 | 
				
			||||||
 | 
					    // implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
 | 
				
			||||||
 | 
					    // implementation "org.jetbrains.kotlin:kotlin-reflect"
 | 
				
			||||||
 | 
					    implementation("com.michael-bull.kotlin-result:kotlin-result-jvm:2.1.0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    testImplementation("io.kotest:kotest-runner-junit5-jvm:5.9.1")
 | 
				
			||||||
 | 
					    testImplementation("io.kotest:kotest-framework-datatest:5.9.1")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					sourceSets {
 | 
				
			||||||
 | 
					    main {
 | 
				
			||||||
 | 
					        java {
 | 
				
			||||||
 | 
					            setSrcDirs(listOf("$projectDir/src"))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        resources {
 | 
				
			||||||
 | 
					            setSrcDirs(listOf("$projectDir/res"))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    test {
 | 
				
			||||||
 | 
					        java {
 | 
				
			||||||
 | 
					            setSrcDirs(listOf("$projectDir/test"))
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					tasks.test {
 | 
				
			||||||
 | 
					    // Enable JUnit 5 (Gradle 4.6+).
 | 
				
			||||||
 | 
					    useJUnitPlatform()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Always run tests, even when nothing changed.
 | 
				
			||||||
 | 
					    dependsOn("cleanTest")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Show test results.
 | 
				
			||||||
 | 
					    testLogging {
 | 
				
			||||||
 | 
					        events("skipped", "failed")
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -11,8 +11,8 @@
 | 
				
			|||||||
    <orderEntry type="sourceFolder" forTests="false" />
 | 
					    <orderEntry type="sourceFolder" forTests="false" />
 | 
				
			||||||
    <orderEntry type="library" name="KotlinJavaRuntime" level="project" />
 | 
					    <orderEntry type="library" name="KotlinJavaRuntime" level="project" />
 | 
				
			||||||
    <orderEntry type="module" module-name="codeCore" />
 | 
					    <orderEntry type="module" module-name="codeCore" />
 | 
				
			||||||
 | 
					    <orderEntry type="module" module-name="simpleAst" />
 | 
				
			||||||
    <orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
 | 
					    <orderEntry type="library" name="michael.bull.kotlin.result.jvm" level="project" />
 | 
				
			||||||
    <orderEntry type="library" name="io.kotest.assertions.core.jvm" level="project" />
 | 
					 | 
				
			||||||
    <orderEntry type="library" name="io.kotest.runner.junit5.jvm" level="project" />
 | 
					    <orderEntry type="library" name="io.kotest.runner.junit5.jvm" level="project" />
 | 
				
			||||||
    <orderEntry type="library" name="io.kotest.framework.datatest" level="project" />
 | 
					    <orderEntry type="library" name="io.kotest.framework.datatest" level="project" />
 | 
				
			||||||
  </component>
 | 
					  </component>
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,15 +1,16 @@
 | 
				
			|||||||
package prog8.codegen.cpu6502
 | 
					package prog8.codegen.cpu6502
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import prog8.code.GENERATED_LABEL_PREFIX
 | 
				
			||||||
import prog8.code.StConstant
 | 
					import prog8.code.StConstant
 | 
				
			||||||
import prog8.code.StMemVar
 | 
					import prog8.code.StMemVar
 | 
				
			||||||
import prog8.code.SymbolTable
 | 
					import prog8.code.SymbolTable
 | 
				
			||||||
import prog8.code.core.IMachineDefinition
 | 
					import prog8.code.core.ICompilationTarget
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// note: see https://wiki.nesdev.org/w/index.php/6502_assembly_optimisations
 | 
					// note: see https://wiki.nesdev.org/w/index.php/6502_assembly_optimisations
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
internal fun optimizeAssembly(lines: MutableList<String>, machine: IMachineDefinition, symbolTable: SymbolTable): Int {
 | 
					internal fun optimizeAssembly(lines: MutableList<String>, machine: ICompilationTarget, symbolTable: SymbolTable): Int {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var numberOfOptimizations = 0
 | 
					    var numberOfOptimizations = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -72,6 +73,13 @@ internal fun optimizeAssembly(lines: MutableList<String>, machine: IMachineDefin
 | 
				
			|||||||
        numberOfOptimizations++
 | 
					        numberOfOptimizations++
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mods = optimizeAddWordToSameVariableOrExtraRegisterLoadInWordStore(linesByFourteen)
 | 
				
			||||||
 | 
					    if(mods.isNotEmpty()) {
 | 
				
			||||||
 | 
					        apply(mods, lines)
 | 
				
			||||||
 | 
					        linesByFourteen = getLinesBy(lines, 14)
 | 
				
			||||||
 | 
					        numberOfOptimizations++
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return numberOfOptimizations
 | 
					    return numberOfOptimizations
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -122,7 +130,7 @@ private fun getLinesBy(lines: MutableList<String>, windowSize: Int) =
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
private fun optimizeSameAssignments(
 | 
					private fun optimizeSameAssignments(
 | 
				
			||||||
    linesByFourteen: Sequence<List<IndexedValue<String>>>,
 | 
					    linesByFourteen: Sequence<List<IndexedValue<String>>>,
 | 
				
			||||||
    machine: IMachineDefinition,
 | 
					    machine: ICompilationTarget,
 | 
				
			||||||
    symbolTable: SymbolTable
 | 
					    symbolTable: SymbolTable
 | 
				
			||||||
): List<Modification> {
 | 
					): List<Modification> {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -361,15 +369,16 @@ or *_afterif labels.
 | 
				
			|||||||
This gets generated after certain if conditions, and only the branch instruction is needed in these cases.
 | 
					This gets generated after certain if conditions, and only the branch instruction is needed in these cases.
 | 
				
			||||||
         */
 | 
					         */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val autoLabelPrefix = GENERATED_LABEL_PREFIX
 | 
				
			||||||
        if(first=="beq  +" && second=="lda  #1" && third=="+") {
 | 
					        if(first=="beq  +" && second=="lda  #1" && third=="+") {
 | 
				
			||||||
            if((fourth.startsWith("beq  label_") || fourth.startsWith("bne  label_")) &&
 | 
					            if((fourth.startsWith("beq  $autoLabelPrefix") || fourth.startsWith("bne  $autoLabelPrefix")) &&
 | 
				
			||||||
                (fourth.endsWith("_shortcut") || fourth.endsWith("_afterif") || fourth.endsWith("_shortcut:") || fourth.endsWith("_afterif:"))) {
 | 
					                (fourth.endsWith("_shortcut") || fourth.endsWith("_afterif") || fourth.endsWith("_shortcut:") || fourth.endsWith("_afterif:"))) {
 | 
				
			||||||
                mods.add(Modification(lines[0].index, true, null))
 | 
					                mods.add(Modification(lines[0].index, true, null))
 | 
				
			||||||
                mods.add(Modification(lines[1].index, true, null))
 | 
					                mods.add(Modification(lines[1].index, true, null))
 | 
				
			||||||
                mods.add(Modification(lines[2].index, true, null))
 | 
					                mods.add(Modification(lines[2].index, true, null))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            else if(fourth.startsWith("label_") && (fourth.endsWith("_shortcut") || fourth.endsWith("_shortcut:"))) {
 | 
					            else if(fourth.startsWith(autoLabelPrefix) && (fourth.endsWith("_shortcut") || fourth.endsWith("_shortcut:"))) {
 | 
				
			||||||
                if((fifth.startsWith("beq  label_") || fifth.startsWith("bne  label_")) &&
 | 
					                if((fifth.startsWith("beq  $autoLabelPrefix") || fifth.startsWith("bne  $autoLabelPrefix")) &&
 | 
				
			||||||
                    (fifth.endsWith("_shortcut") || fifth.endsWith("_afterif") || fifth.endsWith("_shortcut:") || fifth.endsWith("_afterif:"))) {
 | 
					                    (fifth.endsWith("_shortcut") || fifth.endsWith("_afterif") || fifth.endsWith("_shortcut:") || fifth.endsWith("_afterif:"))) {
 | 
				
			||||||
                    mods.add(Modification(lines[0].index, true, null))
 | 
					                    mods.add(Modification(lines[0].index, true, null))
 | 
				
			||||||
                    mods.add(Modification(lines[1].index, true, null))
 | 
					                    mods.add(Modification(lines[1].index, true, null))
 | 
				
			||||||
@@ -384,7 +393,7 @@ This gets generated after certain if conditions, and only the branch instruction
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
private fun optimizeStoreLoadSame(
 | 
					private fun optimizeStoreLoadSame(
 | 
				
			||||||
    linesByFour: Sequence<List<IndexedValue<String>>>,
 | 
					    linesByFour: Sequence<List<IndexedValue<String>>>,
 | 
				
			||||||
    machine: IMachineDefinition,
 | 
					    machine: ICompilationTarget,
 | 
				
			||||||
    symbolTable: SymbolTable
 | 
					    symbolTable: SymbolTable
 | 
				
			||||||
): List<Modification> {
 | 
					): List<Modification> {
 | 
				
			||||||
    val mods = mutableListOf<Modification>()
 | 
					    val mods = mutableListOf<Modification>()
 | 
				
			||||||
@@ -406,7 +415,7 @@ private fun optimizeStoreLoadSame(
 | 
				
			|||||||
                    // a branch instruction follows, we can only remove the load instruction if
 | 
					                    // a branch instruction follows, we can only remove the load instruction if
 | 
				
			||||||
                    // another load instruction of the same register precedes the store instruction
 | 
					                    // another load instruction of the same register precedes the store instruction
 | 
				
			||||||
                    // (otherwise wrong cpu flags are used)
 | 
					                    // (otherwise wrong cpu flags are used)
 | 
				
			||||||
                    val loadinstruction = second.substring(0, 3)
 | 
					                    val loadinstruction = second.take(3)
 | 
				
			||||||
                    lines[0].value.trimStart().startsWith(loadinstruction)
 | 
					                    lines[0].value.trimStart().startsWith(loadinstruction)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                else {
 | 
					                else {
 | 
				
			||||||
@@ -444,20 +453,35 @@ private fun optimizeStoreLoadSame(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // lda X + sta X,  ldy X + sty X,   ldx X + stx X  -> the second instruction can be eliminated
 | 
					        // lda X + sta X,  ldy X + sty X,   ldx X + stx X  -> the second instruction can be eliminated
 | 
				
			||||||
        if ((first.startsWith("lda ") && second.startsWith("sta ")) ||
 | 
					        if (first.startsWith("lda ") && second.startsWith("sta ") ||
 | 
				
			||||||
            (first.startsWith("ldx ") && second.startsWith("stx ")) ||
 | 
					            first.startsWith("ldx ") && second.startsWith("stx ") ||
 | 
				
			||||||
            (first.startsWith("ldy ") && second.startsWith("sty "))
 | 
					            first.startsWith("ldy ") && second.startsWith("sty ")
 | 
				
			||||||
        ) {
 | 
					        ) {
 | 
				
			||||||
            val firstLoc = first.substring(4).trimStart()
 | 
					            val firstLoc = first.substring(4).trimStart()
 | 
				
			||||||
            val secondLoc = second.substring(4).trimStart()
 | 
					            val secondLoc = second.substring(4).trimStart()
 | 
				
			||||||
            if (firstLoc == secondLoc)
 | 
					            if (firstLoc == secondLoc)
 | 
				
			||||||
                mods.add(Modification(lines[2].index, true, null))
 | 
					                mods.add(Modification(lines[2].index, true, null))
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        //  all 3 registers:  lda VALUE + sta SOMEWHERE + lda VALUE  -> last load can be eliminated IF NOT IO ADDRESS
 | 
				
			||||||
 | 
					        if (first.startsWith("lda ") && second.startsWith("sta ") && third.startsWith("lda ") ||
 | 
				
			||||||
 | 
					            first.startsWith("ldx ") && second.startsWith("stx ") && third.startsWith("ldx ") ||
 | 
				
			||||||
 | 
					            first.startsWith("ldy ") && second.startsWith("sty ") && third.startsWith("ldy ")
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            val firstVal = first.substring(4).trimStart()
 | 
				
			||||||
 | 
					            val thirdVal = third.substring(4).trimStart()
 | 
				
			||||||
 | 
					            if (firstVal == thirdVal) {
 | 
				
			||||||
 | 
					                val address = getAddressArg(third, symbolTable)
 | 
				
			||||||
 | 
					                if (address != null && !machine.isIOAddress(address)) {
 | 
				
			||||||
 | 
					                    mods.add(Modification(lines[3].index, true, null))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return mods
 | 
					    return mods
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private val identifierRegex = Regex("""^([a-zA-Z_$][a-zA-Z\d_\.$]*)""")
 | 
					private val identifierRegex = Regex("""^([a-zA-Z_$][a-zA-Z\d_.$]*)""")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private fun getAddressArg(line: String, symbolTable: SymbolTable): UInt? {
 | 
					private fun getAddressArg(line: String, symbolTable: SymbolTable): UInt? {
 | 
				
			||||||
    // try to get the constant value address, could return null if it's a symbol instead
 | 
					    // try to get the constant value address, could return null if it's a symbol instead
 | 
				
			||||||
@@ -506,9 +530,11 @@ private fun optimizeIncDec(linesByFour: Sequence<List<IndexedValue<String>>>): L
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
private fun optimizeJsrRtsAndOtherCombinations(linesByFour: Sequence<List<IndexedValue<String>>>): List<Modification> {
 | 
					private fun optimizeJsrRtsAndOtherCombinations(linesByFour: Sequence<List<IndexedValue<String>>>): List<Modification> {
 | 
				
			||||||
    // jsr Sub + rts -> jmp Sub
 | 
					    // jsr Sub + rts -> jmp Sub
 | 
				
			||||||
 | 
					    // jmp Sub + rts -> jmp Sub
 | 
				
			||||||
    // rts + jmp -> remove jmp
 | 
					    // rts + jmp -> remove jmp
 | 
				
			||||||
    // rts + bxx -> remove bxx
 | 
					    // rts + bxx -> remove bxx
 | 
				
			||||||
    // lda  + cmp #0 -> remove cmp,  same for cpy and cpx.
 | 
					    // lda  + cmp #0 -> remove cmp,  same for cpy and cpx.
 | 
				
			||||||
 | 
					    // bra/jmp + bra/jmp -> remove second bra/jmp   (bra bra / jmp jmp are not removed because this is likely a jump table!)
 | 
				
			||||||
    // and some other optimizations.
 | 
					    // and some other optimizations.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    val mods = mutableListOf<Modification>()
 | 
					    val mods = mutableListOf<Modification>()
 | 
				
			||||||
@@ -518,10 +544,15 @@ private fun optimizeJsrRtsAndOtherCombinations(linesByFour: Sequence<List<Indexe
 | 
				
			|||||||
        val third = lines[2].value
 | 
					        val third = lines[2].value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if(!haslabel(second)) {
 | 
					        if(!haslabel(second)) {
 | 
				
			||||||
            if ((" jsr" in first || "\tjsr" in first ) && (" rts" in second || "\trts" in second)) {
 | 
					            if ((" jmp" in first || "\tjmp" in first ) && (" rts" in second || "\trts" in second)) {
 | 
				
			||||||
 | 
					                mods += Modification(lines[1].index, true, null)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else if ((" jsr" in first || "\tjsr" in first ) && (" rts" in second || "\trts" in second)) {
 | 
				
			||||||
 | 
					                if("floats.pushFAC" !in first && "floats.popFAC" !in first) {       // these 2 routines depend on being called with JSR!!
 | 
				
			||||||
                    mods += Modification(lines[0].index, false, lines[0].value.replace("jsr", "jmp"))
 | 
					                    mods += Modification(lines[0].index, false, lines[0].value.replace("jsr", "jmp"))
 | 
				
			||||||
                    mods += Modification(lines[1].index, true, null)
 | 
					                    mods += Modification(lines[1].index, true, null)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            else if (" rts" in first || "\trts" in first) {
 | 
					            else if (" rts" in first || "\trts" in first) {
 | 
				
			||||||
                if (" jmp" in second || "\tjmp" in second)
 | 
					                if (" jmp" in second || "\tjmp" in second)
 | 
				
			||||||
                    mods += Modification(lines[1].index, true, null)
 | 
					                    mods += Modification(lines[1].index, true, null)
 | 
				
			||||||
@@ -559,6 +590,15 @@ private fun optimizeJsrRtsAndOtherCombinations(linesByFour: Sequence<List<Indexe
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // only remove bra followed by jmp or jmp followed by bra
 | 
				
			||||||
 | 
					            // bra bra or jmp jmp is likely part of a jump table, which should keep all entries!
 | 
				
			||||||
 | 
					            if((" bra" in first || "\tbra" in first) && (" jmp" in second || "\tjmp" in second)) {
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[1].index, true, null))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if((" jmp" in first || "\tjmp" in first) && (" bra" in second || "\tbra" in second)) {
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[1].index, true, null))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /*
 | 
					        /*
 | 
				
			||||||
@@ -676,33 +716,43 @@ private fun optimizeUselessPushPopStack(linesByFour: Sequence<List<IndexedValue<
 | 
				
			|||||||
        optimize('x', lines)
 | 
					        optimize('x', lines)
 | 
				
			||||||
        optimize('y', lines)
 | 
					        optimize('y', lines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val first = lines[1].value.trimStart()
 | 
					        val first = lines[0].value.trimStart()
 | 
				
			||||||
        val second = lines[2].value.trimStart()
 | 
					        val second = lines[1].value.trimStart()
 | 
				
			||||||
        val third = lines[3].value.trimStart()
 | 
					        val third = lines[2].value.trimStart()
 | 
				
			||||||
 | 
					        val fourth = lines[3].value.trimStart()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // phy + ldy + pla -> tya + ldy
 | 
					        // phy + ldy + pla -> tya + ldy
 | 
				
			||||||
        // phx + ldx + pla -> txa + ldx
 | 
					        // phx + ldx + pla -> txa + ldx
 | 
				
			||||||
        // pha + lda + pla -> nop
 | 
					        // pha + lda + pla -> nop
 | 
				
			||||||
        if(first=="phy" && second.startsWith("ldy ") && third=="pla") {
 | 
					        // pha + tya + tay + pla -> nop
 | 
				
			||||||
            mods.add(Modification(lines[3].index, true, null))
 | 
					        // pha + txa + tax + pla -> nop
 | 
				
			||||||
            mods.add(Modification(lines[1].index, false, "  tya"))
 | 
					        when (first) {
 | 
				
			||||||
 | 
					            "phy" if second.startsWith("ldy ") && third=="pla" -> {
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[2].index, true, null))
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[0].index, false, "  tya"))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        else if(first=="phx" && second.startsWith("ldx ") && third=="pla") {
 | 
					            "phx" if second.startsWith("ldx ") && third=="pla" -> {
 | 
				
			||||||
            mods.add(Modification(lines[3].index, true, null))
 | 
					                mods.add(Modification(lines[2].index, true, null))
 | 
				
			||||||
            mods.add(Modification(lines[1].index, false, "  txa"))
 | 
					                mods.add(Modification(lines[0].index, false, "  txa"))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        else if(first=="pha" && second.startsWith("lda ") && third=="pla") {
 | 
					            "pha" if second.startsWith("lda ") && third=="pla" -> {
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[0].index, true, null))
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[1].index, true, null))
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[2].index, true, null))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            "pha" if ((second=="tya" && third=="tay") || (second=="txa" && third=="tax")) && fourth=="pla" -> {
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[0].index, true, null))
 | 
				
			||||||
                mods.add(Modification(lines[1].index, true, null))
 | 
					                mods.add(Modification(lines[1].index, true, null))
 | 
				
			||||||
                mods.add(Modification(lines[2].index, true, null))
 | 
					                mods.add(Modification(lines[2].index, true, null))
 | 
				
			||||||
                mods.add(Modification(lines[3].index, true, null))
 | 
					                mods.add(Modification(lines[3].index, true, null))
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return mods
 | 
					    return mods
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
private fun optimizeTSBtoRegularOr(linesByFour: Sequence<List<IndexedValue<String>>>): List<Modification> {
 | 
					private fun optimizeTSBtoRegularOr(linesByFour: Sequence<List<IndexedValue<String>>>): List<Modification> {
 | 
				
			||||||
    // Asm peephole:   lda var2 / tsb var1 / lda var1  Replace this with this to save 1 cycle:   lda var1 / ora var2 / sta var1
 | 
					    // Asm peephole:   lda var2 / tsb var1 / lda var1  Replace this with this to save 1 cycle:   lda var1 / ora var2 / sta var1
 | 
				
			||||||
    val mods = mutableListOf<Modification>()
 | 
					    val mods = mutableListOf<Modification>()
 | 
				
			||||||
@@ -747,3 +797,120 @@ private fun optimizeUnneededTempvarInAdd(linesByFour: Sequence<List<IndexedValue
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    return mods
 | 
					    return mods
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private fun optimizeAddWordToSameVariableOrExtraRegisterLoadInWordStore(linesByFourteen: Sequence<List<IndexedValue<String>>>): List<Modification> {
 | 
				
			||||||
 | 
					    /*
 | 
				
			||||||
 | 
					        ; FIRST SEQUYENCE: P8ZP_SCRATCH_PTR += AY :
 | 
				
			||||||
 | 
					        clc
 | 
				
			||||||
 | 
					        adc  P8ZP_SCRATCH_PTR
 | 
				
			||||||
 | 
					        pha
 | 
				
			||||||
 | 
					        tya
 | 
				
			||||||
 | 
					        adc  P8ZP_SCRATCH_PTR+1
 | 
				
			||||||
 | 
					        tay
 | 
				
			||||||
 | 
					        pla
 | 
				
			||||||
 | 
					        sta  P8ZP_SCRATCH_PTR
 | 
				
			||||||
 | 
					        sty  P8ZP_SCRATCH_PTR+1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    ->
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        clc
 | 
				
			||||||
 | 
					    	adc  P8ZP_SCRATCH_PTR
 | 
				
			||||||
 | 
					    	sta  P8ZP_SCRATCH_PTR
 | 
				
			||||||
 | 
					    	tya
 | 
				
			||||||
 | 
					    	adc  P8ZP_SCRATCH_PTR+1
 | 
				
			||||||
 | 
					    	sta  P8ZP_SCRATCH_PTR+1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    	also SECOND SEQUENCE:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ldx  VALUE/  ldy  VALUE
 | 
				
			||||||
 | 
						    sta  SOMEWHERE_WITHOUT_,x_OR_,y
 | 
				
			||||||
 | 
						    txa /   tya
 | 
				
			||||||
 | 
					    	ldy  #1
 | 
				
			||||||
 | 
					    	sta  SOMEWHERE
 | 
				
			||||||
 | 
					     	 -->
 | 
				
			||||||
 | 
					    	sta  SOMEWHERE_WITHOUT_,x_OR_,y
 | 
				
			||||||
 | 
					    	lda  VALUE
 | 
				
			||||||
 | 
					    	ldy  #1
 | 
				
			||||||
 | 
					    	sta  SOMEWHERE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        also THIRD SEQUENCE:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        ldx  VALUE
 | 
				
			||||||
 | 
						    ldy  #0
 | 
				
			||||||
 | 
						    sta  SOMEWHERE_WITHOUT_,x
 | 
				
			||||||
 | 
						    txa
 | 
				
			||||||
 | 
						    iny
 | 
				
			||||||
 | 
						    sta  SOMEWHERE
 | 
				
			||||||
 | 
					         -->
 | 
				
			||||||
 | 
						    ldy  #0
 | 
				
			||||||
 | 
						    sta  SOMEWHERE_WITHOUT_,x
 | 
				
			||||||
 | 
						    lda  VALUE
 | 
				
			||||||
 | 
						    iny
 | 
				
			||||||
 | 
						    sta  SOMEWHERE
 | 
				
			||||||
 | 
					    */
 | 
				
			||||||
 | 
					    val mods = mutableListOf<Modification>()
 | 
				
			||||||
 | 
					    for (lines in linesByFourteen) {
 | 
				
			||||||
 | 
					        val first = lines[0].value.trimStart()
 | 
				
			||||||
 | 
					        val second = lines[1].value.trimStart()
 | 
				
			||||||
 | 
					        val third = lines[2].value.trimStart()
 | 
				
			||||||
 | 
					        val fourth = lines[3].value.trimStart()
 | 
				
			||||||
 | 
					        val fifth = lines[4].value.trimStart()
 | 
				
			||||||
 | 
					        val sixth = lines[5].value.trimStart()
 | 
				
			||||||
 | 
					        val seventh = lines[6].value.trimStart()
 | 
				
			||||||
 | 
					        val eight = lines[7].value.trimStart()
 | 
				
			||||||
 | 
					        val ninth = lines[8].value.trimStart()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // FIRST SEQUENCE
 | 
				
			||||||
 | 
					        if(first=="clc" && second.startsWith("adc") && third=="pha" && fourth=="tya" &&
 | 
				
			||||||
 | 
					            fifth.startsWith("adc") && sixth=="tay" && seventh=="pla" && eight.startsWith("sta") && ninth.startsWith("sty")) {
 | 
				
			||||||
 | 
					            val var2 = second.substring(4)
 | 
				
			||||||
 | 
					            val var5 = fifth.substring(4).substringBefore('+')
 | 
				
			||||||
 | 
					            val var8 = eight.substring(4)
 | 
				
			||||||
 | 
					            val var9 = ninth.substring(4).substringBefore('+')
 | 
				
			||||||
 | 
					            if(var2==var5 && var2==var8 && var2==var9) {
 | 
				
			||||||
 | 
					                if(fifth.endsWith("$var5+1") && ninth.endsWith("$var9+1")) {
 | 
				
			||||||
 | 
					                    mods.add(Modification(lines[2].index, false, "  sta  $var2"))
 | 
				
			||||||
 | 
					                    mods.add(Modification(lines[5].index, false, "  sta  $var2+1"))
 | 
				
			||||||
 | 
					                    mods.add(Modification(lines[6].index, true, null))
 | 
				
			||||||
 | 
					                    mods.add(Modification(lines[7].index, true, null))
 | 
				
			||||||
 | 
					                    mods.add(Modification(lines[8].index, true, null))
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // SECOND SEQUENCE
 | 
				
			||||||
 | 
					        if(first.startsWith("ldx ") && second.startsWith("sta ") &&
 | 
				
			||||||
 | 
					            third=="txa" && fourth.startsWith("ldy ") && fifth.startsWith("sta ")
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            if(",x" !in second) {
 | 
				
			||||||
 | 
					                val value = first.substring(4)
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[0].index, true, null))
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[2].index, false, "  lda  $value"))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if(first.startsWith("ldy ") && second.startsWith("sta ") &&
 | 
				
			||||||
 | 
					            third=="tya" && fourth.startsWith("ldy ") && fifth.startsWith("sta ")
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            if(",y" !in second) {
 | 
				
			||||||
 | 
					                val value = first.substring(4)
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[0].index, true, null))
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[2].index, false, "  lda  $value"))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // THIRD SEQUENCE
 | 
				
			||||||
 | 
					        if(first.startsWith("ldx ") && second.startsWith("ldy ") && third.startsWith("sta ") &&
 | 
				
			||||||
 | 
					            fourth=="txa" && fifth=="iny" && sixth.startsWith("sta ")
 | 
				
			||||||
 | 
					        ) {
 | 
				
			||||||
 | 
					            if(",x" !in third) {
 | 
				
			||||||
 | 
					                val value = first.substring(4)
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[0].index, true, null))
 | 
				
			||||||
 | 
					                mods.add(Modification(lines[3].index, false, "  lda  $value"))
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return mods
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -11,18 +11,22 @@ fun asmsub6502ArgsEvalOrder(sub: PtAsmSub): List<Int> {
 | 
				
			|||||||
    //  1) cx16 virtual word registers,
 | 
					    //  1) cx16 virtual word registers,
 | 
				
			||||||
    //  2) paired CPU registers,
 | 
					    //  2) paired CPU registers,
 | 
				
			||||||
    //  3) single CPU registers (order Y,X,A),
 | 
					    //  3) single CPU registers (order Y,X,A),
 | 
				
			||||||
    //  4) CPU Carry status flag
 | 
					    //  4) floating point registers (FAC1, FAC2),
 | 
				
			||||||
 | 
					    //  5) CPU Carry status flag
 | 
				
			||||||
    val args = sub.parameters.withIndex()
 | 
					    val args = sub.parameters.withIndex()
 | 
				
			||||||
    val (cx16regs, args2) = args.partition { it.value.first.registerOrPair in Cx16VirtualRegisters }
 | 
					    val (cx16regs, args2) = args.partition { it.value.first.registerOrPair in Cx16VirtualRegisters }
 | 
				
			||||||
    val pairedRegisters = arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)
 | 
					    val pairedRegisters = arrayOf(RegisterOrPair.AX, RegisterOrPair.AY, RegisterOrPair.XY)
 | 
				
			||||||
    val (pairedRegs , args3) = args2.partition { it.value.first.registerOrPair in pairedRegisters }
 | 
					    val (pairedRegs , args3) = args2.partition { it.value.first.registerOrPair in pairedRegisters }
 | 
				
			||||||
    val (singleRegs, rest) = args3.partition { it.value.first.registerOrPair != null }
 | 
					    val (singleRegsMixed, rest) = args3.partition { it.value.first.registerOrPair != null }
 | 
				
			||||||
 | 
					    val (singleCpuRegs, floatRegs) = singleRegsMixed.partition {it.value.first.registerOrPair != RegisterOrPair.FAC1 && it.value.first.registerOrPair != RegisterOrPair.FAC2  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cx16regs.forEach { order += it.index }
 | 
					    cx16regs.forEach { order += it.index }
 | 
				
			||||||
    pairedRegs.forEach { order += it.index }
 | 
					    pairedRegs.forEach { order += it.index }
 | 
				
			||||||
    singleRegs.sortedBy { it.value.first.registerOrPair!!.asCpuRegister() }.asReversed().forEach { order += it.index }
 | 
					    singleCpuRegs.sortedBy { it.value.first.registerOrPair!!.asCpuRegister() }.asReversed().forEach { order += it.index }
 | 
				
			||||||
    require(rest.all { it.value.first.registerOrPair==null && it.value.first.statusflag!=null})
 | 
					    require(rest.all { it.value.first.registerOrPair==null && it.value.first.statusflag!=null})
 | 
				
			||||||
 | 
					    floatRegs.forEach { order += it.index }
 | 
				
			||||||
    rest.forEach { order += it.index }
 | 
					    rest.forEach { order += it.index }
 | 
				
			||||||
    require(order.size==sub.parameters.size)
 | 
					    require(order.size==sub.parameters.size)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return order
 | 
					    return order
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,14 @@
 | 
				
			|||||||
package prog8.codegen.cpu6502
 | 
					package prog8.codegen.cpu6502
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import prog8.code.core.*
 | 
					import prog8.code.GENERATED_LABEL_PREFIX
 | 
				
			||||||
 | 
					import prog8.code.IAssemblyProgram
 | 
				
			||||||
 | 
					import prog8.code.core.CompilationOptions
 | 
				
			||||||
 | 
					import prog8.code.core.ICompilationTarget
 | 
				
			||||||
 | 
					import prog8.code.core.IErrorReporter
 | 
				
			||||||
 | 
					import prog8.code.core.OutputType
 | 
				
			||||||
 | 
					import prog8.code.target.C128Target
 | 
				
			||||||
import prog8.code.target.C64Target
 | 
					import prog8.code.target.C64Target
 | 
				
			||||||
 | 
					import prog8.code.target.PETTarget
 | 
				
			||||||
import java.nio.file.Path
 | 
					import java.nio.file.Path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -21,15 +28,20 @@ internal class AssemblyProgram(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        val assemblerCommand: List<String>
 | 
					        val assemblerCommand: List<String>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        when (compTarget.name) {
 | 
					        fun addRemainingOptions(command: MutableList<String>, program: Path, assembly: Path): List<String> {
 | 
				
			||||||
            in setOf("c64", "c128", "cx16", "pet32") -> {
 | 
					            if(options.compTarget.additionalAssemblerOptions.isNotEmpty())
 | 
				
			||||||
 | 
					                command.addAll(options.compTarget.additionalAssemblerOptions)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            command.addAll(listOf("--output", program.toString(), assembly.toString()))
 | 
				
			||||||
 | 
					            return command
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        when(options.output) {
 | 
				
			||||||
 | 
					            OutputType.PRG -> {
 | 
				
			||||||
                // CBM machines .prg generation.
 | 
					                // CBM machines .prg generation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // add "-Wlong-branch"  to see warnings about conversion of branch instructions to jumps (default = do this silently)
 | 
					                val command = mutableListOf("64tass", "--cbm-prg", "--ascii", "--case-sensitive", "--long-branch",
 | 
				
			||||||
                val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch",
 | 
					                    "-Wall", "-Wno-implied-reg", "--no-monitor", "--dump-labels", "--vice-labels", "--labels=$viceMonListFile")
 | 
				
			||||||
                    "-Wall", // "-Wno-strict-bool", "-Werror",
 | 
					 | 
				
			||||||
                    "--dump-labels", "--vice-labels", "--labels=$viceMonListFile"
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if(options.warnSymbolShadowing)
 | 
					                if(options.warnSymbolShadowing)
 | 
				
			||||||
                    command.add("-Wshadow")
 | 
					                    command.add("-Wshadow")
 | 
				
			||||||
@@ -40,34 +52,18 @@ internal class AssemblyProgram(
 | 
				
			|||||||
                    command.add("--quiet")
 | 
					                    command.add("--quiet")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if(options.asmListfile) {
 | 
					                if(options.asmListfile) {
 | 
				
			||||||
                    command.addAll(listOf("--list=$listFile", "--no-monitor"))
 | 
					                    command.add("--list=$listFile")
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                val outFile = when (options.output) {
 | 
					                assemblerCommand = addRemainingOptions(command, prgFile, assemblyFile)
 | 
				
			||||||
                    OutputType.PRG -> {
 | 
					                if(!options.quiet)
 | 
				
			||||||
                        command.add("--cbm-prg")
 | 
					 | 
				
			||||||
                    println("\nCreating prg for target ${compTarget.name}.")
 | 
					                    println("\nCreating prg for target ${compTarget.name}.")
 | 
				
			||||||
                        prgFile
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
                    OutputType.RAW -> {
 | 
					            OutputType.XEX -> {
 | 
				
			||||||
                        command.add("--nostart")
 | 
					 | 
				
			||||||
                        println("\nCreating raw binary for target ${compTarget.name}.")
 | 
					 | 
				
			||||||
                        binFile
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    else -> throw AssemblyError("invalid output type")
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                command.addAll(listOf("--output", outFile.toString(), assemblyFile.toString()))
 | 
					 | 
				
			||||||
                assemblerCommand = command
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            "atari" -> {
 | 
					 | 
				
			||||||
                // Atari800XL .xex generation.
 | 
					                // Atari800XL .xex generation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // TODO are these options okay for atari?
 | 
					                val command = mutableListOf("64tass", "--atari-xex", "--case-sensitive", "--long-branch",
 | 
				
			||||||
                val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch",
 | 
					                    "-Wall", "-Wno-implied-reg", "--no-monitor", "--dump-labels", "--vice-labels", "--labels=$viceMonListFile")
 | 
				
			||||||
                    "-Wall", // "-Werror", "-Wno-strict-bool"
 | 
					 | 
				
			||||||
                    "--no-monitor"
 | 
					 | 
				
			||||||
                )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if(options.warnSymbolShadowing)
 | 
					                if(options.warnSymbolShadowing)
 | 
				
			||||||
                    command.add("-Wshadow")
 | 
					                    command.add("-Wshadow")
 | 
				
			||||||
@@ -80,28 +76,67 @@ internal class AssemblyProgram(
 | 
				
			|||||||
                if(options.asmListfile)
 | 
					                if(options.asmListfile)
 | 
				
			||||||
                    command.add("--list=$listFile")
 | 
					                    command.add("--list=$listFile")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                val outFile = when (options.output) {
 | 
					                assemblerCommand = addRemainingOptions(command,xexFile, assemblyFile)
 | 
				
			||||||
                    OutputType.XEX -> {
 | 
					                if(!options.quiet)
 | 
				
			||||||
                        command.add("--atari-xex")
 | 
					 | 
				
			||||||
                    println("\nCreating xex for target ${compTarget.name}.")
 | 
					                    println("\nCreating xex for target ${compTarget.name}.")
 | 
				
			||||||
                        xexFile
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            OutputType.RAW -> {
 | 
					            OutputType.RAW -> {
 | 
				
			||||||
                        command.add("--nostart")
 | 
					                // Neo6502/headerless raw program generation.
 | 
				
			||||||
 | 
					                val command = mutableListOf("64tass", "--nostart", "--case-sensitive", "--long-branch",
 | 
				
			||||||
 | 
					                    "-Wall", "-Wno-implied-reg", "--no-monitor", "--dump-labels", "--vice-labels", "--labels=$viceMonListFile")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(options.warnSymbolShadowing)
 | 
				
			||||||
 | 
					                    command.add("-Wshadow")
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    command.add("-Wno-shadow")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(options.asmQuiet)
 | 
				
			||||||
 | 
					                    command.add("--quiet")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(options.asmListfile)
 | 
				
			||||||
 | 
					                    command.add("--list=$listFile")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                assemblerCommand = addRemainingOptions(command, binFile, assemblyFile)
 | 
				
			||||||
 | 
					                if(!options.quiet)
 | 
				
			||||||
                    println("\nCreating raw binary for target ${compTarget.name}.")
 | 
					                    println("\nCreating raw binary for target ${compTarget.name}.")
 | 
				
			||||||
                        binFile
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
                    else -> throw AssemblyError("invalid output type")
 | 
					            OutputType.LIBRARY -> {
 | 
				
			||||||
                }
 | 
					                // CBM machines library (.bin) generation (with or without 2 byte load address header depending on the compilation target machine)
 | 
				
			||||||
                command.addAll(listOf("--output", outFile.toString(), assemblyFile.toString()))
 | 
					
 | 
				
			||||||
                assemblerCommand = command
 | 
					                val command = mutableListOf("64tass", "--ascii", "--case-sensitive", "--long-branch",
 | 
				
			||||||
            }
 | 
					                    "-Wall", "-Wno-implied-reg", "--no-monitor", "--dump-labels", "--vice-labels", "--labels=$viceMonListFile")
 | 
				
			||||||
            else -> throw AssemblyError("invalid compilation target")
 | 
					
 | 
				
			||||||
 | 
					                if(options.warnSymbolShadowing)
 | 
				
			||||||
 | 
					                    command.add("-Wshadow")
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    command.add("-Wno-shadow")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(options.asmQuiet)
 | 
				
			||||||
 | 
					                    command.add("--quiet")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(options.asmListfile)
 | 
				
			||||||
 | 
					                    command.add("--list=$listFile")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if(compTarget.name in listOf(C64Target.NAME, C128Target.NAME, PETTarget.NAME)) {
 | 
				
			||||||
 | 
					                    if(!options.quiet)
 | 
				
			||||||
 | 
					                        println("\nCreating binary library file with header for target ${compTarget.name}.")
 | 
				
			||||||
 | 
					                    command.add("--cbm-prg")
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    if(!options.quiet)
 | 
				
			||||||
 | 
					                        println("\nCreating binary library file without header for target ${compTarget.name}.")
 | 
				
			||||||
 | 
					                    command.add("--nostart")       // should be headerless bin, because basic has problems doing a normal LOAD"lib",8,1 - need to use BLOAD
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        val proc = ProcessBuilder(assemblerCommand).inheritIO().start()
 | 
					                assemblerCommand = addRemainingOptions(command, binFile, assemblyFile)
 | 
				
			||||||
        val result = proc.waitFor()
 | 
					            }
 | 
				
			||||||
        if (result == 0 && compTarget.name!="atari") {
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val proc = ProcessBuilder(assemblerCommand)
 | 
				
			||||||
 | 
					        if(!options.quiet)
 | 
				
			||||||
 | 
					            proc.inheritIO()
 | 
				
			||||||
 | 
					        val process = proc.start()
 | 
				
			||||||
 | 
					        val result = process.waitFor()
 | 
				
			||||||
 | 
					        if (result == 0) {
 | 
				
			||||||
            removeGeneratedLabelsFromMonlist()
 | 
					            removeGeneratedLabelsFromMonlist()
 | 
				
			||||||
            generateBreakpointList()
 | 
					            generateBreakpointList()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -109,7 +144,7 @@ internal class AssemblyProgram(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun removeGeneratedLabelsFromMonlist() {
 | 
					    private fun removeGeneratedLabelsFromMonlist() {
 | 
				
			||||||
        val pattern = Regex("""al (\w+) \S+prog8_label_.+?""")
 | 
					        val pattern = Regex("""al (\w+) \S+$GENERATED_LABEL_PREFIX.+?""")
 | 
				
			||||||
        val lines = viceMonListFile.toFile().readLines()
 | 
					        val lines = viceMonListFile.toFile().readLines()
 | 
				
			||||||
        viceMonListFile.toFile().outputStream().bufferedWriter().use {
 | 
					        viceMonListFile.toFile().outputStream().bufferedWriter().use {
 | 
				
			||||||
            for (line in lines) {
 | 
					            for (line in lines) {
 | 
				
			||||||
@@ -126,7 +161,7 @@ internal class AssemblyProgram(
 | 
				
			|||||||
        for (line in viceMonListFile.toFile().readLines()) {
 | 
					        for (line in viceMonListFile.toFile().readLines()) {
 | 
				
			||||||
            val match = pattern.matchEntire(line)
 | 
					            val match = pattern.matchEntire(line)
 | 
				
			||||||
            if (match != null)
 | 
					            if (match != null)
 | 
				
			||||||
                breakpoints.add("break \$" + match.groupValues[1])
 | 
					                breakpoints.add("break $" + match.groupValues[1])
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        val num = breakpoints.size
 | 
					        val num = breakpoints.size
 | 
				
			||||||
        breakpoints.add(0, "; breakpoint list now follows")
 | 
					        breakpoints.add(0, "; breakpoint list now follows")
 | 
				
			||||||
 
 | 
				
			|||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,40 +0,0 @@
 | 
				
			|||||||
package prog8.codegen.cpu6502
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import prog8.code.ast.IPtSubroutine
 | 
					 | 
				
			||||||
import prog8.code.ast.PtAsmSub
 | 
					 | 
				
			||||||
import prog8.code.ast.PtSub
 | 
					 | 
				
			||||||
import prog8.code.core.*
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
internal fun IPtSubroutine.returnsWhatWhere(): List<Pair<RegisterOrStatusflag, DataType>> {
 | 
					 | 
				
			||||||
    when(this) {
 | 
					 | 
				
			||||||
        is PtAsmSub -> {
 | 
					 | 
				
			||||||
            return returns
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        is PtSub -> {
 | 
					 | 
				
			||||||
            // for non-asm subroutines, determine the return registers based on the type of the return value
 | 
					 | 
				
			||||||
            return if(returntype==null)
 | 
					 | 
				
			||||||
                emptyList()
 | 
					 | 
				
			||||||
            else {
 | 
					 | 
				
			||||||
                val register = when (returntype!!) {
 | 
					 | 
				
			||||||
                    in ByteDatatypesWithBoolean -> RegisterOrStatusflag(RegisterOrPair.A, null)
 | 
					 | 
				
			||||||
                    in WordDatatypes -> RegisterOrStatusflag(RegisterOrPair.AY, null)
 | 
					 | 
				
			||||||
                    DataType.FLOAT -> RegisterOrStatusflag(RegisterOrPair.FAC1, null)
 | 
					 | 
				
			||||||
                    else -> RegisterOrStatusflag(RegisterOrPair.AY, null)
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                listOf(Pair(register, returntype!!))
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
internal fun PtSub.returnRegister(): RegisterOrStatusflag? {
 | 
					 | 
				
			||||||
    return when(returntype) {
 | 
					 | 
				
			||||||
        in ByteDatatypesWithBoolean -> RegisterOrStatusflag(RegisterOrPair.A, null)
 | 
					 | 
				
			||||||
        in WordDatatypes -> RegisterOrStatusflag(RegisterOrPair.AY, null)
 | 
					 | 
				
			||||||
        DataType.FLOAT -> RegisterOrStatusflag(RegisterOrPair.FAC1, null)
 | 
					 | 
				
			||||||
        null -> null
 | 
					 | 
				
			||||||
        else -> RegisterOrStatusflag(RegisterOrPair.AY, null)
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -33,24 +33,31 @@ internal class ForLoopsAsmGen(
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun translateForOverNonconstRange(stmt: PtForLoop, iterableDt: DataType, range: PtRange) {
 | 
					    private fun translateForOverNonconstRange(stmt: PtForLoop, iterableDt: DataType, range: PtRange) {
 | 
				
			||||||
        val loopLabel = asmgen.makeLabel("for_loop")
 | 
					        if(range.step.asConstInteger()!! < -1) {
 | 
				
			||||||
        val endLabel = asmgen.makeLabel("for_end")
 | 
					 | 
				
			||||||
        val modifiedLabel = asmgen.makeLabel("for_modified")
 | 
					 | 
				
			||||||
        val modifiedLabel2 = asmgen.makeLabel("for_modifiedb")
 | 
					 | 
				
			||||||
        asmgen.loopEndLabels.add(endLabel)
 | 
					 | 
				
			||||||
        val stepsize=range.step.asConstInteger()!!
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if(stepsize < -1) {
 | 
					 | 
				
			||||||
            val limit = range.to.asConstInteger()
 | 
					            val limit = range.to.asConstInteger()
 | 
				
			||||||
            if(limit==0)
 | 
					            if(limit==0)
 | 
				
			||||||
                throw AssemblyError("for unsigned loop variable it's not possible to count down with step != -1 from a non-const value to exactly zero due to value wrapping")
 | 
					                throw AssemblyError("for unsigned loop variable it's not possible to count down with step != -1 from a non-const value to exactly zero due to value wrapping")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        when(iterableDt) {
 | 
					        when {
 | 
				
			||||||
            DataType.ARRAY_B, DataType.ARRAY_UB -> {
 | 
					            iterableDt.isByteArray -> forOverNonconstByteRange(stmt, iterableDt, range)
 | 
				
			||||||
 | 
					            iterableDt.isWordArray && !iterableDt.isSplitWordArray -> forOverNonconstWordRange(stmt, iterableDt, range)
 | 
				
			||||||
 | 
					            else -> throw AssemblyError("range expression can only be byte or word")
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        asmgen.loopEndLabels.removeLast()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun forOverNonconstByteRange(stmt: PtForLoop, iterableDt: DataType, range: PtRange) {
 | 
				
			||||||
 | 
					        val stepsize = range.step.asConstInteger()!!
 | 
				
			||||||
 | 
					        val loopLabel = asmgen.makeLabel("for_loop")
 | 
				
			||||||
 | 
					        val endLabel = asmgen.makeLabel("for_end")
 | 
				
			||||||
 | 
					        asmgen.loopEndLabels.add(endLabel)
 | 
				
			||||||
        val varname = asmgen.asmVariableName(stmt.variable)
 | 
					        val varname = asmgen.asmVariableName(stmt.variable)
 | 
				
			||||||
                asmgen.assignExpressionToVariable(range.from, varname, ArrayToElementTypes.getValue(iterableDt))
 | 
					
 | 
				
			||||||
                if (stepsize==-1 && range.to.asConstInteger()==0) {
 | 
					        asmgen.assignExpressionToVariable(range.from, varname, iterableDt.elementType())
 | 
				
			||||||
 | 
					        when (stepsize) {
 | 
				
			||||||
 | 
					            -1 if range.to.asConstInteger()==0 -> {
 | 
				
			||||||
                // simple loop downto 0 step -1
 | 
					                // simple loop downto 0 step -1
 | 
				
			||||||
                asmgen.out(loopLabel)
 | 
					                asmgen.out(loopLabel)
 | 
				
			||||||
                asmgen.translate(stmt.statements)
 | 
					                asmgen.translate(stmt.statements)
 | 
				
			||||||
@@ -60,7 +67,7 @@ internal class ForLoopsAsmGen(
 | 
				
			|||||||
                    cmp  #255
 | 
					                    cmp  #255
 | 
				
			||||||
                    bne  $loopLabel""")
 | 
					                    bne  $loopLabel""")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
                else if (stepsize==-1 && range.to.asConstInteger()==1) {
 | 
					            -1 if range.to.asConstInteger()==1 -> {
 | 
				
			||||||
                // simple loop downto 1 step -1
 | 
					                // simple loop downto 1 step -1
 | 
				
			||||||
                asmgen.out(loopLabel)
 | 
					                asmgen.out(loopLabel)
 | 
				
			||||||
                asmgen.translate(stmt.statements)
 | 
					                asmgen.translate(stmt.statements)
 | 
				
			||||||
@@ -68,30 +75,41 @@ internal class ForLoopsAsmGen(
 | 
				
			|||||||
                    dec  $varname
 | 
					                    dec  $varname
 | 
				
			||||||
                    bne  $loopLabel""")
 | 
					                    bne  $loopLabel""")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
                else if (stepsize==1 || stepsize==-1) {
 | 
					            1, -1 -> forOverBytesRangeStepOne(range, varname, iterableDt, loopLabel, endLabel, stmt)
 | 
				
			||||||
                    // bytes array, step 1 or -1
 | 
					            else -> forOverBytesRangeStepGreaterOne(range, varname, iterableDt, loopLabel, endLabel, stmt)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun forOverBytesRangeStepOne(range: PtRange, varname: String, iterableDt: DataType, loopLabel: String, endLabel: String, forloop: PtForLoop) {
 | 
				
			||||||
 | 
					        // bytes range, step 1 or -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val stepsize = range.step.asConstInteger()!!
 | 
				
			||||||
        val incdec = if(stepsize==1) "inc" else "dec"
 | 
					        val incdec = if(stepsize==1) "inc" else "dec"
 | 
				
			||||||
                    // loop over byte range via loopvar
 | 
					
 | 
				
			||||||
                    asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A, false)
 | 
					        if(asmgen.options.romable) {
 | 
				
			||||||
 | 
					            // cannot use self-modifying code, cannot use cpu stack (because loop can be interrupted halfway)
 | 
				
			||||||
 | 
					            // so we need to store the loop end value in a newly allocated temporary variable
 | 
				
			||||||
 | 
					            val toValueVar = asmgen.createTempVarReused(iterableDt.elementType().base, false, range)
 | 
				
			||||||
 | 
					            asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A)
 | 
				
			||||||
 | 
					            asmgen.out("  sta  $toValueVar")
 | 
				
			||||||
            // pre-check for end already reached
 | 
					            // pre-check for end already reached
 | 
				
			||||||
                    if(iterableDt==DataType.ARRAY_B) {
 | 
					            if(iterableDt.isSignedByteArray) {
 | 
				
			||||||
                        asmgen.out("  sta  $modifiedLabel+1")
 | 
					 | 
				
			||||||
                if(stepsize<0) {
 | 
					                if(stepsize<0) {
 | 
				
			||||||
                    asmgen.out("""
 | 
					                    asmgen.out("""
 | 
				
			||||||
                        clc
 | 
					                        clc
 | 
				
			||||||
                        sbc  $varname
 | 
					                        sbc  $varname
 | 
				
			||||||
                        bvc  +
 | 
					                        bvc  +
 | 
				
			||||||
                                eor  #${'$'}80
 | 
					                        eor  #$80
 | 
				
			||||||
+                       bpl  $endLabel""")
 | 
					+                       bpl  $endLabel""")
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                        else
 | 
					                else {
 | 
				
			||||||
                    asmgen.out("""
 | 
					                    asmgen.out("""
 | 
				
			||||||
                        sec
 | 
					                        sec
 | 
				
			||||||
                        sbc  $varname
 | 
					                        sbc  $varname
 | 
				
			||||||
                        bvc  +
 | 
					                        bvc  +
 | 
				
			||||||
                                eor  #${'$'}80
 | 
					                        eor  #$80
 | 
				
			||||||
+                       bmi  $endLabel""")
 | 
					+                       bmi  $endLabel""")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                if(stepsize<0) {
 | 
					                if(stepsize<0) {
 | 
				
			||||||
                    asmgen.out("""
 | 
					                    asmgen.out("""
 | 
				
			||||||
@@ -100,15 +118,15 @@ internal class ForLoopsAsmGen(
 | 
				
			|||||||
                        bcs  $endLabel
 | 
					                        bcs  $endLabel
 | 
				
			||||||
+""")
 | 
					+""")
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                        else
 | 
					                else {
 | 
				
			||||||
                    asmgen.out("  cmp  $varname  |  bcc  $endLabel")
 | 
					                    asmgen.out("  cmp  $varname  |  bcc  $endLabel")
 | 
				
			||||||
                        asmgen.out("  sta  $modifiedLabel+1")
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            asmgen.out(loopLabel)
 | 
					            asmgen.out(loopLabel)
 | 
				
			||||||
                    asmgen.translate(stmt.statements)
 | 
					            asmgen.translate(forloop.statements)
 | 
				
			||||||
            asmgen.out("""
 | 
					            asmgen.out("""
 | 
				
			||||||
                lda  $varname
 | 
					                lda  $varname
 | 
				
			||||||
$modifiedLabel          cmp  #0         ; modified 
 | 
					                cmp  $toValueVar
 | 
				
			||||||
                beq  $endLabel
 | 
					                beq  $endLabel
 | 
				
			||||||
                $incdec  $varname""")
 | 
					                $incdec  $varname""")
 | 
				
			||||||
            asmgen.jmp(loopLabel)
 | 
					            asmgen.jmp(loopLabel)
 | 
				
			||||||
@@ -116,26 +134,75 @@ $modifiedLabel          cmp  #0         ; modified
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // bytes, step >= 2 or <= -2
 | 
					            // use self-modifying code to store the loop end comparison value
 | 
				
			||||||
 | 
					            val modifiedLabel = asmgen.makeLabel("for_modified")
 | 
				
			||||||
                    // loop over byte range via loopvar
 | 
					            asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A)
 | 
				
			||||||
                    asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A, false)
 | 
					 | 
				
			||||||
            // pre-check for end already reached
 | 
					            // pre-check for end already reached
 | 
				
			||||||
                    if(iterableDt==DataType.ARRAY_B) {
 | 
					            if(iterableDt.isSignedByteArray) {
 | 
				
			||||||
 | 
					                asmgen.out("  sta  $modifiedLabel+1")
 | 
				
			||||||
 | 
					                if(stepsize<0) {
 | 
				
			||||||
 | 
					                    asmgen.out("""
 | 
				
			||||||
 | 
					                        clc
 | 
				
			||||||
 | 
					                        sbc  $varname
 | 
				
			||||||
 | 
					                        bvc  +
 | 
				
			||||||
 | 
					                        eor  #$80
 | 
				
			||||||
 | 
					+                       bpl  $endLabel""")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    asmgen.out("""
 | 
				
			||||||
 | 
					                        sec
 | 
				
			||||||
 | 
					                        sbc  $varname
 | 
				
			||||||
 | 
					                        bvc  +
 | 
				
			||||||
 | 
					                        eor  #$80
 | 
				
			||||||
 | 
					+                       bmi  $endLabel""")
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                if(stepsize<0) {
 | 
				
			||||||
 | 
					                    asmgen.out("""
 | 
				
			||||||
 | 
					                        cmp  $varname
 | 
				
			||||||
 | 
					                        beq  +
 | 
				
			||||||
 | 
					                        bcs  $endLabel
 | 
				
			||||||
 | 
					+""")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                else {
 | 
				
			||||||
 | 
					                    asmgen.out("  cmp  $varname  |  bcc  $endLabel")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                asmgen.out("  sta  $modifiedLabel+1")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            asmgen.out(loopLabel)
 | 
				
			||||||
 | 
					            asmgen.translate(forloop.statements)
 | 
				
			||||||
 | 
					            asmgen.out("""
 | 
				
			||||||
 | 
					                lda  $varname
 | 
				
			||||||
 | 
					$modifiedLabel  cmp  #0         ; modified 
 | 
				
			||||||
 | 
					                beq  $endLabel
 | 
				
			||||||
 | 
					                $incdec  $varname""")
 | 
				
			||||||
 | 
					            asmgen.jmp(loopLabel)
 | 
				
			||||||
 | 
					            asmgen.out(endLabel)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun forOverBytesRangeStepGreaterOne(range: PtRange, varname: String, iterableDt: DataType, loopLabel: String, endLabel: String, forloop: PtForLoop) {
 | 
				
			||||||
 | 
					        // bytes range, step >= 2 or <= -2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val stepsize = range.step.asConstInteger()!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        val modifiedLabel = asmgen.makeLabel("for_modified")
 | 
				
			||||||
 | 
					        asmgen.assignExpressionToRegister(range.to, RegisterOrPair.A)
 | 
				
			||||||
 | 
					        // pre-check for end already reached
 | 
				
			||||||
 | 
					        if(iterableDt.isSignedByteArray) {
 | 
				
			||||||
            asmgen.out("  sta  $modifiedLabel+1")
 | 
					            asmgen.out("  sta  $modifiedLabel+1")
 | 
				
			||||||
            if(stepsize<0)
 | 
					            if(stepsize<0)
 | 
				
			||||||
                asmgen.out("""
 | 
					                asmgen.out("""
 | 
				
			||||||
                    clc
 | 
					                    clc
 | 
				
			||||||
                    sbc  $varname
 | 
					                    sbc  $varname
 | 
				
			||||||
                    bvc  +
 | 
					                    bvc  +
 | 
				
			||||||
                                eor  #${'$'}80
 | 
					                    eor  #$80
 | 
				
			||||||
+                   bpl  $endLabel""")
 | 
					+                   bpl  $endLabel""")
 | 
				
			||||||
            else
 | 
					            else
 | 
				
			||||||
                asmgen.out("""
 | 
					                asmgen.out("""
 | 
				
			||||||
                    sec
 | 
					                    sec
 | 
				
			||||||
                    sbc  $varname
 | 
					                    sbc  $varname
 | 
				
			||||||
                    bvc  +
 | 
					                    bvc  +
 | 
				
			||||||
                                eor  #${'$'}80
 | 
					                    eor  #$80
 | 
				
			||||||
+                   bmi  $endLabel""")
 | 
					+                   bmi  $endLabel""")
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            if(stepsize<0)
 | 
					            if(stepsize<0)
 | 
				
			||||||
@@ -144,12 +211,15 @@ $modifiedLabel          cmp  #0         ; modified
 | 
				
			|||||||
                    beq  +
 | 
					                    beq  +
 | 
				
			||||||
                    bcs  $endLabel
 | 
					                    bcs  $endLabel
 | 
				
			||||||
+""")
 | 
					+""")
 | 
				
			||||||
                        else
 | 
					            else {
 | 
				
			||||||
                asmgen.out("  cmp  $varname  |  bcc  $endLabel")
 | 
					                asmgen.out("  cmp  $varname  |  bcc  $endLabel")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            asmgen.out("  sta  $modifiedLabel+1")
 | 
					            asmgen.out("  sta  $modifiedLabel+1")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        asmgen.out(loopLabel)
 | 
					        asmgen.out(loopLabel)
 | 
				
			||||||
                    asmgen.translate(stmt.statements)
 | 
					        asmgen.translate(forloop.statements)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        asmgen.romableError("self-modifying code (forloop over bytes range)", forloop.position)  // TODO fix romable; there is self-modifying code below
 | 
				
			||||||
        if(stepsize>0) {
 | 
					        if(stepsize>0) {
 | 
				
			||||||
            asmgen.out("""
 | 
					            asmgen.out("""
 | 
				
			||||||
                lda  $varname
 | 
					                lda  $varname
 | 
				
			||||||
@@ -170,8 +240,12 @@ $modifiedLabel              cmp  #0     ; modified
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        asmgen.out(endLabel)
 | 
					        asmgen.out(endLabel)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
            }
 | 
					
 | 
				
			||||||
            DataType.ARRAY_W, DataType.ARRAY_UW -> {
 | 
					    private fun forOverNonconstWordRange(stmt: PtForLoop, iterableDt: DataType, range: PtRange) {
 | 
				
			||||||
 | 
					        val stepsize = range.step.asConstInteger()!!
 | 
				
			||||||
 | 
					        val loopLabel = asmgen.makeLabel("for_loop")
 | 
				
			||||||
 | 
					        val endLabel = asmgen.makeLabel("for_end")
 | 
				
			||||||
 | 
					        asmgen.loopEndLabels.add(endLabel)
 | 
				
			||||||
        val varname = asmgen.asmVariableName(stmt.variable)
 | 
					        val varname = asmgen.asmVariableName(stmt.variable)
 | 
				
			||||||
        assignLoopvarWord(stmt, range)
 | 
					        assignLoopvarWord(stmt, range)
 | 
				
			||||||
        if(stepsize==-1 && range.to.asConstInteger()==0) {
 | 
					        if(stepsize==-1 && range.to.asConstInteger()==0) {
 | 
				
			||||||
@@ -207,15 +281,62 @@ $modifiedLabel              cmp  #0     ; modified
 | 
				
			|||||||
            asmgen.jmp(loopLabel)
 | 
					            asmgen.jmp(loopLabel)
 | 
				
			||||||
            asmgen.out(endLabel)
 | 
					            asmgen.out(endLabel)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
                else if (stepsize == 1 || stepsize == -1) {
 | 
					        else if (stepsize == 1 || stepsize == -1)
 | 
				
			||||||
                    // words, step 1 or -1
 | 
					            forOverWordsRangeStepOne(range, varname, iterableDt, loopLabel, endLabel, stmt)
 | 
				
			||||||
 | 
					        else if (stepsize > 0)
 | 
				
			||||||
 | 
					            forOverWordsRangeStepGreaterOne(range, varname, iterableDt, loopLabel, endLabel, stmt)
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            forOverWordsRangeStepGreaterOneDescending(range, varname, iterableDt, loopLabel, endLabel, stmt)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun forOverWordsRangeStepOne(range: PtRange, varname: String, iterableDt: DataType, loopLabel: String, endLabel: String, forloop: PtForLoop) {
 | 
				
			||||||
 | 
					        // words range, step 1 or -1
 | 
				
			||||||
 | 
					        val stepsize = range.step.asConstInteger()!!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if(asmgen.options.romable) {
 | 
				
			||||||
 | 
					            // cannot use self-modifying code, cannot use cpu stack (because loop can be interrupted halfway)
 | 
				
			||||||
 | 
					            // so we need to store the loop end value in a newly allocated temporary variable
 | 
				
			||||||
 | 
					            val toValueVar = asmgen.createTempVarReused(iterableDt.elementType().base, false, range)
 | 
				
			||||||
 | 
					            asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
 | 
				
			||||||
 | 
					            precheckFromToWord(iterableDt, stepsize, varname, endLabel)
 | 
				
			||||||
 | 
					            asmgen.out("  sta  $toValueVar")
 | 
				
			||||||
 | 
					            asmgen.out("  sty  $toValueVar+1")
 | 
				
			||||||
 | 
					            asmgen.out(loopLabel)
 | 
				
			||||||
 | 
					            asmgen.translate(forloop.statements)
 | 
				
			||||||
 | 
					            asmgen.out("""
 | 
				
			||||||
 | 
					                lda  $varname+1
 | 
				
			||||||
 | 
					                cmp  $toValueVar+1
 | 
				
			||||||
 | 
					                bne  +
 | 
				
			||||||
 | 
					                lda  $varname
 | 
				
			||||||
 | 
					                cmp  $toValueVar
 | 
				
			||||||
 | 
					                beq  $endLabel""")
 | 
				
			||||||
 | 
					            if(stepsize==1) {
 | 
				
			||||||
 | 
					                asmgen.out("""
 | 
				
			||||||
 | 
					+                   inc  $varname
 | 
				
			||||||
 | 
					                    bne  $loopLabel
 | 
				
			||||||
 | 
					                    inc  $varname+1""")
 | 
				
			||||||
 | 
					                asmgen.jmp(loopLabel)
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                asmgen.out("""
 | 
				
			||||||
 | 
					+                   lda  $varname
 | 
				
			||||||
 | 
					                    bne  +
 | 
				
			||||||
 | 
					                    dec  $varname+1
 | 
				
			||||||
 | 
					+                   dec  $varname""")
 | 
				
			||||||
 | 
					                asmgen.jmp(loopLabel)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            asmgen.out(endLabel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            val modifiedLabel = asmgen.makeLabel("for_modified")
 | 
				
			||||||
 | 
					            val modifiedLabel2 = asmgen.makeLabel("for_modifiedb")
 | 
				
			||||||
            asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
 | 
					            asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
 | 
				
			||||||
            precheckFromToWord(iterableDt, stepsize, varname, endLabel)
 | 
					            precheckFromToWord(iterableDt, stepsize, varname, endLabel)
 | 
				
			||||||
            asmgen.out("""
 | 
					            asmgen.out("""
 | 
				
			||||||
                sty  $modifiedLabel+1
 | 
					                sty  $modifiedLabel+1
 | 
				
			||||||
                sta  $modifiedLabel2+1
 | 
					                sta  $modifiedLabel2+1
 | 
				
			||||||
$loopLabel""")
 | 
					$loopLabel""")
 | 
				
			||||||
                    asmgen.translate(stmt.statements)
 | 
					            asmgen.translate(forloop.statements)
 | 
				
			||||||
            asmgen.out("""
 | 
					            asmgen.out("""
 | 
				
			||||||
                lda  $varname+1
 | 
					                lda  $varname+1
 | 
				
			||||||
$modifiedLabel  cmp  #0    ; modified 
 | 
					$modifiedLabel  cmp  #0    ; modified 
 | 
				
			||||||
@@ -239,8 +360,13 @@ $modifiedLabel2 cmp  #0    ; modified
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
            asmgen.out(endLabel)
 | 
					            asmgen.out(endLabel)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
                else if (stepsize > 0) {
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun forOverWordsRangeStepGreaterOne(range: PtRange, varname: String, iterableDt: DataType, loopLabel: String, endLabel: String, stmt: PtForLoop) {
 | 
				
			||||||
        // (u)words, step >= 2
 | 
					        // (u)words, step >= 2
 | 
				
			||||||
 | 
					        val stepsize = range.step.asConstInteger()!!
 | 
				
			||||||
 | 
					        val modifiedLabel = asmgen.makeLabel("for_modified")
 | 
				
			||||||
 | 
					        val modifiedLabel2 = asmgen.makeLabel("for_modifiedb")
 | 
				
			||||||
        asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
 | 
					        asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
 | 
				
			||||||
        precheckFromToWord(iterableDt, stepsize, varname, endLabel)
 | 
					        precheckFromToWord(iterableDt, stepsize, varname, endLabel)
 | 
				
			||||||
        asmgen.out("""
 | 
					        asmgen.out("""
 | 
				
			||||||
@@ -249,7 +375,8 @@ $modifiedLabel2 cmp  #0    ; modified
 | 
				
			|||||||
$loopLabel""")
 | 
					$loopLabel""")
 | 
				
			||||||
        asmgen.translate(stmt.statements)
 | 
					        asmgen.translate(stmt.statements)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (iterableDt == DataType.ARRAY_UW) {
 | 
					        asmgen.romableError("self-modifying code (forloop over word range)", stmt.position)  // TODO fix romable; there is self-modifying code below
 | 
				
			||||||
 | 
					        if (iterableDt.isUnsignedWordArray) {
 | 
				
			||||||
            asmgen.out("""
 | 
					            asmgen.out("""
 | 
				
			||||||
                lda  $varname
 | 
					                lda  $varname
 | 
				
			||||||
                clc
 | 
					                clc
 | 
				
			||||||
@@ -285,17 +412,20 @@ $modifiedLabel  lda  #0   ; modified
 | 
				
			|||||||
$endLabel""")
 | 
					$endLabel""")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
                else {
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private fun forOverWordsRangeStepGreaterOneDescending(range: PtRange, varname: String, iterableDt: DataType, loopLabel: String, endLabel: String, stmt: PtForLoop) {
 | 
				
			||||||
        // (u)words, step <= -2
 | 
					        // (u)words, step <= -2
 | 
				
			||||||
 | 
					        val stepsize = range.step.asConstInteger()!!
 | 
				
			||||||
 | 
					        val modifiedLabel = asmgen.makeLabel("for_modified")
 | 
				
			||||||
 | 
					        val modifiedLabel2 = asmgen.makeLabel("for_modifiedb")
 | 
				
			||||||
        asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
 | 
					        asmgen.assignExpressionToRegister(range.to, RegisterOrPair.AY)
 | 
				
			||||||
        precheckFromToWord(iterableDt, stepsize, varname, endLabel)
 | 
					        precheckFromToWord(iterableDt, stepsize, varname, endLabel)
 | 
				
			||||||
 | 
					        asmgen.romableError("self-modifying code (forloop over words range)", stmt.position)  // TODO fix romable; there is self-modifying code below
 | 
				
			||||||
        asmgen.out("""
 | 
					        asmgen.out("""
 | 
				
			||||||
                sty  $modifiedLabel+1
 | 
					                sty  $modifiedLabel+1
 | 
				
			||||||
                sta  $modifiedLabel2+1
 | 
					                sta  $modifiedLabel2+1
 | 
				
			||||||
$loopLabel""")
 | 
					$loopLabel""")
 | 
				
			||||||
        asmgen.translate(stmt.statements)
 | 
					        asmgen.translate(stmt.statements)
 | 
				
			||||||
 | 
					 | 
				
			||||||
        asmgen.out("""
 | 
					        asmgen.out("""
 | 
				
			||||||
                lda  $varname
 | 
					                lda  $varname
 | 
				
			||||||
                sec
 | 
					                sec
 | 
				
			||||||
@@ -314,17 +444,11 @@ $modifiedLabel  sbc  #0    ; modified
 | 
				
			|||||||
+               bpl  $loopLabel                
 | 
					+               bpl  $loopLabel                
 | 
				
			||||||
$endLabel""")
 | 
					$endLabel""")
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            else -> throw AssemblyError("range expression can only be byte or word")
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        asmgen.loopEndLabels.removeLast()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private fun precheckFromToWord(iterableDt: DataType, stepsize: Int, fromVar: String, endLabel: String) {
 | 
					    private fun precheckFromToWord(iterableDt: DataType, stepsize: Int, fromVar: String, endLabel: String) {
 | 
				
			||||||
        // pre-check for end already reached.
 | 
					        // pre-check for end already reached.
 | 
				
			||||||
        // 'to' is in AY, do NOT clobber this!
 | 
					        // 'to' is in AY, do NOT clobber this!
 | 
				
			||||||
        if(iterableDt==DataType.ARRAY_W) {
 | 
					        if(iterableDt.isSignedWordArray) {
 | 
				
			||||||
            if(stepsize<0)
 | 
					            if(stepsize<0)
 | 
				
			||||||
                asmgen.out("""
 | 
					                asmgen.out("""
 | 
				
			||||||
                    sta  P8ZP_SCRATCH_W2        ; to
 | 
					                    sta  P8ZP_SCRATCH_W2        ; to
 | 
				
			||||||
@@ -334,7 +458,7 @@ $endLabel""")
 | 
				
			|||||||
                    lda  $fromVar+1
 | 
					                    lda  $fromVar+1
 | 
				
			||||||
                    sbc  P8ZP_SCRATCH_W2+1
 | 
					                    sbc  P8ZP_SCRATCH_W2+1
 | 
				
			||||||
                    bvc  +
 | 
					                    bvc  +
 | 
				
			||||||
	                eor  #${'$'}80
 | 
					                    eor  #$80
 | 
				
			||||||
+                   bmi  $endLabel
 | 
					+                   bmi  $endLabel
 | 
				
			||||||
                    lda  P8ZP_SCRATCH_W2
 | 
					                    lda  P8ZP_SCRATCH_W2
 | 
				
			||||||
                    ldy  P8ZP_SCRATCH_W2+1""")
 | 
					                    ldy  P8ZP_SCRATCH_W2+1""")
 | 
				
			||||||
@@ -345,7 +469,7 @@ $endLabel""")
 | 
				
			|||||||
                    tya
 | 
					                    tya
 | 
				
			||||||
                    sbc  $fromVar+1
 | 
					                    sbc  $fromVar+1
 | 
				
			||||||
                    bvc  +
 | 
					                    bvc  +
 | 
				
			||||||
	                eor  #${'$'}80
 | 
					                    eor  #$80
 | 
				
			||||||
+                   bmi  $endLabel
 | 
					+                   bmi  $endLabel
 | 
				
			||||||
                    lda  P8ZP_SCRATCH_REG""")
 | 
					                    lda  P8ZP_SCRATCH_REG""")
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
@@ -376,38 +500,57 @@ $endLabel""")
 | 
				
			|||||||
        val endLabel = asmgen.makeLabel("for_end")
 | 
					        val endLabel = asmgen.makeLabel("for_end")
 | 
				
			||||||
        asmgen.loopEndLabels.add(endLabel)
 | 
					        asmgen.loopEndLabels.add(endLabel)
 | 
				
			||||||
        val iterableName = asmgen.asmVariableName(ident)
 | 
					        val iterableName = asmgen.asmVariableName(ident)
 | 
				
			||||||
        val numElements = when(val symbol = asmgen.symbolTable.lookup(ident.name)) {
 | 
					        val numElements: UInt = when(val symbol = asmgen.symbolTable.lookup(ident.name)) {
 | 
				
			||||||
            is StStaticVariable -> symbol.length!!
 | 
					            is StStaticVariable -> symbol.length!!
 | 
				
			||||||
            is StMemVar -> symbol.length!!
 | 
					            is StMemVar -> symbol.length!!
 | 
				
			||||||
            else -> 0
 | 
					            else -> 0u
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        when(iterableDt) {
 | 
					
 | 
				
			||||||
            DataType.STR -> {
 | 
					        fun iterateStrings() {
 | 
				
			||||||
 | 
					            if(asmgen.options.romable) {
 | 
				
			||||||
 | 
					                val indexVar = asmgen.createTempVarReused(BaseDataType.UBYTE, false, stmt)
 | 
				
			||||||
                asmgen.out("""
 | 
					                asmgen.out("""
 | 
				
			||||||
                    lda  #<$iterableName
 | 
					                        ldy  #0
 | 
				
			||||||
                    ldy  #>$iterableName
 | 
					                        sty  $indexVar
 | 
				
			||||||
                    sta  $loopLabel+1
 | 
					$loopLabel              lda  $iterableName,y
 | 
				
			||||||
                    sty  $loopLabel+2
 | 
					 | 
				
			||||||
$loopLabel          lda  ${65535.toHex()}       ; modified
 | 
					 | 
				
			||||||
                        beq  $endLabel
 | 
					                        beq  $endLabel
 | 
				
			||||||
                        sta  ${asmgen.asmVariableName(stmt.variable)}""")
 | 
					                        sta  ${asmgen.asmVariableName(stmt.variable)}""")
 | 
				
			||||||
                asmgen.translate(stmt.statements)
 | 
					                asmgen.translate(stmt.statements)
 | 
				
			||||||
                asmgen.out("""
 | 
					                asmgen.out("""
 | 
				
			||||||
                    inc  $loopLabel+1
 | 
					                        inc  $indexVar
 | 
				
			||||||
                    bne  $loopLabel
 | 
					                        ldy  $indexVar
 | 
				
			||||||
                    inc  $loopLabel+2
 | 
					 | 
				
			||||||
                        bne  $loopLabel
 | 
					                        bne  $loopLabel
 | 
				
			||||||
$endLabel""")
 | 
					$endLabel""")
 | 
				
			||||||
            }
 | 
					            } else {
 | 
				
			||||||
            DataType.ARRAY_UB, DataType.ARRAY_B, DataType.ARRAY_BOOL -> {
 | 
					 | 
				
			||||||
                val indexVar = asmgen.makeLabel("for_index")
 | 
					                val indexVar = asmgen.makeLabel("for_index")
 | 
				
			||||||
                asmgen.out("""
 | 
					                asmgen.out("""
 | 
				
			||||||
                        ldy  #0
 | 
					                        ldy  #0
 | 
				
			||||||
 | 
					                        sty  $indexVar
 | 
				
			||||||
 | 
					$loopLabel              lda  $iterableName,y
 | 
				
			||||||
 | 
					                        beq  $endLabel
 | 
				
			||||||
 | 
					                        sta  ${asmgen.asmVariableName(stmt.variable)}""")
 | 
				
			||||||
 | 
					                asmgen.translate(stmt.statements)
 | 
				
			||||||
 | 
					                asmgen.out("""
 | 
				
			||||||
 | 
					                        inc  $indexVar
 | 
				
			||||||
 | 
					                        ldy  $indexVar
 | 
				
			||||||
 | 
					                        bne  $loopLabel
 | 
				
			||||||
 | 
					$indexVar   .byte  0                        
 | 
				
			||||||
 | 
					$endLabel""")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        fun iterateBytes() {
 | 
				
			||||||
 | 
					            val indexVar = if(asmgen.options.romable)
 | 
				
			||||||
 | 
					                asmgen.createTempVarReused(iterableDt.elementType().base, false, stmt)
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                asmgen.makeLabel("for_index")
 | 
				
			||||||
 | 
					            asmgen.out("""
 | 
				
			||||||
 | 
					                    ldy  #0
 | 
				
			||||||
$loopLabel          sty  $indexVar
 | 
					$loopLabel          sty  $indexVar
 | 
				
			||||||
                    lda  $iterableName,y
 | 
					                    lda  $iterableName,y
 | 
				
			||||||
                    sta  ${asmgen.asmVariableName(stmt.variable)}""")
 | 
					                    sta  ${asmgen.asmVariableName(stmt.variable)}""")
 | 
				
			||||||
            asmgen.translate(stmt.statements)
 | 
					            asmgen.translate(stmt.statements)
 | 
				
			||||||
                if(numElements<=255) {
 | 
					            if(numElements<=255u) {
 | 
				
			||||||
                asmgen.out("""
 | 
					                asmgen.out("""
 | 
				
			||||||
                        ldy  $indexVar
 | 
					                        ldy  $indexVar
 | 
				
			||||||
                        iny
 | 
					                        iny
 | 
				
			||||||
@@ -422,8 +565,9 @@ $loopLabel          sty  $indexVar
 | 
				
			|||||||
                        bne  $loopLabel
 | 
					                        bne  $loopLabel
 | 
				
			||||||
                        beq  $endLabel""")
 | 
					                        beq  $endLabel""")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
                if(numElements>=16) {
 | 
					            if(!asmgen.options.romable) {
 | 
				
			||||||
                    // allocate index var on ZP if possible
 | 
					                if(numElements>=16u) {
 | 
				
			||||||
 | 
					                    // allocate index var on ZP if possible, otherwise inline
 | 
				
			||||||
                    val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
 | 
					                    val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
 | 
				
			||||||
                    result.fold(
 | 
					                    result.fold(
 | 
				
			||||||
                        success = { (address, _, _)-> asmgen.out("""$indexVar = $address  ; auto zp UBYTE""") },
 | 
					                        success = { (address, _, _)-> asmgen.out("""$indexVar = $address  ; auto zp UBYTE""") },
 | 
				
			||||||
@@ -432,51 +576,15 @@ $loopLabel          sty  $indexVar
 | 
				
			|||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    asmgen.out("$indexVar    .byte  0")
 | 
					                    asmgen.out("$indexVar    .byte  0")
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                asmgen.out(endLabel)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            DataType.ARRAY_W, DataType.ARRAY_UW -> {
 | 
					 | 
				
			||||||
                val length = numElements * 2
 | 
					 | 
				
			||||||
                val indexVar = asmgen.makeLabel("for_index")
 | 
					 | 
				
			||||||
                val loopvarName = asmgen.asmVariableName(stmt.variable)
 | 
					 | 
				
			||||||
                asmgen.out("""
 | 
					 | 
				
			||||||
                    ldy  #0
 | 
					 | 
				
			||||||
$loopLabel          sty  $indexVar
 | 
					 | 
				
			||||||
                    lda  $iterableName,y
 | 
					 | 
				
			||||||
                    sta  $loopvarName
 | 
					 | 
				
			||||||
                    lda  $iterableName+1,y
 | 
					 | 
				
			||||||
                    sta  $loopvarName+1""")
 | 
					 | 
				
			||||||
                asmgen.translate(stmt.statements)
 | 
					 | 
				
			||||||
                if(length<=127) {
 | 
					 | 
				
			||||||
                    asmgen.out("""
 | 
					 | 
				
			||||||
                        ldy  $indexVar
 | 
					 | 
				
			||||||
                        iny
 | 
					 | 
				
			||||||
                        iny
 | 
					 | 
				
			||||||
                        cpy  #$length
 | 
					 | 
				
			||||||
                        beq  $endLabel
 | 
					 | 
				
			||||||
                        bne  $loopLabel""")
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    // length is 128 words, 256 bytes
 | 
					 | 
				
			||||||
                    asmgen.out("""
 | 
					 | 
				
			||||||
                        ldy  $indexVar
 | 
					 | 
				
			||||||
                        iny
 | 
					 | 
				
			||||||
                        iny
 | 
					 | 
				
			||||||
                        bne  $loopLabel
 | 
					 | 
				
			||||||
                        beq  $endLabel""")
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
                if(length>=16) {
 | 
					 | 
				
			||||||
                    // allocate index var on ZP if possible
 | 
					 | 
				
			||||||
                    val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
 | 
					 | 
				
			||||||
                    result.fold(
 | 
					 | 
				
			||||||
                        success = { (address,_,_)-> asmgen.out("""$indexVar = $address  ; auto zp UBYTE""") },
 | 
					 | 
				
			||||||
                        failure = { asmgen.out("$indexVar    .byte  0") }
 | 
					 | 
				
			||||||
                    )
 | 
					 | 
				
			||||||
                } else {
 | 
					 | 
				
			||||||
                    asmgen.out("$indexVar    .byte  0")
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            asmgen.out(endLabel)
 | 
					            asmgen.out(endLabel)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
            DataType.ARRAY_UW_SPLIT, DataType.ARRAY_W_SPLIT -> {
 | 
					
 | 
				
			||||||
                val indexVar = asmgen.makeLabel("for_index")
 | 
					        fun iterateSplitWords() {
 | 
				
			||||||
 | 
					            val indexVar = if(asmgen.options.romable)
 | 
				
			||||||
 | 
					                asmgen.createTempVarReused(BaseDataType.UBYTE, false, stmt)
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                asmgen.makeLabel("for_index")
 | 
				
			||||||
            val loopvarName = asmgen.asmVariableName(stmt.variable)
 | 
					            val loopvarName = asmgen.asmVariableName(stmt.variable)
 | 
				
			||||||
            asmgen.out("""
 | 
					            asmgen.out("""
 | 
				
			||||||
                    ldy  #0
 | 
					                    ldy  #0
 | 
				
			||||||
@@ -486,7 +594,7 @@ $loopLabel          sty  $indexVar
 | 
				
			|||||||
                    lda  ${iterableName}_msb,y
 | 
					                    lda  ${iterableName}_msb,y
 | 
				
			||||||
                    sta  $loopvarName+1""")
 | 
					                    sta  $loopvarName+1""")
 | 
				
			||||||
            asmgen.translate(stmt.statements)
 | 
					            asmgen.translate(stmt.statements)
 | 
				
			||||||
                if(numElements<=255) {
 | 
					            if(numElements<=255u) {
 | 
				
			||||||
                asmgen.out("""
 | 
					                asmgen.out("""
 | 
				
			||||||
                        ldy  $indexVar
 | 
					                        ldy  $indexVar
 | 
				
			||||||
                        iny
 | 
					                        iny
 | 
				
			||||||
@@ -501,21 +609,106 @@ $loopLabel          sty  $indexVar
 | 
				
			|||||||
                        bne  $loopLabel
 | 
					                        bne  $loopLabel
 | 
				
			||||||
                        beq  $endLabel""")
 | 
					                        beq  $endLabel""")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
                if(numElements>=16) {
 | 
					            if(!asmgen.options.romable) {
 | 
				
			||||||
                    // allocate index var on ZP if possible
 | 
					                if(numElements>=16u) {
 | 
				
			||||||
 | 
					                    // allocate index var on ZP if possible, otherwise inline
 | 
				
			||||||
                    val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
 | 
					                    val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
 | 
				
			||||||
                    result.fold(
 | 
					                    result.fold(
 | 
				
			||||||
                        success = { (address,_,_)-> asmgen.out("""$indexVar = $address  ; auto zp UBYTE""") },
 | 
					                        success = { (address, _, _)-> asmgen.out("""$indexVar = $address  ; auto zp UBYTE""") },
 | 
				
			||||||
                        failure = { asmgen.out("$indexVar    .byte  0") }
 | 
					                        failure = { asmgen.out("$indexVar    .byte  0") }
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    asmgen.out("$indexVar    .byte  0")
 | 
					                    asmgen.out("$indexVar    .byte  0")
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
            asmgen.out(endLabel)
 | 
					            asmgen.out(endLabel)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
            DataType.ARRAY_F -> {
 | 
					
 | 
				
			||||||
                throw AssemblyError("for loop with floating point variables is not supported")
 | 
					        fun iterateWords(actuallyLongs: Boolean = false) {
 | 
				
			||||||
 | 
					            val indexVar = if(asmgen.options.romable)
 | 
				
			||||||
 | 
					                asmgen.createTempVarReused(BaseDataType.UBYTE, false, stmt)
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					                asmgen.makeLabel("for_index")
 | 
				
			||||||
 | 
					            val loopvarName = asmgen.asmVariableName(stmt.variable)
 | 
				
			||||||
 | 
					            asmgen.out("""
 | 
				
			||||||
 | 
					                    ldy  #0
 | 
				
			||||||
 | 
					$loopLabel          sty  $indexVar
 | 
				
			||||||
 | 
					                    lda  $iterableName,y
 | 
				
			||||||
 | 
					                    sta  $loopvarName
 | 
				
			||||||
 | 
					                    lda  $iterableName+1,y
 | 
				
			||||||
 | 
					                    sta  $loopvarName+1""")
 | 
				
			||||||
 | 
					            if(actuallyLongs) {
 | 
				
			||||||
 | 
					                asmgen.out("""
 | 
				
			||||||
 | 
					                    lda  $iterableName+2,y
 | 
				
			||||||
 | 
					                    sta  $loopvarName+2
 | 
				
			||||||
 | 
					                    lda  $iterableName+3,y
 | 
				
			||||||
 | 
					                    sta  $loopvarName+3""")
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            asmgen.translate(stmt.statements)
 | 
				
			||||||
 | 
					            if(numElements<=127u) {
 | 
				
			||||||
 | 
					                if(actuallyLongs) {
 | 
				
			||||||
 | 
					                    asmgen.out("""
 | 
				
			||||||
 | 
					                        ldy  $indexVar
 | 
				
			||||||
 | 
					                        iny
 | 
				
			||||||
 | 
					                        iny
 | 
				
			||||||
 | 
					                        iny
 | 
				
			||||||
 | 
					                        iny
 | 
				
			||||||
 | 
					                        cpy  #${numElements*4u}
 | 
				
			||||||
 | 
					                        beq  $endLabel
 | 
				
			||||||
 | 
					                        bne  $loopLabel""")
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    asmgen.out("""
 | 
				
			||||||
 | 
					                        ldy  $indexVar
 | 
				
			||||||
 | 
					                        iny
 | 
				
			||||||
 | 
					                        iny
 | 
				
			||||||
 | 
					                        cpy  #${numElements*2u}
 | 
				
			||||||
 | 
					                        beq  $endLabel
 | 
				
			||||||
 | 
					                        bne  $loopLabel""")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                if(actuallyLongs) {
 | 
				
			||||||
 | 
					                    // array size is 64 longs, 256 bytes
 | 
				
			||||||
 | 
					                    asmgen.out("""
 | 
				
			||||||
 | 
					                        ldy  $indexVar
 | 
				
			||||||
 | 
					                        iny
 | 
				
			||||||
 | 
					                        iny
 | 
				
			||||||
 | 
					                        iny
 | 
				
			||||||
 | 
					                        iny
 | 
				
			||||||
 | 
					                        bne  $loopLabel
 | 
				
			||||||
 | 
					                        beq  $endLabel""")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    // array size is 128 words, 256 bytes
 | 
				
			||||||
 | 
					                    asmgen.out("""
 | 
				
			||||||
 | 
					                        ldy  $indexVar
 | 
				
			||||||
 | 
					                        iny
 | 
				
			||||||
 | 
					                        iny
 | 
				
			||||||
 | 
					                        bne  $loopLabel
 | 
				
			||||||
 | 
					                        beq  $endLabel""")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if(!asmgen.options.romable) {
 | 
				
			||||||
 | 
					                if(numElements>=16u) {
 | 
				
			||||||
 | 
					                    // allocate index var on ZP if possible, otherwise inline
 | 
				
			||||||
 | 
					                    val result = zeropage.allocate(indexVar, DataType.UBYTE, null, stmt.position, asmgen.errors)
 | 
				
			||||||
 | 
					                    result.fold(
 | 
				
			||||||
 | 
					                        success = { (address, _, _)-> asmgen.out("""$indexVar = $address  ; auto zp UBYTE""") },
 | 
				
			||||||
 | 
					                        failure = { asmgen.out("$indexVar    .byte  0") }
 | 
				
			||||||
 | 
					                    )
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    asmgen.out("$indexVar    .byte  0")
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            asmgen.out(endLabel)
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        when {
 | 
				
			||||||
 | 
					            iterableDt.isString -> iterateStrings()
 | 
				
			||||||
 | 
					            iterableDt.isByteArray || iterableDt.isBoolArray -> iterateBytes()
 | 
				
			||||||
 | 
					            iterableDt.isSplitWordArray -> iterateSplitWords()
 | 
				
			||||||
 | 
					            iterableDt.isWordArray -> iterateWords()
 | 
				
			||||||
 | 
					            iterableDt.isLongArray -> iterateWords(true)
 | 
				
			||||||
 | 
					            iterableDt.isFloatArray -> throw AssemblyError("for loop with floating point variables is not supported")
 | 
				
			||||||
            else -> throw AssemblyError("can't iterate over $iterableDt")
 | 
					            else -> throw AssemblyError("can't iterate over $iterableDt")
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        asmgen.loopEndLabels.removeLast()
 | 
					        asmgen.loopEndLabels.removeLast()
 | 
				
			||||||
@@ -524,12 +717,12 @@ $loopLabel          sty  $indexVar
 | 
				
			|||||||
    private fun translateForOverConstRange(stmt: PtForLoop, iterableDt: DataType, range: IntProgression) {
 | 
					    private fun translateForOverConstRange(stmt: PtForLoop, iterableDt: DataType, range: IntProgression) {
 | 
				
			||||||
        if (range.isEmpty() || range.step==0)
 | 
					        if (range.isEmpty() || range.step==0)
 | 
				
			||||||
            throw AssemblyError("empty range or step 0")
 | 
					            throw AssemblyError("empty range or step 0")
 | 
				
			||||||
        if(iterableDt==DataType.ARRAY_B || iterableDt==DataType.ARRAY_UB) {
 | 
					        if(iterableDt.isByteArray) {
 | 
				
			||||||
            if(range.last==range.first) return translateForSimpleByteRangeAsc(stmt, range)
 | 
					            if(range.last==range.first) return translateForSimpleByteRangeAsc(stmt, range)
 | 
				
			||||||
            if(range.step==1 && range.last>range.first) return translateForSimpleByteRangeAsc(stmt, range)
 | 
					            if(range.step==1 && range.last>range.first) return translateForSimpleByteRangeAsc(stmt, range)
 | 
				
			||||||
            if(range.step==-1 && range.last<range.first) return translateForSimpleByteRangeDesc(stmt, range, iterableDt==DataType.ARRAY_UB)
 | 
					            if(range.step==-1 && range.last<range.first) return translateForSimpleByteRangeDesc(stmt, range, iterableDt.isUnsignedByteArray)
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        else if(iterableDt==DataType.ARRAY_W || iterableDt==DataType.ARRAY_UW) {
 | 
					        else if(iterableDt.isWordArray) {
 | 
				
			||||||
            if(range.last==range.first) return translateForSimpleWordRangeAsc(stmt, range)
 | 
					            if(range.last==range.first) return translateForSimpleWordRangeAsc(stmt, range)
 | 
				
			||||||
            if(range.step==1 && range.last>range.first) return translateForSimpleWordRangeAsc(stmt, range)
 | 
					            if(range.step==1 && range.last>range.first) return translateForSimpleWordRangeAsc(stmt, range)
 | 
				
			||||||
            if(range.step==-1 && range.last<range.first) return translateForSimpleWordRangeDesc(stmt, range)
 | 
					            if(range.step==-1 && range.last<range.first) return translateForSimpleWordRangeDesc(stmt, range)
 | 
				
			||||||
@@ -539,8 +732,8 @@ $loopLabel          sty  $indexVar
 | 
				
			|||||||
        val loopLabel = asmgen.makeLabel("for_loop")
 | 
					        val loopLabel = asmgen.makeLabel("for_loop")
 | 
				
			||||||
        val endLabel = asmgen.makeLabel("for_end")
 | 
					        val endLabel = asmgen.makeLabel("for_end")
 | 
				
			||||||
        asmgen.loopEndLabels.add(endLabel)
 | 
					        asmgen.loopEndLabels.add(endLabel)
 | 
				
			||||||
        when(iterableDt) {
 | 
					        when {
 | 
				
			||||||
            DataType.ARRAY_B, DataType.ARRAY_UB -> {
 | 
					            iterableDt.isByteArray -> {
 | 
				
			||||||
                // loop over byte range via loopvar, step >= 2 or <= -2
 | 
					                // loop over byte range via loopvar, step >= 2 or <= -2
 | 
				
			||||||
                val varname = asmgen.asmVariableName(stmt.variable)
 | 
					                val varname = asmgen.asmVariableName(stmt.variable)
 | 
				
			||||||
                asmgen.out("""
 | 
					                asmgen.out("""
 | 
				
			||||||
@@ -605,7 +798,7 @@ $loopLabel""")
 | 
				
			|||||||
                }
 | 
					                }
 | 
				
			||||||
                asmgen.out(endLabel)
 | 
					                asmgen.out(endLabel)
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            DataType.ARRAY_W, DataType.ARRAY_UW -> {
 | 
					            iterableDt.isWordArray && !iterableDt.isSplitWordArray -> {
 | 
				
			||||||
                // loop over word range via loopvar, step >= 2 or <= -2
 | 
					                // loop over word range via loopvar, step >= 2 or <= -2
 | 
				
			||||||
                val varname = asmgen.asmVariableName(stmt.variable)
 | 
					                val varname = asmgen.asmVariableName(stmt.variable)
 | 
				
			||||||
                when (range.step) {
 | 
					                when (range.step) {
 | 
				
			||||||
 
 | 
				
			|||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user