mirror of
				https://github.com/KevinMidboe/linguist.git
				synced 2025-10-29 17:50:22 +00:00 
			
		
		
		
	Compare commits
	
		
			1029 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | 32b07a4e10 | ||
|  | 8890c57681 | ||
|  | de188126fb | ||
|  | 97a1adcef1 | ||
|  | ffbe95d6e5 | ||
|  | d54f86ae58 | ||
|  | 92ace440b9 | ||
|  | d5ee477d3b | ||
|  | 6e8152c423 | ||
|  | 8149356668 | ||
|  | 806e30d70f | ||
|  | 299ec8f8ea | ||
|  | f6fbd18bd5 | ||
|  | ecd30d3ccf | ||
|  | 228d89649a | ||
|  | 751360ecf1 | ||
|  | d9ed216092 | ||
|  | 18a3ef9e5e | ||
|  | e7b670c5de | ||
|  | 114fabd29a | ||
|  | 0946791434 | ||
|  | 06bcdba9c4 | ||
|  | 1dbbcb73e7 | ||
|  | f2cd75332c | ||
|  | 2cd7579e21 | ||
|  | d9daae176e | ||
|  | 20814ec533 | ||
|  | 9d8ab16a38 | ||
|  | 49c2793bf5 | ||
|  | 20aee11cea | ||
|  | e8cf750e18 | ||
|  | 21f56744d4 | ||
|  | 02aeb4f895 | ||
|  | f9de16fbd2 | ||
|  | abe002f30c | ||
|  | e5ae6fb00d | ||
|  | a0a8dd8897 | ||
|  | e00f073726 | ||
|  | 1a9ee8e187 | ||
|  | 213fce00e0 | ||
|  | 380739b209 | ||
|  | 36322f8ac0 | ||
|  | 57d1ec7733 | ||
|  | 648c6d4547 | ||
|  | 6ab5870b59 | ||
|  | 7dbe2bb774 | ||
|  | 163a039e0d | ||
|  | 9595e2ba7e | ||
|  | a696e3a7a2 | ||
|  | ebabcfc84f | ||
|  | 8336dc33e4 | ||
|  | 5f22bf225c | ||
|  | 8eee8ad9cf | ||
|  | 24743985e4 | ||
|  | 94fba197d1 | ||
|  | 3504a36c3e | ||
|  | c8038d1c80 | ||
|  | 8ba8b48caf | ||
|  | 92d0c1f3b7 | ||
|  | d4186bd34a | ||
|  | 008ba9e23f | ||
|  | fd707ddf7e | ||
|  | f258e4940d | ||
|  | a7b8e38bf3 | ||
|  | b65129a8e1 | ||
|  | b6a9993c97 | ||
|  | 9c044c5bd0 | ||
|  | 6b0783936f | ||
|  | 2a66b754c2 | ||
|  | 460443b3c8 | ||
|  | cd99ab2d6e | ||
|  | b2cb74cabf | ||
|  | 6d07302963 | ||
|  | d831205f6a | ||
|  | a9b9e6216b | ||
|  | 3ba090de7e | ||
|  | c105208481 | ||
|  | 0c9e14eeff | ||
|  | 2a8a5cdca9 | ||
|  | 1f91acbd9d | ||
|  | 6f8278aa79 | ||
|  | 3e48a84cf1 | ||
|  | 31728a3a78 | ||
|  | e56a2ed6ad | ||
|  | 35aa57657b | ||
|  | 423c8865bd | ||
|  | 55ecc5f7eb | ||
|  | 6aae7882df | ||
|  | 240fcec3ce | ||
|  | 170c1d4ee8 | ||
|  | 38f0a71ea3 | ||
|  | 62936dc6b5 | ||
|  | fb9c784f4f | ||
|  | 89477ed2fa | ||
|  | 844679dcbe | ||
|  | cd743332f4 | ||
|  | 47843e7e78 | ||
|  | 85957ecf56 | ||
|  | 4232b04571 | ||
|  | 34f717526a | ||
|  | b0b94182a2 | ||
|  | 843e196f00 | ||
|  | 63661dfc6e | ||
|  | f100dc91c2 | ||
|  | fd9d63d605 | ||
|  | 5c21c35875 | ||
|  | 370d55fd74 | ||
|  | 0fcc26f778 | ||
|  | 8dd2ddcbf7 | ||
|  | 037857623d | ||
|  | d7b19d577b | ||
|  | c70048a3e2 | ||
|  | a1884ca261 | ||
|  | e452291314 | ||
|  | 6d51117a91 | ||
|  | 848a1cc1e5 | ||
|  | 9092dfdc7f | ||
|  | d7fe0cc5c7 | ||
|  | 15ec37d4bc | ||
|  | 43cc701ac3 | ||
|  | 7cb8357f73 | ||
|  | 4b46bcf649 | ||
|  | a954a6465e | ||
|  | afb6041104 | ||
|  | 4b28fdbc4d | ||
|  | b8a5e8505a | ||
|  | 3087d640a3 | ||
|  | e87b89ab5b | ||
|  | 7aabc6a5ad | ||
|  | 5cc053694a | ||
|  | 653314448c | ||
|  | 4f14db10ea | ||
|  | 98e348ba5f | ||
|  | a69b20c1a4 | ||
|  | 9275e5240f | ||
|  | 7dcc3b3edf | ||
|  | 6e872c11b6 | ||
|  | e5b6001759 | ||
|  | 769f1b8658 | ||
|  | 5814b61356 | ||
|  | 8a6d7f67ed | ||
|  | bcb016a938 | ||
|  | 065c6c02a8 | ||
|  | f7386fcd72 | ||
|  | df703ef997 | ||
|  | 9f6c421d91 | ||
|  | 91370ae955 | ||
|  | ffc0be191e | ||
|  | 6e9f6da2a2 | ||
|  | 48f2949d69 | ||
|  | baa3cba0fc | ||
|  | eb54a92328 | ||
|  | ce1e2441f4 | ||
|  | c8cb7b7cab | ||
|  | 7baa130d8d | ||
|  | 332d97b57f | ||
|  | 9c0dbdd48e | ||
|  | bec0052065 | ||
|  | 5010f32421 | ||
|  | ded4672ccc | ||
|  | 03bb48cf28 | ||
|  | e71eefe8fc | ||
|  | c203781e1b | ||
|  | 7a2be16d77 | ||
|  | 77126e9e17 | ||
|  | d1d5c61df5 | ||
|  | 09323c8bbc | ||
|  | ac9f82544a | ||
|  | 2e4e602787 | ||
|  | 9d0ba5801b | ||
|  | 0cd7d85ec4 | ||
|  | b0f674e511 | ||
|  | 2b411aad90 | ||
|  | 1c6483a499 | ||
|  | 6edf4498ce | ||
|  | b160a39678 | ||
|  | 86b4de89bd | ||
|  | a35d9a8d29 | ||
|  | 8012876d5e | ||
|  | 2e3e8c5b89 | ||
|  | 5284608942 | ||
|  | ea2c7d8b27 | ||
|  | b0db064d09 | ||
|  | 3ff1e38f6c | ||
|  | b533b682d5 | ||
|  | f59cf24a82 | ||
|  | f87436d499 | ||
|  | 178d4756ef | ||
|  | 5152bd7124 | ||
|  | b5015b6cc7 | ||
|  | 097900a327 | ||
|  | 1d2a6c38c7 | ||
|  | cc87ceb0d5 | ||
|  | a38f77683b | ||
|  | d8da05cde2 | ||
|  | 554b5bfe7f | ||
|  | 86aa4c3f3d | ||
|  | 19b8721225 | ||
|  | 0cb1ebc41e | ||
|  | c7c4883f49 | ||
|  | d8b4d4639c | ||
|  | ebe45e6f37 | ||
|  | cb016f8439 | ||
|  | 92212d2652 | ||
|  | 950882be78 | ||
|  | 036855072e | ||
|  | 29bbf50900 | ||
|  | ca59303dba | ||
|  | e21f35039b | ||
|  | f2b377fae8 | ||
|  | 24a36bf4bb | ||
|  | 3284450dc4 | ||
|  | ea9d326819 | ||
|  | 4cc679c1e5 | ||
|  | c49ce55714 | ||
|  | 9d4b5416a5 | ||
|  | 5a59ecbc2a | ||
|  | 82285df54b | ||
|  | e67c1789b8 | ||
|  | 015af19eaf | ||
|  | 156985ed52 | ||
|  | 71d1bd75c0 | ||
|  | 8e7c9c4bc4 | ||
|  | 7b7236fe30 | ||
|  | 55d997f43a | ||
|  | 1829b38339 | ||
|  | e4c28e12cf | ||
|  | 066cf45f4a | ||
|  | ac32b09a6b | ||
|  | 92296f4b4b | ||
|  | 3b4d2499eb | ||
|  | f38e15790e | ||
|  | b67c2bc2b2 | ||
|  | 393c9b759e | ||
|  | 54a7cf6785 | ||
|  | 1cf7a6389c | ||
|  | c204d7c297 | ||
|  | 5932f5f273 | ||
|  | 98977c87db | ||
|  | ff457af2d4 | ||
|  | 0e86ab9044 | ||
|  | 3d39e842ec | ||
|  | 16c1aa2845 | ||
|  | d0cf883558 | ||
|  | 64e4830aad | ||
|  | 0c47f2af75 | ||
|  | 14c5d8c95a | ||
|  | 6850499056 | ||
|  | 9288f784a1 | ||
|  | dab75f6f97 | ||
|  | 4a017d9033 | ||
|  | 6f896d988f | ||
|  | 35a9d241fc | ||
|  | 9ba0a7db64 | ||
|  | 9968503872 | ||
|  | 34218c5f58 | ||
|  | ebd41f1f20 | ||
|  | 62b1816297 | ||
|  | 2dfb864e4e | ||
|  | 2d1e1d4747 | ||
|  | f785aa0ae2 | ||
|  | cc476e212e | ||
|  | bca9716fc6 | ||
|  | fae6dbfebd | ||
|  | a7a0800b46 | ||
|  | 305293d3e5 | ||
|  | 17d4eb7a5e | ||
|  | f97e103b6d | ||
|  | dafca264b2 | ||
|  | be970e9e3d | ||
|  | e76837fa20 | ||
|  | e1b3403dc8 | ||
|  | 79da17c5c8 | ||
|  | e9623d542d | ||
|  | bc999f4067 | ||
|  | 474e536ae8 | ||
|  | 79647c5bb4 | ||
|  | 5409c39e35 | ||
|  | 5d4a24dd4f | ||
|  | c97abe7ef5 | ||
|  | edaea7bede | ||
|  | 909bce8ed9 | ||
|  | 4090c492e8 | ||
|  | a24afb0e12 | ||
|  | bc01f8b25f | ||
|  | 077c4141d6 | ||
|  | e5f20314e9 | ||
|  | 8a61bcb6b5 | ||
|  | 61b301b380 | ||
|  | be86f28be1 | ||
|  | a443380869 | ||
|  | 3d1d431cda | ||
|  | 9559ece8af | ||
|  | 8f56a1096d | ||
|  | 0ec85f902a | ||
|  | a47dde2166 | ||
|  | abdd6bfbd2 | ||
|  | d64104f472 | ||
|  | 1cd5ae2d57 | ||
|  | e27bf1627d | ||
|  | 0689d64efd | ||
|  | 3ba47aec38 | ||
|  | b90253981b | ||
|  | 513f678b6c | ||
|  | 478b9cf189 | ||
|  | 6675baff13 | ||
|  | a6efeebd21 | ||
|  | 6e2bb25b6e | ||
|  | a54edf71d1 | ||
|  | 8ff7eaf893 | ||
|  | a8d3872002 | ||
|  | dea03b7a46 | ||
|  | f5723dcccf | ||
|  | d772d1f162 | ||
|  | 46cfd16ae7 | ||
|  | 315243350b | ||
|  | 886d8a7293 | ||
|  | 54318f4001 | ||
|  | b3aee8abab | ||
|  | 1bdbadc1b3 | ||
|  | e0997b311b | ||
|  | 3c2ca312b9 | ||
|  | 315df1339a | ||
|  | e03b3e5ec4 | ||
|  | 43923976c2 | ||
|  | 6b8ee2f3f7 | ||
|  | 8cdb8ed48d | ||
|  | 417bf7e1c9 | ||
|  | b8e570bb3d | ||
|  | 69ff3c79b4 | ||
|  | eff4da20f8 | ||
|  | 473688b109 | ||
|  | 7bfb6ed5d7 | ||
|  | 276080aeec | ||
|  | 41c880afc7 | ||
|  | 3d242c3a3a | ||
|  | 9325b07d68 | ||
|  | ddeeb5d416 | ||
|  | c8bc0a5c79 | ||
|  | f58522d5a9 | ||
|  | 27a621531b | ||
|  | 0235433b7e | ||
|  | 6b5d1fe25b | ||
|  | f811ab1b28 | ||
|  | fc73f51855 | ||
|  | dd181421a7 | ||
|  | f6e2189739 | ||
|  | d61f31d3ed | ||
|  | 4e83a6ad23 | ||
|  | 7fc39dc8d1 | ||
|  | f10154a782 | ||
|  | 8761dc4e17 | ||
|  | 5a044b1c07 | ||
|  | 0100b76412 | ||
|  | 149f8967ad | ||
|  | c8754292f4 | ||
|  | e376fe921b | ||
|  | 61faea0298 | ||
|  | 8d8020ddb5 | ||
|  | 7d13b9eb99 | ||
|  | 6ed0a05b44 | ||
|  | c4c479578a | ||
|  | 441caa91dd | ||
|  | 20154eb049 | ||
|  | 84ea710d42 | ||
|  | 8d524d618e | ||
|  | 9fa34ab1fe | ||
|  | 47db1cf1ac | ||
|  | f2f9b70659 | ||
|  | 61c93ab08c | ||
|  | d72f3fae33 | ||
|  | 3f14d15722 | ||
|  | 963c0b46a0 | ||
|  | 66b4977a67 | ||
|  | 126c2147e9 | ||
|  | f7c42a4e6a | ||
|  | b1ea1fd96f | ||
|  | a5475bf839 | ||
|  | be9e187cc6 | ||
|  | d5098c6f66 | ||
|  | 41fc785330 | ||
|  | 4d83bf34f3 | ||
|  | 3a797e2583 | ||
|  | 7802030a53 | ||
|  | e8e1e0ca23 | ||
|  | 973431be40 | ||
|  | 24fb5a8e29 | ||
|  | 37d161c290 | ||
|  | ddefa5f9e6 | ||
|  | 955dd3d4d5 | ||
|  | d125205564 | ||
|  | 7fa1b52497 | ||
|  | a90d21899a | ||
|  | 569058f481 | ||
|  | 4ecda08f1f | ||
|  | 3b23059c09 | ||
|  | a474ffc101 | ||
|  | f7672b837a | ||
|  | 5235871fd8 | ||
|  | cac9873e20 | ||
|  | 9094923de9 | ||
|  | 6454c96e6a | ||
|  | 7fbb9edc0f | ||
|  | 0a717f5c81 | ||
|  | dab9777621 | ||
|  | c8d1e9def1 | ||
|  | 272dd45a43 | ||
|  | 5abec96df7 | ||
|  | e860f961a9 | ||
|  | b9ecf61dcb | ||
|  | 437f81c4a0 | ||
|  | 26dad7dada | ||
|  | b1e5d6f8f8 | ||
|  | 8c7b54d6e3 | ||
|  | fea0d8963c | ||
|  | 7aca52c68c | ||
|  | 529d3faaf8 | ||
|  | 9f0f4657a2 | ||
|  | 90ff1b5896 | ||
|  | feb82e34d6 | ||
|  | 4d7a34c177 | ||
|  | 5c3385ecd8 | ||
|  | a1af3a509c | ||
|  | 2913a87cc4 | ||
|  | 69cc86c572 | ||
|  | 60144c907e | ||
|  | 1828cf6fc7 | ||
|  | ad4d273241 | ||
|  | 0d03a94cde | ||
|  | c4b876472f | ||
|  | 6af5adaac1 | ||
|  | 17a28f2e91 | ||
|  | baaa7a5c13 | ||
|  | cfeb2a833c | ||
|  | e6fd58b3aa | ||
|  | 2ef905ef1e | ||
|  | db80aa84dc | ||
|  | f404cc16a1 | ||
|  | 8b4acf7023 | ||
|  | 7393c2ef91 | ||
|  | 4948ec2999 | ||
|  | 408a325732 | ||
|  | 5ca211b9f7 | ||
|  | bc7596a8b5 | ||
|  | 6762ca8aa7 | ||
|  | bb7d6ab429 | ||
|  | 986611ac36 | ||
|  | 94b4ad1de6 | ||
|  | 3e2f18bf3f | ||
|  | 48c06cc299 | ||
|  | f10821ac49 | ||
|  | cd5298dee6 | ||
|  | a8c955609a | ||
|  | c5acce0604 | ||
|  | a6ccce7b76 | ||
|  | aa72012d41 | ||
|  | 458831b885 | ||
|  | f5e4789ccb | ||
|  | 1b712d2800 | ||
|  | e274196441 | ||
|  | c4c3c27cfe | ||
|  | a2dd9d2c8c | ||
|  | 06e095e5fc | ||
|  | b26d5bc1b1 | ||
|  | 607792e1b2 | ||
|  | fb38135a61 | ||
|  | a5d5b6e6c7 | ||
|  | 2fd2cdf68a | ||
|  | 11049ca3ca | ||
|  | c29bea19ef | ||
|  | 8c8434ed64 | ||
|  | 9281bd043a | ||
|  | 6771f7c272 | ||
|  | 76b896a66d | ||
|  | a12520763c | ||
|  | 819bb7caab | ||
|  | 152205a146 | ||
|  | 85dbcb5444 | ||
|  | df09a746a0 | ||
|  | 5199fcf0a2 | ||
|  | dd557ed00a | ||
|  | addf4e2485 | ||
|  | d9be472ccb | ||
|  | 32828a9af5 | ||
|  | d206131df0 | ||
|  | 65eaf98d0b | ||
|  | 12429b90fe | ||
|  | 621042e639 | ||
|  | 526244be11 | ||
|  | bc53d0b55e | ||
|  | 907d3c5a36 | ||
|  | 898f1e215e | ||
|  | 324ac83489 | ||
|  | 00a873dcc7 | ||
|  | bc34345a56 | ||
|  | 659d27cae5 | ||
|  | 29072d6eae | ||
|  | 1fd59361b5 | ||
|  | 5896bb8fa3 | ||
|  | ea1fc90cf5 | ||
|  | 463f48f04f | ||
|  | cd58a30c7c | ||
|  | c4260ae681 | ||
|  | d40b4a33de | ||
|  | 87498679bd | ||
|  | f4e254202b | ||
|  | e91d225e7d | ||
|  | b90d940aef | ||
|  | b83a364b0e | ||
|  | dbff196b08 | ||
|  | 5b7316fb2a | ||
|  | 2f4ea20fdd | ||
|  | fa4dfe39ba | ||
|  | 89999e60bf | ||
|  | 4819fb12a3 | ||
|  | 27a4eeb206 | ||
|  | bacf4d5780 | ||
|  | f92fed60f8 | ||
|  | 5e797b548c | ||
|  | 700e2f1b2b | ||
|  | 861656978b | ||
|  | 9c05bdac85 | ||
|  | bd34c16c8f | ||
|  | 81fcb4452e | ||
|  | 4f1a5cd456 | ||
|  | 13109bb9b8 | ||
|  | 84f3b3720b | ||
|  | 858a66ccc8 | ||
|  | abb05eace6 | ||
|  | 62bd96a778 | ||
|  | 8cb736adfa | ||
|  | 0758c05186 | ||
|  | 62bc6f0457 | ||
|  | ea7e894139 | ||
|  | 21f0ac99e6 | ||
|  | b251866a29 | ||
|  | bf3db20a9d | ||
|  | bd55147847 | ||
|  | f4d64af39b | ||
|  | b7bda34645 | ||
|  | b13dea6df0 | ||
|  | 28a64c9318 | ||
|  | 74be618fff | ||
|  | 8bbe10bf50 | ||
|  | d275911624 | ||
|  | c26382301c | ||
|  | ae2d3d7e61 | ||
|  | 58ae0908e3 | ||
|  | e12bc07041 | ||
|  | 20416369ac | ||
|  | 2be91e9b2e | ||
|  | e91caeaade | ||
|  | dc1b8d9e80 | ||
|  | bf0a814514 | ||
|  | b14267d40f | ||
|  | 195a4115d8 | ||
|  | e1da8eb841 | ||
|  | bd694c60e1 | ||
|  | 14738f037f | ||
|  | a437943516 | ||
|  | 900ee57de8 | ||
|  | 947f4e1c57 | ||
|  | d9f17a65dd | ||
|  | f71def19ae | ||
|  | e452e85cae | ||
|  | 5059fe90b0 | ||
|  | b90da731d6 | ||
|  | d2012519ba | ||
|  | 1b7f26091c | ||
|  | 548e4f1845 | ||
|  | 625bed8fca | ||
|  | db15367775 | ||
|  | 309d14a955 | ||
|  | 5ff16e1195 | ||
|  | cf43aa9111 | ||
|  | 138c1e6024 | ||
|  | 382870a881 | ||
|  | 31921838cd | ||
|  | a707587182 | ||
|  | bc482af999 | ||
|  | 6818744dae | ||
|  | 607185ac61 | ||
|  | 81b7a412c3 | ||
|  | 09b9a8b441 | ||
|  | 85479cc2de | ||
|  | 3ad4eb2b59 | ||
|  | 878fe95ec3 | ||
|  | 3d23d1be69 | ||
|  | 5580f39df2 | ||
|  | 701e720ab8 | ||
|  | e709ce7d56 | ||
|  | 32c89a5405 | ||
|  | 1735982a73 | ||
|  | 625e0aa1af | ||
|  | 00e1a3f8fd | ||
|  | 539256b08e | ||
|  | ff791f5a39 | ||
|  | de4d48b0fe | ||
|  | b5c49f6d1c | ||
|  | 03cb7d6ffb | ||
|  | 304fc344a1 | ||
|  | 33c42638e9 | ||
|  | 9d940755e7 | ||
|  | bc04232f87 | ||
|  | e17ebec098 | ||
|  | a7cba23526 | ||
|  | 7cd23036a7 | ||
|  | 44c5413abf | ||
|  | 50ab58e91f | ||
|  | 1fd0732390 | ||
|  | ed1b9ee899 | ||
|  | d3c04d6310 | ||
|  | f66ffe305f | ||
|  | 2a9ff0083c | ||
|  | c1cf7ea825 | ||
|  | 67f7268a55 | ||
|  | a55ee7eb09 | ||
|  | 203f6d1944 | ||
|  | 42c68f21d1 | ||
|  | 7e8be1293e | ||
|  | 09c234ec26 | ||
|  | 65a26c3e73 | ||
|  | 98f35aefdc | ||
|  | 38a3714514 | ||
|  | 491700f925 | ||
|  | 4d033e7e83 | ||
|  | efc3638065 | ||
|  | b7685ab317 | ||
|  | 83c5f6a004 | ||
|  | aa5a94cc3e | ||
|  | a5b6331ab5 | ||
|  | 2164b28c64 | ||
|  | 0fb824b345 | ||
|  | 29ee094d66 | ||
|  | 4a7ae50ec8 | ||
|  | 398439a937 | ||
|  | a3bc3a7615 | ||
|  | 7989fbd613 | ||
|  | c389c79be9 | ||
|  | 1fd2f921fd | ||
|  | ed851849db | ||
|  | cfb9f6f0a4 | ||
|  | 3d5a0da62e | ||
|  | 4e15369f9a | ||
|  | 5b3152d99d | ||
|  | a6955f4edb | ||
|  | 280ef7d1bd | ||
|  | 8d2ea90a5b | ||
|  | 4bf7abd73d | ||
|  | 8f251e6756 | ||
|  | 4cd35c1f33 | ||
|  | 78fda33707 | ||
|  | 5c6a98f479 | ||
|  | efbcb942c3 | ||
|  | f3da1bc3b1 | ||
|  | 72a6186f08 | ||
|  | 8cde6d2e8f | ||
|  | 4f2c7fdc3c | ||
|  | 5a830504a4 | ||
|  | 086fb09038 | ||
|  | 5544a041ce | ||
|  | 6447333368 | ||
|  | 1d6a42f0eb | ||
|  | de14b75517 | ||
|  | 0f302713da | ||
|  | a66d064d4a | ||
|  | 4fefe2020f | ||
|  | 72fab07a14 | ||
|  | adbf4f6b17 | ||
|  | cfcf4ca915 | ||
|  | c427fba87f | ||
|  | ab14bcab03 | ||
|  | 78de3fb959 | ||
|  | b9eda90ddd | ||
|  | 66b346c8fb | ||
|  | 8215b225d9 | ||
|  | 41da8c6352 | ||
|  | 04f4b05412 | ||
|  | b7dad4df5e | ||
|  | 1a98ccbf5f | ||
|  | 8d16a3365e | ||
|  | 67bf48fafc | ||
|  | 9a3c9a8c19 | ||
|  | 6a192dae63 | ||
|  | f5895216a8 | ||
|  | 09a33f8daa | ||
|  | 185db0e8d5 | ||
|  | 85efbde3f7 | ||
|  | 93d7aa3d07 | ||
|  | e96096f786 | ||
|  | 0a850eeddd | ||
|  | 42658ffd61 | ||
|  | 24fc2842d2 | ||
|  | ac2723abe3 | ||
|  | 0d0e219532 | ||
|  | cf35807709 | ||
|  | c2b53db96d | ||
|  | 8e6efc3a7d | ||
|  | 4b6f05b4d1 | ||
|  | 7aad5f93e4 | ||
|  | 9b6a7622d2 | ||
|  | 6c666075b5 | ||
|  | 6d26bf5c82 | ||
|  | 6d5da4c9ec | ||
|  | 51dde1f6a4 | ||
|  | 13c9259d23 | ||
|  | a22c2d678b | ||
|  | 5c36f8df85 | ||
|  | 37781cb58e | ||
|  | dcc598442b | ||
|  | 91877056fb | ||
|  | 868e9df434 | ||
|  | c3642ba7ed | ||
|  | 56f128af66 | ||
|  | c1e560b901 | ||
|  | 92bc1cdcdf | ||
|  | 9fde0ec447 | ||
|  | 297ef6195d | ||
|  | 9873157076 | ||
|  | 675c1f3c0b | ||
|  | fee7a34ddc | ||
|  | a148d52aed | ||
|  | 5da8831aff | ||
|  | e9ff0f4998 | ||
|  | 658bf98b4c | ||
|  | 452cfd32d7 | ||
|  | 3f1dc71cc2 | ||
|  | 256157cd42 | ||
|  | 843279ff1d | ||
|  | 8118546ac7 | ||
|  | 15c05c723e | ||
|  | d0d40c0d2e | ||
|  | f494972d04 | ||
|  | 1c4def7320 | ||
|  | 6e22b946bd | ||
|  | 0a54df3a12 | ||
|  | 20af70cd90 | ||
|  | a2f721d4ef | ||
|  | 03a1a733f6 | ||
|  | 4a76088b43 | ||
|  | 5a1dab8073 | ||
|  | 86a97610bd | ||
|  | 87bfe3657a | ||
|  | 3802e31b90 | ||
|  | 4eff60e4b1 | ||
|  | f103306e91 | ||
|  | 8b878784a4 | ||
|  | 44a0d19ac0 | ||
|  | 3023516796 | ||
|  | 6038a06c43 | ||
|  | 20735a4cdd | ||
|  | df3b1a983e | ||
|  | 84e43d7d3f | ||
|  | 7e81a9e50b | ||
|  | 28acee8e33 | ||
|  | 80184f1e1d | ||
|  | d893259e75 | ||
|  | d3f37f5013 | ||
|  | 0e6a46abfc | ||
|  | 49e27387b7 | ||
|  | c2495c27d3 | ||
|  | f0a3acd735 | ||
|  | 29d2930de8 | ||
|  | 2d82071103 | ||
|  | f4a3636371 | ||
|  | d8f96441da | ||
|  | cf5646d45a | ||
|  | 5c3d32cafd | ||
|  | ea45db38e9 | ||
|  | a978c4eb34 | ||
|  | 65302dbec7 | ||
|  | 3c82131863 | ||
|  | 00873da7a6 | ||
|  | a17f7d1cb2 | ||
|  | 9f850db126 | ||
|  | e513ac628a | ||
|  | 3dc11186a1 | ||
|  | 2fbca98e7f | ||
|  | 7ad411fbaa | ||
|  | 4e4e77bc9a | ||
|  | a7afdaa677 | ||
|  | dd24b54a31 | ||
|  | 833e409bd8 | ||
|  | c2a376fbc9 | ||
|  | c21707b8b1 | ||
|  | c04f4519a7 | ||
|  | fd7db27b48 | ||
|  | cab85f3de3 | ||
|  | 34893650eb | ||
|  | bb58840c1c | ||
|  | cbcbb969d5 | ||
|  | 3c21f8db51 | ||
|  | 6c3f8a7787 | ||
|  | 915a11f2b6 | ||
|  | 55ce1e8b93 | ||
|  | ccce5475bf | ||
|  | cb844a1913 | ||
|  | 6c4c2fa0e0 | ||
|  | ba26e1f5d5 | ||
|  | bbddd3f946 | ||
|  | 2634866b91 | ||
|  | d13825daff | ||
|  | e7233db9fa | ||
|  | cec5942d6b | ||
|  | aaef516c22 | ||
|  | 09ae07d003 | ||
|  | a144c9f394 | ||
|  | 0e10a8c857 | ||
|  | 33387b7227 | ||
|  | 3b5a237f1e | ||
|  | 152e3ace99 | ||
|  | 64b6f18e66 | ||
|  | be1003648a | ||
|  | 536800f9f5 | ||
|  | 20f858c305 | ||
|  | 07fdea7496 | ||
|  | 449d675e3d | ||
|  | bdcb9ecffe | ||
|  | 850756cf7d | ||
|  | b3f55c72f8 | ||
|  | 021848eb8e | ||
|  | 06ceed0e66 | ||
|  | d599f000c1 | ||
|  | cd9760d69b | ||
|  | ada4cad25c | ||
|  | 4ba6f9567b | ||
|  | d84867d6f3 | ||
|  | 05aaba4d89 | ||
|  | 33e5d3a444 | ||
|  | 7b6a0e9cad | ||
|  | 8e681359ba | ||
|  | 39e5f5bab3 | ||
|  | 4ff37a783f | ||
|  | 1c5916d3f2 | ||
|  | d8425af684 | ||
|  | 8db3638ce4 | ||
|  | d8cc60a026 | ||
|  | 9f49efef0a | ||
|  | 9d569c8bd5 | ||
|  | 58d65c2d27 | ||
|  | 9c921b331c | ||
|  | b065d8c0d7 | ||
|  | 5148422e39 | ||
|  | 88131e0844 | ||
|  | 6c8c815ad8 | ||
|  | 06cee71e07 | ||
|  | 6106441e58 | ||
|  | a949338a91 | ||
|  | ad93511c98 | ||
|  | 014f026eb2 | ||
|  | ca8ad800ca | ||
|  | 54335c74f6 | ||
|  | fb2f19e666 | ||
|  | 7e9612fe9f | ||
|  | acbe0e4a51 | ||
|  | 22e09a587c | ||
|  | 1b5d35a536 | ||
|  | 5d480fc6d6 | ||
|  | f5b361c31b | ||
|  | 918a69e6f0 | ||
|  | 6d346fdc8d | ||
|  | 09506dbbd9 | ||
|  | e11a671a1d | ||
|  | c72ad3f402 | ||
|  | 48b240630e | ||
|  | 715732bb93 | ||
|  | 2f01a4bd78 | ||
|  | 62e34caa4c | ||
|  | 142dcd27e5 | ||
|  | 2f94e46f1f | ||
|  | 5c5999fbf3 | ||
|  | 26fbc45baf | ||
|  | a2537fa108 | ||
|  | 8e76ba2020 | ||
|  | 0f5e2a1ea4 | ||
|  | 00ff4a1d8a | ||
|  | 98dacd07c2 | ||
|  | 701f5220fc | ||
|  | 2aa27c99b3 | ||
|  | 236f521e13 | ||
|  | d0d6dfa5c0 | ||
|  | 5af528184d | ||
|  | 01c4fba092 | ||
|  | 20c9ed9f36 | ||
|  | 40f4c49ba9 | ||
|  | a265237b2e | ||
|  | a4eea6b8cd | ||
|  | e7f5cadfcb | ||
|  | 21d3a3a141 | ||
|  | 96a162225d | ||
|  | 09c2f763f1 | ||
|  | ce096e277d | ||
|  | c0bb883aaa | ||
|  | 23eea82139 | ||
|  | edd9881642 | ||
|  | e46c6968ba | ||
|  | 1528847249 | ||
|  | 182aaf8fce | ||
|  | d6dfa1dcbc | ||
|  | 6450d5861a | ||
|  | 9562b8ad3d | ||
|  | 507248dd95 | ||
|  | 19a67c07fe | ||
|  | 2ef130530d | ||
|  | 5606916d99 | ||
|  | 3d4b682d63 | ||
|  | 96561c24be | ||
|  | 0cd1566145 | ||
|  | b6aa9f9b12 | ||
|  | 0240b76cc3 | ||
|  | 9b8823ab3c | ||
|  | 8ba9446fcd | ||
|  | 04a6af4272 | ||
|  | a1641f2ffa | ||
|  | fe183c07f5 | ||
|  | a620d45635 | ||
|  | fa9660d5a1 | ||
|  | 8b39d30a6e | ||
|  | 090ffa4191 | ||
|  | 42194094a2 | ||
|  | 08058f9f2e | ||
|  | 3d76ba001f | ||
|  | 078a2877c7 | ||
|  | 9ae0bdbb43 | ||
|  | a22ba56596 | ||
|  | b6cadc93f2 | ||
|  | a5fa26461c | ||
|  | a3aaa1ec4d | ||
|  | 5ddcdede74 | ||
|  | c4cdcc8db7 | ||
|  | 7219ebdf3c | ||
|  | cd548c6ed6 | ||
|  | 75140f5d52 | ||
|  | 774303a846 | ||
|  | 6b18b25039 | ||
|  | bb2afbb03d | ||
|  | 50ddb0ba16 | ||
|  | 556a98b525 | ||
|  | 1f022a84ea | ||
|  | 110fa6d384 | ||
|  | c971c14a83 | ||
|  | 4bec82a19e | ||
|  | 0c23050eaf | ||
|  | e1c81a8884 | ||
|  | 19e4dabf01 | ||
|  | a98ad13af4 | ||
|  | 24eb965adb | ||
|  | 852957c769 | ||
|  | e1eff56d6a | ||
|  | 220ecabd8c | ||
|  | 27ea8d0bf5 | ||
|  | 8f02926d68 | ||
|  | 1769083a85 | ||
|  | 05c714af76 | ||
|  | ee3c9bcdbd | ||
|  | 911a532051 | ||
|  | 44910dbcd8 | ||
|  | 42cb8ec3cf | ||
|  | 1e9435c999 | ||
|  | dc1b0e3c48 | ||
|  | 869cf8ba11 | ||
|  | d394e8db21 | ||
|  | a8b6267471 | ||
|  | 637682e452 | ||
|  | 68b6152b42 | ||
|  | a349f81e2d | ||
|  | 8c2e41cc99 | ||
|  | 6c0618f75a | ||
|  | b1eed16422 | ||
|  | 432f27480e | ||
|  | 23addec9a9 | ||
|  | e50cc9b210 | ||
|  | 58d865f293 | ||
|  | b69fef2c39 | ||
|  | f8fee56446 | ||
|  | 10903e7e38 | ||
|  | 54c1d7c9d9 | ||
|  | 3a19ba4523 | ||
|  | cb9bef43a5 | ||
|  | 4c500e1fb2 | ||
|  | a2690b7dac | ||
|  | ee370cbf43 | ||
|  | 4ec878ba0d | ||
|  | 28a2b39a55 | ||
|  | d94bffb198 | ||
|  | 3bea39eb10 | ||
|  | c60328383d | ||
|  | e2b1fe3641 | ||
|  | 0eebd42d72 | ||
|  | 2beb450df6 | ||
|  | 487cad7041 | ||
|  | 43f393a02d | ||
|  | 3c1f4c8ee1 | ||
|  | 81db880a7b | ||
|  | 277a71f6f6 | ||
|  | 681561229e | ||
|  | 43825c3426 | ||
|  | f4fd6ed94e | ||
|  | ef42680646 | ||
|  | e9f9a9ef12 | ||
|  | 476b39c353 | ||
|  | 0eea2bd7bb | ||
|  | 028f2ab92c | ||
|  | 34c83d9495 | ||
|  | e37f5b8df5 | ||
|  | df342798b0 | ||
|  | 293ed8aa8d | ||
|  | 49fd25236e | ||
|  | 83a742621f | ||
|  | bc923bb6b1 | ||
|  | aa78060e41 | ||
|  | 9cae54bb55 | ||
|  | 89795ebd1f | ||
|  | 5fb6f34d8a | ||
|  | 3ecc1f883c | ||
|  | edf19a0941 | ||
|  | dfeaaaa17e | ||
|  | bcefa61fe0 | ||
|  | f0ad498b93 | ||
|  | a0aae8cdc1 | ||
|  | a2d6b374da | ||
|  | 7c1716aa1e | ||
|  | 6df8bd62d3 | ||
|  | d6e3bcc875 | ||
|  | 200473ba27 | ||
|  | 05fb0c35fa | ||
|  | 395f4375da | ||
|  | bb348c4038 | ||
|  | 1a4be4dfa0 | 
							
								
								
									
										0
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1 +1,4 @@ | |||||||
| Gemfile.lock | Gemfile.lock | ||||||
|  | .bundle/ | ||||||
|  | benchmark/ | ||||||
|  | lib/linguist/samples.json | ||||||
|   | |||||||
| @@ -1,11 +1,12 @@ | |||||||
| before_install: | before_install: | ||||||
|  |   - git fetch origin master:master | ||||||
|  |   - git fetch origin v2.0.0:v2.0.0 | ||||||
|  |   - git fetch origin test/attributes:test/attributes | ||||||
|   - sudo apt-get install libicu-dev -y |   - sudo apt-get install libicu-dev -y | ||||||
|   - gem update --system 2.1.11 |  | ||||||
| rvm: | rvm: | ||||||
|   - 1.8.7 |  | ||||||
|   - 1.9.2 |  | ||||||
|   - 1.9.3 |   - 1.9.3 | ||||||
|   - 2.0.0 |   - 2.0.0 | ||||||
|   - ree |   - 2.1 | ||||||
|  |   - 2.2 | ||||||
| notifications: | notifications: | ||||||
|   disabled: true |   disabled: true | ||||||
|   | |||||||
							
								
								
									
										6
									
								
								Gemfile
									
									
									
									
									
								
							
							
						
						
									
										6
									
								
								Gemfile
									
									
									
									
									
								
							| @@ -1,7 +1,3 @@ | |||||||
| source 'https://rubygems.org' | source 'https://rubygems.org' | ||||||
| gemspec | gemspec | ||||||
|  | gem 'test-unit', require: false if RUBY_VERSION >= '2.2' | ||||||
| if RUBY_VERSION < "1.9.3" |  | ||||||
|   # escape_utils 1.0.0 requires 1.9.3 and above |  | ||||||
|   gem "escape_utils", "0.3.2" |  | ||||||
| end |  | ||||||
|   | |||||||
							
								
								
									
										125
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										125
									
								
								README.md
									
									
									
									
									
								
							| @@ -32,33 +32,57 @@ The Language stats bar that you see on every repository is built by aggregating | |||||||
|  |  | ||||||
| The repository stats API, accessed through `#languages`, can be used on a directory: | The repository stats API, accessed through `#languages`, can be used on a directory: | ||||||
|  |  | ||||||
|  | ***API UPDATE*** | ||||||
|  |  | ||||||
|  | Since [Version 3.0.0](https://github.com/github/linguist/releases/tag/v3.0.0) Linguist expects a git repository (in the form of a [Rugged::Repository](https://github.com/libgit2/rugged#repositories)) to be passed when initializing `Linguist::Repository`. | ||||||
|  |  | ||||||
|  |  | ||||||
| ```ruby | ```ruby | ||||||
| project = Linguist::Repository.from_directory(".") | require 'rugged' | ||||||
| project.language.name  #=> "Ruby" | require 'linguist' | ||||||
| project.languages      #=> { "Ruby" => 0.98, "Shell" => 0.02 } |  | ||||||
|  | repo = Rugged::Repository.new('.') | ||||||
|  | project = Linguist::Repository.new(repo, repo.head.target_id) | ||||||
|  | project.language       #=> "Ruby" | ||||||
|  | project.languages      #=> { "Ruby" => 119387 } | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
| These stats are also printed out by the `linguist` binary. You can use the | These stats are also printed out by the `linguist` binary. You can use the | ||||||
| `--breakdown` flag, and the binary will also output the breakdown of files by language. | `--breakdown` flag, and the binary will also output the breakdown of files by language. | ||||||
|  |  | ||||||
| You can try running `linguist` on the `lib/` directory in this repository itself: | You can try running `linguist` on the root directory in this repository itself: | ||||||
|  |  | ||||||
|     $ bundle exec linguist lib/ --breakdown |     $ bundle exec linguist --breakdown | ||||||
|  |  | ||||||
|     100.00% Ruby |     100.00% Ruby | ||||||
|  |  | ||||||
|     Ruby: |     Ruby: | ||||||
|     linguist/blob_helper.rb |     Gemfile | ||||||
|     linguist/classifier.rb |     Rakefile | ||||||
|     linguist/file_blob.rb |     bin/linguist | ||||||
|     linguist/generated.rb |     github-linguist.gemspec | ||||||
|     linguist/heuristics.rb |     lib/linguist.rb | ||||||
|     linguist/language.rb |     lib/linguist/blob_helper.rb | ||||||
|     linguist/md5.rb |     lib/linguist/classifier.rb | ||||||
|     linguist/repository.rb |     lib/linguist/file_blob.rb | ||||||
|     linguist/samples.rb |     lib/linguist/generated.rb | ||||||
|     linguist/tokenizer.rb |     lib/linguist/heuristics.rb | ||||||
|     linguist.rb |     lib/linguist/language.rb | ||||||
|  |     lib/linguist/lazy_blob.rb | ||||||
|  |     lib/linguist/md5.rb | ||||||
|  |     lib/linguist/repository.rb | ||||||
|  |     lib/linguist/samples.rb | ||||||
|  |     lib/linguist/tokenizer.rb | ||||||
|  |     lib/linguist/version.rb | ||||||
|  |     test/test_blob.rb | ||||||
|  |     test/test_classifier.rb | ||||||
|  |     test/test_heuristics.rb | ||||||
|  |     test/test_language.rb | ||||||
|  |     test/test_md5.rb | ||||||
|  |     test/test_pedantic.rb | ||||||
|  |     test/test_repository.rb | ||||||
|  |     test/test_samples.rb | ||||||
|  |     test/test_tokenizer.rb | ||||||
|  |  | ||||||
| #### Ignore vendored files | #### Ignore vendored files | ||||||
|  |  | ||||||
| @@ -80,9 +104,34 @@ Linguist::FileBlob.new("underscore.min.js").generated? # => true | |||||||
|  |  | ||||||
| See [Linguist::Generated#generated?](https://github.com/github/linguist/blob/master/lib/linguist/generated.rb). | See [Linguist::Generated#generated?](https://github.com/github/linguist/blob/master/lib/linguist/generated.rb). | ||||||
|  |  | ||||||
|  | ## Overrides | ||||||
|  |  | ||||||
|  | Linguist supports custom overrides for language definitions and vendored paths. Add a `.gitattributes` file to your project using the keys `linguist-language` and `linguist-vendored` with the standard git-style path matchers for the files you want to override. | ||||||
|  |  | ||||||
|  | Please note that the overrides currently only affect the language statistics for a repository and not the syntax-highlighting of files. | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | $ cat .gitattributes | ||||||
|  | *.rb linguist-language=Java | ||||||
|  |  | ||||||
|  | $ linguist --breakdown | ||||||
|  | 100.00% Java | ||||||
|  |  | ||||||
|  | Java: | ||||||
|  | ruby_file.rb | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | By default, Linguist treats all of the paths defined in [lib/linguist/vendor.yml](https://github.com/github/linguist/blob/master/lib/linguist/vendor.yml) as vendored and therefore doesn't include them in the language statistics for a repository. Use the `linguist-vendored` attribute to vendor or un-vendor paths. | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | $ cat .gitattributes | ||||||
|  | special-vendored-path/* linguist-vendored | ||||||
|  | jquery.js linguist-vendored=false | ||||||
|  | ``` | ||||||
|  |  | ||||||
| ## Installation | ## Installation | ||||||
|  |  | ||||||
| github.com is usually running the latest version of the `github-linguist` gem that is released on [RubyGems.org](http://rubygems.org/gems/github-linguist). | Github.com is usually running the latest version of the `github-linguist` gem that is released on [RubyGems.org](http://rubygems.org/gems/github-linguist). | ||||||
|  |  | ||||||
| But for development you are going to want to checkout out the source. To get it, clone the repo and run [Bundler](http://gembundler.com/) to install its dependencies. | But for development you are going to want to checkout out the source. To get it, clone the repo and run [Bundler](http://gembundler.com/) to install its dependencies. | ||||||
|  |  | ||||||
| @@ -102,12 +151,50 @@ We try to only add languages once they have some usage on GitHub, so please note | |||||||
|  |  | ||||||
| Almost all bug fixes or new language additions should come with some additional code samples. Just drop them under [`samples/`](https://github.com/github/linguist/tree/master/samples) in the correct subdirectory and our test suite will automatically test them. In most cases you shouldn't need to add any new assertions. | Almost all bug fixes or new language additions should come with some additional code samples. Just drop them under [`samples/`](https://github.com/github/linguist/tree/master/samples) in the correct subdirectory and our test suite will automatically test them. In most cases you shouldn't need to add any new assertions. | ||||||
|  |  | ||||||
| To update the `samples.json` after adding new files to [`samples/`](https://github.com/github/linguist/tree/master/samples): | ### A note on language extensions | ||||||
|  |  | ||||||
|     bundle exec rake samples | Linguist has a number of methods available to it for identifying the language of a particular file. The initial lookup is based upon the extension of the file, possible file extensions are defined in an array called `extensions`. Take a look at this example for example for `Perl`: | ||||||
|  |  | ||||||
|  | ``` | ||||||
|  | Perl: | ||||||
|  |   type: programming | ||||||
|  |   ace_mode: perl | ||||||
|  |   color: "#0298c3" | ||||||
|  |   extensions: | ||||||
|  |   - .pl | ||||||
|  |   - .PL | ||||||
|  |   - .perl | ||||||
|  |   - .ph | ||||||
|  |   - .plx | ||||||
|  |   - .pm | ||||||
|  |   - .pod | ||||||
|  |   - .psgi | ||||||
|  |   interpreters: | ||||||
|  |   - perl | ||||||
|  | ``` | ||||||
|  | Any of the extensions defined are valid but the first in this array should be the most popular. | ||||||
|  |  | ||||||
| ### Testing | ### Testing | ||||||
|  |  | ||||||
| Sometimes getting the tests running can be too much work, especially if you don't have much Ruby experience. It's okay: be lazy and let our build bot [Travis](http://travis-ci.org/#!/github/linguist) run the tests for you. Just open a pull request and the bot will start cranking away. | Sometimes getting the tests running can be too much work, especially if you don't have much Ruby experience. It's okay: be lazy and let our build bot [Travis](http://travis-ci.org/#!/github/linguist) run the tests for you. Just open a pull request and the bot will start cranking away. | ||||||
|  |  | ||||||
| Here's our current build status, which is hopefully green: [](http://travis-ci.org/github/linguist) | Here's our current build status, which is hopefully green: [](http://travis-ci.org/github/linguist) | ||||||
|  |  | ||||||
|  | ### Releasing | ||||||
|  |  | ||||||
|  | If you are the current maintainer of this gem: | ||||||
|  |  | ||||||
|  |  0. Create a branch for the release: `git checkout -b cut-release-vxx.xx.xx` | ||||||
|  |  0. Make sure your local dependencies are up to date: `bundle install` | ||||||
|  |  0. Ensure that samples are updated: `bundle exec rake samples` | ||||||
|  |  0. Ensure that tests are green: `bundle exec rake test` | ||||||
|  |  0. Bump gem version in `lib/linguist/version.rb`.  For example, [like this](https://github.com/github/linguist/commit/8d2ea90a5ba3b2fe6e1508b7155aa4632eea2985). | ||||||
|  |  0. Make a PR to github/linguist.  For example, [#1238](https://github.com/github/linguist/pull/1238). | ||||||
|  |  0. Build a local gem: `bundle exec rake build_gem` | ||||||
|  |  0. Testing: | ||||||
|  |    0. Bump the Gemfile and Gemfile.lock versions for an app which relies on this gem | ||||||
|  |    0. Install the new gem locally | ||||||
|  |    0. Test behavior locally, branch deploy, whatever needs to happen | ||||||
|  |  0. Merge github/linguist PR | ||||||
|  |  0. Tag and push: `git tag vx.xx.xx; git push --tags` | ||||||
|  |  0. Push to rubygems.org -- `gem push github-linguist-3.0.0.gem` | ||||||
|   | |||||||
							
								
								
									
										101
									
								
								Rakefile
									
									
									
									
									
								
							
							
						
						
									
										101
									
								
								Rakefile
									
									
									
									
									
								
							| @@ -1,27 +1,97 @@ | |||||||
| require 'json' | require 'bundler/setup' | ||||||
| require 'rake/clean' | require 'rake/clean' | ||||||
| require 'rake/testtask' | require 'rake/testtask' | ||||||
| require 'yaml' | require 'yaml' | ||||||
|  | require 'yajl' | ||||||
|  |  | ||||||
| task :default => :test | task :default => :test | ||||||
|  |  | ||||||
| Rake::TestTask.new | Rake::TestTask.new | ||||||
|  |  | ||||||
| task :samples do | # Extend test task to check for samples | ||||||
|   require 'linguist/samples' | task :test => :check_samples | ||||||
|   require 'yajl' |  | ||||||
|   data = Linguist::Samples.data | desc "Check that we have samples.json generated" | ||||||
|   json = Yajl::Encoder.encode(data, :pretty => true) | task :check_samples do | ||||||
|   File.open('lib/linguist/samples.json', 'w') { |io| io.write json } |   unless File.exist?('lib/linguist/samples.json') | ||||||
|  |     Rake::Task[:samples].invoke | ||||||
|  |   end | ||||||
| end | end | ||||||
|  |  | ||||||
| task :build_gem do | task :samples do | ||||||
|  |   require 'linguist/samples' | ||||||
|  |   json = Yajl.dump(Linguist::Samples.data, :pretty => true) | ||||||
|  |   File.write 'lib/linguist/samples.json', json | ||||||
|  | end | ||||||
|  |  | ||||||
|  | task :build_gem => :samples do | ||||||
|   languages = YAML.load_file("lib/linguist/languages.yml") |   languages = YAML.load_file("lib/linguist/languages.yml") | ||||||
|   File.write("lib/linguist/languages.json", JSON.dump(languages)) |   File.write("lib/linguist/languages.json", Yajl.dump(languages)) | ||||||
|   `gem build github-linguist.gemspec` |   `gem build github-linguist.gemspec` | ||||||
|   File.delete("lib/linguist/languages.json") |   File.delete("lib/linguist/languages.json") | ||||||
| end | end | ||||||
|  |  | ||||||
|  | namespace :benchmark do | ||||||
|  |   benchmark_path = "benchmark/results" | ||||||
|  |  | ||||||
|  |   # $ bundle exec rake benchmark:generate CORPUS=path/to/samples | ||||||
|  |   desc "Generate results for" | ||||||
|  |   task :generate do | ||||||
|  |     ref = `git rev-parse HEAD`.strip[0,8] | ||||||
|  |  | ||||||
|  |     corpus = File.expand_path(ENV["CORPUS"] || "samples") | ||||||
|  |  | ||||||
|  |     require 'linguist/language' | ||||||
|  |  | ||||||
|  |     results = Hash.new | ||||||
|  |     Dir.glob("#{corpus}/**/*").each do |file| | ||||||
|  |       next unless File.file?(file) | ||||||
|  |       filename = file.gsub("#{corpus}/", "") | ||||||
|  |       results[filename] = Linguist::FileBlob.new(file).language | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     # Ensure results directory exists | ||||||
|  |     FileUtils.mkdir_p("benchmark/results") | ||||||
|  |  | ||||||
|  |     # Write results | ||||||
|  |     if `git status`.include?('working directory clean') | ||||||
|  |       result_filename = "benchmark/results/#{File.basename(corpus)}-#{ref}.json" | ||||||
|  |     else | ||||||
|  |       result_filename = "benchmark/results/#{File.basename(corpus)}-#{ref}-unstaged.json" | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     File.write(result_filename, results.to_json) | ||||||
|  |     puts "wrote #{result_filename}" | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   # $ bundle exec rake benchmark:compare REFERENCE=path/to/reference.json CANDIDATE=path/to/candidate.json | ||||||
|  |   desc "Compare results" | ||||||
|  |   task :compare do | ||||||
|  |     reference_file = ENV["REFERENCE"] | ||||||
|  |     candidate_file = ENV["CANDIDATE"] | ||||||
|  |  | ||||||
|  |     reference = Yajl.load(File.read(reference_file)) | ||||||
|  |     reference_counts = Hash.new(0) | ||||||
|  |     reference.each { |filename, language| reference_counts[language] += 1 } | ||||||
|  |  | ||||||
|  |     candidate = Yajl.load(File.read(candidate_file)) | ||||||
|  |     candidate_counts = Hash.new(0) | ||||||
|  |     candidate.each { |filename, language| candidate_counts[language] += 1 } | ||||||
|  |  | ||||||
|  |     changes = diff(reference_counts, candidate_counts) | ||||||
|  |  | ||||||
|  |     if changes.any? | ||||||
|  |       changes.each do |language, (before, after)| | ||||||
|  |         before_percent = 100 * before / reference.size.to_f | ||||||
|  |         after_percent = 100 * after / candidate.size.to_f | ||||||
|  |         puts "%s changed from %.1f%% to %.1f%%" % [language || 'unknown', before_percent, after_percent] | ||||||
|  |       end | ||||||
|  |     else | ||||||
|  |       puts "No changes" | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
|  |  | ||||||
| namespace :classifier do | namespace :classifier do | ||||||
|   LIMIT = 1_000 |   LIMIT = 1_000 | ||||||
|  |  | ||||||
| @@ -37,7 +107,7 @@ namespace :classifier do | |||||||
|       next if file_language.nil? || file_language == 'Text' |       next if file_language.nil? || file_language == 'Text' | ||||||
|       begin |       begin | ||||||
|         data = open(file_url).read |         data = open(file_url).read | ||||||
|         guessed_language, score = Linguist::Classifier.classify(Linguist::Samples::DATA, data).first |         guessed_language, score = Linguist::Classifier.classify(Linguist::Samples.cache, data).first | ||||||
|  |  | ||||||
|         total += 1 |         total += 1 | ||||||
|         guessed_language == file_language ? correct += 1 : incorrect += 1 |         guessed_language == file_language ? correct += 1 : incorrect += 1 | ||||||
| @@ -54,14 +124,12 @@ namespace :classifier do | |||||||
|  |  | ||||||
|   def each_public_gist |   def each_public_gist | ||||||
|     require 'open-uri' |     require 'open-uri' | ||||||
|     require 'json' |  | ||||||
|  |  | ||||||
|     url = "https://api.github.com/gists/public" |     url = "https://api.github.com/gists/public" | ||||||
|  |  | ||||||
|     loop do |     loop do | ||||||
|       resp = open(url) |       resp = open(url) | ||||||
|       url = resp.meta['link'][/<([^>]+)>; rel="next"/, 1] |       url = resp.meta['link'][/<([^>]+)>; rel="next"/, 1] | ||||||
|       gists = JSON.parse(resp.read) |       gists = Yajl.load(resp.read) | ||||||
|  |  | ||||||
|       for gist in gists |       for gist in gists | ||||||
|         for filename, attrs in gist['files'] |         for filename, attrs in gist['files'] | ||||||
| @@ -71,3 +139,10 @@ namespace :classifier do | |||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def diff(a, b) | ||||||
|  |   (a.keys | b.keys).each_with_object({}) do |key, diff| | ||||||
|  |     diff[key] = [a[key], b[key]] unless a[key] == b[key] | ||||||
|  |   end | ||||||
|  | end | ||||||
|   | |||||||
| @@ -4,7 +4,9 @@ | |||||||
| #     usage: linguist <path> [<--breakdown>] | #     usage: linguist <path> [<--breakdown>] | ||||||
|  |  | ||||||
| require 'linguist/file_blob' | require 'linguist/file_blob' | ||||||
|  | require 'linguist/language' | ||||||
| require 'linguist/repository' | require 'linguist/repository' | ||||||
|  | require 'rugged' | ||||||
|  |  | ||||||
| path = ARGV[0] || Dir.pwd | path = ARGV[0] || Dir.pwd | ||||||
|  |  | ||||||
| @@ -18,7 +20,8 @@ ARGV.shift | |||||||
| breakdown = true if ARGV[0] == "--breakdown" | breakdown = true if ARGV[0] == "--breakdown" | ||||||
|  |  | ||||||
| if File.directory?(path) | if File.directory?(path) | ||||||
|   repo = Linguist::Repository.from_directory(path) |   rugged = Rugged::Repository.new(path) | ||||||
|  |   repo = Linguist::Repository.new(rugged, rugged.head.target_id) | ||||||
|   repo.languages.sort_by { |_, size| size }.reverse.each do |language, size| |   repo.languages.sort_by { |_, size| size }.reverse.each do |language, size| | ||||||
|     percentage = ((size / repo.size.to_f) * 100) |     percentage = ((size / repo.size.to_f) * 100) | ||||||
|     percentage = sprintf '%.2f' % percentage |     percentage = sprintf '%.2f' % percentage | ||||||
|   | |||||||
| @@ -1,6 +1,8 @@ | |||||||
|  | require File.expand_path('../lib/linguist/version', __FILE__) | ||||||
|  |  | ||||||
| Gem::Specification.new do |s| | Gem::Specification.new do |s| | ||||||
|   s.name    = 'github-linguist' |   s.name    = 'github-linguist' | ||||||
|   s.version = '2.10.12' |   s.version = Linguist::VERSION | ||||||
|   s.summary = "GitHub Language detection" |   s.summary = "GitHub Language detection" | ||||||
|   s.description = 'We use this library at GitHub to detect blob languages, highlight code, ignore binary files, suppress generated files in diffs, and generate language breakdown graphs.' |   s.description = 'We use this library at GitHub to detect blob languages, highlight code, ignore binary files, suppress generated files in diffs, and generate language breakdown graphs.' | ||||||
|  |  | ||||||
| @@ -11,13 +13,14 @@ Gem::Specification.new do |s| | |||||||
|   s.files = Dir['lib/**/*'] |   s.files = Dir['lib/**/*'] | ||||||
|   s.executables << 'linguist' |   s.executables << 'linguist' | ||||||
|  |  | ||||||
|   s.add_dependency 'charlock_holmes', '~> 0.6.6' |   s.add_dependency 'charlock_holmes', '~> 0.7.3' | ||||||
|   s.add_dependency 'escape_utils',    '>= 0.3.1' |   s.add_dependency 'escape_utils',    '~> 1.0.1' | ||||||
|   s.add_dependency 'mime-types',      '~> 1.19' |   s.add_dependency 'mime-types',      '~> 1.19' | ||||||
|   s.add_dependency 'pygments.rb',     '~> 0.5.4' |   s.add_dependency 'pygments.rb',     '~> 0.6.0' | ||||||
|  |   s.add_dependency 'rugged',          '~> 0.21.1b2' | ||||||
|  |  | ||||||
|   s.add_development_dependency 'json' |  | ||||||
|   s.add_development_dependency 'mocha' |   s.add_development_dependency 'mocha' | ||||||
|  |   s.add_development_dependency 'pry' | ||||||
|   s.add_development_dependency 'rake' |   s.add_development_dependency 'rake' | ||||||
|   s.add_development_dependency 'yajl-ruby' |   s.add_development_dependency 'yajl-ruby' | ||||||
| end | end | ||||||
|   | |||||||
| @@ -4,3 +4,4 @@ require 'linguist/heuristics' | |||||||
| require 'linguist/language' | require 'linguist/language' | ||||||
| require 'linguist/repository' | require 'linguist/repository' | ||||||
| require 'linguist/samples' | require 'linguist/samples' | ||||||
|  | require 'linguist/version' | ||||||
|   | |||||||
| @@ -1,6 +1,4 @@ | |||||||
| require 'linguist/generated' | require 'linguist/generated' | ||||||
| require 'linguist/language' |  | ||||||
|  |  | ||||||
| require 'charlock_holmes' | require 'charlock_holmes' | ||||||
| require 'escape_utils' | require 'escape_utils' | ||||||
| require 'mime/types' | require 'mime/types' | ||||||
| @@ -112,6 +110,12 @@ module Linguist | |||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  |     def ruby_encoding | ||||||
|  |       if hash = detect_encoding | ||||||
|  |         hash[:ruby_encoding] | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |  | ||||||
|     # Try to guess the encoding |     # Try to guess the encoding | ||||||
|     # |     # | ||||||
|     # Returns: a Hash, with :encoding, :confidence, :type |     # Returns: a Hash, with :encoding, :confidence, :type | ||||||
| @@ -241,7 +245,31 @@ module Linguist | |||||||
|     def lines |     def lines | ||||||
|       @lines ||= |       @lines ||= | ||||||
|         if viewable? && data |         if viewable? && data | ||||||
|           data.split(/\r\n|\r|\n/, -1) |           # `data` is usually encoded as ASCII-8BIT even when the content has | ||||||
|  |           # been detected as a different encoding. However, we are not allowed | ||||||
|  |           # to change the encoding of `data` because we've made the implicit | ||||||
|  |           # guarantee that each entry in `lines` is encoded the same way as | ||||||
|  |           # `data`. | ||||||
|  |           # | ||||||
|  |           # Instead, we re-encode each possible newline sequence as the | ||||||
|  |           # detected encoding, then force them back to the encoding of `data` | ||||||
|  |           # (usually a binary encoding like ASCII-8BIT). This means that the | ||||||
|  |           # byte sequence will match how newlines are likely encoded in the | ||||||
|  |           # file, but we don't have to change the encoding of `data` as far as | ||||||
|  |           # Ruby is concerned. This allows us to correctly parse out each line | ||||||
|  |           # without changing the encoding of `data`, and | ||||||
|  |           # also--importantly--without having to duplicate many (potentially | ||||||
|  |           # large) strings. | ||||||
|  |           begin | ||||||
|  |             encoded_newlines = ["\r\n", "\r", "\n"]. | ||||||
|  |               map { |nl| nl.encode(ruby_encoding, "ASCII-8BIT").force_encoding(data.encoding) } | ||||||
|  |  | ||||||
|  |             data.split(Regexp.union(encoded_newlines), -1) | ||||||
|  |           rescue Encoding::ConverterNotFoundError | ||||||
|  |             # The data is not splittable in the detected encoding.  Assume it's | ||||||
|  |             # one big line. | ||||||
|  |             [data] | ||||||
|  |           end | ||||||
|         else |         else | ||||||
|           [] |           [] | ||||||
|         end |         end | ||||||
| @@ -283,15 +311,7 @@ module Linguist | |||||||
|     # |     # | ||||||
|     # Returns a Language or nil if none is detected |     # Returns a Language or nil if none is detected | ||||||
|     def language |     def language | ||||||
|       return @language if defined? @language |       @language ||= Language.detect(self) | ||||||
|  |  | ||||||
|       if defined?(@data) && @data.is_a?(String) |  | ||||||
|         data = @data |  | ||||||
|       else |  | ||||||
|         data = lambda { (binary_mime_type? || binary?) ? "" : self.data } |  | ||||||
|       end |  | ||||||
|  |  | ||||||
|       @language = Language.detect(name.to_s, data, mode) |  | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Internal: Get the lexer of the blob. |     # Internal: Get the lexer of the blob. | ||||||
| @@ -301,6 +321,11 @@ module Linguist | |||||||
|       language ? language.lexer : Pygments::Lexer.find_by_name('Text only') |       language ? language.lexer : Pygments::Lexer.find_by_name('Text only') | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  |     # Internal: Get the TextMate compatible scope for the blob | ||||||
|  |     def tm_scope | ||||||
|  |       language && language.tm_scope | ||||||
|  |     end | ||||||
|  |  | ||||||
|     # Public: Highlight syntax of blob |     # Public: Highlight syntax of blob | ||||||
|     # |     # | ||||||
|     # options - A Hash of options (defaults to {}) |     # options - A Hash of options (defaults to {}) | ||||||
|   | |||||||
| @@ -52,5 +52,20 @@ module Linguist | |||||||
|     def size |     def size | ||||||
|       File.size(@path) |       File.size(@path) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  |     # Public: Get file extension. | ||||||
|  |     # | ||||||
|  |     # Returns a String. | ||||||
|  |     def extension | ||||||
|  |       # File.extname returns nil if the filename is an extension. | ||||||
|  |       extension = File.extname(name) | ||||||
|  |       basename = File.basename(name) | ||||||
|  |       # Checks if the filename is an extension. | ||||||
|  |       if extension.empty? && basename[0] == "." | ||||||
|  |         basename | ||||||
|  |       else | ||||||
|  |         extension | ||||||
|  |       end | ||||||
|  |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|   | |||||||
| @@ -54,7 +54,7 @@ module Linguist | |||||||
|       name == 'Gemfile.lock' || |       name == 'Gemfile.lock' || | ||||||
|         minified_files? || |         minified_files? || | ||||||
|         compiled_coffeescript? || |         compiled_coffeescript? || | ||||||
|         xcode_project_file? || |         xcode_file? || | ||||||
|         generated_parser? || |         generated_parser? || | ||||||
|         generated_net_docfile? || |         generated_net_docfile? || | ||||||
|         generated_net_designer_file? || |         generated_net_designer_file? || | ||||||
| @@ -63,17 +63,19 @@ module Linguist | |||||||
|         generated_jni_header? || |         generated_jni_header? || | ||||||
|         composer_lock? || |         composer_lock? || | ||||||
|         node_modules? || |         node_modules? || | ||||||
|         vcr_cassette? |         godeps? || | ||||||
|  |         vcr_cassette? || | ||||||
|  |         generated_by_zephir? | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Internal: Is the blob an XCode project file? |     # Internal: Is the blob an Xcode file? | ||||||
|     # |     # | ||||||
|     # Generated if the file extension is an XCode project |     # Generated if the file extension is an Xcode  | ||||||
|     # file extension. |     # file extension. | ||||||
|     # |     # | ||||||
|     # Returns true of false. |     # Returns true of false. | ||||||
|     def xcode_project_file? |     def xcode_file? | ||||||
|       ['.xib', '.nib', '.storyboard', '.pbxproj', '.xcworkspacedata', '.xcuserstate'].include?(extname) |       ['.nib', '.xcworkspacedata', '.xcuserstate'].include?(extname) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Internal: Is the blob minified files? |     # Internal: Is the blob minified files? | ||||||
| @@ -230,11 +232,26 @@ module Linguist | |||||||
|       !!name.match(/node_modules\//) |       !!name.match(/node_modules\//) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  |     # Internal: Is the blob part of Godeps/, | ||||||
|  |     # which are not meant for humans in pull requests. | ||||||
|  |     # | ||||||
|  |     # Returns true or false. | ||||||
|  |     def godeps? | ||||||
|  |       !!name.match(/Godeps\//) | ||||||
|  |     end | ||||||
|  |  | ||||||
|     # Internal: Is the blob a generated php composer lock file? |     # Internal: Is the blob a generated php composer lock file? | ||||||
|     # |     # | ||||||
|     # Returns true or false. |     # Returns true or false. | ||||||
|     def composer_lock? |     def composer_lock? | ||||||
|       !!name.match(/composer.lock/) |       !!name.match(/composer\.lock/) | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     # Internal: Is the blob a generated by Zephir | ||||||
|  |     # | ||||||
|  |     # Returns true or false. | ||||||
|  |     def generated_by_zephir? | ||||||
|  |       !!name.match(/.\.zep\.(?:c|h|php)$/) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Is the blob a VCR Cassette file? |     # Is the blob a VCR Cassette file? | ||||||
| @@ -248,3 +265,4 @@ module Linguist | |||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| module Linguist | module Linguist | ||||||
|   # A collection of simple heuristics that can be used to better analyze languages. |   # A collection of simple heuristics that can be used to better analyze languages. | ||||||
|   class Heuristics |   class Heuristics | ||||||
|     ACTIVE = false |     ACTIVE = true | ||||||
|  |  | ||||||
|     # Public: Given an array of String language names, |     # Public: Given an array of String language names, | ||||||
|     # apply heuristics against the given data and return an array |     # apply heuristics against the given data and return an array | ||||||
| @@ -13,25 +13,32 @@ module Linguist | |||||||
|     # Returns an array of Languages or [] |     # Returns an array of Languages or [] | ||||||
|     def self.find_by_heuristics(data, languages) |     def self.find_by_heuristics(data, languages) | ||||||
|       if active? |       if active? | ||||||
|         if languages.all? { |l| ["Objective-C", "C++"].include?(l) } |  | ||||||
|           disambiguate_c(data, languages) |  | ||||||
|         end |  | ||||||
|         if languages.all? { |l| ["Perl", "Prolog"].include?(l) } |         if languages.all? { |l| ["Perl", "Prolog"].include?(l) } | ||||||
|           disambiguate_pl(data, languages) |           result = disambiguate_pl(data, languages) | ||||||
|         end |         end | ||||||
|         if languages.all? { |l| ["ECL", "Prolog"].include?(l) } |         if languages.all? { |l| ["ECL", "Prolog"].include?(l) } | ||||||
|           disambiguate_ecl(data, languages) |           result = disambiguate_ecl(data, languages) | ||||||
|         end |         end | ||||||
|         if languages.all? { |l| ["TypeScript", "XML"].include?(l) } |         if languages.all? { |l| ["IDL", "Prolog"].include?(l) } | ||||||
|           disambiguate_ts(data, languages) |           result = disambiguate_pro(data, languages) | ||||||
|         end |         end | ||||||
|         if languages.all? { |l| ["Common Lisp", "OpenCL"].include?(l) } |         if languages.all? { |l| ["Common Lisp", "OpenCL"].include?(l) } | ||||||
|           disambiguate_cl(data, languages) |           result = disambiguate_cl(data, languages) | ||||||
|         end |         end | ||||||
|  |         if languages.all? { |l| ["Hack", "PHP"].include?(l) } | ||||||
|  |           result = disambiguate_hack(data, languages) | ||||||
|  |         end | ||||||
|  |         if languages.all? { |l| ["Scala", "SuperCollider"].include?(l) } | ||||||
|  |           result = disambiguate_sc(data, languages) | ||||||
|  |         end | ||||||
|  |         if languages.all? { |l| ["AsciiDoc", "AGS Script"].include?(l) } | ||||||
|  |           result = disambiguate_asc(data, languages) | ||||||
|  |         end | ||||||
|  |         return result | ||||||
|       end |       end | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # .h extensions are ambigious between C, C++, and Objective-C. |     # .h extensions are ambiguous between C, C++, and Objective-C. | ||||||
|     # We want to shortcut look for Objective-C _and_ now C++ too! |     # We want to shortcut look for Objective-C _and_ now C++ too! | ||||||
|     # |     # | ||||||
|     # Returns an array of Languages or [] |     # Returns an array of Languages or [] | ||||||
| @@ -56,6 +63,16 @@ module Linguist | |||||||
|       matches |       matches | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  |     def self.disambiguate_pro(data, languages) | ||||||
|  |       matches = [] | ||||||
|  |       if (data.include?(":-")) | ||||||
|  |         matches << Language["Prolog"] | ||||||
|  |       else | ||||||
|  |         matches << Language["IDL"] | ||||||
|  |       end | ||||||
|  |       matches | ||||||
|  |     end | ||||||
|  |  | ||||||
|     def self.disambiguate_ts(data, languages) |     def self.disambiguate_ts(data, languages) | ||||||
|       matches = [] |       matches = [] | ||||||
|       if (data.include?("</translation>")) |       if (data.include?("</translation>")) | ||||||
| @@ -73,6 +90,40 @@ module Linguist | |||||||
|       matches |       matches | ||||||
|     end |     end | ||||||
|  |  | ||||||
|  |     def self.disambiguate_r(data, languages) | ||||||
|  |       matches = [] | ||||||
|  |       matches << Language["Rebol"] if /\bRebol\b/i.match(data) | ||||||
|  |       matches << Language["R"] if data.include?("<-") | ||||||
|  |       matches | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def self.disambiguate_hack(data, languages) | ||||||
|  |       matches = [] | ||||||
|  |       if data.include?("<?hh") | ||||||
|  |         matches << Language["Hack"] | ||||||
|  |       elsif /<?[^h]/.match(data) | ||||||
|  |         matches << Language["PHP"] | ||||||
|  |       end | ||||||
|  |       matches | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def self.disambiguate_sc(data, languages) | ||||||
|  |       matches = [] | ||||||
|  |       if (/\^(this|super)\./.match(data) || /^\s*(\+|\*)\s*\w+\s*{/.match(data) || /^\s*~\w+\s*=\./.match(data)) | ||||||
|  |         matches << Language["SuperCollider"] | ||||||
|  |       end | ||||||
|  |       if (/^\s*import (scala|java)\./.match(data) || /^\s*val\s+\w+\s*=/.match(data) || /^\s*class\b/.match(data)) | ||||||
|  |         matches << Language["Scala"] | ||||||
|  |       end | ||||||
|  |       matches | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def self.disambiguate_asc(data, languages) | ||||||
|  |       matches = [] | ||||||
|  |       matches << Language["AsciiDoc"] if /^=+(\s|\n)/.match(data) | ||||||
|  |       matches | ||||||
|  |     end | ||||||
|  |  | ||||||
|     def self.active? |     def self.active? | ||||||
|       !!ACTIVE |       !!ACTIVE | ||||||
|     end |     end | ||||||
|   | |||||||
| @@ -2,13 +2,15 @@ require 'escape_utils' | |||||||
| require 'pygments' | require 'pygments' | ||||||
| require 'yaml' | require 'yaml' | ||||||
| begin | begin | ||||||
|   require 'json' |   require 'yajl' | ||||||
| rescue LoadError | rescue LoadError | ||||||
| end | end | ||||||
|  |  | ||||||
| require 'linguist/classifier' | require 'linguist/classifier' | ||||||
| require 'linguist/heuristics' | require 'linguist/heuristics' | ||||||
| require 'linguist/samples' | require 'linguist/samples' | ||||||
|  | require 'linguist/file_blob' | ||||||
|  | require 'linguist/blob_helper' | ||||||
|  |  | ||||||
| module Linguist | module Linguist | ||||||
|   # Language names that are recognizable by GitHub. Defined languages |   # Language names that are recognizable by GitHub. Defined languages | ||||||
| @@ -24,7 +26,6 @@ module Linguist | |||||||
|     @extension_index          = Hash.new { |h,k| h[k] = [] } |     @extension_index          = Hash.new { |h,k| h[k] = [] } | ||||||
|     @interpreter_index        = Hash.new { |h,k| h[k] = [] } |     @interpreter_index        = Hash.new { |h,k| h[k] = [] } | ||||||
|     @filename_index           = Hash.new { |h,k| h[k] = [] } |     @filename_index           = Hash.new { |h,k| h[k] = [] } | ||||||
|     @primary_extension_index  = {} |  | ||||||
|  |  | ||||||
|     # Valid Languages types |     # Valid Languages types | ||||||
|     TYPES = [:data, :markup, :programming, :prose] |     TYPES = [:data, :markup, :programming, :prose] | ||||||
| @@ -61,7 +62,7 @@ module Linguist | |||||||
|       end |       end | ||||||
|  |  | ||||||
|       # Language name index |       # Language name index | ||||||
|       @index[language.name] = @name_index[language.name] = language |       @index[language.name.downcase] = @name_index[language.name.downcase] = language | ||||||
|  |  | ||||||
|       language.aliases.each do |name| |       language.aliases.each do |name| | ||||||
|         # All Language aliases should be unique. Raise if there is a duplicate. |         # All Language aliases should be unique. Raise if there is a duplicate. | ||||||
| @@ -69,7 +70,7 @@ module Linguist | |||||||
|           raise ArgumentError, "Duplicate alias: #{name}" |           raise ArgumentError, "Duplicate alias: #{name}" | ||||||
|         end |         end | ||||||
|  |  | ||||||
|         @index[name] = @alias_index[name] = language |         @index[name.downcase] = @alias_index[name.downcase] = language | ||||||
|       end |       end | ||||||
|  |  | ||||||
|       language.extensions.each do |extension| |       language.extensions.each do |extension| | ||||||
| @@ -80,12 +81,6 @@ module Linguist | |||||||
|         @extension_index[extension] << language |         @extension_index[extension] << language | ||||||
|       end |       end | ||||||
|  |  | ||||||
|       if @primary_extension_index.key?(language.primary_extension) |  | ||||||
|         raise ArgumentError, "Duplicate primary extension: #{language.primary_extension}" |  | ||||||
|       end |  | ||||||
|  |  | ||||||
|       @primary_extension_index[language.primary_extension] = language |  | ||||||
|  |  | ||||||
|       language.interpreters.each do |interpreter| |       language.interpreters.each do |interpreter| | ||||||
|         @interpreter_index[interpreter] << language |         @interpreter_index[interpreter] << language | ||||||
|       end |       end | ||||||
| @@ -99,18 +94,25 @@ module Linguist | |||||||
|  |  | ||||||
|     # Public: Detects the Language of the blob. |     # Public: Detects the Language of the blob. | ||||||
|     # |     # | ||||||
|     # name - String filename |     # blob - an object that includes the Linguist `BlobHelper` interface; | ||||||
|     # data - String blob data. A block also maybe passed in for lazy |     #       see Linguist::LazyBlob and Linguist::FileBlob for examples | ||||||
|     #        loading. This behavior is deprecated and you should always |  | ||||||
|     #        pass in a String. |  | ||||||
|     # mode - Optional String mode (defaults to nil) |  | ||||||
|     # |     # | ||||||
|     # Returns Language or nil. |     # Returns Language or nil. | ||||||
|     def self.detect(name, data, mode = nil) |     def self.detect(blob) | ||||||
|  |       name = blob.name.to_s | ||||||
|  |  | ||||||
|  |       # Check if the blob is possibly binary and bail early; this is a cheap | ||||||
|  |       # test that uses the extension name to guess a binary binary mime type. | ||||||
|  |       # | ||||||
|  |       # We'll perform a more comprehensive test later which actually involves | ||||||
|  |       # looking for binary characters in the blob | ||||||
|  |       return nil if blob.likely_binary? || blob.binary? | ||||||
|  |  | ||||||
|       # A bit of an elegant hack. If the file is executable but extensionless, |       # A bit of an elegant hack. If the file is executable but extensionless, | ||||||
|       # append a "magic" extension so it can be classified with other |       # append a "magic" extension so it can be classified with other | ||||||
|       # languages that have shebang scripts. |       # languages that have shebang scripts. | ||||||
|       if File.extname(name).empty? && mode && (mode.to_i(8) & 05) == 05 |       extension = FileBlob.new(name).extension | ||||||
|  |       if extension.empty? && blob.mode && (blob.mode.to_i(8) & 05) == 05 | ||||||
|         name += ".script!" |         name += ".script!" | ||||||
|       end |       end | ||||||
|  |  | ||||||
| @@ -121,10 +123,10 @@ module Linguist | |||||||
|       # extension at all, in the case of extensionless scripts), we need to continue |       # extension at all, in the case of extensionless scripts), we need to continue | ||||||
|       # our detection work |       # our detection work | ||||||
|       if possible_languages.length > 1 |       if possible_languages.length > 1 | ||||||
|         data = data.call() if data.respond_to?(:call) |         data = blob.data | ||||||
|         possible_language_names = possible_languages.map(&:name) |         possible_language_names = possible_languages.map(&:name) | ||||||
|  |  | ||||||
|         # Don't bother with emptiness |         # Don't bother with binary contents or an empty file | ||||||
|         if data.nil? || data == "" |         if data.nil? || data == "" | ||||||
|           nil |           nil | ||||||
|         # Check if there's a shebang line and use that as authoritative |         # Check if there's a shebang line and use that as authoritative | ||||||
| @@ -133,8 +135,8 @@ module Linguist | |||||||
|         # No shebang. Still more work to do. Try to find it with our heuristics. |         # No shebang. Still more work to do. Try to find it with our heuristics. | ||||||
|         elsif (determined = Heuristics.find_by_heuristics(data, possible_language_names)) && !determined.empty? |         elsif (determined = Heuristics.find_by_heuristics(data, possible_language_names)) && !determined.empty? | ||||||
|           determined.first |           determined.first | ||||||
|         # Lastly, fall back to the probablistic classifier. |         # Lastly, fall back to the probabilistic classifier. | ||||||
|         elsif classified = Classifier.classify(Samples::DATA, data, possible_language_names ).first |         elsif classified = Classifier.classify(Samples.cache, data, possible_language_names).first | ||||||
|           # Return the actual Language object based of the string language name (i.e., first element of `#classify`) |           # Return the actual Language object based of the string language name (i.e., first element of `#classify`) | ||||||
|           Language[classified[0]] |           Language[classified[0]] | ||||||
|         end |         end | ||||||
| @@ -162,7 +164,7 @@ module Linguist | |||||||
|     # |     # | ||||||
|     # Returns the Language or nil if none was found. |     # Returns the Language or nil if none was found. | ||||||
|     def self.find_by_name(name) |     def self.find_by_name(name) | ||||||
|       @name_index[name] |       @name_index[name.downcase] | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Public: Look up Language by one of its aliases. |     # Public: Look up Language by one of its aliases. | ||||||
| @@ -176,7 +178,7 @@ module Linguist | |||||||
|     # |     # | ||||||
|     # Returns the Lexer or nil if none was found. |     # Returns the Lexer or nil if none was found. | ||||||
|     def self.find_by_alias(name) |     def self.find_by_alias(name) | ||||||
|       @alias_index[name] |       @alias_index[name.downcase] | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Public: Look up Languages by filename. |     # Public: Look up Languages by filename. | ||||||
| @@ -190,11 +192,27 @@ module Linguist | |||||||
|     # |     # | ||||||
|     # Returns all matching Languages or [] if none were found. |     # Returns all matching Languages or [] if none were found. | ||||||
|     def self.find_by_filename(filename) |     def self.find_by_filename(filename) | ||||||
|       basename, extname = File.basename(filename), File.extname(filename) |       basename = File.basename(filename) | ||||||
|       langs = [@primary_extension_index[extname]] + |       extname = FileBlob.new(filename).extension | ||||||
|               @filename_index[basename] + |       (@filename_index[basename] + find_by_extension(extname)).compact.uniq | ||||||
|               @extension_index[extname] |     end | ||||||
|       langs.compact.uniq |  | ||||||
|  |     # Public: Look up Languages by file extension. | ||||||
|  |     # | ||||||
|  |     # extname - The extension String. | ||||||
|  |     # | ||||||
|  |     # Examples | ||||||
|  |     # | ||||||
|  |     #   Language.find_by_extension('.rb') | ||||||
|  |     #   # => [#<Language name="Ruby">] | ||||||
|  |     # | ||||||
|  |     #   Language.find_by_extension('rb') | ||||||
|  |     #   # => [#<Language name="Ruby">] | ||||||
|  |     # | ||||||
|  |     # Returns all matching Languages or [] if none were found. | ||||||
|  |     def self.find_by_extension(extname) | ||||||
|  |       extname = ".#{extname}" unless extname.start_with?(".") | ||||||
|  |       @extension_index[extname] | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Public: Look up Languages by shebang line. |     # Public: Look up Languages by shebang line. | ||||||
| @@ -225,7 +243,7 @@ module Linguist | |||||||
|     # |     # | ||||||
|     # Returns the Language or nil if none was found. |     # Returns the Language or nil if none was found. | ||||||
|     def self.[](name) |     def self.[](name) | ||||||
|       @index[name] |       @index[name.downcase] | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Public: A List of popular languages |     # Public: A List of popular languages | ||||||
| @@ -288,6 +306,16 @@ module Linguist | |||||||
|       @lexer = Pygments::Lexer.find_by_name(attributes[:lexer] || name) || |       @lexer = Pygments::Lexer.find_by_name(attributes[:lexer] || name) || | ||||||
|         raise(ArgumentError, "#{@name} is missing lexer") |         raise(ArgumentError, "#{@name} is missing lexer") | ||||||
|  |  | ||||||
|  |       @tm_scope = attributes[:tm_scope] || begin | ||||||
|  |         context = case @type | ||||||
|  |                   when :data, :markup, :prose | ||||||
|  |                     'text' | ||||||
|  |                   when :programming, nil | ||||||
|  |                     'source' | ||||||
|  |                   end | ||||||
|  |         "#{context}.#{@name.downcase}" | ||||||
|  |       end | ||||||
|  |  | ||||||
|       @ace_mode = attributes[:ace_mode] |       @ace_mode = attributes[:ace_mode] | ||||||
|       @wrap = attributes[:wrap] || false |       @wrap = attributes[:wrap] || false | ||||||
|  |  | ||||||
| @@ -299,15 +327,6 @@ module Linguist | |||||||
|       @interpreters = attributes[:interpreters]   || [] |       @interpreters = attributes[:interpreters]   || [] | ||||||
|       @filenames  = attributes[:filenames]  || [] |       @filenames  = attributes[:filenames]  || [] | ||||||
|  |  | ||||||
|       unless @primary_extension = attributes[:primary_extension] |  | ||||||
|         raise ArgumentError, "#{@name} is missing primary extension" |  | ||||||
|       end |  | ||||||
|  |  | ||||||
|       # Prepend primary extension unless its already included |  | ||||||
|       if primary_extension && !extensions.include?(primary_extension) |  | ||||||
|         @extensions = [primary_extension] + extensions |  | ||||||
|       end |  | ||||||
|  |  | ||||||
|       # Set popular, and searchable flags |       # Set popular, and searchable flags | ||||||
|       @popular    = attributes.key?(:popular)    ? attributes[:popular]    : false |       @popular    = attributes.key?(:popular)    ? attributes[:popular]    : false | ||||||
|       @searchable = attributes.key?(:searchable) ? attributes[:searchable] : true |       @searchable = attributes.key?(:searchable) ? attributes[:searchable] : true | ||||||
| @@ -370,6 +389,11 @@ module Linguist | |||||||
|     # Returns the Lexer |     # Returns the Lexer | ||||||
|     attr_reader :lexer |     attr_reader :lexer | ||||||
|  |  | ||||||
|  |     # Public: Get the name of a TextMate-compatible scope | ||||||
|  |     # | ||||||
|  |     # Returns the scope | ||||||
|  |     attr_reader :tm_scope | ||||||
|  |  | ||||||
|     # Public: Get Ace mode |     # Public: Get Ace mode | ||||||
|     # |     # | ||||||
|     # Examples |     # Examples | ||||||
| @@ -395,20 +419,6 @@ module Linguist | |||||||
|     # Returns the extensions Array |     # Returns the extensions Array | ||||||
|     attr_reader :extensions |     attr_reader :extensions | ||||||
|  |  | ||||||
|     # Deprecated: Get primary extension |  | ||||||
|     # |  | ||||||
|     # Defaults to the first extension but can be overridden |  | ||||||
|     # in the languages.yml. |  | ||||||
|     # |  | ||||||
|     # The primary extension can not be nil. Tests should verify this. |  | ||||||
|     # |  | ||||||
|     # This attribute is only used by app/helpers/gists_helper.rb for |  | ||||||
|     # creating the language dropdown. It really should be using `name` |  | ||||||
|     # instead. Would like to drop primary extension. |  | ||||||
|     # |  | ||||||
|     # Returns the extension String. |  | ||||||
|     attr_reader :primary_extension |  | ||||||
|  |  | ||||||
|     # Public: Get interpreters |     # Public: Get interpreters | ||||||
|     # |     # | ||||||
|     # Examples |     # Examples | ||||||
| @@ -427,6 +437,27 @@ module Linguist | |||||||
|     # Returns the extensions Array |     # Returns the extensions Array | ||||||
|     attr_reader :filenames |     attr_reader :filenames | ||||||
|  |  | ||||||
|  |     # Public: Return all possible extensions for language | ||||||
|  |     def all_extensions | ||||||
|  |       (extensions + [primary_extension]).uniq | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     # Deprecated: Get primary extension | ||||||
|  |     # | ||||||
|  |     # Defaults to the first extension but can be overridden | ||||||
|  |     # in the languages.yml. | ||||||
|  |     # | ||||||
|  |     # The primary extension can not be nil. Tests should verify this. | ||||||
|  |     # | ||||||
|  |     # This method is only used by app/helpers/gists_helper.rb for creating | ||||||
|  |     # the language dropdown. It really should be using `name` instead. | ||||||
|  |     # Would like to drop primary extension. | ||||||
|  |     # | ||||||
|  |     # Returns the extension String. | ||||||
|  |     def primary_extension | ||||||
|  |       extensions.first | ||||||
|  |     end | ||||||
|  |  | ||||||
|     # Public: Get URL escaped name. |     # Public: Get URL escaped name. | ||||||
|     # |     # | ||||||
|     # Examples |     # Examples | ||||||
| @@ -485,7 +516,7 @@ module Linguist | |||||||
|     # |     # | ||||||
|     # Returns html String |     # Returns html String | ||||||
|     def colorize(text, options = {}) |     def colorize(text, options = {}) | ||||||
|       lexer.highlight(text, options = {}) |       lexer.highlight(text, options) | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Public: Return name as String representation |     # Public: Return name as String representation | ||||||
| @@ -510,16 +541,16 @@ module Linguist | |||||||
|     end |     end | ||||||
|   end |   end | ||||||
|  |  | ||||||
|   extensions = Samples::DATA['extnames'] |   extensions = Samples.cache['extnames'] | ||||||
|   interpreters = Samples::DATA['interpreters'] |   interpreters = Samples.cache['interpreters'] | ||||||
|   filenames = Samples::DATA['filenames'] |   filenames = Samples.cache['filenames'] | ||||||
|   popular = YAML.load_file(File.expand_path("../popular.yml", __FILE__)) |   popular = YAML.load_file(File.expand_path("../popular.yml", __FILE__)) | ||||||
|  |  | ||||||
|   languages_yml = File.expand_path("../languages.yml", __FILE__) |   languages_yml = File.expand_path("../languages.yml", __FILE__) | ||||||
|   languages_json = File.expand_path("../languages.json", __FILE__) |   languages_json = File.expand_path("../languages.json", __FILE__) | ||||||
|  |  | ||||||
|   if File.exist?(languages_json) && defined?(JSON) |   if File.exist?(languages_json) && defined?(Yajl) | ||||||
|     languages = JSON.load(File.read(languages_json)) |     languages = Yajl.load(File.read(languages_json)) | ||||||
|   else |   else | ||||||
|     languages = YAML.load_file(languages_yml) |     languages = YAML.load_file(languages_yml) | ||||||
|   end |   end | ||||||
| @@ -532,6 +563,7 @@ module Linguist | |||||||
|     if extnames = extensions[name] |     if extnames = extensions[name] | ||||||
|       extnames.each do |extname| |       extnames.each do |extname| | ||||||
|         if !options['extensions'].include?(extname) |         if !options['extensions'].include?(extname) | ||||||
|  |           warn "#{name} has a sample with extension (#{extname}) that isn't explicitly defined in languages.yml" unless extname == '.script!' | ||||||
|           options['extensions'] << extname |           options['extensions'] << extname | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
| @@ -563,14 +595,14 @@ module Linguist | |||||||
|       :type              => options['type'], |       :type              => options['type'], | ||||||
|       :aliases           => options['aliases'], |       :aliases           => options['aliases'], | ||||||
|       :lexer             => options['lexer'], |       :lexer             => options['lexer'], | ||||||
|  |       :tm_scope          => options['tm_scope'], | ||||||
|       :ace_mode          => options['ace_mode'], |       :ace_mode          => options['ace_mode'], | ||||||
|       :wrap              => options['wrap'], |       :wrap              => options['wrap'], | ||||||
|       :group_name        => options['group'], |       :group_name        => options['group'], | ||||||
|       :searchable        => options.key?('searchable') ? options['searchable'] : true, |       :searchable        => options.key?('searchable') ? options['searchable'] : true, | ||||||
|       :search_term       => options['search_term'], |       :search_term       => options['search_term'], | ||||||
|       :extensions        => options['extensions'].sort, |       :extensions        => [options['extensions'].first] + options['extensions'][1..-1].sort, | ||||||
|       :interpreters      => options['interpreters'].sort, |       :interpreters      => options['interpreters'].sort, | ||||||
|       :primary_extension => options['primary_extension'], |  | ||||||
|       :filenames         => options['filenames'], |       :filenames         => options['filenames'], | ||||||
|       :popular           => popular.include?(name) |       :popular           => popular.include?(name) | ||||||
|     ) |     ) | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										71
									
								
								lib/linguist/lazy_blob.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								lib/linguist/lazy_blob.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | |||||||
|  | require 'linguist/blob_helper' | ||||||
|  | require 'linguist/language' | ||||||
|  | require 'rugged' | ||||||
|  |  | ||||||
|  | module Linguist | ||||||
|  |   class LazyBlob | ||||||
|  |     GIT_ATTR = ['linguist-language', 'linguist-vendored'] | ||||||
|  |     GIT_ATTR_OPTS = { :priority => [:index], :skip_system => true } | ||||||
|  |     GIT_ATTR_FLAGS = Rugged::Repository::Attributes.parse_opts(GIT_ATTR_OPTS) | ||||||
|  |  | ||||||
|  |     include BlobHelper | ||||||
|  |  | ||||||
|  |     MAX_SIZE = 128 * 1024 | ||||||
|  |  | ||||||
|  |     attr_reader :repository | ||||||
|  |     attr_reader :oid | ||||||
|  |     attr_reader :name | ||||||
|  |     attr_reader :mode | ||||||
|  |  | ||||||
|  |     def initialize(repo, oid, name, mode = nil) | ||||||
|  |       @repository = repo | ||||||
|  |       @oid = oid | ||||||
|  |       @name = name | ||||||
|  |       @mode = mode | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def git_attributes | ||||||
|  |       @git_attributes ||= repository.fetch_attributes( | ||||||
|  |         name, GIT_ATTR, GIT_ATTR_FLAGS) | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def vendored? | ||||||
|  |       if attr = git_attributes['linguist-vendored'] | ||||||
|  |         return boolean_attribute(attr) | ||||||
|  |       else | ||||||
|  |         return super | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def language | ||||||
|  |       return @language if defined?(@language) | ||||||
|  |  | ||||||
|  |       @language = if lang = git_attributes['linguist-language'] | ||||||
|  |         Language.find_by_name(lang) | ||||||
|  |       else | ||||||
|  |         super | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def data | ||||||
|  |       load_blob! | ||||||
|  |       @data | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def size | ||||||
|  |       load_blob! | ||||||
|  |       @size | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     protected | ||||||
|  |  | ||||||
|  |     # Returns true if the attribute is present and not the string "false". | ||||||
|  |     def boolean_attribute(attr) | ||||||
|  |       attr != "false" | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def load_blob! | ||||||
|  |       @data, @size = Rugged::Blob.to_buffer(repository, oid, MAX_SIZE) if @data.nil? | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
| @@ -1,4 +1,5 @@ | |||||||
| require 'linguist/file_blob' | require 'linguist/lazy_blob' | ||||||
|  | require 'rugged' | ||||||
|  |  | ||||||
| module Linguist | module Linguist | ||||||
|   # A Repository is an abstraction of a Grit::Repo or a basic file |   # A Repository is an abstraction of a Grit::Repo or a basic file | ||||||
| @@ -7,100 +8,165 @@ module Linguist | |||||||
|   # Its primary purpose is for gathering language statistics across |   # Its primary purpose is for gathering language statistics across | ||||||
|   # the entire project. |   # the entire project. | ||||||
|   class Repository |   class Repository | ||||||
|     # Public: Initialize a new Repository from a File directory |     attr_reader :repository | ||||||
|     # |  | ||||||
|     # base_path - A path String |     # Public: Create a new Repository based on the stats of | ||||||
|     # |     # an existing one | ||||||
|     # Returns a Repository |     def self.incremental(repo, commit_oid, old_commit_oid, old_stats) | ||||||
|     def self.from_directory(base_path) |       repo = self.new(repo, commit_oid) | ||||||
|       new Dir["#{base_path}/**/*"]. |       repo.load_existing_stats(old_commit_oid, old_stats) | ||||||
|         select { |f| File.file?(f) }. |       repo | ||||||
|         map { |path| FileBlob.new(path, base_path) } |  | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Public: Initialize a new Repository |     # Public: Initialize a new Repository to be analyzed for language | ||||||
|  |     # data | ||||||
|     # |     # | ||||||
|     # enum - Enumerator that responds to `each` and |     # repo - a Rugged::Repository object | ||||||
|     #        yields Blob objects |     # commit_oid - the sha1 of the commit that will be analyzed; | ||||||
|  |     #              this is usually the master branch | ||||||
|     # |     # | ||||||
|     # Returns a Repository |     # Returns a Repository | ||||||
|     def initialize(enum) |     def initialize(repo, commit_oid) | ||||||
|       @enum = enum |       @repository = repo | ||||||
|       @computed_stats = false |       @commit_oid = commit_oid | ||||||
|       @language = @size = nil |  | ||||||
|       @sizes = Hash.new { 0 } |       raise TypeError, 'commit_oid must be a commit SHA1' unless commit_oid.is_a?(String) | ||||||
|       @file_breakdown = Hash.new { |h,k| h[k] = Array.new } |     end | ||||||
|  |  | ||||||
|  |     # Public: Load the results of a previous analysis on this repository | ||||||
|  |     # to speed up the new scan. | ||||||
|  |     # | ||||||
|  |     # The new analysis will be performed incrementally as to only take | ||||||
|  |     # into account the file changes since the last time the repository | ||||||
|  |     # was scanned | ||||||
|  |     # | ||||||
|  |     # old_commit_oid - the sha1 of the commit that was previously analyzed | ||||||
|  |     # old_stats - the result of the previous analysis, obtained by calling | ||||||
|  |     #             Repository#cache on the old repository | ||||||
|  |     # | ||||||
|  |     # Returns nothing | ||||||
|  |     def load_existing_stats(old_commit_oid, old_stats) | ||||||
|  |       @old_commit_oid = old_commit_oid | ||||||
|  |       @old_stats = old_stats | ||||||
|  |       nil | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Public: Returns a breakdown of language stats. |     # Public: Returns a breakdown of language stats. | ||||||
|     # |     # | ||||||
|     # Examples |     # Examples | ||||||
|     # |     # | ||||||
|     #   # => { Language['Ruby'] => 46319, |     #   # => { 'Ruby' => 46319, | ||||||
|     #          Language['JavaScript'] => 258 } |     #          'JavaScript' => 258 } | ||||||
|     # |     # | ||||||
|     # Returns a Hash of Language keys and Integer size values. |     # Returns a Hash of language names and Integer size values. | ||||||
|     def languages |     def languages | ||||||
|       compute_stats |       @sizes ||= begin | ||||||
|       @sizes |         sizes = Hash.new { 0 } | ||||||
|  |         cache.each do |_, (language, size)| | ||||||
|  |           sizes[language] += size | ||||||
|  |         end | ||||||
|  |         sizes | ||||||
|  |       end | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Public: Get primary Language of repository. |     # Public: Get primary Language of repository. | ||||||
|     # |     # | ||||||
|     # Returns a Language |     # Returns a language name | ||||||
|     def language |     def language | ||||||
|       compute_stats |       @language ||= begin | ||||||
|       @language |         primary = languages.max_by { |(_, size)| size } | ||||||
|  |         primary && primary[0] | ||||||
|  |       end | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Public: Get the total size of the repository. |     # Public: Get the total size of the repository. | ||||||
|     # |     # | ||||||
|     # Returns a byte size Integer |     # Returns a byte size Integer | ||||||
|     def size |     def size | ||||||
|       compute_stats |       @size ||= languages.inject(0) { |s,(_,v)| s + v } | ||||||
|       @size |  | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Public: Return the language breakdown of this repository by file |     # Public: Return the language breakdown of this repository by file | ||||||
|  |     # | ||||||
|  |     # Returns a map of language names => [filenames...] | ||||||
|     def breakdown_by_file |     def breakdown_by_file | ||||||
|       compute_stats |       @file_breakdown ||= begin | ||||||
|       @file_breakdown |         breakdown = Hash.new { |h,k| h[k] = Array.new } | ||||||
|  |         cache.each do |filename, (language, _)| | ||||||
|  |           breakdown[language] << filename | ||||||
|  |         end | ||||||
|  |         breakdown | ||||||
|  |       end | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Internal: Compute language breakdown for each blob in the Repository. |     # Public: Return the cached results of the analysis | ||||||
|     # |     # | ||||||
|     # Returns nothing |     # This is a per-file breakdown that can be passed to other instances | ||||||
|     def compute_stats |     # of Linguist::Repository to perform incremental scans | ||||||
|       return if @computed_stats |     # | ||||||
|  |     # Returns a map of filename => [language, size] | ||||||
|  |     def cache | ||||||
|  |       @cache ||= begin | ||||||
|  |         if @old_commit_oid == @commit_oid | ||||||
|  |           @old_stats | ||||||
|  |         else | ||||||
|  |           compute_stats(@old_commit_oid, @old_stats) | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |  | ||||||
|       @enum.each do |blob| |     def read_index | ||||||
|         # Skip files that are likely binary |       attr_index = Rugged::Index.new | ||||||
|         next if blob.likely_binary? |       attr_index.read_tree(current_tree) | ||||||
|  |       repository.index = attr_index | ||||||
|  |     end | ||||||
|  |  | ||||||
|         # Skip vendored or generated blobs |     def current_tree | ||||||
|         next if blob.vendored? || blob.generated? || blob.language.nil? |       @tree ||= Rugged::Commit.lookup(repository, @commit_oid).tree | ||||||
|  |     end | ||||||
|  |  | ||||||
|         # Only include programming languages and acceptable markup languages |     protected | ||||||
|         if blob.language.type == :programming || Language.detectable_markup.include?(blob.language.name) |  | ||||||
|  |  | ||||||
|           # Build up the per-file breakdown stats |     def compute_stats(old_commit_oid, cache = nil) | ||||||
|           @file_breakdown[blob.language.group.name] << blob.name |       old_tree = old_commit_oid && Rugged::Commit.lookup(repository, old_commit_oid).tree | ||||||
|  |  | ||||||
|           @sizes[blob.language.group] += blob.size |       read_index | ||||||
|  |  | ||||||
|  |       diff = Rugged::Tree.diff(repository, old_tree, current_tree) | ||||||
|  |  | ||||||
|  |       # Clear file map and fetch full diff if any .gitattributes files are changed | ||||||
|  |       if cache && diff.each_delta.any? { |delta| File.basename(delta.new_file[:path]) == ".gitattributes" } | ||||||
|  |         diff = Rugged::Tree.diff(repository, old_tree = nil, current_tree) | ||||||
|  |         file_map = {} | ||||||
|  |       else | ||||||
|  |         file_map = cache ? cache.dup : {} | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       diff.each_delta do |delta| | ||||||
|  |         old = delta.old_file[:path] | ||||||
|  |         new = delta.new_file[:path] | ||||||
|  |  | ||||||
|  |         file_map.delete(old) | ||||||
|  |         next if delta.binary | ||||||
|  |  | ||||||
|  |         if [:added, :modified].include? delta.status | ||||||
|  |           # Skip submodules | ||||||
|  |           mode = delta.new_file[:mode] | ||||||
|  |           next if (mode & 040000) != 0 | ||||||
|  |  | ||||||
|  |           blob = Linguist::LazyBlob.new(repository, delta.new_file[:oid], new, mode.to_s(8)) | ||||||
|  |  | ||||||
|  |           # Skip vendored or generated blobs | ||||||
|  |           next if blob.vendored? || blob.generated? || blob.language.nil? | ||||||
|  |  | ||||||
|  |           # Only include programming languages and acceptable markup languages | ||||||
|  |           if blob.language.type == :programming || Language.detectable_markup.include?(blob.language.name) | ||||||
|  |             file_map[new] = [blob.language.group.name, blob.size] | ||||||
|  |           end | ||||||
|         end |         end | ||||||
|       end |       end | ||||||
|  |  | ||||||
|       # Compute total size |       file_map | ||||||
|       @size = @sizes.inject(0) { |s,(_,v)| s + v } |  | ||||||
|  |  | ||||||
|       # Get primary language |  | ||||||
|       if primary = @sizes.max_by { |(_, size)| size } |  | ||||||
|         @language = primary[0] |  | ||||||
|       end |  | ||||||
|  |  | ||||||
|       @computed_stats = true |  | ||||||
|  |  | ||||||
|       nil |  | ||||||
|     end |     end | ||||||
|   end |   end | ||||||
| end | end | ||||||
|   | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,5 +1,5 @@ | |||||||
| begin | begin | ||||||
|   require 'json' |   require 'yajl' | ||||||
| rescue LoadError | rescue LoadError | ||||||
|   require 'yaml' |   require 'yaml' | ||||||
| end | end | ||||||
| @@ -17,9 +17,11 @@ module Linguist | |||||||
|     PATH = File.expand_path('../samples.json', __FILE__) |     PATH = File.expand_path('../samples.json', __FILE__) | ||||||
|  |  | ||||||
|     # Hash of serialized samples object |     # Hash of serialized samples object | ||||||
|     if File.exist?(PATH) |     def self.cache | ||||||
|       serializer = defined?(JSON) ? JSON : YAML |       @cache ||= begin | ||||||
|       DATA = serializer.load(File.read(PATH)) |         serializer = defined?(Yajl) ? Yajl : YAML | ||||||
|  |         serializer.load(File.read(PATH)) | ||||||
|  |       end | ||||||
|     end |     end | ||||||
|  |  | ||||||
|     # Public: Iterate over each sample. |     # Public: Iterate over each sample. | ||||||
| @@ -28,7 +30,7 @@ module Linguist | |||||||
|     # |     # | ||||||
|     # Returns nothing. |     # Returns nothing. | ||||||
|     def self.each(&block) |     def self.each(&block) | ||||||
|       Dir.entries(ROOT).each do |category| |       Dir.entries(ROOT).sort!.each do |category| | ||||||
|         next if category == '.' || category == '..' |         next if category == '.' || category == '..' | ||||||
|  |  | ||||||
|         # Skip text and binary for now |         # Skip text and binary for now | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
| ## Vendor Conventions ## | ## Vendor Conventions ## | ||||||
|  |  | ||||||
| # Caches | # Caches | ||||||
| - cache/ | - (^|/)cache/ | ||||||
|  |  | ||||||
| # Dependencies | # Dependencies | ||||||
| - ^[Dd]ependencies/ | - ^[Dd]ependencies/ | ||||||
| @@ -33,16 +33,36 @@ | |||||||
| # Erlang bundles | # Erlang bundles | ||||||
| - ^rebar$ | - ^rebar$ | ||||||
|  |  | ||||||
| # Bootstrap minified css and js | # Go dependencies | ||||||
| - (^|/)bootstrap([^.]*)(\.min)?\.(js|css)$ | - Godeps/_workspace/ | ||||||
|  |  | ||||||
|  | # Minified JavaScript and CSS | ||||||
|  | - (\.|-)min\.(js|css)$ | ||||||
|  |  | ||||||
|  | # Bootstrap css and js | ||||||
|  | - (^|/)bootstrap([^.]*)\.(js|css)$ | ||||||
|  |  | ||||||
|  | # Font Awesome | ||||||
|  | - font-awesome.css | ||||||
|  |  | ||||||
| # Foundation css | # Foundation css | ||||||
| - foundation.min.css |  | ||||||
| - foundation.css | - foundation.css | ||||||
|  |  | ||||||
|  | # Normalize.css | ||||||
|  | - normalize.css | ||||||
|  |  | ||||||
|  | # Bourbon SCSS | ||||||
|  | - (^|/)[Bb]ourbon/.*\.css$ | ||||||
|  | - (^|/)[Bb]ourbon/.*\.scss$ | ||||||
|  |  | ||||||
|  | # Animate.css | ||||||
|  | - animate.css | ||||||
|  |  | ||||||
| # Vendored dependencies | # Vendored dependencies | ||||||
| - thirdparty/ | - third[-_]?party/ | ||||||
|  | - 3rd[-_]?party/ | ||||||
| - vendors?/ | - vendors?/ | ||||||
|  | - extern(al)?/ | ||||||
|  |  | ||||||
| # Debian packaging | # Debian packaging | ||||||
| - ^debian/ | - ^debian/ | ||||||
| @@ -53,12 +73,12 @@ | |||||||
| ## Commonly Bundled JavaScript frameworks ## | ## Commonly Bundled JavaScript frameworks ## | ||||||
|  |  | ||||||
| # jQuery | # jQuery | ||||||
| - (^|/)jquery([^.]*)(\.min)?\.js$ | - (^|/)jquery([^.]*)\.js$ | ||||||
| - (^|/)jquery\-\d\.\d+(\.\d+)?(\.min)?\.js$ | - (^|/)jquery\-\d\.\d+(\.\d+)?\.js$ | ||||||
|  |  | ||||||
| # jQuery UI | # jQuery UI | ||||||
| - (^|/)jquery\-ui(\-\d\.\d+(\.\d+)?)?(\.\w+)?(\.min)?\.(js|css)$ | - (^|/)jquery\-ui(\-\d\.\d+(\.\d+)?)?(\.\w+)?\.(js|css)$ | ||||||
| - (^|/)jquery\.(ui|effects)\.([^.]*)(\.min)?\.(js|css)$ | - (^|/)jquery\.(ui|effects)\.([^.]*)\.(js|css)$ | ||||||
|  |  | ||||||
| # Prototype | # Prototype | ||||||
| - (^|/)prototype(.*)\.js$ | - (^|/)prototype(.*)\.js$ | ||||||
| @@ -96,7 +116,20 @@ | |||||||
| - (^|/)shLegacy\.js$ | - (^|/)shLegacy\.js$ | ||||||
|  |  | ||||||
| # AngularJS | # AngularJS | ||||||
| - (^|/)angular([^.]*)(\.min)?\.js$ | - (^|/)angular([^.]*)\.js$ | ||||||
|  |  | ||||||
|  | # D3.js | ||||||
|  | - (^|\/)d3(\.v\d+)?([^.]*)\.js$ | ||||||
|  |  | ||||||
|  | # React | ||||||
|  | - (^|/)react(-[^.]*)?\.js$ | ||||||
|  |  | ||||||
|  | # Modernizr | ||||||
|  | - (^|/)modernizr\-\d\.\d+(\.\d+)?\.js$ | ||||||
|  | - (^|/)modernizr\.custom\.\d+\.js$ | ||||||
|  |  | ||||||
|  | # Knockout | ||||||
|  | - (^|/)knockout-(\d+\.){3}(debug\.)?js$ | ||||||
|  |  | ||||||
| ## Python ## | ## Python ## | ||||||
|  |  | ||||||
| @@ -114,6 +147,9 @@ | |||||||
|  |  | ||||||
| ## Obj-C ## | ## Obj-C ## | ||||||
|  |  | ||||||
|  | # Cocoapods | ||||||
|  | - ^Pods/ | ||||||
|  |  | ||||||
| # Sparkle | # Sparkle | ||||||
| - (^|/)Sparkle/ | - (^|/)Sparkle/ | ||||||
|  |  | ||||||
| @@ -128,16 +164,17 @@ | |||||||
|  |  | ||||||
| # Visual Studio IntelliSense | # Visual Studio IntelliSense | ||||||
| - -vsdoc\.js$ | - -vsdoc\.js$ | ||||||
|  | - \.intellisense\.js$ | ||||||
|  |  | ||||||
| # jQuery validation plugin (MS bundles this with asp.net mvc) | # jQuery validation plugin (MS bundles this with asp.net mvc) | ||||||
| - (^|/)jquery([^.]*)\.validate(\.unobtrusive)?(\.min)?\.js$ | - (^|/)jquery([^.]*)\.validate(\.unobtrusive)?\.js$ | ||||||
| - (^|/)jquery([^.]*)\.unobtrusive\-ajax(\.min)?\.js$ | - (^|/)jquery([^.]*)\.unobtrusive\-ajax\.js$ | ||||||
|  |  | ||||||
| # Microsoft Ajax | # Microsoft Ajax | ||||||
| - (^|/)[Mm]icrosoft([Mm]vc)?([Aa]jax|[Vv]alidation)(\.debug)?\.js$ | - (^|/)[Mm]icrosoft([Mm]vc)?([Aa]jax|[Vv]alidation)(\.debug)?\.js$ | ||||||
|  |  | ||||||
| # NuGet | # NuGet | ||||||
| - ^[Pp]ackages/ | - ^[Pp]ackages\/.+\.\d+\/ | ||||||
|  |  | ||||||
| # ExtJS | # ExtJS | ||||||
| - (^|/)extjs/.*?\.js$ | - (^|/)extjs/.*?\.js$ | ||||||
| @@ -157,6 +194,9 @@ | |||||||
| - (^|/)extjs/src/ | - (^|/)extjs/src/ | ||||||
| - (^|/)extjs/welcome/ | - (^|/)extjs/welcome/ | ||||||
|  |  | ||||||
|  | # Html5shiv | ||||||
|  | - (^|/)html5shiv\.js$ | ||||||
|  |  | ||||||
| # Samples folders | # Samples folders | ||||||
| - ^[Ss]amples/ | - ^[Ss]amples/ | ||||||
|  |  | ||||||
| @@ -174,11 +214,33 @@ | |||||||
| - ^[Tt]est/fixtures/ | - ^[Tt]est/fixtures/ | ||||||
|  |  | ||||||
| # PhoneGap/Cordova | # PhoneGap/Cordova | ||||||
| - (^|/)cordova([^.]*)(\.min)?\.js$ | - (^|/)cordova([^.]*)\.js$ | ||||||
| - (^|/)cordova\-\d\.\d(\.\d)?(\.min)?\.js$ | - (^|/)cordova\-\d\.\d(\.\d)?\.js$ | ||||||
|  |  | ||||||
|  | # Foundation js | ||||||
|  | - foundation(\..*)?\.js$ | ||||||
|  |  | ||||||
| # Vagrant | # Vagrant | ||||||
| - ^Vagrantfile$ | - ^Vagrantfile$ | ||||||
|  |  | ||||||
| # .DS_Store's | # .DS_Store's | ||||||
| - .[Dd][Ss]_[Ss]tore$ | - .[Dd][Ss]_[Ss]tore$ | ||||||
|  |  | ||||||
|  | # Mercury --use-subdirs | ||||||
|  | - Mercury/ | ||||||
|  |  | ||||||
|  | # R packages | ||||||
|  | - ^vignettes/ | ||||||
|  | - ^inst/extdata/ | ||||||
|  |  | ||||||
|  | # Octicons | ||||||
|  | - octicons.css | ||||||
|  | - sprockets-octicons.scss | ||||||
|  |  | ||||||
|  | # Typesafe Activator | ||||||
|  | - (^|/)activator$ | ||||||
|  | - (^|/)activator\.bat$ | ||||||
|  |  | ||||||
|  | # ProGuard | ||||||
|  | - proguard.pro | ||||||
|  | - proguard-rules.pro | ||||||
|   | |||||||
							
								
								
									
										3
									
								
								lib/linguist/version.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								lib/linguist/version.rb
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | module Linguist | ||||||
|  |   VERSION = "3.5.0" | ||||||
|  | end | ||||||
							
								
								
									
										521
									
								
								samples/AGS Script/GlobalScript.asc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										521
									
								
								samples/AGS Script/GlobalScript.asc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,521 @@ | |||||||
|  | // main global script file | ||||||
|  |  | ||||||
|  | // A function that initializes a bunch of stuff. | ||||||
|  | function initialize_control_panel() {  | ||||||
|  |   // Centre the control panel | ||||||
|  |   gPanel.Centre();  | ||||||
|  |   // Centre the Restart dialog as well | ||||||
|  |   gRestartYN.Centre();  | ||||||
|  |   if (!IsSpeechVoxAvailable()) {  | ||||||
|  |     // If there is no speech-vox file, and therefore no speech, | ||||||
|  |     // disable all the controls related with speech. | ||||||
|  |     lblVoice.Visible = false;   | ||||||
|  |     btnVoice.Visible = false;   | ||||||
|  |     sldVoice.Visible = false; | ||||||
|  |   } | ||||||
|  |   else { | ||||||
|  |     // If there *is*, then set it to voice and text. It's best to use | ||||||
|  |     // both whenever possible, for the player's sake. | ||||||
|  |     SetVoiceMode(eSpeechVoiceAndText);  | ||||||
|  |     // And reflect this in the control panel. | ||||||
|  |     btnVoice.Text = "Voice and Text";  | ||||||
|  |   } | ||||||
|  |   if (!System.SupportsGammaControl) { | ||||||
|  |     // If we can't change the gamma settings, disable the relevant options. | ||||||
|  |     sldGamma.Visible = false;  | ||||||
|  |     lblGamma.Visible = false; | ||||||
|  |   }  | ||||||
|  |    | ||||||
|  |   //And now, set all the defaults | ||||||
|  |   System.Volume = 100; | ||||||
|  |   sldAudio.Value = System.Volume; | ||||||
|  |   SetGameSpeed(40); | ||||||
|  |   sldSpeed.Value = 40; | ||||||
|  |   if (IsSpeechVoxAvailable()) { | ||||||
|  |      SetVoiceMode(eSpeechVoiceAndText); | ||||||
|  |      btnVoice.Text = "Voice and Text"; | ||||||
|  |      sldVoice.Value = 255; | ||||||
|  |      SetSpeechVolume(255); | ||||||
|  |   } | ||||||
|  |   if (System.SupportsGammaControl) { | ||||||
|  |     System.Gamma = 100; | ||||||
|  |     sldGamma.Value = 100; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Called when the game starts, before the first room is loaded | ||||||
|  | function game_start() {    | ||||||
|  |   // Put the code all in a function and then just call the function.  | ||||||
|  |   // It saves cluttering up places like game_start. | ||||||
|  |   initialize_control_panel();  | ||||||
|  |   // Use the KeyboardMovement module to, per default, replicate the standard | ||||||
|  |   // keyboard movement of most Sierra games. See KeyboardMovement.txt for more info | ||||||
|  |   KeyboardMovement.SetMode(eKeyboardMovement_Tapping);  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function repeatedly_execute() { | ||||||
|  |    | ||||||
|  |   // Put here anything you want to happen every game cycle, even when | ||||||
|  |   // the game is paused. This will not run when the game is blocked | ||||||
|  |   // inside a command like a blocking Walk() | ||||||
|  |    | ||||||
|  |   if (IsGamePaused() == 1) return; | ||||||
|  |  | ||||||
|  |   // Put here anything you want to happen every game cycle, but not | ||||||
|  |   // when the game is paused. | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function repeatedly_execute_always() { | ||||||
|  |    | ||||||
|  |   // Put anything you want to happen every game cycle, even | ||||||
|  |   // when the game is blocked inside a command like a | ||||||
|  |   // blocking Walk(). | ||||||
|  |   // You cannot run blocking commands from this function. | ||||||
|  |    | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function show_inventory_window ()  | ||||||
|  | { | ||||||
|  |   gInventory.Visible = true; | ||||||
|  |   // switch to the Use cursor (to select items with) | ||||||
|  |   mouse.Mode = eModeInteract; | ||||||
|  |   // But, override the appearance to look like the arrow | ||||||
|  |   mouse.UseModeGraphic(eModePointer); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function show_save_game_dialog() | ||||||
|  | { | ||||||
|  |   gSaveGame.Visible = true; | ||||||
|  |   // Get the list of save games | ||||||
|  |   lstSaveGamesList.FillSaveGameList(); | ||||||
|  |   if (lstSaveGamesList.ItemCount > 0) | ||||||
|  |   { | ||||||
|  |     // If there is at least one, set the default text | ||||||
|  |     // to be the first game's name | ||||||
|  |     txtNewSaveName.Text = lstSaveGamesList.Items[0]; | ||||||
|  |   } | ||||||
|  |   else | ||||||
|  |   { | ||||||
|  |     // No save games yet, default empty text. | ||||||
|  |     txtNewSaveName.Text = ""; | ||||||
|  |   } | ||||||
|  |   mouse.UseModeGraphic(eModePointer); | ||||||
|  |   gIconbar.Visible = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function show_restore_game_dialog() | ||||||
|  | { | ||||||
|  |   gRestoreGame.Visible = true; | ||||||
|  |   lstRestoreGamesList.FillSaveGameList(); | ||||||
|  |   mouse.UseModeGraphic(eModePointer); | ||||||
|  |   gIconbar.Visible = false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function close_save_game_dialog() | ||||||
|  | { | ||||||
|  |   gSaveGame.Visible = false; | ||||||
|  |   mouse.UseDefaultGraphic(); | ||||||
|  |   gIconbar.Visible = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function close_restore_game_dialog() | ||||||
|  | { | ||||||
|  |   gRestoreGame.Visible = false; | ||||||
|  |   mouse.UseDefaultGraphic(); | ||||||
|  |   gIconbar.Visible = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // Called when a key is pressed. keycode holds the key's ASCII code | ||||||
|  | function on_key_press(eKeyCode keycode) { | ||||||
|  |   // The following is called before "if game is paused keycode=0", so | ||||||
|  |   // it'll happen even when the game is paused. | ||||||
|  |    | ||||||
|  |   if ((keycode == eKeyEscape) && gRestartYN.Visible) { | ||||||
|  |     //Use ESC to cancel restart. | ||||||
|  |     gRestartYN.Visible = false;  | ||||||
|  |     gIconbar.Visible = true; | ||||||
|  |     // If the panel's not ON, then the player must have gotten here by tapping F9, | ||||||
|  |     // therefore his cursor needs restoring. If the panel IS on, then it doesn't, | ||||||
|  |     // because it's already a pointer. Get used to thinking like this!! | ||||||
|  |     if (!gPanel.Visible) mouse.UseDefaultGraphic();  | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if ((keycode == eKeyEscape) && gPanel.Visible) { | ||||||
|  |     // Use ESC to turn the panel off. | ||||||
|  |     gPanel.Visible = false;  | ||||||
|  |     mouse.UseDefaultGraphic(); | ||||||
|  |     gIconbar.Visible = true; | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if ((keycode == eKeyEscape) && (gSaveGame.Visible)) | ||||||
|  |   { | ||||||
|  |     // Use ESC to close the save game dialog | ||||||
|  |     close_save_game_dialog(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if ((keycode == eKeyEscape) && (gRestoreGame.Visible)) | ||||||
|  |   { | ||||||
|  |     // Use ESC to close the restore game dialog | ||||||
|  |     close_restore_game_dialog(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   if (keycode == eKeyReturn) {  | ||||||
|  |     // ENTER, in this case merely confirms restart | ||||||
|  |     if (gRestartYN.Visible) RestartGame(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (IsGamePaused() || (IsInterfaceEnabled() == 0)) | ||||||
|  |   { | ||||||
|  |     // If the game is paused with a modal GUI on the | ||||||
|  |     // screen, or the player interface is disabled in | ||||||
|  |     // a cut scene, ignore any keypresses. | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // FUNCTION KEYS AND SYSTEM SHORTCUTS | ||||||
|  |   if (keycode == eKeyEscape) { | ||||||
|  |     // ESC | ||||||
|  |     gPanel.Visible = true;  | ||||||
|  |     gIconbar.Visible = false; | ||||||
|  |     mouse.UseModeGraphic(eModePointer); | ||||||
|  |   } | ||||||
|  |   if (keycode == eKeyCtrlQ)  QuitGame(1);   // Ctrl-Q | ||||||
|  |   if (keycode == eKeyF5) show_save_game_dialog();   // F5 | ||||||
|  |   if (keycode == eKeyF7) show_restore_game_dialog();  // F7 | ||||||
|  |   if (keycode == eKeyF9) { | ||||||
|  |     // F9, asks the player to confirm restarting (so much better to always confirm first) | ||||||
|  |     gRestartYN.Visible = true;   | ||||||
|  |     gIconbar.Visible = false; | ||||||
|  |     mouse.UseModeGraphic(eModePointer); | ||||||
|  |   } | ||||||
|  |   if (keycode == eKeyF12) SaveScreenShot("scrnshot.bmp");  // F12 | ||||||
|  |   if (keycode == eKeyTab)   show_inventory_window();  // Tab, show inventory | ||||||
|  |  | ||||||
|  |   // GAME COMMAND SHORTCUTS | ||||||
|  |   if (keycode == 'W') mouse.Mode=eModeWalkto; //Notice this alternate way to indicate keycodes. | ||||||
|  |   if (keycode == 'L') mouse.Mode=eModeLookat; //Note that all we do here is set modes. | ||||||
|  |   if (keycode == 'U') mouse.Mode=eModeInteract; //If you want something else to happen, such as GUI buttons highlighting, | ||||||
|  |   if (keycode == 'T') mouse.Mode=eModeTalkto; //you'll need some more scripting done. | ||||||
|  |   if (keycode == 'I') mouse.Mode=eModeUseinv; //But this will, as-is, give you some standard keyboard shortcuts your players will very much appreciate. | ||||||
|  |  | ||||||
|  |   // For extra cursor modes, such as pick up, feel free to add as you will. | ||||||
|  |   // Uncomment the line below if you use the "Pick Up" mode. | ||||||
|  |   //if (keycode == 'P' || keycode == 'G') mouse.Mode=eModePickup;  | ||||||
|  |  | ||||||
|  |   // DEBUG FUNCTIONS | ||||||
|  |   if (keycode == eKeyCtrlS)  Debug(0,0);  // Ctrl-S, give all inventory | ||||||
|  |   if (keycode == eKeyCtrlV)  Debug(1,0);  // Ctrl-V, version | ||||||
|  |   if (keycode == eKeyCtrlA)  Debug(2,0);  // Ctrl-A, show walkable areas | ||||||
|  |   if (keycode == eKeyCtrlX)  Debug(3,0);  // Ctrl-X, teleport to room | ||||||
|  |   if (keycode == eKeyCtrlW && game.debug_mode)  | ||||||
|  |     player.PlaceOnWalkableArea(); //Ctrl-W, move to walkable area  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function on_mouse_click(MouseButton button) { | ||||||
|  |   // called when a mouse button is clicked. button is either LEFT or RIGHT | ||||||
|  |   if (IsGamePaused() == 1) { | ||||||
|  |     // Game is paused, so do nothing (ie. don't allow mouse click) | ||||||
|  |   } | ||||||
|  |   else if (button == eMouseLeft) { | ||||||
|  |     ProcessClick(mouse.x, mouse.y, mouse.Mode ); | ||||||
|  |   } | ||||||
|  |   else if (button == eMouseRight || button == eMouseWheelSouth){ | ||||||
|  |     // right-click our mouse-wheel down, so cycle cursor | ||||||
|  |     mouse.SelectNextMode(); | ||||||
|  |   } | ||||||
|  |   else if (button == eMouseMiddle) {  | ||||||
|  |     // Middle-button-click, default make character walk to clicked area (a little shortcut) | ||||||
|  |     // Could have been just "player.Walk(mouse.x,mouse.y)", but it's best to | ||||||
|  |     // leave our options open - what if you have a special script triggered | ||||||
|  |     // on "walking" mode? | ||||||
|  |     ProcessClick(mouse.x, mouse.y, eModeWalkto);  | ||||||
|  |   } | ||||||
|  |   else if (button == eMouseWheelNorth) {  | ||||||
|  |     // Mouse-wheel up, cycle cursors  | ||||||
|  |     // If mode isn't WALK, set the previous mode (notice usage of numbers instead | ||||||
|  |     // of eNums, when it suits us)... | ||||||
|  |     if (mouse.Mode>0) mouse.Mode=mouse.Mode-1;  | ||||||
|  |     else  | ||||||
|  |     {  | ||||||
|  |       // ...but if it is WALK mode... | ||||||
|  |       if (player.ActiveInventory!=null)  | ||||||
|  |       { | ||||||
|  |         //...and the player has a selected inventory item, set mouse mode to UseInv.  | ||||||
|  |         mouse.Mode=eModeUseinv;  | ||||||
|  |       } | ||||||
|  |       else  | ||||||
|  |       { | ||||||
|  |         // If they don't, however, just set it to mode TALK (change this line if you add more cursor modes) | ||||||
|  |         mouse.Mode=eModeTalkto;  | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function interface_click(int interface, int button) { | ||||||
|  |   // This function is obsolete, from 2.62 and earlier versions. | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnInvUp_Click(GUIControl *control, MouseButton button) { | ||||||
|  |   invCustomInv.ScrollUp(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnInvDown_Click(GUIControl *control, MouseButton button) { | ||||||
|  |   invCustomInv.ScrollDown(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnInvOK_Click(GUIControl *control, MouseButton button) { | ||||||
|  | 	// They pressed the OK button, close the GUI | ||||||
|  | 	gInventory.Visible = false; | ||||||
|  | 	mouse.UseDefaultGraphic(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnInvSelect_Click(GUIControl *control, MouseButton button) { | ||||||
|  |    | ||||||
|  | 	// They pressed SELECT, so switch to the Get cursor | ||||||
|  | 	mouse.Mode = eModeInteract; | ||||||
|  | 	// But, override the appearance to look like the arrow | ||||||
|  | 	mouse.UseModeGraphic(eModePointer); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnIconInv_Click(GUIControl *control, MouseButton button) { | ||||||
|  |    | ||||||
|  |   show_inventory_window(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnIconCurInv_Click(GUIControl *control, MouseButton button) { | ||||||
|  |    | ||||||
|  |   if (player.ActiveInventory != null) | ||||||
|  |     mouse.Mode = eModeUseinv; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnIconSave_Click(GUIControl *control, MouseButton button)  | ||||||
|  | { | ||||||
|  |   show_save_game_dialog(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnIconLoad_Click(GUIControl *control, MouseButton button)  | ||||||
|  | { | ||||||
|  |   show_restore_game_dialog(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnIconExit_Click(GUIControl *control, MouseButton button) { | ||||||
|  |    | ||||||
|  |   QuitGame(1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnIconAbout_Click(GUIControl *control, MouseButton button) { | ||||||
|  |    | ||||||
|  |   gPanel.Visible=true; | ||||||
|  |   gIconbar.Visible=false; | ||||||
|  |   mouse.UseModeGraphic(eModePointer); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function cEgo_Look() | ||||||
|  | { | ||||||
|  |   Display("Damn, I'm looking good!"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function cEgo_Interact() | ||||||
|  | { | ||||||
|  |   Display("You rub your hands up and down your clothes."); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function cEgo_Talk() | ||||||
|  | { | ||||||
|  |   Display("Talking to yourself is a sign of madness!"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //START OF CONTROL PANEL FUNCTIONS | ||||||
|  | function btnSave_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   gPanel.Visible = false; | ||||||
|  |   mouse.UseDefaultGraphic(); | ||||||
|  |   gIconbar.Visible = true; | ||||||
|  |   Wait(1); | ||||||
|  |   btnIconSave_Click(btnIconSave, eMouseLeft); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function gControl_OnClick(GUI *theGui, MouseButton button) | ||||||
|  | { | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnAbout_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  | Display("Adventure Game Studio run-time engine default game."); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnQuit_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   gPanel.Visible = false; | ||||||
|  |   Wait(1); | ||||||
|  |   QuitGame(1); | ||||||
|  |   gPanel.Visible = true; | ||||||
|  |   gIconbar.Visible = false; | ||||||
|  |   mouse.UseModeGraphic(eModePointer); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnLoad_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   gPanel.Visible = false; | ||||||
|  |   mouse.UseDefaultGraphic(); | ||||||
|  |   gIconbar.Visible = true; | ||||||
|  |   Wait(1); | ||||||
|  |   btnIconLoad_Click(btnIconLoad, eMouseLeft); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnResume_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   gPanel.Visible = false; | ||||||
|  |   mouse.UseDefaultGraphic(); | ||||||
|  |   gIconbar.Visible = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function sldAudio_OnChange(GUIControl *control) | ||||||
|  | { | ||||||
|  |   System.Volume = sldAudio.Value; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function sldVoice_OnChange(GUIControl *control) | ||||||
|  | { | ||||||
|  |   // Sets voice volume. Note that we don't check for the existence of speech.vox -  | ||||||
|  |   // we did that in game_start, so if it's not there the slider won't even be available. | ||||||
|  |   SetSpeechVolume(sldVoice.Value);  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnVoice_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   // Note that we don't check for the existence of speech.vox - we did that in game_start, | ||||||
|  |   // so if it's not there the button won't even be available. | ||||||
|  |   if (btnVoice.Text == "Voice and Text") {  | ||||||
|  |     SetVoiceMode(eSpeechVoiceOnly);  | ||||||
|  |     btnVoice.Text = "Voice only"; | ||||||
|  |   } | ||||||
|  |   else if (btnVoice.Text == "Voice only") { | ||||||
|  |     SetVoiceMode(eSpeechTextOnly); | ||||||
|  |     btnVoice.Text = "Text only"; | ||||||
|  |   } | ||||||
|  |   else if (btnVoice.Text == "Text only") { | ||||||
|  |     SetVoiceMode(eSpeechVoiceAndText); | ||||||
|  |     btnVoice.Text = "Voice and Text"; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function sldGamma_OnChange(GUIControl *control) | ||||||
|  | { | ||||||
|  |   // Set the gamma. Note there's no need to check for anything else, as we ensured, | ||||||
|  |   // in game_start, that the slider won't even appear if it's not possible to do this. | ||||||
|  |   System.Gamma = sldGamma.Value;  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnDefault_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   // Reset everything to default. You'll have to edit these as well as the sliders | ||||||
|  |   // if you'd rather have different default parameters. | ||||||
|  |   System.Volume = 100; | ||||||
|  |   sldAudio.Value = System.Volume; | ||||||
|  |   sldSpeed.Value = 40; | ||||||
|  |   SetGameSpeed(40); | ||||||
|  |   if (IsSpeechVoxAvailable()) { | ||||||
|  |      SetVoiceMode(eSpeechVoiceAndText); | ||||||
|  |      btnVoice.Text = "Voice and Text"; | ||||||
|  |      sldVoice.Value = 255; | ||||||
|  |      SetSpeechVolume(255); | ||||||
|  |   } | ||||||
|  |   if (System.SupportsGammaControl) { | ||||||
|  |     System.Gamma = 100; | ||||||
|  |     sldGamma.Value = 100; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | //END OF CONTROL PANEL FUNCTIONS | ||||||
|  |  | ||||||
|  | function dialog_request(int param)  | ||||||
|  | { | ||||||
|  |   // This is used by the dialog text parser if you need to process | ||||||
|  |   // text that the player types in to the parser. | ||||||
|  |   // It is not used by default. | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function sldSpeed_OnChange(GUIControl *control) | ||||||
|  | { | ||||||
|  |   SetGameSpeed(sldSpeed.Value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnRestart_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   gRestartYN.Visible=true; | ||||||
|  |   gIconbar.Visible=false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnRestartYes_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   RestartGame(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnRestartNo_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   gRestartYN.Visible = false; | ||||||
|  |   gIconbar.Visible = true; | ||||||
|  |   // If the panel's not ON, then the player must have gotten here by tapping F9, | ||||||
|  |   // therefore his cursor needs restoring. If the panel IS on, then it doesn't, | ||||||
|  |   // because it's already a pointer. Get used to thinking like this!! | ||||||
|  |   if (!gPanel.Visible) mouse.UseDefaultGraphic();  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnCancelSave_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   close_save_game_dialog(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnSaveGame_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   int gameSlotToSaveInto = lstSaveGamesList.ItemCount + 1; | ||||||
|  |   int i = 0; | ||||||
|  |   while (i < lstSaveGamesList.ItemCount) | ||||||
|  |   { | ||||||
|  |     if (lstSaveGamesList.Items[i] == txtNewSaveName.Text) | ||||||
|  |     { | ||||||
|  |       gameSlotToSaveInto = lstSaveGamesList.SaveGameSlots[i]; | ||||||
|  |     } | ||||||
|  |     i++; | ||||||
|  |   } | ||||||
|  |   SaveGameSlot(gameSlotToSaveInto, txtNewSaveName.Text); | ||||||
|  |   close_save_game_dialog(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnCancelRestore_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   close_restore_game_dialog(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnRestoreGame_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   if (lstRestoreGamesList.SelectedIndex >= 0) | ||||||
|  |   { | ||||||
|  |     RestoreGameSlot(lstRestoreGamesList.SaveGameSlots[lstRestoreGamesList.SelectedIndex]); | ||||||
|  |   } | ||||||
|  |   close_restore_game_dialog(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function lstSaveGamesList_OnSelectionCh(GUIControl *control) | ||||||
|  | { | ||||||
|  |   txtNewSaveName.Text = lstSaveGamesList.Items[lstSaveGamesList.SelectedIndex]; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function txtNewSaveName_OnActivate(GUIControl *control) | ||||||
|  | { | ||||||
|  |   // Pressing return in the text box simulates clicking the Save button | ||||||
|  |   btnSaveGame_OnClick(control, eMouseLeft); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function btnDeleteSave_OnClick(GUIControl *control, MouseButton button) | ||||||
|  | { | ||||||
|  |   if (lstSaveGamesList.SelectedIndex >= 0) | ||||||
|  |   { | ||||||
|  |     DeleteSaveSlot(lstSaveGamesList.SaveGameSlots[lstSaveGamesList.SelectedIndex]); | ||||||
|  |     lstSaveGamesList.FillSaveGameList(); | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										4
									
								
								samples/AGS Script/GlobalScript.ash
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								samples/AGS Script/GlobalScript.ash
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | |||||||
|  | // Main header script - this will be included into every script in | ||||||
|  | // the game (local and global). Do not place functions here; rather, | ||||||
|  | // place import definitions and #define names here to be used by all | ||||||
|  | // scripts. | ||||||
							
								
								
									
										216
									
								
								samples/AGS Script/KeyboardMovement_102.asc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								samples/AGS Script/KeyboardMovement_102.asc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | |||||||
|  | // Main script for module 'KeyboardMovement' | ||||||
|  |  | ||||||
|  | //**************************************************************************************************** | ||||||
|  | // DEFINITIONS | ||||||
|  | //**************************************************************************************************** | ||||||
|  |  | ||||||
|  | #define DISTANCE 10000// distance player walks in Tapping mode before he stops | ||||||
|  |  | ||||||
|  | enum KeyboardMovement_Directions { | ||||||
|  | 	eKeyboardMovement_Stop,  | ||||||
|  | 	eKeyboardMovement_DownLeft,  | ||||||
|  | 	eKeyboardMovement_Down,  | ||||||
|  | 	eKeyboardMovement_DownRight,  | ||||||
|  | 	eKeyboardMovement_Left,  | ||||||
|  | 	eKeyboardMovement_Right,  | ||||||
|  | 	eKeyboardMovement_UpLeft,  | ||||||
|  | 	eKeyboardMovement_Up,  | ||||||
|  | 	eKeyboardMovement_UpRight | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | //**************************************************************************************************** | ||||||
|  | // VARIABLES | ||||||
|  | //**************************************************************************************************** | ||||||
|  |  | ||||||
|  | // keycodes as variables for future key customization functions (static variables?): | ||||||
|  | int KeyboardMovement_KeyDown = 380; // down arrow | ||||||
|  | int KeyboardMovement_KeyLeft = 375; // left arrow | ||||||
|  | int KeyboardMovement_KeyRight = 377; // right arrow | ||||||
|  | int KeyboardMovement_KeyUp = 372; // up arrow | ||||||
|  | int KeyboardMovement_KeyDownRight = 381; // PgDn (numpad) | ||||||
|  | int KeyboardMovement_KeyUpRight = 373; // PgUp (numpad) | ||||||
|  | int KeyboardMovement_KeyDownLeft = 379; // End (numpad) | ||||||
|  | int KeyboardMovement_KeyUpLeft = 371; // Home (numpad) | ||||||
|  | int KeyboardMovement_KeyStop = 376; // 5 (numpad) | ||||||
|  |  | ||||||
|  | KeyboardMovement_Modes KeyboardMovement_Mode = eKeyboardMovement_None; // stores current keyboard control mode (disabled by default) | ||||||
|  |  | ||||||
|  | KeyboardMovement_Directions KeyboardMovement_CurrentDirection = eKeyboardMovement_Stop; // stores current walking direction of player character | ||||||
|  |  | ||||||
|  | //**************************************************************************************************** | ||||||
|  | // USER FUNCTIONS | ||||||
|  | //**************************************************************************************************** | ||||||
|  |  | ||||||
|  | //==================================================================================================== | ||||||
|  |  | ||||||
|  | static function KeyboardMovement::SetMode(KeyboardMovement_Modes mode) { | ||||||
|  | 	KeyboardMovement_Mode = mode; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //==================================================================================================== | ||||||
|  |  | ||||||
|  | // key customization functions here | ||||||
|  |  | ||||||
|  | //==================================================================================================== | ||||||
|  |  | ||||||
|  | //**************************************************************************************************** | ||||||
|  | // EVENT HANDLER FUNCTIONS | ||||||
|  | //**************************************************************************************************** | ||||||
|  |  | ||||||
|  | //==================================================================================================== | ||||||
|  |  | ||||||
|  | function repeatedly_execute() { | ||||||
|  |  | ||||||
|  | 	//-------------------------------------------------- | ||||||
|  | 	// Pressing mode | ||||||
|  | 	//-------------------------------------------------- | ||||||
|  |  | ||||||
|  | 	if ((IsGamePaused() == true) || (KeyboardMovement_Mode != eKeyboardMovement_Pressing) || (IsInterfaceEnabled() == false) || (player.on == false)) return 0; | ||||||
|  | 	  // if game is paused, module or mode disabled, interface disabled or player character hidden, quit function | ||||||
|  |  | ||||||
|  | 	KeyboardMovement_Directions newdirection; // declare variable storing new direction | ||||||
|  |  | ||||||
|  | 	// get new direction: | ||||||
|  | 	if ( ((IsKeyPressed(KeyboardMovement_KeyDown)) && (IsKeyPressed(KeyboardMovement_KeyRight))) || (IsKeyPressed(KeyboardMovement_KeyDownRight)) ) newdirection = eKeyboardMovement_DownRight; // if down&right arrows or PgDn (numeric pad) held down, set new direction to Down-Right | ||||||
|  | 	else if ( ((IsKeyPressed(KeyboardMovement_KeyUp)) && (IsKeyPressed(KeyboardMovement_KeyRight))) || (IsKeyPressed(KeyboardMovement_KeyUpRight)) ) newdirection = eKeyboardMovement_UpRight; // up&right arrows or PgUp (numpad) | ||||||
|  | 	else if ( ((IsKeyPressed(KeyboardMovement_KeyDown)) && (IsKeyPressed(KeyboardMovement_KeyLeft))) || (IsKeyPressed(KeyboardMovement_KeyDownLeft)) ) newdirection = eKeyboardMovement_DownLeft; // down&left arrows or End (numpad) | ||||||
|  | 	else if ( ((IsKeyPressed(KeyboardMovement_KeyUp)) && (IsKeyPressed(KeyboardMovement_KeyLeft))) || (IsKeyPressed(KeyboardMovement_KeyUpLeft)) ) newdirection = eKeyboardMovement_UpLeft; // up&left arrows or Home (numpad) | ||||||
|  | 	else if (IsKeyPressed(KeyboardMovement_KeyDown)) newdirection = eKeyboardMovement_Down; // down arrow | ||||||
|  | 	else if (IsKeyPressed(KeyboardMovement_KeyLeft)) newdirection = eKeyboardMovement_Left; // left arrow | ||||||
|  | 	else if (IsKeyPressed(KeyboardMovement_KeyRight)) newdirection = eKeyboardMovement_Right; // right arrow | ||||||
|  | 	else if (IsKeyPressed(KeyboardMovement_KeyUp)) newdirection = eKeyboardMovement_Up; // up arrow | ||||||
|  | 	else newdirection = eKeyboardMovement_Stop; // if none of the above held down, set it to stop player character | ||||||
|  |  | ||||||
|  | 	if (IsKeyPressed(KeyboardMovement_KeyStop)) newdirection = eKeyboardMovement_Stop; // if 5 (numeric pad) held down, stop player character, regardless of whether some of the above are held down | ||||||
|  |  | ||||||
|  | 	if (newdirection != KeyboardMovement_CurrentDirection) { // if new direction is different from current direction | ||||||
|  |  | ||||||
|  | 		if (newdirection == eKeyboardMovement_Stop) player.StopMoving(); // if new direction is the Stop command, stop movement of player character | ||||||
|  | 		else { // if new direction is NOT the Stop command | ||||||
|  |  | ||||||
|  | 			int dx, dy; // declare variables storing new walk coordinates | ||||||
|  | 			if (newdirection == eKeyboardMovement_DownRight) { | ||||||
|  | 				dx = DISTANCE; | ||||||
|  | 				dy = DISTANCE; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_UpRight) { | ||||||
|  | 				dx = DISTANCE; | ||||||
|  | 				dy = -DISTANCE; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_DownLeft) { | ||||||
|  | 				dx = -DISTANCE; | ||||||
|  | 				dy = DISTANCE; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_UpLeft) { | ||||||
|  | 				dx = -DISTANCE; | ||||||
|  | 				dy = -DISTANCE; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_Down) { | ||||||
|  | 				dx = 0; | ||||||
|  | 				dy = DISTANCE; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_Left) { | ||||||
|  | 				dx = -DISTANCE; | ||||||
|  | 				dy = 0; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_Right) { | ||||||
|  | 				dx = DISTANCE; | ||||||
|  | 				dy = 0; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_Up) { | ||||||
|  | 				dx = 0; | ||||||
|  | 				dy = -DISTANCE; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			player.WalkStraight(player.x + dx, player.y + dy, eNoBlock); // walk player character to the new coordinates | ||||||
|  | 		} | ||||||
|  | 		KeyboardMovement_CurrentDirection = newdirection; // update current direction to new direction | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //==================================================================================================== | ||||||
|  |  | ||||||
|  | function on_key_press(int keycode) { | ||||||
|  |  | ||||||
|  | 	//-------------------------------------------------- | ||||||
|  | 	// Tapping mode | ||||||
|  | 	//-------------------------------------------------- | ||||||
|  |  | ||||||
|  | 	if ((IsGamePaused() == true) || (KeyboardMovement_Mode != eKeyboardMovement_Tapping) || (IsInterfaceEnabled() == false) || (player.on == false)) return 0; | ||||||
|  | 	  // if game is paused, module or mode disabled, interface disabled or player character hidden, quit function | ||||||
|  |  | ||||||
|  | 	KeyboardMovement_Directions newdirection; // declare variable storing new direction | ||||||
|  |  | ||||||
|  | 	// get new direction: | ||||||
|  | 	if (keycode == KeyboardMovement_KeyDownRight) newdirection = eKeyboardMovement_DownRight; // if down-right key pressed, set new direction to Down-Right | ||||||
|  | 	else if (keycode == KeyboardMovement_KeyUpRight) newdirection = eKeyboardMovement_UpRight; | ||||||
|  | 	else if (keycode == KeyboardMovement_KeyDownLeft) newdirection = eKeyboardMovement_DownLeft; | ||||||
|  | 	else if (keycode == KeyboardMovement_KeyUpLeft) newdirection = eKeyboardMovement_UpLeft; | ||||||
|  | 	else if (keycode == KeyboardMovement_KeyDown) newdirection = eKeyboardMovement_Down; | ||||||
|  | 	else if (keycode == KeyboardMovement_KeyLeft) newdirection = eKeyboardMovement_Left; | ||||||
|  | 	else if (keycode == KeyboardMovement_KeyRight) newdirection = eKeyboardMovement_Right; | ||||||
|  | 	else if (keycode == KeyboardMovement_KeyUp) newdirection = eKeyboardMovement_Up; | ||||||
|  | 	else if (keycode == KeyboardMovement_KeyStop) newdirection = eKeyboardMovement_Stop; // if stop key pressed, set to stop player character | ||||||
|  |  | ||||||
|  | 	if (newdirection != KeyboardMovement_CurrentDirection) { // if new direction is different from current direction | ||||||
|  |  | ||||||
|  | 		if (newdirection == eKeyboardMovement_Stop) player.StopMoving(); // if new direction is the Stop command, stop movement of player character | ||||||
|  | 		else { // if new direction is NOT the Stop command | ||||||
|  |  | ||||||
|  | 			int dx, dy; // declare variables storing new walk coordinates | ||||||
|  | 			if (newdirection == eKeyboardMovement_DownRight) { | ||||||
|  | 				dx = DISTANCE; | ||||||
|  | 				dy = DISTANCE; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_UpRight) { | ||||||
|  | 				dx = DISTANCE; | ||||||
|  | 				dy = -DISTANCE; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_DownLeft) { | ||||||
|  | 				dx = -DISTANCE; | ||||||
|  | 				dy = DISTANCE; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_UpLeft) { | ||||||
|  | 				dx = -DISTANCE; | ||||||
|  | 				dy = -DISTANCE; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_Down) { | ||||||
|  | 				dx = 0; | ||||||
|  | 				dy = DISTANCE; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_Left) { | ||||||
|  | 				dx = -DISTANCE; | ||||||
|  | 				dy = 0; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_Right) { | ||||||
|  | 				dx = DISTANCE; | ||||||
|  | 				dy = 0; | ||||||
|  | 			} | ||||||
|  | 			else if (newdirection == eKeyboardMovement_Up) { | ||||||
|  | 				dx = 0; | ||||||
|  | 				dy = -DISTANCE; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			player.WalkStraight(player.x + dx, player.y + dy, eNoBlock); // walk player character to the new coordinates | ||||||
|  | 		} | ||||||
|  | 		KeyboardMovement_CurrentDirection = newdirection; // update current direction to new direction | ||||||
|  |  | ||||||
|  | 	} | ||||||
|  | 	else { // if new direction is same as current direction | ||||||
|  | 		player.StopMoving(); // stop player character | ||||||
|  | 		KeyboardMovement_CurrentDirection = eKeyboardMovement_Stop; // update current direction | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //==================================================================================================== | ||||||
|  |  | ||||||
|  | function on_event(EventType event, int data) { | ||||||
|  |  | ||||||
|  | 	if (event == eEventLeaveRoom) KeyboardMovement_CurrentDirection = eKeyboardMovement_Stop; | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | //==================================================================================================== | ||||||
							
								
								
									
										13
									
								
								samples/AGS Script/KeyboardMovement_102.ash
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								samples/AGS Script/KeyboardMovement_102.ash
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | // Script header for module 'KeyboardMovement' | ||||||
|  |  | ||||||
|  | #define KeyboardMovement_VERSION 101 | ||||||
|  |  | ||||||
|  | enum KeyboardMovement_Modes { | ||||||
|  | 	eKeyboardMovement_None,  | ||||||
|  | 	eKeyboardMovement_Tapping,  | ||||||
|  | 	eKeyboardMovement_Pressing | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | struct KeyboardMovement { | ||||||
|  | 	import static function SetMode(KeyboardMovement_Modes mode); | ||||||
|  | }; | ||||||
							
								
								
									
										18
									
								
								samples/APL/DeepakChopra.apl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								samples/APL/DeepakChopra.apl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | ⍝   You can try this at http://tryapl.org/ | ||||||
|  | ⍝   I can not explain how much I suddenly love this crypto-language | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Starts     ← 'Experiential truth ' 'The physical world ' 'Non-judgment '       'Quantum physics ' | ||||||
|  | Middles    ← 'nurtures an '        'projects onto '      'imparts reality to ' 'constructs with ' | ||||||
|  | Qualifiers ← 'abundance of '       'the barrier of '     'self-righteous '     'potential ' | ||||||
|  | Finishes   ← 'marvel.'             'choices.'            'creativity.'         'actions.' | ||||||
|  |  | ||||||
|  | rf     ← {(?⍴⍵)⊃⍵} | ||||||
|  | erf    ← {rf ¨ ⍵} | ||||||
|  |  | ||||||
|  | deepak ← {erf Starts Middles Qualifiers Finishes} | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | deepak ⍬ | ||||||
							
								
								
									
										367
									
								
								samples/APL/UT.dyalog
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										367
									
								
								samples/APL/UT.dyalog
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,367 @@ | |||||||
|  | :NameSpace UT | ||||||
|  |  | ||||||
|  |     sac ← 0 | ||||||
|  |     expect_orig ← expect ← ⎕NS⍬ | ||||||
|  |     exception ← ⍬ | ||||||
|  |     nexpect_orig ← nexpect ← ⎕NS⍬ | ||||||
|  |  | ||||||
|  |     ∇ {Z}←{Conf}run Argument;PRE_test;POST_test;TEST_step;COVER_step;FromSpace | ||||||
|  |       | ||||||
|  |       load_display_if_not_already_loaded | ||||||
|  |       load_salt_scripts_into_current_namespace_if_configured | ||||||
|  |       | ||||||
|  |       FromSpace←1⊃⎕RSI | ||||||
|  |       | ||||||
|  |       PRE_test←{} | ||||||
|  |       POST_test←{} | ||||||
|  |       COVER_step←{} | ||||||
|  |       :If 0≠⎕NC'Conf' | ||||||
|  |           :If Conf has'cover_target' | ||||||
|  |               PRE_test←{{}⎕PROFILE'start'} | ||||||
|  |               POST_test←{{}⎕PROFILE'stop'} | ||||||
|  |           :EndIf | ||||||
|  |       :EndIf | ||||||
|  |       | ||||||
|  |       :If is_function Argument | ||||||
|  |           TEST_step←single_function_test_function | ||||||
|  |           COVER_file←Argument,'_coverage.html' | ||||||
|  |       | ||||||
|  |       :ElseIf is_list_of_functions Argument | ||||||
|  |           TEST_step←list_of_functions_test_function | ||||||
|  |           COVER_file←'list_coverage.html' | ||||||
|  |       | ||||||
|  |       :ElseIf is_file Argument | ||||||
|  |           TEST_step←file_test_function | ||||||
|  |           COVER_file←(get_file_name Argument),'_coverage.html' | ||||||
|  |       | ||||||
|  |       :ElseIf is_dir Argument | ||||||
|  |           test_files←test_files_in_dir Argument | ||||||
|  |           TEST_step←test_dir_function | ||||||
|  |           Argument←test_files | ||||||
|  |       :EndIf | ||||||
|  |       | ||||||
|  |       :If 0≠⎕NC'Conf' | ||||||
|  |           :If Conf has'cover_target' | ||||||
|  |               COVER_step←{Conf,←⊂('cover_file'COVER_file) | ||||||
|  |                   generate_coverage_page Conf} | ||||||
|  |           :EndIf | ||||||
|  |       :EndIf | ||||||
|  |       | ||||||
|  |       PRE_test ⍬ | ||||||
|  |       Z←FromSpace TEST_step Argument | ||||||
|  |       POST_test ⍬ | ||||||
|  |       COVER_step ⍬ | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ load_display_if_not_already_loaded | ||||||
|  |       :If 0=⎕NC'#.DISPLAY' | ||||||
|  |           'DISPLAY'#.⎕CY'display' | ||||||
|  |       :EndIf | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ load_salt_scripts_into_current_namespace_if_configured | ||||||
|  |       :If 0≠⎕NC'#.UT.appdir' | ||||||
|  |           :If ⍬≢#.UT.appdir | ||||||
|  |               ⎕SE.SALT.Load #.UT.appdir,'src/*.dyalog -target=#' | ||||||
|  |               ⎕SE.SALT.Load #.UT.appdir,'test/*.dyalog -target=#' | ||||||
|  |           :EndIf | ||||||
|  |       :EndIf | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←FromSpace single_function_test_function TestName | ||||||
|  |       Z←run_ut FromSpace TestName | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←FromSpace list_of_functions_test_function ListOfNames;t | ||||||
|  |       t←⎕TS | ||||||
|  |       Z←run_ut¨{FromSpace ⍵}¨ListOfNames | ||||||
|  |       t←⎕TS-t | ||||||
|  |       ('Test execution report')print_passed_crashed_failed Z t | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←FromSpace file_test_function FilePath;FileNS;Functions;TestFunctions;t | ||||||
|  |       FileNS←⎕SE.SALT.Load FilePath,' -target=#' | ||||||
|  |       Functions←↓FileNS.⎕NL 3 | ||||||
|  |       TestFunctions←(is_test¨Functions)/Functions | ||||||
|  |       :If (0/⍬,⊂0/'')≡TestFunctions | ||||||
|  |           ⎕←'No test functions found' | ||||||
|  |           Z←⍬ | ||||||
|  |       :Else | ||||||
|  |           t←⎕TS | ||||||
|  |           Z←run_ut¨{FileNS ⍵}¨TestFunctions | ||||||
|  |           t←⎕TS-t | ||||||
|  |           (FilePath,' tests')print_passed_crashed_failed Z t | ||||||
|  |       :EndIf | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←FromSpace test_dir_function Test_files | ||||||
|  |       :If Test_files≡⍬/⍬,⊂'' | ||||||
|  |           ⎕←'No test files found' | ||||||
|  |           Z←⍬ | ||||||
|  |       :Else | ||||||
|  |           Z←#.UT.run¨Test_files | ||||||
|  |       :EndIf | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←get_file_name Argument;separator | ||||||
|  |       separator←⊃⌽(Argument∊'/\')/⍳⍴Argument | ||||||
|  |       Z←¯7↓separator↓Argument | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ generate_coverage_page Conf;ProfileData;CoverResults;HTML | ||||||
|  |       ProfileData←⎕PROFILE'data' | ||||||
|  |       ToCover←retrieve_coverables¨(⊃'cover_target'in Conf) | ||||||
|  |       :If (⍴ToCover)≡(⍴⊂1) | ||||||
|  |           ToCover←⊃ToCover | ||||||
|  |       :EndIf | ||||||
|  |       Representations←get_representation¨ToCover | ||||||
|  |       CoverResults←ProfileData∘generate_cover_result¨↓ToCover,[1.5]Representations | ||||||
|  |       HTML←generate_html CoverResults | ||||||
|  |       Conf write_html_to_page HTML | ||||||
|  |       ⎕PROFILE'clear' | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←retrieve_coverables Something;nc;functions | ||||||
|  |       nc←⎕NC Something | ||||||
|  |       :If nc=3 | ||||||
|  |           Z←Something | ||||||
|  |       :ElseIf nc=9 | ||||||
|  |           functions←strip¨↓⍎Something,'.⎕NL 3' | ||||||
|  |           Z←{(Something,'.',⍵)}¨functions | ||||||
|  |       :EndIf | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←strip input | ||||||
|  |       Z←(input≠' ')/input | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←get_representation Function;nc;rep | ||||||
|  |       nc←⎕NC⊂Function | ||||||
|  |       :If nc=3.1 | ||||||
|  |           rep←↓⎕CR Function | ||||||
|  |           rep[1]←⊂'∇',⊃rep[1] | ||||||
|  |           rep,←⊂'∇' | ||||||
|  |           rep←↑rep | ||||||
|  |       :Else | ||||||
|  |           rep←⎕CR Function | ||||||
|  |       :EndIf | ||||||
|  |       Z←rep | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←ProfileData generate_cover_result(name representation);Indices;lines;functionlines;covered_lines | ||||||
|  |       Indices←({name≡⍵}¨ProfileData[;1])/⍳⍴ProfileData[;1] | ||||||
|  |       lines←ProfileData[Indices;2] | ||||||
|  |       nc←⎕NC⊂name | ||||||
|  |       :If 3.1=nc | ||||||
|  |           functionlines←¯2+⍴↓representation | ||||||
|  |       :Else | ||||||
|  |           functionlines←⊃⍴↓representation | ||||||
|  |       :EndIf | ||||||
|  |       covered_lines←(⍬∘≢¨lines)/lines | ||||||
|  |       Z←(nc lines functionlines covered_lines representation) | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←generate_html CoverResults;Covered;Total;Percentage;CoverageText;ColorizedCode;Timestamp;Page | ||||||
|  |       Covered←⊃⊃+/{⍴4⊃⍵}¨CoverResults | ||||||
|  |       Total←⊃⊃+/{3⊃⍵}¨CoverResults | ||||||
|  |       Percentage←100×Covered÷Total | ||||||
|  |       CoverageText←'Coverage: ',Percentage,'% (',Covered,'/',Total,')' | ||||||
|  |       ColorizedCode←⊃,/{colorize_code_by_coverage ⍵}¨CoverResults | ||||||
|  |       Timestamp←generate_timestamp_text | ||||||
|  |       Page←⍬ | ||||||
|  |       Page,←⊂⍬,'<html>' | ||||||
|  |       Page,←⊂⍬,'<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>' | ||||||
|  |       Page,←⊂⍬,'<style>pre cov {line-height:80%;}' | ||||||
|  |       Page,←⊂⍬,'pre cov {color: green;}' | ||||||
|  |       Page,←⊂⍬,'pre uncov {line-height:80%;}' | ||||||
|  |       Page,←⊂⍬,'pre uncov {color:red;}</style>' | ||||||
|  |       Page,←⊂⍬,CoverageText | ||||||
|  |       Page,←⊂⍬,'<pre>' | ||||||
|  |       Page,←ColorizedCode | ||||||
|  |       Page,←⊂⍬,'</pre>' | ||||||
|  |       Page,←Timestamp | ||||||
|  |       Page,←⊂⍬,'</html>' | ||||||
|  |       Z←Page | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←colorize_code_by_coverage CoverResult;Colors;Ends;Code | ||||||
|  |       :If 3.1=⊃CoverResult | ||||||
|  |           Colors←(2+3⊃CoverResult)⍴⊂'<uncov>' | ||||||
|  |           Colors[1]←⊂'' | ||||||
|  |           Colors[⍴Colors]←⊂'' | ||||||
|  |           Ends←(2+3⊃CoverResult)⍴⊂'</uncov>' | ||||||
|  |           Ends[1]←⊂'' | ||||||
|  |           Ends[⍴Ends]←⊂'' | ||||||
|  |       :Else | ||||||
|  |           Colors←(3⊃CoverResult)⍴⊂'<uncov>' | ||||||
|  |           Ends←(3⊃CoverResult)⍴⊂'</uncov>' | ||||||
|  |       :EndIf | ||||||
|  |       Colors[1+4⊃CoverResult]←⊂'<cov>' | ||||||
|  |       Ends[1+4⊃CoverResult]←⊂'</cov>' | ||||||
|  |       Code←↓5⊃CoverResult | ||||||
|  |       Z←Colors,[1.5]Code | ||||||
|  |       Z←{⍺,(⎕UCS 13),⍵}/Z,Ends | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←generate_timestamp_text;TS;YYMMDD;HHMMSS | ||||||
|  |       TS←⎕TS | ||||||
|  |       YYMMDD←⊃{⍺,'-',⍵}/3↑TS | ||||||
|  |       HHMMSS←⊃{⍺,':',⍵}/3↑3↓TS | ||||||
|  |       Z←'Page generated: ',YYMMDD,'|',HHMMSS | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Conf write_html_to_page Page;tie;filename | ||||||
|  |       filename←(⊃'cover_out'in Conf),(⊃'cover_file'in Conf) | ||||||
|  |       :Trap 22 | ||||||
|  |           tie←filename ⎕NTIE 0 | ||||||
|  |           filename ⎕NERASE tie | ||||||
|  |           filename ⎕NCREATE tie | ||||||
|  |       :Else | ||||||
|  |           tie←filename ⎕NCREATE 0 | ||||||
|  |       :EndTrap | ||||||
|  |       Simple_array←⍕⊃,/Page | ||||||
|  |       (⎕UCS'UTF-8'⎕UCS Simple_array)⎕NAPPEND tie | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←is_function Argument | ||||||
|  |       Z←'_TEST'≡¯5↑Argument | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←is_list_of_functions Argument | ||||||
|  |       Z←2=≡Argument | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←is_file Argument | ||||||
|  |       Z←'.dyalog'≡¯7↑Argument | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←is_dir Argument;attr | ||||||
|  |       :If 'Linux'≡5↑⊃'.'⎕WG'APLVersion' | ||||||
|  |           Z←'yes'≡⊃⎕CMD'test -d ',Argument,' && echo yes || echo no' | ||||||
|  |       :Else | ||||||
|  |           'gfa'⎕NA'I kernel32|GetFileAttributes* <0t' | ||||||
|  |           :If Z←¯1≠attr←gfa⊂Argument ⍝ If file exists | ||||||
|  |               Z←⊃2 16⊤attr           ⍝ Return bit 4 | ||||||
|  |           :EndIf | ||||||
|  |       :EndIf | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     ∇ Z←test_files_in_dir Argument | ||||||
|  |       :If 'Linux'≡5↑⊃'.'⎕WG'APLVersion' | ||||||
|  |           Z←⎕SH'find ',Argument,' -name \*_tests.dyalog' | ||||||
|  |       :Else | ||||||
|  |           #.⎕CY'files' | ||||||
|  |           Z←#.Files.Dir Argument,'\*_tests.dyalog' | ||||||
|  |           Z←(Argument,'\')∘,¨Z | ||||||
|  |       :EndIf | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←run_ut ut_data;returned;crashed;pass;crash;fail;message | ||||||
|  |       (returned crashed time)←execute_function ut_data | ||||||
|  |       (pass crash fail)←determine_pass_crash_or_fail returned crashed | ||||||
|  |       message←determine_message pass fail crashed(2⊃ut_data)returned time | ||||||
|  |       print_message_to_screen message | ||||||
|  |       Z←(pass crash fail) | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←execute_function ut_data;function;t | ||||||
|  |       reset_UT_globals | ||||||
|  |       function←(⍕(⊃ut_data[1])),'.',⊃ut_data[2] | ||||||
|  |       :Trap sac | ||||||
|  |           :If 3.2≡⎕NC⊂function | ||||||
|  |               t←⎕TS | ||||||
|  |               Z←(⍎function,' ⍬')0 | ||||||
|  |               t←⎕TS-t | ||||||
|  |           :Else | ||||||
|  |               t←⎕TS | ||||||
|  |               Z←(⍎function)0 | ||||||
|  |               t←⎕TS-t | ||||||
|  |           :EndIf | ||||||
|  |       | ||||||
|  |       :Else | ||||||
|  |           Z←(↑⎕DM)1 | ||||||
|  |           :If exception≢⍬ | ||||||
|  |               expect←exception | ||||||
|  |               Z[2]←0 | ||||||
|  |               t←⎕TS-t | ||||||
|  |           :EndIf | ||||||
|  |       :EndTrap | ||||||
|  |       Z,←⊂t | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ reset_UT_globals | ||||||
|  |       expect_orig ← expect← ⎕NS⍬ | ||||||
|  |       exception←⍬ | ||||||
|  |       nexpect_orig ← nexpect← ⎕NS⍬ | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←is_test FunctionName;wsIndex | ||||||
|  |       wsIndex←FunctionName⍳' ' | ||||||
|  |       FunctionName←(wsIndex-1)↑FunctionName | ||||||
|  |       Z←'_TEST'≡¯5↑FunctionName | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Heading print_passed_crashed_failed(ArrayRes time) | ||||||
|  |       ⎕←'-----------------------------------------' | ||||||
|  |       ⎕←Heading | ||||||
|  |       ⎕←'    ⍋  Passed: ',+/{1⊃⍵}¨ArrayRes | ||||||
|  |       ⎕←'    ⍟ Crashed: ',+/{2⊃⍵}¨ArrayRes | ||||||
|  |       ⎕←'    ⍒  Failed: ',+/{3⊃⍵}¨ArrayRes | ||||||
|  |       ⎕←'    ○ Runtime: ',time[5],'m',time[6],'s',time[7],'ms' | ||||||
|  |     ∇ | ||||||
|  |      | ||||||
|  |     determine_pass_crash_or_fail←{ | ||||||
|  |       r c←⍵ ⋄ 0≠c:0 1 0 ⋄ z←(0 0 1)(1 0 0) | ||||||
|  |       expect_orig≢expect:(⎕IO+expect≡r)⊃z ⋄ (⎕IO+nexpect≢r)⊃z | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ∇ Z←determine_message(pass fail crashed name returned time) | ||||||
|  |       :If crashed | ||||||
|  |           Z←'CRASHED: 'failure_message name returned | ||||||
|  |       :ElseIf pass | ||||||
|  |           Z←'Passed ',time[5],'m',time[6],'s',time[7],'ms' | ||||||
|  |       :Else | ||||||
|  |           Z←'FAILED: 'failure_message name returned | ||||||
|  |       :EndIf | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ print_message_to_screen message | ||||||
|  |       ⎕←message | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←term_to_text Term;Text;Rows | ||||||
|  |       Text←#.DISPLAY Term | ||||||
|  |       Rows←1⊃⍴Text | ||||||
|  |       Z←(Rows 4⍴''),Text | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←Cause failure_message(name returned);hdr;exp;expterm;got;gotterm | ||||||
|  |       hdr←Cause,name | ||||||
|  |       exp←'Expected' | ||||||
|  |       expterm←term_to_text #.UT.expect | ||||||
|  |       got←'Got' | ||||||
|  |       gotterm←term_to_text returned | ||||||
|  |       Z←align_and_join_message_parts hdr exp expterm got gotterm | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←align_and_join_message_parts Parts;hdr;exp;expterm;got;gotterm;R1;C1;R2;C2;W | ||||||
|  |       (hdr exp expterm got gotterm)←Parts | ||||||
|  |       (R1 C1)←⍴expterm | ||||||
|  |       (R2 C2)←⍴gotterm | ||||||
|  |       W←⊃⊃⌈/C1 C2(⍴hdr)(⍴exp)(⍴got) | ||||||
|  |       Z←(W↑hdr),[0.5](W↑exp) | ||||||
|  |       Z←Z⍪(R1 W↑expterm) | ||||||
|  |       Z←Z⍪(W↑got) | ||||||
|  |       Z←Z⍪(R2 W↑gotterm) | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←confparam in config | ||||||
|  |       Z←1↓⊃({confparam≡⊃⍵}¨config)/config | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  |     ∇ Z←config has confparam | ||||||
|  |       Z←∨/{confparam≡⊃⍵}¨config | ||||||
|  |     ∇ | ||||||
|  |  | ||||||
|  | :EndNameSpace | ||||||
							
								
								
									
										59
									
								
								samples/Alloy/file_system.als
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								samples/Alloy/file_system.als
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | |||||||
|  | module examples/systems/file_system | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Model of a generic file system. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | abstract sig Object {} | ||||||
|  |  | ||||||
|  | sig Name {} | ||||||
|  |  | ||||||
|  | sig File extends Object {} { some d: Dir | this in d.entries.contents } | ||||||
|  |  | ||||||
|  | sig Dir extends Object { | ||||||
|  |   entries: set DirEntry, | ||||||
|  |   parent: lone Dir | ||||||
|  | } { | ||||||
|  |   parent = this.~@contents.~@entries | ||||||
|  |   all e1, e2 : entries | e1.name = e2.name => e1 = e2 | ||||||
|  |   this !in this.^@parent | ||||||
|  |   this != Root => Root in this.^@parent | ||||||
|  | } | ||||||
|  |  | ||||||
|  | one sig Root extends Dir {} { no parent } | ||||||
|  |  | ||||||
|  | lone sig Cur extends Dir {} | ||||||
|  |  | ||||||
|  | sig DirEntry { | ||||||
|  |   name: Name, | ||||||
|  |   contents: Object | ||||||
|  | } { | ||||||
|  |   one this.~entries | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * all directories besides root have one parent | ||||||
|  |  */ | ||||||
|  | pred OneParent_buggyVersion { | ||||||
|  |     all d: Dir - Root | one d.parent | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * all directories besides root have one parent | ||||||
|  |  */ | ||||||
|  | pred OneParent_correctVersion { | ||||||
|  |     all d: Dir - Root | (one d.parent && one contents.d) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Only files may be linked (that is, have more than one entry) | ||||||
|  |  * That is, all directories are the contents of at most one directory entry | ||||||
|  |  */ | ||||||
|  | pred NoDirAliases { | ||||||
|  |     all o: Dir | lone o.~contents | ||||||
|  | } | ||||||
|  |  | ||||||
|  | check { OneParent_buggyVersion => NoDirAliases } for 5 expect 1 | ||||||
|  |  | ||||||
|  | check { OneParent_correctVersion => NoDirAliases } for 5 expect 0 | ||||||
							
								
								
									
										83
									
								
								samples/Alloy/marksweepgc.als
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								samples/Alloy/marksweepgc.als
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | |||||||
|  | module examples/systems/marksweepgc | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Model of mark and sweep garbage collection. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | // a node in the heap | ||||||
|  | sig Node {} | ||||||
|  |  | ||||||
|  | sig HeapState { | ||||||
|  |   left, right : Node -> lone Node, | ||||||
|  |   marked : set Node, | ||||||
|  |   freeList : lone Node | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pred clearMarks[hs, hs' : HeapState] { | ||||||
|  |   // clear marked set | ||||||
|  |   no hs'.marked | ||||||
|  |   // left and right fields are unchanged | ||||||
|  |   hs'.left = hs.left | ||||||
|  |   hs'.right = hs.right | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * simulate the recursion of the mark() function using transitive closure | ||||||
|  |  */ | ||||||
|  | fun reachable[hs: HeapState, n: Node] : set Node { | ||||||
|  |   n + n.^(hs.left + hs.right) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pred mark[hs: HeapState, from : Node, hs': HeapState] { | ||||||
|  |   hs'.marked = hs.reachable[from] | ||||||
|  |   hs'.left = hs.left | ||||||
|  |   hs'.right = hs.right | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * complete hack to simulate behavior of code to set freeList | ||||||
|  |  */ | ||||||
|  | pred setFreeList[hs, hs': HeapState] { | ||||||
|  |   // especially hackish | ||||||
|  |   hs'.freeList.*(hs'.left) in (Node - hs.marked) | ||||||
|  |   all n: Node | | ||||||
|  |     (n !in hs.marked) => { | ||||||
|  |       no hs'.right[n] | ||||||
|  |       hs'.left[n] in (hs'.freeList.*(hs'.left)) | ||||||
|  |       n in hs'.freeList.*(hs'.left) | ||||||
|  |     } else { | ||||||
|  |       hs'.left[n] = hs.left[n] | ||||||
|  |       hs'.right[n] = hs.right[n] | ||||||
|  |     } | ||||||
|  |   hs'.marked = hs.marked | ||||||
|  | } | ||||||
|  |  | ||||||
|  | pred GC[hs: HeapState, root : Node, hs': HeapState] { | ||||||
|  |   some hs1, hs2: HeapState | | ||||||
|  |     hs.clearMarks[hs1] && hs1.mark[root, hs2] && hs2.setFreeList[hs'] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | assert Soundness1 { | ||||||
|  |   all h, h' : HeapState, root : Node | | ||||||
|  |     h.GC[root, h'] => | ||||||
|  |       (all live : h.reachable[root] | { | ||||||
|  |         h'.left[live] = h.left[live] | ||||||
|  |         h'.right[live] = h.right[live] | ||||||
|  |       }) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | assert Soundness2 { | ||||||
|  |   all h, h' : HeapState, root : Node | | ||||||
|  |     h.GC[root, h'] => | ||||||
|  |       no h'.reachable[root] & h'.reachable[h'.freeList] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | assert Completeness { | ||||||
|  |   all h, h' : HeapState, root : Node | | ||||||
|  |     h.GC[root, h'] => | ||||||
|  |       (Node - h'.reachable[root]) in h'.reachable[h'.freeList] | ||||||
|  | } | ||||||
|  |  | ||||||
|  | check Soundness1 for 3 expect 0 | ||||||
|  | check Soundness2 for 3 expect 0 | ||||||
|  | check Completeness for 3 expect 0 | ||||||
							
								
								
									
										217
									
								
								samples/Alloy/views.als
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										217
									
								
								samples/Alloy/views.als
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,217 @@ | |||||||
|  | module examples/systems/views | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Model of views in object-oriented programming. | ||||||
|  |  * | ||||||
|  |  * Two object references, called the view and the backing, | ||||||
|  |  * are related by a view mechanism when changes to the | ||||||
|  |  * backing are automatically propagated to the view. Note | ||||||
|  |  * that the state of a view need not be a projection of the | ||||||
|  |  * state of the backing; the keySet method of Map, for | ||||||
|  |  * example, produces two view relationships, and for the | ||||||
|  |  * one in which the map is modified by changes to the key | ||||||
|  |  * set, the value of the new map cannot be determined from | ||||||
|  |  * the key set. Note that in the iterator view mechanism, | ||||||
|  |  * the iterator is by this definition the backing object, | ||||||
|  |  * since changes are propagated from iterator to collection | ||||||
|  |  * and not vice versa. Oddly, a reference may be a view of | ||||||
|  |  * more than one backing: there can be two iterators on the | ||||||
|  |  * same collection, eg. A reference cannot be a view under | ||||||
|  |  * more than one view type. | ||||||
|  |  * | ||||||
|  |  * A reference is made dirty when it is a backing for a view | ||||||
|  |  * with which it is no longer related by the view invariant. | ||||||
|  |  * This usually happens when a view is modified, either | ||||||
|  |  * directly or via another backing. For example, changing a | ||||||
|  |  * collection directly when it has an iterator invalidates | ||||||
|  |  * it, as does changing the collection through one iterator | ||||||
|  |  * when there are others. | ||||||
|  |  * | ||||||
|  |  * More work is needed if we want to model more closely the | ||||||
|  |  * failure of an iterator when its collection is invalidated. | ||||||
|  |  * | ||||||
|  |  * As a terminological convention, when there are two | ||||||
|  |  * complementary view relationships, we will give them types | ||||||
|  |  * t and t'. For example, KeySetView propagates from map to | ||||||
|  |  * set, and KeySetView' propagates from set to map. | ||||||
|  |  * | ||||||
|  |  * author: Daniel Jackson | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | open util/ordering[State] as so | ||||||
|  | open util/relation as rel | ||||||
|  |  | ||||||
|  | sig Ref {} | ||||||
|  | sig Object {} | ||||||
|  |  | ||||||
|  | -- t->b->v in views when v is view of type t of backing b | ||||||
|  | -- dirty contains refs that have been invalidated | ||||||
|  | sig State { | ||||||
|  |   refs: set Ref, | ||||||
|  |   obj: refs -> one Object, | ||||||
|  |   views: ViewType -> refs -> refs, | ||||||
|  |   dirty: set refs | ||||||
|  | --  , anyviews: Ref -> Ref -- for visualization | ||||||
|  |   } | ||||||
|  | -- {anyviews = ViewType.views} | ||||||
|  |  | ||||||
|  | sig Map extends Object { | ||||||
|  |   keys: set Ref, | ||||||
|  |   map: keys -> one Ref | ||||||
|  |   }{all s: State |  keys + Ref.map in s.refs} | ||||||
|  | sig MapRef extends Ref {} | ||||||
|  | fact {State.obj[MapRef] in Map} | ||||||
|  |  | ||||||
|  | sig Iterator extends Object { | ||||||
|  |   left, done: set Ref, | ||||||
|  |   lastRef: lone done | ||||||
|  |   }{all s: State | done + left + lastRef in s.refs} | ||||||
|  | sig IteratorRef extends Ref {} | ||||||
|  | fact {State.obj[IteratorRef] in Iterator} | ||||||
|  |  | ||||||
|  | sig Set extends Object { | ||||||
|  |   elts: set Ref | ||||||
|  |   }{all s: State | elts in s.refs} | ||||||
|  | sig SetRef extends Ref {} | ||||||
|  | fact {State.obj[SetRef] in Set} | ||||||
|  |  | ||||||
|  | abstract sig ViewType {} | ||||||
|  | one sig KeySetView, KeySetView', IteratorView extends ViewType {} | ||||||
|  | fact ViewTypes { | ||||||
|  |   State.views[KeySetView] in MapRef -> SetRef | ||||||
|  |   State.views[KeySetView'] in SetRef -> MapRef | ||||||
|  |   State.views[IteratorView] in IteratorRef -> SetRef | ||||||
|  |   all s: State | s.views[KeySetView] = ~(s.views[KeySetView']) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * mods is refs modified directly or by view mechanism | ||||||
|  |  * doesn't handle possibility of modifying an object and its view at once? | ||||||
|  |  * should we limit frame conds to non-dirty refs? | ||||||
|  |  */ | ||||||
|  | pred modifies [pre, post: State, rs: set Ref] { | ||||||
|  |   let vr = pre.views[ViewType], mods = rs.*vr { | ||||||
|  |     all r: pre.refs - mods | pre.obj[r] = post.obj[r] | ||||||
|  |     all b: mods, v: pre.refs, t: ViewType | | ||||||
|  |       b->v in pre.views[t] => viewFrame [t, pre.obj[v], post.obj[v], post.obj[b]] | ||||||
|  |     post.dirty = pre.dirty + | ||||||
|  |       {b: pre.refs | some v: Ref, t: ViewType | | ||||||
|  |           b->v in pre.views[t] && !viewFrame [t, pre.obj[v], post.obj[v], post.obj[b]] | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | pred allocates [pre, post: State, rs: set Ref] { | ||||||
|  |   no rs & pre.refs | ||||||
|  |   post.refs = pre.refs + rs | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | /**  | ||||||
|  |  * models frame condition that limits change to view object from v to v' when backing object changes to b' | ||||||
|  |  */ | ||||||
|  | pred viewFrame [t: ViewType, v, v', b': Object] { | ||||||
|  |   t in KeySetView => v'.elts = dom [b'.map] | ||||||
|  |   t in KeySetView' => b'.elts = dom [v'.map] | ||||||
|  |   t in KeySetView' => (b'.elts) <: (v.map) = (b'.elts) <: (v'.map) | ||||||
|  |   t in IteratorView => v'.elts = b'.left + b'.done | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | pred MapRef.keySet [pre, post: State, setRefs: SetRef] { | ||||||
|  |   post.obj[setRefs].elts = dom [pre.obj[this].map] | ||||||
|  |   modifies [pre, post, none] | ||||||
|  |   allocates [pre, post, setRefs] | ||||||
|  |   post.views = pre.views + KeySetView->this->setRefs + KeySetView'->setRefs->this | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | pred MapRef.put [pre, post: State, k, v: Ref] { | ||||||
|  |   post.obj[this].map = pre.obj[this].map ++ k->v | ||||||
|  |   modifies [pre, post, this] | ||||||
|  |   allocates [pre, post, none] | ||||||
|  |   post.views = pre.views | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | pred SetRef.iterator [pre, post: State, iterRef: IteratorRef] { | ||||||
|  |   let i = post.obj[iterRef] { | ||||||
|  |     i.left = pre.obj[this].elts | ||||||
|  |     no i.done + i.lastRef | ||||||
|  |     } | ||||||
|  |   modifies [pre,post,none] | ||||||
|  |   allocates [pre, post, iterRef] | ||||||
|  |   post.views = pre.views + IteratorView->iterRef->this | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | pred IteratorRef.remove [pre, post: State] { | ||||||
|  |   let i = pre.obj[this], i' = post.obj[this] { | ||||||
|  |     i'.left = i.left | ||||||
|  |     i'.done = i.done - i.lastRef | ||||||
|  |     no i'.lastRef | ||||||
|  |     } | ||||||
|  |   modifies [pre,post,this] | ||||||
|  |   allocates [pre, post, none] | ||||||
|  |   pre.views = post.views | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | pred IteratorRef.next [pre, post: State, ref: Ref] { | ||||||
|  |   let i = pre.obj[this], i' = post.obj[this] { | ||||||
|  |     ref in i.left | ||||||
|  |     i'.left = i.left - ref | ||||||
|  |     i'.done = i.done + ref | ||||||
|  |     i'.lastRef = ref | ||||||
|  |     } | ||||||
|  |   modifies [pre, post, this] | ||||||
|  |   allocates [pre, post, none] | ||||||
|  |   pre.views = post.views | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | pred IteratorRef.hasNext [s: State] { | ||||||
|  |   some s.obj[this].left | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | assert zippishOK { | ||||||
|  |   all | ||||||
|  |     ks, vs: SetRef, | ||||||
|  |     m: MapRef, | ||||||
|  |     ki, vi: IteratorRef, | ||||||
|  |     k, v: Ref | | ||||||
|  |     let s0=so/first, | ||||||
|  |     s1=so/next[s0], | ||||||
|  |     s2=so/next[s1], | ||||||
|  |     s3=so/next[s2], | ||||||
|  |     s4=so/next[s3], | ||||||
|  |     s5=so/next[s4], | ||||||
|  |     s6=so/next[s5], | ||||||
|  |     s7=so/next[s6] | | ||||||
|  |   ({ | ||||||
|  |     precondition [s0, ks, vs, m] | ||||||
|  |     no s0.dirty | ||||||
|  |     ks.iterator [s0, s1, ki] | ||||||
|  |     vs.iterator [s1, s2, vi] | ||||||
|  |     ki.hasNext [s2] | ||||||
|  |     vi.hasNext [s2] | ||||||
|  |     ki.this/next [s2, s3, k] | ||||||
|  |     vi.this/next [s3, s4, v] | ||||||
|  |     m.put [s4, s5, k, v] | ||||||
|  |     ki.remove [s5, s6] | ||||||
|  |     vi.remove [s6, s7] | ||||||
|  |   } => no State.dirty) | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | pred precondition [pre: State, ks, vs, m: Ref] { | ||||||
|  |   // all these conditions and other errors discovered in scope of 6 but 8,3 | ||||||
|  |   // in initial state, must have view invariants hold | ||||||
|  |   (all t: ViewType, b, v: pre.refs | | ||||||
|  |     b->v in pre.views[t] => viewFrame [t, pre.obj[v], pre.obj[v], pre.obj[b]]) | ||||||
|  |   // sets are not aliases | ||||||
|  | --  ks != vs | ||||||
|  |   // sets are not views of map | ||||||
|  | --  no (ks+vs)->m & ViewType.pre.views | ||||||
|  |   // no iterator currently on either set | ||||||
|  | --  no Ref->(ks+vs) & ViewType.pre.views | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | check zippishOK for 6 but 8 State, 3 ViewType expect 1 | ||||||
|  |  | ||||||
|  | /**  | ||||||
|  |  * experiment with controlling heap size | ||||||
|  |  */ | ||||||
|  | fact {all s: State | #s.obj < 5} | ||||||
							
								
								
									
										41
									
								
								samples/AspectJ/CacheAspect.aj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								samples/AspectJ/CacheAspect.aj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | |||||||
|  | package com.blogspot.miguelinlas3.aspectj.cache; | ||||||
|  |  | ||||||
|  | import java.util.Map; | ||||||
|  | import java.util.WeakHashMap; | ||||||
|  |  | ||||||
|  | import org.aspectj.lang.JoinPoint; | ||||||
|  |  | ||||||
|  | import com.blogspot.miguelinlas3.aspectj.cache.marker.Cachable; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * This simple aspect simulates the behaviour of a very simple cache | ||||||
|  |  *   | ||||||
|  |  * @author migue | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | public aspect CacheAspect { | ||||||
|  |  | ||||||
|  | 	public pointcut cache(Cachable cachable): execution(@Cachable * * (..)) && @annotation(cachable); | ||||||
|  | 	 | ||||||
|  | 	Object around(Cachable cachable): cache(cachable){ | ||||||
|  | 	 | ||||||
|  | 		String evaluatedKey = this.evaluateKey(cachable.scriptKey(), thisJoinPoint); | ||||||
|  | 		 | ||||||
|  | 		if(cache.containsKey(evaluatedKey)){ | ||||||
|  | 			System.out.println("Cache hit for key " + evaluatedKey); | ||||||
|  | 			return this.cache.get(evaluatedKey); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		System.out.println("Cache miss for key " + evaluatedKey); | ||||||
|  | 		Object value = proceed(cachable); | ||||||
|  | 		cache.put(evaluatedKey, value); | ||||||
|  | 		return value; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	protected String evaluateKey(String key, JoinPoint joinPoint) { | ||||||
|  | 		// TODO add some smart staff to allow simple scripting in @Cachable annotation | ||||||
|  | 		return key; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	protected Map<String, Object> cache = new WeakHashMap<String, Object>(); | ||||||
|  | } | ||||||
							
								
								
									
										50
									
								
								samples/AspectJ/OptimizeRecursionCache.aj
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								samples/AspectJ/OptimizeRecursionCache.aj
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | |||||||
|  | package aspects.caching; | ||||||
|  |  | ||||||
|  | import java.util.Map; | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Cache aspect for optimize recursive functions. | ||||||
|  |  *  | ||||||
|  |  * @author Migueli | ||||||
|  |  * @date 05/11/2013 | ||||||
|  |  * @version 1.0 | ||||||
|  |  * | ||||||
|  |  */ | ||||||
|  | public abstract aspect OptimizeRecursionCache { | ||||||
|  | 		 | ||||||
|  | 	@SuppressWarnings("rawtypes") | ||||||
|  | 	private Map _cache; | ||||||
|  | 	 | ||||||
|  | 	public OptimizeRecursionCache() { | ||||||
|  | 		_cache = getCache(); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	@SuppressWarnings("rawtypes") | ||||||
|  | 	abstract public Map getCache(); | ||||||
|  | 	 | ||||||
|  | 	abstract public pointcut operation(Object o); | ||||||
|  |  | ||||||
|  | 	pointcut topLevelOperation(Object o): operation(o) && !cflowbelow(operation(Object)); | ||||||
|  |  | ||||||
|  | 	before(Object o) : topLevelOperation(o) { | ||||||
|  | 		System.out.println("Seeking value for " + o); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	Object around(Object o) : operation(o) { | ||||||
|  | 		Object cachedValue = _cache.get(o); | ||||||
|  | 		if (cachedValue != null) { | ||||||
|  | 			System.out.println("Found cached value for " + o + ": " + cachedValue); | ||||||
|  | 			return cachedValue; | ||||||
|  | 		} | ||||||
|  | 		return proceed(o); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	@SuppressWarnings("unchecked") | ||||||
|  | 	after(Object o) returning(Object result) : topLevelOperation(o) { | ||||||
|  | 		_cache.put(o, result); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	after(Object o) returning(Object result) : topLevelOperation(o) { | ||||||
|  | 		System.out.println("cache size: " + _cache.size()); | ||||||
|  | 	} | ||||||
|  | } | ||||||
							
								
								
									
										66
									
								
								samples/Assembly/External Interrupt.a51
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								samples/Assembly/External Interrupt.a51
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | |||||||
|  | 	ORG	0000h | ||||||
|  | 	SJMP	START | ||||||
|  | 	ORG	0003h | ||||||
|  | 	LCALL	INT0_ISR | ||||||
|  | 	RETI | ||||||
|  | 	ORG	000Bh | ||||||
|  | 	LCALL	T0_ISR | ||||||
|  | 	RETI | ||||||
|  | 	ORG	0013h | ||||||
|  | 	LCALL	INT1_ISR | ||||||
|  | 	RETI | ||||||
|  | 	ORG	001Bh | ||||||
|  | 	LCALL	T1_ISR | ||||||
|  | 	RETI | ||||||
|  | 	ORG	0023h | ||||||
|  | 	LCALL	UART_ISR | ||||||
|  | 	RETI | ||||||
|  | 	ORG	0030h | ||||||
|  | START: | ||||||
|  | 	MOV	A,#11111110b | ||||||
|  | 	SETB	IT0	; Set External Interrupt 0 to be falling edge triggered | ||||||
|  | 	SETB	EX0	; Enable External Interrut 0 | ||||||
|  | 	SETB	EA	; Enable Interrupt | ||||||
|  | LEFT:			 | ||||||
|  | 	CJNE	A,#01111111b,LOOP1 | ||||||
|  | 	JMP	RIGHT | ||||||
|  | LOOP1: | ||||||
|  | 	MOV	P1,A | ||||||
|  | 	RL	A	 | ||||||
|  | 	LCALL	DELAY | ||||||
|  | 	SJMP	LEFT	 | ||||||
|  | RIGHT: | ||||||
|  | 	CJNE	A,#11111110b,LOOP2 | ||||||
|  | 	JMP	LEFT | ||||||
|  | LOOP2: | ||||||
|  | 	MOV	P1,A | ||||||
|  | 	RR	A	 | ||||||
|  | 	LCALL	DELAY | ||||||
|  | 	SJMP	RIGHT | ||||||
|  | 	 | ||||||
|  | INT0_ISR: | ||||||
|  | 	MOV	R1,#3 | ||||||
|  | FLASH: | ||||||
|  | 	MOV	P1,#00h | ||||||
|  | 	LCALL	DELAY | ||||||
|  | 	MOV	P1,#0FFh | ||||||
|  | 	LCALL	DELAY | ||||||
|  | 	DJNZ	R1,FLASH | ||||||
|  | 	RET | ||||||
|  | T0_ISR: | ||||||
|  | 	RET | ||||||
|  | INT1_ISR: | ||||||
|  | 	RET | ||||||
|  | T1_ISR: | ||||||
|  | 	RET | ||||||
|  | UART_ISR: | ||||||
|  | 	RET | ||||||
|  |  | ||||||
|  | DELAY:	MOV	R5,#20	;R5*20 mS | ||||||
|  | D1:     MOV	R6,#40 | ||||||
|  | D2:     MOV	R7,#249 | ||||||
|  | 	DJNZ	R7,$ | ||||||
|  |  	DJNZ	R6,D2 | ||||||
|  |   	DJNZ	R5,D1 | ||||||
|  |    	RET | ||||||
|  | 	END | ||||||
							
								
								
									
										350
									
								
								samples/Assembly/FASM.asm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								samples/Assembly/FASM.asm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,350 @@ | |||||||
|  |  | ||||||
|  | ; flat assembler interface for Win32 | ||||||
|  | ; Copyright (c) 1999-2014, Tomasz Grysztar. | ||||||
|  | ; All rights reserved. | ||||||
|  |  | ||||||
|  | 	format	PE console | ||||||
|  |  | ||||||
|  | section '.text' code readable executable | ||||||
|  |  | ||||||
|  | start: | ||||||
|  |  | ||||||
|  | 	mov	[con_handle],STD_OUTPUT_HANDLE | ||||||
|  | 	mov	esi,_logo | ||||||
|  | 	call	display_string | ||||||
|  |  | ||||||
|  | 	call	get_params | ||||||
|  | 	jc	information | ||||||
|  |  | ||||||
|  | 	call	init_memory | ||||||
|  |  | ||||||
|  | 	mov	esi,_memory_prefix | ||||||
|  | 	call	display_string | ||||||
|  | 	mov	eax,[memory_end] | ||||||
|  | 	sub	eax,[memory_start] | ||||||
|  | 	add	eax,[additional_memory_end] | ||||||
|  | 	sub	eax,[additional_memory] | ||||||
|  | 	shr	eax,10 | ||||||
|  | 	call	display_number | ||||||
|  | 	mov	esi,_memory_suffix | ||||||
|  | 	call	display_string | ||||||
|  |  | ||||||
|  | 	call	[GetTickCount] | ||||||
|  | 	mov	[start_time],eax | ||||||
|  |  | ||||||
|  | 	call	preprocessor | ||||||
|  | 	call	parser | ||||||
|  | 	call	assembler | ||||||
|  | 	call	formatter | ||||||
|  |  | ||||||
|  | 	call	display_user_messages | ||||||
|  | 	movzx	eax,[current_pass] | ||||||
|  | 	inc	eax | ||||||
|  | 	call	display_number | ||||||
|  | 	mov	esi,_passes_suffix | ||||||
|  | 	call	display_string | ||||||
|  | 	call	[GetTickCount] | ||||||
|  | 	sub	eax,[start_time] | ||||||
|  | 	xor	edx,edx | ||||||
|  | 	mov	ebx,100 | ||||||
|  | 	div	ebx | ||||||
|  | 	or	eax,eax | ||||||
|  | 	jz	display_bytes_count | ||||||
|  | 	xor	edx,edx | ||||||
|  | 	mov	ebx,10 | ||||||
|  | 	div	ebx | ||||||
|  | 	push	edx | ||||||
|  | 	call	display_number | ||||||
|  | 	mov	dl,'.' | ||||||
|  | 	call	display_character | ||||||
|  | 	pop	eax | ||||||
|  | 	call	display_number | ||||||
|  | 	mov	esi,_seconds_suffix | ||||||
|  | 	call	display_string | ||||||
|  |       display_bytes_count: | ||||||
|  | 	mov	eax,[written_size] | ||||||
|  | 	call	display_number | ||||||
|  | 	mov	esi,_bytes_suffix | ||||||
|  | 	call	display_string | ||||||
|  | 	xor	al,al | ||||||
|  | 	jmp	exit_program | ||||||
|  |  | ||||||
|  | information: | ||||||
|  | 	mov	esi,_usage | ||||||
|  | 	call	display_string | ||||||
|  | 	mov	al,1 | ||||||
|  | 	jmp	exit_program | ||||||
|  |  | ||||||
|  | get_params: | ||||||
|  | 	mov	[input_file],0 | ||||||
|  | 	mov	[output_file],0 | ||||||
|  | 	mov	[symbols_file],0 | ||||||
|  | 	mov	[memory_setting],0 | ||||||
|  | 	mov	[passes_limit],100 | ||||||
|  | 	call	[GetCommandLine] | ||||||
|  | 	mov	esi,eax | ||||||
|  | 	mov	edi,params | ||||||
|  |     find_command_start: | ||||||
|  | 	lodsb | ||||||
|  | 	cmp	al,20h | ||||||
|  | 	je	find_command_start | ||||||
|  | 	cmp	al,22h | ||||||
|  | 	je	skip_quoted_name | ||||||
|  |     skip_name: | ||||||
|  | 	lodsb | ||||||
|  | 	cmp	al,20h | ||||||
|  | 	je	find_param | ||||||
|  | 	or	al,al | ||||||
|  | 	jz	all_params | ||||||
|  | 	jmp	skip_name | ||||||
|  |     skip_quoted_name: | ||||||
|  | 	lodsb | ||||||
|  | 	cmp	al,22h | ||||||
|  | 	je	find_param | ||||||
|  | 	or	al,al | ||||||
|  | 	jz	all_params | ||||||
|  | 	jmp	skip_quoted_name | ||||||
|  |     find_param: | ||||||
|  | 	lodsb | ||||||
|  | 	cmp	al,20h | ||||||
|  | 	je	find_param | ||||||
|  | 	cmp	al,'-' | ||||||
|  | 	je	option_param | ||||||
|  | 	cmp	al,0Dh | ||||||
|  | 	je	all_params | ||||||
|  | 	or	al,al | ||||||
|  | 	jz	all_params | ||||||
|  | 	cmp	[input_file],0 | ||||||
|  | 	jne	get_output_file | ||||||
|  | 	mov	[input_file],edi | ||||||
|  | 	jmp	process_param | ||||||
|  |       get_output_file: | ||||||
|  | 	cmp	[output_file],0 | ||||||
|  | 	jne	bad_params | ||||||
|  | 	mov	[output_file],edi | ||||||
|  |     process_param: | ||||||
|  | 	cmp	al,22h | ||||||
|  | 	je	string_param | ||||||
|  |     copy_param: | ||||||
|  | 	stosb | ||||||
|  | 	lodsb | ||||||
|  | 	cmp	al,20h | ||||||
|  | 	je	param_end | ||||||
|  | 	cmp	al,0Dh | ||||||
|  | 	je	param_end | ||||||
|  | 	or	al,al | ||||||
|  | 	jz	param_end | ||||||
|  | 	jmp	copy_param | ||||||
|  |     string_param: | ||||||
|  | 	lodsb | ||||||
|  | 	cmp	al,22h | ||||||
|  | 	je	string_param_end | ||||||
|  | 	cmp	al,0Dh | ||||||
|  | 	je	param_end | ||||||
|  | 	or	al,al | ||||||
|  | 	jz	param_end | ||||||
|  | 	stosb | ||||||
|  | 	jmp	string_param | ||||||
|  |     option_param: | ||||||
|  | 	lodsb | ||||||
|  | 	cmp	al,'m' | ||||||
|  | 	je	memory_option | ||||||
|  | 	cmp	al,'M' | ||||||
|  | 	je	memory_option | ||||||
|  | 	cmp	al,'p' | ||||||
|  | 	je	passes_option | ||||||
|  | 	cmp	al,'P' | ||||||
|  | 	je	passes_option | ||||||
|  | 	cmp	al,'s' | ||||||
|  | 	je	symbols_option | ||||||
|  | 	cmp	al,'S' | ||||||
|  | 	je	symbols_option | ||||||
|  |     bad_params: | ||||||
|  | 	stc | ||||||
|  | 	ret | ||||||
|  |     get_option_value: | ||||||
|  | 	xor	eax,eax | ||||||
|  | 	mov	edx,eax | ||||||
|  |     get_option_digit: | ||||||
|  | 	lodsb | ||||||
|  | 	cmp	al,20h | ||||||
|  | 	je	option_value_ok | ||||||
|  | 	cmp	al,0Dh | ||||||
|  | 	je	option_value_ok | ||||||
|  | 	or	al,al | ||||||
|  | 	jz	option_value_ok | ||||||
|  | 	sub	al,30h | ||||||
|  | 	jc	invalid_option_value | ||||||
|  | 	cmp	al,9 | ||||||
|  | 	ja	invalid_option_value | ||||||
|  | 	imul	edx,10 | ||||||
|  | 	jo	invalid_option_value | ||||||
|  | 	add	edx,eax | ||||||
|  | 	jc	invalid_option_value | ||||||
|  | 	jmp	get_option_digit | ||||||
|  |     option_value_ok: | ||||||
|  | 	dec	esi | ||||||
|  | 	clc | ||||||
|  | 	ret | ||||||
|  |     invalid_option_value: | ||||||
|  | 	stc | ||||||
|  | 	ret | ||||||
|  |     memory_option: | ||||||
|  | 	lodsb | ||||||
|  | 	cmp	al,20h | ||||||
|  | 	je	memory_option | ||||||
|  | 	cmp	al,0Dh | ||||||
|  | 	je	bad_params | ||||||
|  | 	or	al,al | ||||||
|  | 	jz	bad_params | ||||||
|  | 	dec	esi | ||||||
|  | 	call	get_option_value | ||||||
|  | 	or	edx,edx | ||||||
|  | 	jz	bad_params | ||||||
|  | 	cmp	edx,1 shl (32-10) | ||||||
|  | 	jae	bad_params | ||||||
|  | 	mov	[memory_setting],edx | ||||||
|  | 	jmp	find_param | ||||||
|  |     passes_option: | ||||||
|  | 	lodsb | ||||||
|  | 	cmp	al,20h | ||||||
|  | 	je	passes_option | ||||||
|  | 	cmp	al,0Dh | ||||||
|  | 	je	bad_params | ||||||
|  | 	or	al,al | ||||||
|  | 	jz	bad_params | ||||||
|  | 	dec	esi | ||||||
|  | 	call	get_option_value | ||||||
|  | 	or	edx,edx | ||||||
|  | 	jz	bad_params | ||||||
|  | 	cmp	edx,10000h | ||||||
|  | 	ja	bad_params | ||||||
|  | 	mov	[passes_limit],dx | ||||||
|  | 	jmp	find_param | ||||||
|  |     symbols_option: | ||||||
|  | 	mov	[symbols_file],edi | ||||||
|  |       find_symbols_file_name: | ||||||
|  | 	lodsb | ||||||
|  | 	cmp	al,20h | ||||||
|  | 	jne	process_param | ||||||
|  | 	jmp	find_symbols_file_name | ||||||
|  |     param_end: | ||||||
|  | 	dec	esi | ||||||
|  |     string_param_end: | ||||||
|  | 	xor	al,al | ||||||
|  | 	stosb | ||||||
|  | 	jmp	find_param | ||||||
|  |     all_params: | ||||||
|  | 	cmp	[input_file],0 | ||||||
|  | 	je	bad_params | ||||||
|  | 	clc | ||||||
|  | 	ret | ||||||
|  |  | ||||||
|  | include 'system.inc' | ||||||
|  |  | ||||||
|  | include '..\errors.inc' | ||||||
|  | include '..\symbdump.inc' | ||||||
|  | include '..\preproce.inc' | ||||||
|  | include '..\parser.inc' | ||||||
|  | include '..\exprpars.inc' | ||||||
|  | include '..\assemble.inc' | ||||||
|  | include '..\exprcalc.inc' | ||||||
|  | include '..\formats.inc' | ||||||
|  | include '..\x86_64.inc' | ||||||
|  | include '..\avx.inc' | ||||||
|  |  | ||||||
|  | include '..\tables.inc' | ||||||
|  | include '..\messages.inc' | ||||||
|  |  | ||||||
|  | section '.data' data readable writeable | ||||||
|  |  | ||||||
|  | include '..\version.inc' | ||||||
|  |  | ||||||
|  | _copyright db 'Copyright (c) 1999-2014, Tomasz Grysztar',0Dh,0Ah,0 | ||||||
|  |  | ||||||
|  | _logo db 'flat assembler  version ',VERSION_STRING,0 | ||||||
|  | _usage db 0Dh,0Ah | ||||||
|  |        db 'usage: fasm <source> [output]',0Dh,0Ah | ||||||
|  |        db 'optional settings:',0Dh,0Ah | ||||||
|  |        db ' -m <limit>    set the limit in kilobytes for the available memory',0Dh,0Ah | ||||||
|  |        db ' -p <limit>    set the maximum allowed number of passes',0Dh,0Ah | ||||||
|  |        db ' -s <file>     dump symbolic information for debugging',0Dh,0Ah | ||||||
|  |        db 0 | ||||||
|  | _memory_prefix db '  (',0 | ||||||
|  | _memory_suffix db ' kilobytes memory)',0Dh,0Ah,0 | ||||||
|  | _passes_suffix db ' passes, ',0 | ||||||
|  | _seconds_suffix db ' seconds, ',0 | ||||||
|  | _bytes_suffix db ' bytes.',0Dh,0Ah,0 | ||||||
|  |  | ||||||
|  | align 4 | ||||||
|  |  | ||||||
|  | include '..\variable.inc' | ||||||
|  |  | ||||||
|  | con_handle dd ? | ||||||
|  | memory_setting dd ? | ||||||
|  | start_time dd ? | ||||||
|  | bytes_count dd ? | ||||||
|  | displayed_count dd ? | ||||||
|  | character db ? | ||||||
|  | last_displayed rb 2 | ||||||
|  |  | ||||||
|  | params rb 1000h | ||||||
|  | options rb 1000h | ||||||
|  | buffer rb 4000h | ||||||
|  |  | ||||||
|  | stack 10000h | ||||||
|  |  | ||||||
|  | section '.idata' import data readable writeable | ||||||
|  |  | ||||||
|  |   dd 0,0,0,rva kernel_name,rva kernel_table | ||||||
|  |   dd 0,0,0,0,0 | ||||||
|  |  | ||||||
|  |   kernel_table: | ||||||
|  |     ExitProcess dd rva _ExitProcess | ||||||
|  |     CreateFile dd rva _CreateFileA | ||||||
|  |     ReadFile dd rva _ReadFile | ||||||
|  |     WriteFile dd rva _WriteFile | ||||||
|  |     CloseHandle dd rva _CloseHandle | ||||||
|  |     SetFilePointer dd rva _SetFilePointer | ||||||
|  |     GetCommandLine dd rva _GetCommandLineA | ||||||
|  |     GetEnvironmentVariable dd rva _GetEnvironmentVariable | ||||||
|  |     GetStdHandle dd rva _GetStdHandle | ||||||
|  |     VirtualAlloc dd rva _VirtualAlloc | ||||||
|  |     VirtualFree dd rva _VirtualFree | ||||||
|  |     GetTickCount dd rva _GetTickCount | ||||||
|  |     GetSystemTime dd rva _GetSystemTime | ||||||
|  |     GlobalMemoryStatus dd rva _GlobalMemoryStatus | ||||||
|  |     dd 0 | ||||||
|  |  | ||||||
|  |   kernel_name db 'KERNEL32.DLL',0 | ||||||
|  |  | ||||||
|  |   _ExitProcess dw 0 | ||||||
|  |     db 'ExitProcess',0 | ||||||
|  |   _CreateFileA dw 0 | ||||||
|  |     db 'CreateFileA',0 | ||||||
|  |   _ReadFile dw 0 | ||||||
|  |     db 'ReadFile',0 | ||||||
|  |   _WriteFile dw 0 | ||||||
|  |     db 'WriteFile',0 | ||||||
|  |   _CloseHandle dw 0 | ||||||
|  |     db 'CloseHandle',0 | ||||||
|  |   _SetFilePointer dw 0 | ||||||
|  |     db 'SetFilePointer',0 | ||||||
|  |   _GetCommandLineA dw 0 | ||||||
|  |     db 'GetCommandLineA',0 | ||||||
|  |   _GetEnvironmentVariable dw 0 | ||||||
|  |     db 'GetEnvironmentVariableA',0 | ||||||
|  |   _GetStdHandle dw 0 | ||||||
|  |     db 'GetStdHandle',0 | ||||||
|  |   _VirtualAlloc dw 0 | ||||||
|  |     db 'VirtualAlloc',0 | ||||||
|  |   _VirtualFree dw 0 | ||||||
|  |     db 'VirtualFree',0 | ||||||
|  |   _GetTickCount dw 0 | ||||||
|  |     db 'GetTickCount',0 | ||||||
|  |   _GetSystemTime dw 0 | ||||||
|  |     db 'GetSystemTime',0 | ||||||
|  |   _GlobalMemoryStatus dw 0 | ||||||
|  |     db 'GlobalMemoryStatus',0 | ||||||
|  |  | ||||||
|  | section '.reloc' fixups data readable discardable | ||||||
							
								
								
									
										25
									
								
								samples/BlitzMax/sample.bmx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								samples/BlitzMax/sample.bmx
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | SuperStrict | ||||||
|  |  | ||||||
|  | Framework Brl.StandardIO | ||||||
|  |  | ||||||
|  | Type TMyType | ||||||
|  | 	Field property:int | ||||||
|  |  | ||||||
|  | 	Function A:int(param:int) | ||||||
|  | 		'do nothing | ||||||
|  | 	End Function | ||||||
|  |  | ||||||
|  | 	Method B:int(param:int) | ||||||
|  | 		'do nothing | ||||||
|  | 	End Method | ||||||
|  | End Type | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Global my:TMyType = new TMyType | ||||||
|  | ?Win32 | ||||||
|  | 	my.A() | ||||||
|  | 	my.B() | ||||||
|  | ?Linux | ||||||
|  | 	my.B() | ||||||
|  | 	my.A() | ||||||
|  | ? | ||||||
							
								
								
									
										530
									
								
								samples/C++/Math.inl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										530
									
								
								samples/C++/Math.inl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,530 @@ | |||||||
|  | /* | ||||||
|  | =========================================================================== | ||||||
|  | The Open Game Libraries. | ||||||
|  | Copyright (C) 2007-2010 Lusito Software | ||||||
|  |  | ||||||
|  | Author:  Santo Pfingsten (TTK-Bandit) | ||||||
|  | Purpose: Math namespace | ||||||
|  | ----------------------------------------- | ||||||
|  |  | ||||||
|  | This software is provided 'as-is', without any express or implied | ||||||
|  | warranty. In no event will the authors be held liable for any damages | ||||||
|  | arising from the use of this software. | ||||||
|  |  | ||||||
|  | Permission is granted to anyone to use this software for any purpose, | ||||||
|  | including commercial applications, and to alter it and redistribute it | ||||||
|  | freely, subject to the following restrictions: | ||||||
|  |  | ||||||
|  | 1. The origin of this software must not be misrepresented; you must not | ||||||
|  |    claim that you wrote the original software. If you use this software | ||||||
|  |    in a product, an acknowledgment in the product documentation would be | ||||||
|  |    appreciated but is not required. | ||||||
|  |  | ||||||
|  | 2. Altered source versions must be plainly marked as such, and must not be | ||||||
|  |    misrepresented as being the original software. | ||||||
|  |  | ||||||
|  | 3. This notice may not be removed or altered from any source distribution. | ||||||
|  | =========================================================================== | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | #ifndef __OG_MATH_INL__ | ||||||
|  | #define __OG_MATH_INL__ | ||||||
|  |  | ||||||
|  | namespace og { | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ============================================================================== | ||||||
|  |  | ||||||
|  |   Math | ||||||
|  |  | ||||||
|  | ============================================================================== | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Abs | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE int Math::Abs( int i ) { | ||||||
|  | #if 1 | ||||||
|  | 	if ( i & 0x80000000 ) | ||||||
|  | 		return 0x80000000 - (i & MASK_SIGNED); | ||||||
|  | 	return i; | ||||||
|  | #else | ||||||
|  |    int y = x >> 31; | ||||||
|  |    return ( ( x ^ y ) - y ); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Fabs | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Fabs( float f ) { | ||||||
|  | #if 1 | ||||||
|  | 	uInt *pf = reinterpret_cast<uInt*>(&f); | ||||||
|  | 	*(pf) &= MASK_SIGNED; | ||||||
|  | 	return f; | ||||||
|  | #else | ||||||
|  | 	return fabsf( f ); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Round | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Round( float f ) { | ||||||
|  | 	return floorf( f + 0.5f ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Floor | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Floor( float f ) { | ||||||
|  | 	return floorf( f ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Ceil | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Ceil( float f ) { | ||||||
|  | 	return ceilf( f ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Ftoi | ||||||
|  |  | ||||||
|  | ok since this is SSE, why should the other ftoi be the faster one ? | ||||||
|  | and: we might need to add a check for SSE extensions.. | ||||||
|  | because sse isn't *really* faster (I actually read that GCC does not handle | ||||||
|  | SSE extensions perfectly. I'll find the link and send it to you when you're online) | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE int Math::Ftoi( float f ) { | ||||||
|  | 	//! @todo	needs testing | ||||||
|  | 	// note: sse function cvttss2si | ||||||
|  | #if OG_ASM_MSVC | ||||||
|  | 	int i; | ||||||
|  | #if defined(OG_FTOI_USE_SSE) | ||||||
|  | 	if( SysInfo::cpu.general.SSE ) { | ||||||
|  | 		__asm cvttss2si	eax, f | ||||||
|  | 		__asm mov		i, eax | ||||||
|  | 		return i; | ||||||
|  | 	} else | ||||||
|  | #endif | ||||||
|  | 	{ | ||||||
|  | 		__asm fld		f | ||||||
|  | 		__asm fistp		i | ||||||
|  | 		//__asm mov eax, i // do we need this ? O_o | ||||||
|  | 	} | ||||||
|  | 	return i; | ||||||
|  | #elif OG_ASM_GNU | ||||||
|  | 	int i; | ||||||
|  | #if defined(OG_FTOI_USE_SSE) | ||||||
|  | 	if( SysInfo::cpu.general.SSE ) { | ||||||
|  | 		__asm__ __volatile__( "cvttss2si %1    \n\t" | ||||||
|  | 			: "=m" (i) | ||||||
|  | 			: "m" (f) | ||||||
|  | 		); | ||||||
|  | 	} else | ||||||
|  | #endif | ||||||
|  | 	{ | ||||||
|  | 		__asm__ __volatile__( "flds %1    \n\t" | ||||||
|  | 							  "fistpl %0  \n\t" | ||||||
|  | 			: "=m" (i) | ||||||
|  | 			: "m" (f) | ||||||
|  | 		); | ||||||
|  | 	} | ||||||
|  | 	return i; | ||||||
|  | #else | ||||||
|  | 	// we use c++ cast instead of c cast (not sure why id did that) | ||||||
|  | 	return static_cast<int>(f); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::FtoiFast | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE int Math::FtoiFast( float f ) { | ||||||
|  | #if OG_ASM_MSVC | ||||||
|  | 	int i; | ||||||
|  | 	__asm fld		f | ||||||
|  | 	__asm fistp		i | ||||||
|  | 	//__asm mov eax, i // do we need this ? O_o | ||||||
|  | 	return i; | ||||||
|  | #elif OG_ASM_GNU | ||||||
|  | 	int i; | ||||||
|  | 	__asm__ __volatile__( "flds %1    \n\t" | ||||||
|  | 						  "fistpl %0  \n\t" | ||||||
|  | 		: "=m" (i) | ||||||
|  | 		: "m" (f) | ||||||
|  | 	); | ||||||
|  | 	return i; | ||||||
|  | #else | ||||||
|  | 	// we use c++ cast instead of c cast (not sure why id did that) | ||||||
|  | 	return static_cast<int>(f); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Ftol | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE long Math::Ftol( float f ) { | ||||||
|  | #if OG_ASM_MSVC | ||||||
|  | 	long i; | ||||||
|  | 	__asm fld		f | ||||||
|  | 	__asm fistp		i | ||||||
|  | 	//__asm mov eax, i // do we need this ? O_o | ||||||
|  | 	return i; | ||||||
|  | #elif OG_ASM_GNU | ||||||
|  | 	long i; | ||||||
|  | 	__asm__ __volatile__( "flds %1    \n\t" | ||||||
|  | 						  "fistpl %0  \n\t" | ||||||
|  | 		: "=m" (i) | ||||||
|  | 		: "m" (f) | ||||||
|  | 	); | ||||||
|  | 	return i; | ||||||
|  | #else | ||||||
|  | 	// we use c++ cast instead of c cast (not sure why id did that) | ||||||
|  | 	return static_cast<long>(f); | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Sign | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Sign( float f )	{ | ||||||
|  | 	if ( f > 0.0f ) | ||||||
|  | 		return 1.0f; | ||||||
|  | 	if ( f < 0.0f ) | ||||||
|  | 		return -1.0f; | ||||||
|  | 	return 0.0f; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Fmod | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Fmod( float numerator, float denominator ) { | ||||||
|  | 	return fmodf( numerator, denominator ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Modf | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Modf( float f, float& i ) { | ||||||
|  | 	return modff( f, &i ); | ||||||
|  | } | ||||||
|  | OG_INLINE float Math::Modf( float f ) { | ||||||
|  | 	float i; | ||||||
|  | 	return modff( f, &i ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Sqrt | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Sqrt( float f ) { | ||||||
|  | 	return sqrtf( f ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::InvSqrt | ||||||
|  |  | ||||||
|  | Cannot be 0.0f | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::InvSqrt( float f ) { | ||||||
|  | 	OG_ASSERT( f != 0.0f ); | ||||||
|  | 	return 1.0f / sqrtf( f ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::RSqrt | ||||||
|  |  | ||||||
|  | Can be 0.0f | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::RSqrt( float f ) { | ||||||
|  | 	float g = 0.5f * f; | ||||||
|  | 	int i = *reinterpret_cast<int *>(&f); | ||||||
|  |  | ||||||
|  | 	// do a guess | ||||||
|  | 	i = 0x5f375a86 - ( i>>1 ); | ||||||
|  | 	f = *reinterpret_cast<float *>(&i); | ||||||
|  |  | ||||||
|  | 	// Newtons calculation | ||||||
|  | 	f = f * ( 1.5f - g * f * f ); | ||||||
|  | 	return f; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Log/Log2/Log10 | ||||||
|  |  | ||||||
|  | Log of 0 is bad. | ||||||
|  | I've also heard you're not really | ||||||
|  | supposed to do log of negatives, yet | ||||||
|  | they work fine. | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Log( float f ) { | ||||||
|  | 	OG_ASSERT( f != 0.0f ); | ||||||
|  | 	return logf( f ); | ||||||
|  | } | ||||||
|  | OG_INLINE float Math::Log2( float f ) { | ||||||
|  | 	OG_ASSERT( f != 0.0f ); | ||||||
|  | 	return INV_LN_2 * logf( f ); | ||||||
|  | } | ||||||
|  | OG_INLINE float Math::Log10( float f ) { | ||||||
|  | 	OG_ASSERT( f != 0.0f ); | ||||||
|  | 	return INV_LN_10 * logf( f ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Pow | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Pow( float base, float exp ) { | ||||||
|  | 	return powf( base, exp ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Exp | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Exp( float f ) { | ||||||
|  | 	return expf( f ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::IsPowerOfTwo | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE bool Math::IsPowerOfTwo( int x ) { | ||||||
|  | 	// This is the faster of the two known methods | ||||||
|  | 	// with the x > 0 check moved to the beginning | ||||||
|  | 	return x > 0 && ( x & ( x - 1 ) ) == 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::HigherPowerOfTwo | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE int Math::HigherPowerOfTwo( int x ) { | ||||||
|  | 	x--; | ||||||
|  | 	x |= x >> 1; | ||||||
|  | 	x |= x >> 2; | ||||||
|  | 	x |= x >> 4; | ||||||
|  | 	x |= x >> 8; | ||||||
|  | 	x |= x >> 16; | ||||||
|  | 	return x + 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::LowerPowerOfTwo | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE int Math::LowerPowerOfTwo( int x ) { | ||||||
|  | 	return HigherPowerOfTwo( x ) >> 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::FloorPowerOfTwo | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE int Math::FloorPowerOfTwo( int x ) { | ||||||
|  | 	return IsPowerOfTwo( x ) ? x : LowerPowerOfTwo( x ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::CeilPowerOfTwo | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE int Math::CeilPowerOfTwo( int x ) { | ||||||
|  | 	return IsPowerOfTwo( x ) ? x : HigherPowerOfTwo( x ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::ClosestPowerOfTwo | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE int Math::ClosestPowerOfTwo( int x ) { | ||||||
|  | 	if ( IsPowerOfTwo( x ) ) | ||||||
|  | 		return x; | ||||||
|  | 	int high = HigherPowerOfTwo( x ); | ||||||
|  | 	int low = high >> 1; | ||||||
|  | 	return ((high-x) < (x-low)) ? high : low; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Digits | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE int Math::Digits( int x ) { | ||||||
|  | 	int digits = 1; | ||||||
|  | 	int step = 10; | ||||||
|  | 	while (step <= x) { | ||||||
|  | 		digits++; | ||||||
|  | 		step *= 10; | ||||||
|  | 	} | ||||||
|  | 	return digits; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Sin/ASin | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Sin( float f ) { | ||||||
|  | 	return sinf( f ); | ||||||
|  | } | ||||||
|  | OG_INLINE float Math::ASin( float f ) { | ||||||
|  | 	if ( f <= -1.0f ) | ||||||
|  | 		return -HALF_PI; | ||||||
|  | 	if ( f >= 1.0f ) | ||||||
|  | 		return HALF_PI; | ||||||
|  | 	return asinf( f ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Cos/ACos | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Cos( float f ) { | ||||||
|  | 	return cosf( f ); | ||||||
|  | } | ||||||
|  | OG_INLINE float Math::ACos( float f ) { | ||||||
|  | 	if ( f <= -1.0f ) | ||||||
|  | 		return PI; | ||||||
|  | 	if ( f >= 1.0f ) | ||||||
|  | 		return 0.0f; | ||||||
|  | 	return acosf( f ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Tan/ATan | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Tan( float f ) { | ||||||
|  | 	return tanf( f ); | ||||||
|  | } | ||||||
|  | OG_INLINE float Math::ATan( float f ) { | ||||||
|  | 	return atanf( f ); | ||||||
|  | } | ||||||
|  | OG_INLINE float Math::ATan( float f1, float f2 ) { | ||||||
|  | 	return atan2f( f1, f2 ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::SinCos | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE void Math::SinCos( float f, float &s, float &c ) { | ||||||
|  | #if OG_ASM_MSVC | ||||||
|  | 	// sometimes assembler is just waaayy faster | ||||||
|  | 	_asm { | ||||||
|  | 		fld		f | ||||||
|  | 		fsincos | ||||||
|  | 		mov		ecx, c | ||||||
|  | 		mov		edx, s | ||||||
|  | 		fstp	dword ptr [ecx] | ||||||
|  | 		fstp	dword ptr [edx] | ||||||
|  | 	} | ||||||
|  | #elif OG_ASM_GNU | ||||||
|  | 	asm ("fsincos" : "=t" (c), "=u" (s) : "0" (f)); | ||||||
|  | #else | ||||||
|  | 	s = Sin(f); | ||||||
|  | 	c = Sqrt( 1.0f - s * s ); // faster than calling Cos(f) | ||||||
|  | #endif | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Deg2Rad | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Deg2Rad( float f ) { | ||||||
|  | 	return f * DEG_TO_RAD; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Rad2Deg | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Rad2Deg( float f ) { | ||||||
|  | 	return f * RAD_TO_DEG; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Square | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Square( float v ) { | ||||||
|  | 	return v * v; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Cube | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE float Math::Cube( float v ) { | ||||||
|  | 	return v * v * v; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Sec2Ms | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE int Math::Sec2Ms( int sec ) { | ||||||
|  | 	return sec * 1000; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | ================ | ||||||
|  | Math::Ms2Sec | ||||||
|  | ================ | ||||||
|  | */ | ||||||
|  | OG_INLINE int Math::Ms2Sec( int ms ) { | ||||||
|  | 	return FtoiFast( ms * 0.001f ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										10
									
								
								samples/C++/bar.hh
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								samples/C++/bar.hh
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | class Bar | ||||||
|  | { | ||||||
|  |   protected: | ||||||
|  |  | ||||||
|  |     char *name; | ||||||
|  |  | ||||||
|  |   public: | ||||||
|  |  | ||||||
|  |     void hello(); | ||||||
|  | } | ||||||
							
								
								
									
										664
									
								
								samples/C++/epoll_reactor.ipp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										664
									
								
								samples/C++/epoll_reactor.ipp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,664 @@ | |||||||
|  | // | ||||||
|  | // detail/impl/epoll_reactor.ipp | ||||||
|  | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||||||
|  | // | ||||||
|  | // Copyright (c) 2003-2013 Christopher M. Kohlhoff (chris at kohlhoff dot com) | ||||||
|  | // | ||||||
|  | // Distributed under the Boost Software License, Version 1.0. (See accompanying | ||||||
|  | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | ||||||
|  | // | ||||||
|  |  | ||||||
|  | #ifndef BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP | ||||||
|  | #define BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP | ||||||
|  |  | ||||||
|  | #if defined(_MSC_VER) && (_MSC_VER >= 1200) | ||||||
|  | # pragma once | ||||||
|  | #endif // defined(_MSC_VER) && (_MSC_VER >= 1200) | ||||||
|  |  | ||||||
|  | #include <boost/asio/detail/config.hpp> | ||||||
|  |  | ||||||
|  | #if defined(BOOST_ASIO_HAS_EPOLL) | ||||||
|  |  | ||||||
|  | #include <cstddef> | ||||||
|  | #include <sys/epoll.h> | ||||||
|  | #include <boost/asio/detail/epoll_reactor.hpp> | ||||||
|  | #include <boost/asio/detail/throw_error.hpp> | ||||||
|  | #include <boost/asio/error.hpp> | ||||||
|  |  | ||||||
|  | #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  | # include <sys/timerfd.h> | ||||||
|  | #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |  | ||||||
|  | #include <boost/asio/detail/push_options.hpp> | ||||||
|  |  | ||||||
|  | namespace boost { | ||||||
|  | namespace asio { | ||||||
|  | namespace detail { | ||||||
|  |  | ||||||
|  | epoll_reactor::epoll_reactor(boost::asio::io_service& io_service) | ||||||
|  |   : boost::asio::detail::service_base<epoll_reactor>(io_service), | ||||||
|  |     io_service_(use_service<io_service_impl>(io_service)), | ||||||
|  |     mutex_(), | ||||||
|  |     interrupter_(), | ||||||
|  |     epoll_fd_(do_epoll_create()), | ||||||
|  |     timer_fd_(do_timerfd_create()), | ||||||
|  |     shutdown_(false) | ||||||
|  | { | ||||||
|  |   // Add the interrupter's descriptor to epoll. | ||||||
|  |   epoll_event ev = { 0, { 0 } }; | ||||||
|  |   ev.events = EPOLLIN | EPOLLERR | EPOLLET; | ||||||
|  |   ev.data.ptr = &interrupter_; | ||||||
|  |   epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); | ||||||
|  |   interrupter_.interrupt(); | ||||||
|  |  | ||||||
|  |   // Add the timer descriptor to epoll. | ||||||
|  |   if (timer_fd_ != -1) | ||||||
|  |   { | ||||||
|  |     ev.events = EPOLLIN | EPOLLERR; | ||||||
|  |     ev.data.ptr = &timer_fd_; | ||||||
|  |     epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | epoll_reactor::~epoll_reactor() | ||||||
|  | { | ||||||
|  |   if (epoll_fd_ != -1) | ||||||
|  |     close(epoll_fd_); | ||||||
|  |   if (timer_fd_ != -1) | ||||||
|  |     close(timer_fd_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::shutdown_service() | ||||||
|  | { | ||||||
|  |   mutex::scoped_lock lock(mutex_); | ||||||
|  |   shutdown_ = true; | ||||||
|  |   lock.unlock(); | ||||||
|  |  | ||||||
|  |   op_queue<operation> ops; | ||||||
|  |  | ||||||
|  |   while (descriptor_state* state = registered_descriptors_.first()) | ||||||
|  |   { | ||||||
|  |     for (int i = 0; i < max_ops; ++i) | ||||||
|  |       ops.push(state->op_queue_[i]); | ||||||
|  |     state->shutdown_ = true; | ||||||
|  |     registered_descriptors_.free(state); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   timer_queues_.get_all_timers(ops); | ||||||
|  |  | ||||||
|  |   io_service_.abandon_operations(ops); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::fork_service(boost::asio::io_service::fork_event fork_ev) | ||||||
|  | { | ||||||
|  |   if (fork_ev == boost::asio::io_service::fork_child) | ||||||
|  |   { | ||||||
|  |     if (epoll_fd_ != -1) | ||||||
|  |       ::close(epoll_fd_); | ||||||
|  |     epoll_fd_ = -1; | ||||||
|  |     epoll_fd_ = do_epoll_create(); | ||||||
|  |  | ||||||
|  |     if (timer_fd_ != -1) | ||||||
|  |       ::close(timer_fd_); | ||||||
|  |     timer_fd_ = -1; | ||||||
|  |     timer_fd_ = do_timerfd_create(); | ||||||
|  |  | ||||||
|  |     interrupter_.recreate(); | ||||||
|  |  | ||||||
|  |     // Add the interrupter's descriptor to epoll. | ||||||
|  |     epoll_event ev = { 0, { 0 } }; | ||||||
|  |     ev.events = EPOLLIN | EPOLLERR | EPOLLET; | ||||||
|  |     ev.data.ptr = &interrupter_; | ||||||
|  |     epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupter_.read_descriptor(), &ev); | ||||||
|  |     interrupter_.interrupt(); | ||||||
|  |  | ||||||
|  |     // Add the timer descriptor to epoll. | ||||||
|  |     if (timer_fd_ != -1) | ||||||
|  |     { | ||||||
|  |       ev.events = EPOLLIN | EPOLLERR; | ||||||
|  |       ev.data.ptr = &timer_fd_; | ||||||
|  |       epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, timer_fd_, &ev); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     update_timeout(); | ||||||
|  |  | ||||||
|  |     // Re-register all descriptors with epoll. | ||||||
|  |     mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); | ||||||
|  |     for (descriptor_state* state = registered_descriptors_.first(); | ||||||
|  |         state != 0; state = state->next_) | ||||||
|  |     { | ||||||
|  |       ev.events = state->registered_events_; | ||||||
|  |       ev.data.ptr = state; | ||||||
|  |       int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, state->descriptor_, &ev); | ||||||
|  |       if (result != 0) | ||||||
|  |       { | ||||||
|  |         boost::system::error_code ec(errno, | ||||||
|  |             boost::asio::error::get_system_category()); | ||||||
|  |         boost::asio::detail::throw_error(ec, "epoll re-registration"); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::init_task() | ||||||
|  | { | ||||||
|  |   io_service_.init_task(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int epoll_reactor::register_descriptor(socket_type descriptor, | ||||||
|  |     epoll_reactor::per_descriptor_data& descriptor_data) | ||||||
|  | { | ||||||
|  |   descriptor_data = allocate_descriptor_state(); | ||||||
|  |  | ||||||
|  |   { | ||||||
|  |     mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); | ||||||
|  |  | ||||||
|  |     descriptor_data->reactor_ = this; | ||||||
|  |     descriptor_data->descriptor_ = descriptor; | ||||||
|  |     descriptor_data->shutdown_ = false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   epoll_event ev = { 0, { 0 } }; | ||||||
|  |   ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET; | ||||||
|  |   descriptor_data->registered_events_ = ev.events; | ||||||
|  |   ev.data.ptr = descriptor_data; | ||||||
|  |   int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); | ||||||
|  |   if (result != 0) | ||||||
|  |     return errno; | ||||||
|  |  | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int epoll_reactor::register_internal_descriptor( | ||||||
|  |     int op_type, socket_type descriptor, | ||||||
|  |     epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op) | ||||||
|  | { | ||||||
|  |   descriptor_data = allocate_descriptor_state(); | ||||||
|  |  | ||||||
|  |   { | ||||||
|  |     mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); | ||||||
|  |  | ||||||
|  |     descriptor_data->reactor_ = this; | ||||||
|  |     descriptor_data->descriptor_ = descriptor; | ||||||
|  |     descriptor_data->shutdown_ = false; | ||||||
|  |     descriptor_data->op_queue_[op_type].push(op); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   epoll_event ev = { 0, { 0 } }; | ||||||
|  |   ev.events = EPOLLIN | EPOLLERR | EPOLLHUP | EPOLLPRI | EPOLLET; | ||||||
|  |   descriptor_data->registered_events_ = ev.events; | ||||||
|  |   ev.data.ptr = descriptor_data; | ||||||
|  |   int result = epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, descriptor, &ev); | ||||||
|  |   if (result != 0) | ||||||
|  |     return errno; | ||||||
|  |  | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::move_descriptor(socket_type, | ||||||
|  |     epoll_reactor::per_descriptor_data& target_descriptor_data, | ||||||
|  |     epoll_reactor::per_descriptor_data& source_descriptor_data) | ||||||
|  | { | ||||||
|  |   target_descriptor_data = source_descriptor_data; | ||||||
|  |   source_descriptor_data = 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::start_op(int op_type, socket_type descriptor, | ||||||
|  |     epoll_reactor::per_descriptor_data& descriptor_data, reactor_op* op, | ||||||
|  |     bool is_continuation, bool allow_speculative) | ||||||
|  | { | ||||||
|  |   if (!descriptor_data) | ||||||
|  |   { | ||||||
|  |     op->ec_ = boost::asio::error::bad_descriptor; | ||||||
|  |     post_immediate_completion(op, is_continuation); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); | ||||||
|  |  | ||||||
|  |   if (descriptor_data->shutdown_) | ||||||
|  |   { | ||||||
|  |     post_immediate_completion(op, is_continuation); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (descriptor_data->op_queue_[op_type].empty()) | ||||||
|  |   { | ||||||
|  |     if (allow_speculative | ||||||
|  |         && (op_type != read_op | ||||||
|  |           || descriptor_data->op_queue_[except_op].empty())) | ||||||
|  |     { | ||||||
|  |       if (op->perform()) | ||||||
|  |       { | ||||||
|  |         descriptor_lock.unlock(); | ||||||
|  |         io_service_.post_immediate_completion(op, is_continuation); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (op_type == write_op) | ||||||
|  |       { | ||||||
|  |         if ((descriptor_data->registered_events_ & EPOLLOUT) == 0) | ||||||
|  |         { | ||||||
|  |           epoll_event ev = { 0, { 0 } }; | ||||||
|  |           ev.events = descriptor_data->registered_events_ | EPOLLOUT; | ||||||
|  |           ev.data.ptr = descriptor_data; | ||||||
|  |           if (epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev) == 0) | ||||||
|  |           { | ||||||
|  |             descriptor_data->registered_events_ |= ev.events; | ||||||
|  |           } | ||||||
|  |           else | ||||||
|  |           { | ||||||
|  |             op->ec_ = boost::system::error_code(errno, | ||||||
|  |                 boost::asio::error::get_system_category()); | ||||||
|  |             io_service_.post_immediate_completion(op, is_continuation); | ||||||
|  |             return; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       if (op_type == write_op) | ||||||
|  |       { | ||||||
|  |         descriptor_data->registered_events_ |= EPOLLOUT; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       epoll_event ev = { 0, { 0 } }; | ||||||
|  |       ev.events = descriptor_data->registered_events_; | ||||||
|  |       ev.data.ptr = descriptor_data; | ||||||
|  |       epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   descriptor_data->op_queue_[op_type].push(op); | ||||||
|  |   io_service_.work_started(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::cancel_ops(socket_type, | ||||||
|  |     epoll_reactor::per_descriptor_data& descriptor_data) | ||||||
|  | { | ||||||
|  |   if (!descriptor_data) | ||||||
|  |     return; | ||||||
|  |  | ||||||
|  |   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); | ||||||
|  |  | ||||||
|  |   op_queue<operation> ops; | ||||||
|  |   for (int i = 0; i < max_ops; ++i) | ||||||
|  |   { | ||||||
|  |     while (reactor_op* op = descriptor_data->op_queue_[i].front()) | ||||||
|  |     { | ||||||
|  |       op->ec_ = boost::asio::error::operation_aborted; | ||||||
|  |       descriptor_data->op_queue_[i].pop(); | ||||||
|  |       ops.push(op); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   descriptor_lock.unlock(); | ||||||
|  |  | ||||||
|  |   io_service_.post_deferred_completions(ops); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::deregister_descriptor(socket_type descriptor, | ||||||
|  |     epoll_reactor::per_descriptor_data& descriptor_data, bool closing) | ||||||
|  | { | ||||||
|  |   if (!descriptor_data) | ||||||
|  |     return; | ||||||
|  |  | ||||||
|  |   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); | ||||||
|  |  | ||||||
|  |   if (!descriptor_data->shutdown_) | ||||||
|  |   { | ||||||
|  |     if (closing) | ||||||
|  |     { | ||||||
|  |       // The descriptor will be automatically removed from the epoll set when | ||||||
|  |       // it is closed. | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       epoll_event ev = { 0, { 0 } }; | ||||||
|  |       epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     op_queue<operation> ops; | ||||||
|  |     for (int i = 0; i < max_ops; ++i) | ||||||
|  |     { | ||||||
|  |       while (reactor_op* op = descriptor_data->op_queue_[i].front()) | ||||||
|  |       { | ||||||
|  |         op->ec_ = boost::asio::error::operation_aborted; | ||||||
|  |         descriptor_data->op_queue_[i].pop(); | ||||||
|  |         ops.push(op); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     descriptor_data->descriptor_ = -1; | ||||||
|  |     descriptor_data->shutdown_ = true; | ||||||
|  |  | ||||||
|  |     descriptor_lock.unlock(); | ||||||
|  |  | ||||||
|  |     free_descriptor_state(descriptor_data); | ||||||
|  |     descriptor_data = 0; | ||||||
|  |  | ||||||
|  |     io_service_.post_deferred_completions(ops); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::deregister_internal_descriptor(socket_type descriptor, | ||||||
|  |     epoll_reactor::per_descriptor_data& descriptor_data) | ||||||
|  | { | ||||||
|  |   if (!descriptor_data) | ||||||
|  |     return; | ||||||
|  |  | ||||||
|  |   mutex::scoped_lock descriptor_lock(descriptor_data->mutex_); | ||||||
|  |  | ||||||
|  |   if (!descriptor_data->shutdown_) | ||||||
|  |   { | ||||||
|  |     epoll_event ev = { 0, { 0 } }; | ||||||
|  |     epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, descriptor, &ev); | ||||||
|  |  | ||||||
|  |     op_queue<operation> ops; | ||||||
|  |     for (int i = 0; i < max_ops; ++i) | ||||||
|  |       ops.push(descriptor_data->op_queue_[i]); | ||||||
|  |  | ||||||
|  |     descriptor_data->descriptor_ = -1; | ||||||
|  |     descriptor_data->shutdown_ = true; | ||||||
|  |  | ||||||
|  |     descriptor_lock.unlock(); | ||||||
|  |  | ||||||
|  |     free_descriptor_state(descriptor_data); | ||||||
|  |     descriptor_data = 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::run(bool block, op_queue<operation>& ops) | ||||||
|  | { | ||||||
|  |   // This code relies on the fact that the task_io_service queues the reactor | ||||||
|  |   // task behind all descriptor operations generated by this function. This | ||||||
|  |   // means, that by the time we reach this point, any previously returned | ||||||
|  |   // descriptor operations have already been dequeued. Therefore it is now safe | ||||||
|  |   // for us to reuse and return them for the task_io_service to queue again. | ||||||
|  |  | ||||||
|  |   // Calculate a timeout only if timerfd is not used. | ||||||
|  |   int timeout; | ||||||
|  |   if (timer_fd_ != -1) | ||||||
|  |     timeout = block ? -1 : 0; | ||||||
|  |   else | ||||||
|  |   { | ||||||
|  |     mutex::scoped_lock lock(mutex_); | ||||||
|  |     timeout = block ? get_timeout() : 0; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Block on the epoll descriptor. | ||||||
|  |   epoll_event events[128]; | ||||||
|  |   int num_events = epoll_wait(epoll_fd_, events, 128, timeout); | ||||||
|  |  | ||||||
|  | #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |   bool check_timers = (timer_fd_ == -1); | ||||||
|  | #else // defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |   bool check_timers = true; | ||||||
|  | #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |  | ||||||
|  |   // Dispatch the waiting events. | ||||||
|  |   for (int i = 0; i < num_events; ++i) | ||||||
|  |   { | ||||||
|  |     void* ptr = events[i].data.ptr; | ||||||
|  |     if (ptr == &interrupter_) | ||||||
|  |     { | ||||||
|  |       // No need to reset the interrupter since we're leaving the descriptor | ||||||
|  |       // in a ready-to-read state and relying on edge-triggered notifications | ||||||
|  |       // to make it so that we only get woken up when the descriptor's epoll | ||||||
|  |       // registration is updated. | ||||||
|  |  | ||||||
|  | #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |       if (timer_fd_ == -1) | ||||||
|  |         check_timers = true; | ||||||
|  | #else // defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |       check_timers = true; | ||||||
|  | #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |     } | ||||||
|  | #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |     else if (ptr == &timer_fd_) | ||||||
|  |     { | ||||||
|  |       check_timers = true; | ||||||
|  |     } | ||||||
|  | #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       // The descriptor operation doesn't count as work in and of itself, so we | ||||||
|  |       // don't call work_started() here. This still allows the io_service to | ||||||
|  |       // stop if the only remaining operations are descriptor operations. | ||||||
|  |       descriptor_state* descriptor_data = static_cast<descriptor_state*>(ptr); | ||||||
|  |       descriptor_data->set_ready_events(events[i].events); | ||||||
|  |       ops.push(descriptor_data); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (check_timers) | ||||||
|  |   { | ||||||
|  |     mutex::scoped_lock common_lock(mutex_); | ||||||
|  |     timer_queues_.get_ready_timers(ops); | ||||||
|  |  | ||||||
|  | #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |     if (timer_fd_ != -1) | ||||||
|  |     { | ||||||
|  |       itimerspec new_timeout; | ||||||
|  |       itimerspec old_timeout; | ||||||
|  |       int flags = get_timeout(new_timeout); | ||||||
|  |       timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); | ||||||
|  |     } | ||||||
|  | #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::interrupt() | ||||||
|  | { | ||||||
|  |   epoll_event ev = { 0, { 0 } }; | ||||||
|  |   ev.events = EPOLLIN | EPOLLERR | EPOLLET; | ||||||
|  |   ev.data.ptr = &interrupter_; | ||||||
|  |   epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, interrupter_.read_descriptor(), &ev); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int epoll_reactor::do_epoll_create() | ||||||
|  | { | ||||||
|  | #if defined(EPOLL_CLOEXEC) | ||||||
|  |   int fd = epoll_create1(EPOLL_CLOEXEC); | ||||||
|  | #else // defined(EPOLL_CLOEXEC) | ||||||
|  |   int fd = -1; | ||||||
|  |   errno = EINVAL; | ||||||
|  | #endif // defined(EPOLL_CLOEXEC) | ||||||
|  |  | ||||||
|  |   if (fd == -1 && (errno == EINVAL || errno == ENOSYS)) | ||||||
|  |   { | ||||||
|  |     fd = epoll_create(epoll_size); | ||||||
|  |     if (fd != -1) | ||||||
|  |       ::fcntl(fd, F_SETFD, FD_CLOEXEC); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (fd == -1) | ||||||
|  |   { | ||||||
|  |     boost::system::error_code ec(errno, | ||||||
|  |         boost::asio::error::get_system_category()); | ||||||
|  |     boost::asio::detail::throw_error(ec, "epoll"); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return fd; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int epoll_reactor::do_timerfd_create() | ||||||
|  | { | ||||||
|  | #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  | # if defined(TFD_CLOEXEC) | ||||||
|  |   int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC); | ||||||
|  | # else // defined(TFD_CLOEXEC) | ||||||
|  |   int fd = -1; | ||||||
|  |   errno = EINVAL; | ||||||
|  | # endif // defined(TFD_CLOEXEC) | ||||||
|  |  | ||||||
|  |   if (fd == -1 && errno == EINVAL) | ||||||
|  |   { | ||||||
|  |     fd = timerfd_create(CLOCK_MONOTONIC, 0); | ||||||
|  |     if (fd != -1) | ||||||
|  |       ::fcntl(fd, F_SETFD, FD_CLOEXEC); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return fd; | ||||||
|  | #else // defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |   return -1; | ||||||
|  | #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  | } | ||||||
|  |  | ||||||
|  | epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state() | ||||||
|  | { | ||||||
|  |   mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); | ||||||
|  |   return registered_descriptors_.alloc(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s) | ||||||
|  | { | ||||||
|  |   mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_); | ||||||
|  |   registered_descriptors_.free(s); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::do_add_timer_queue(timer_queue_base& queue) | ||||||
|  | { | ||||||
|  |   mutex::scoped_lock lock(mutex_); | ||||||
|  |   timer_queues_.insert(&queue); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::do_remove_timer_queue(timer_queue_base& queue) | ||||||
|  | { | ||||||
|  |   mutex::scoped_lock lock(mutex_); | ||||||
|  |   timer_queues_.erase(&queue); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::update_timeout() | ||||||
|  | { | ||||||
|  | #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |   if (timer_fd_ != -1) | ||||||
|  |   { | ||||||
|  |     itimerspec new_timeout; | ||||||
|  |     itimerspec old_timeout; | ||||||
|  |     int flags = get_timeout(new_timeout); | ||||||
|  |     timerfd_settime(timer_fd_, flags, &new_timeout, &old_timeout); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  | #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |   interrupt(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int epoll_reactor::get_timeout() | ||||||
|  | { | ||||||
|  |   // By default we will wait no longer than 5 minutes. This will ensure that | ||||||
|  |   // any changes to the system clock are detected after no longer than this. | ||||||
|  |   return timer_queues_.wait_duration_msec(5 * 60 * 1000); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #if defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  | int epoll_reactor::get_timeout(itimerspec& ts) | ||||||
|  | { | ||||||
|  |   ts.it_interval.tv_sec = 0; | ||||||
|  |   ts.it_interval.tv_nsec = 0; | ||||||
|  |  | ||||||
|  |   long usec = timer_queues_.wait_duration_usec(5 * 60 * 1000 * 1000); | ||||||
|  |   ts.it_value.tv_sec = usec / 1000000; | ||||||
|  |   ts.it_value.tv_nsec = usec ? (usec % 1000000) * 1000 : 1; | ||||||
|  |  | ||||||
|  |   return usec ? 0 : TFD_TIMER_ABSTIME; | ||||||
|  | } | ||||||
|  | #endif // defined(BOOST_ASIO_HAS_TIMERFD) | ||||||
|  |  | ||||||
|  | struct epoll_reactor::perform_io_cleanup_on_block_exit | ||||||
|  | { | ||||||
|  |   explicit perform_io_cleanup_on_block_exit(epoll_reactor* r) | ||||||
|  |     : reactor_(r), first_op_(0) | ||||||
|  |   { | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   ~perform_io_cleanup_on_block_exit() | ||||||
|  |   { | ||||||
|  |     if (first_op_) | ||||||
|  |     { | ||||||
|  |       // Post the remaining completed operations for invocation. | ||||||
|  |       if (!ops_.empty()) | ||||||
|  |         reactor_->io_service_.post_deferred_completions(ops_); | ||||||
|  |  | ||||||
|  |       // A user-initiated operation has completed, but there's no need to | ||||||
|  |       // explicitly call work_finished() here. Instead, we'll take advantage of | ||||||
|  |       // the fact that the task_io_service will call work_finished() once we | ||||||
|  |       // return. | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |     { | ||||||
|  |       // No user-initiated operations have completed, so we need to compensate | ||||||
|  |       // for the work_finished() call that the task_io_service will make once | ||||||
|  |       // this operation returns. | ||||||
|  |       reactor_->io_service_.work_started(); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   epoll_reactor* reactor_; | ||||||
|  |   op_queue<operation> ops_; | ||||||
|  |   operation* first_op_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | epoll_reactor::descriptor_state::descriptor_state() | ||||||
|  |   : operation(&epoll_reactor::descriptor_state::do_complete) | ||||||
|  | { | ||||||
|  | } | ||||||
|  |  | ||||||
|  | operation* epoll_reactor::descriptor_state::perform_io(uint32_t events) | ||||||
|  | { | ||||||
|  |   mutex_.lock(); | ||||||
|  |   perform_io_cleanup_on_block_exit io_cleanup(reactor_); | ||||||
|  |   mutex::scoped_lock descriptor_lock(mutex_, mutex::scoped_lock::adopt_lock); | ||||||
|  |  | ||||||
|  |   // Exception operations must be processed first to ensure that any | ||||||
|  |   // out-of-band data is read before normal data. | ||||||
|  |   static const int flag[max_ops] = { EPOLLIN, EPOLLOUT, EPOLLPRI }; | ||||||
|  |   for (int j = max_ops - 1; j >= 0; --j) | ||||||
|  |   { | ||||||
|  |     if (events & (flag[j] | EPOLLERR | EPOLLHUP)) | ||||||
|  |     { | ||||||
|  |       while (reactor_op* op = op_queue_[j].front()) | ||||||
|  |       { | ||||||
|  |         if (op->perform()) | ||||||
|  |         { | ||||||
|  |           op_queue_[j].pop(); | ||||||
|  |           io_cleanup.ops_.push(op); | ||||||
|  |         } | ||||||
|  |         else | ||||||
|  |           break; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // The first operation will be returned for completion now. The others will | ||||||
|  |   // be posted for later by the io_cleanup object's destructor. | ||||||
|  |   io_cleanup.first_op_ = io_cleanup.ops_.front(); | ||||||
|  |   io_cleanup.ops_.pop(); | ||||||
|  |   return io_cleanup.first_op_; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void epoll_reactor::descriptor_state::do_complete( | ||||||
|  |     io_service_impl* owner, operation* base, | ||||||
|  |     const boost::system::error_code& ec, std::size_t bytes_transferred) | ||||||
|  | { | ||||||
|  |   if (owner) | ||||||
|  |   { | ||||||
|  |     descriptor_state* descriptor_data = static_cast<descriptor_state*>(base); | ||||||
|  |     uint32_t events = static_cast<uint32_t>(bytes_transferred); | ||||||
|  |     if (operation* op = descriptor_data->perform_io(events)) | ||||||
|  |     { | ||||||
|  |       op->complete(*owner, ec, 0); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | } // namespace detail | ||||||
|  | } // namespace asio | ||||||
|  | } // namespace boost | ||||||
|  |  | ||||||
|  | #include <boost/asio/detail/pop_options.hpp> | ||||||
|  |  | ||||||
|  | #endif // defined(BOOST_ASIO_HAS_EPOLL) | ||||||
|  |  | ||||||
|  | #endif // BOOST_ASIO_DETAIL_IMPL_EPOLL_REACTOR_IPP | ||||||
| @@ -1,13 +1,13 @@ | |||||||
| doc "Test function for Ceylon" | "Test function for Ceylon" | ||||||
| by  "Enrique" | by ("Enrique") | ||||||
| shared void test() { | shared void test() { | ||||||
|   print("test"); |     print("test"); | ||||||
| } | } | ||||||
|  |  | ||||||
| doc "Test class for Ceylon" | "Test class for Ceylon" | ||||||
| shared class Test(name) satisfies Comparable<Test> { | shared class Test(name) satisfies Comparable<Test> { | ||||||
|     shared String name; |     shared String name; | ||||||
|     shared actual String string = "Test " name "."; |     shared actual String string = "Test ``name``."; | ||||||
|  |  | ||||||
|     shared actual Comparison compare(Test other) { |     shared actual Comparison compare(Test other) { | ||||||
|         return name<=>other.name; |         return name<=>other.name; | ||||||
|   | |||||||
							
								
								
									
										304
									
								
								samples/Chapel/distributions.chpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										304
									
								
								samples/Chapel/distributions.chpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,304 @@ | |||||||
|  | // | ||||||
|  | // Distributions Primer | ||||||
|  | // | ||||||
|  | // This primer demonstrates uses of some of Chapel's standard | ||||||
|  | // distributions.  To use these distributions in a Chapel program, | ||||||
|  | // the respective module must be used: | ||||||
|  | // | ||||||
|  | use BlockDist, CyclicDist, BlockCycDist, ReplicatedDist; | ||||||
|  | use DimensionalDist2D, ReplicatedDim, BlockCycDim; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // For each distribution, we'll create a distributed domain and array | ||||||
|  | // and then initialize it just to give a brief flavor of how the | ||||||
|  | // distribution maps across locales.  Running this example on 6 | ||||||
|  | // locales does a nice job of illustrating the distribution | ||||||
|  | // characteristics. | ||||||
|  | // | ||||||
|  | // All of these distributions support options to map to a different | ||||||
|  | // virtual locale grid than the one used by default (a | ||||||
|  | // multidimensional factoring of the built-in Locales array), as well | ||||||
|  | // as to control the amount of parallelism used in data parallel | ||||||
|  | // loops.  See the Standard Distributions chapter of the language spec | ||||||
|  | // for more details. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Make the program size configurable from the command line. | ||||||
|  | // | ||||||
|  | config const n = 8; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Declare a 2-dimensional domain Space that we will later use to | ||||||
|  | // initialize the distributed domains. | ||||||
|  | // | ||||||
|  | const Space = {1..n, 1..n}; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // The Block distribution distributes a bounding box from | ||||||
|  | // n-dimensional space across the target locale array viewed as an | ||||||
|  | // n-dimensional virtual locale grid.  The bounding box is blocked | ||||||
|  | // into roughly equal portions across the locales.  Note that domains | ||||||
|  | // declared over a Block distribution can also store indices outside | ||||||
|  | // of the bounding box; the bounding box is merely used to compute | ||||||
|  | // the blocking of space. | ||||||
|  | // | ||||||
|  | // In this example, we declare a 2-dimensional Block-distributed | ||||||
|  | // domain BlockSpace and a Block-distributed array BA declared over | ||||||
|  | // the domain. | ||||||
|  | // | ||||||
|  | const BlockSpace = Space dmapped Block(boundingBox=Space); | ||||||
|  | var BA: [BlockSpace] int; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // To illustrate how the index set is distributed across locales, | ||||||
|  | // we'll use a forall loop to initialize each array element to the | ||||||
|  | // locale ID that stores that index/element/iteration. | ||||||
|  | // | ||||||
|  | forall ba in BA do | ||||||
|  |   ba = here.id; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Output the Block-distributed array to visually see how the elements | ||||||
|  | // are partitioned across the locales. | ||||||
|  | // | ||||||
|  | writeln("Block Array Index Map"); | ||||||
|  | writeln(BA); | ||||||
|  | writeln(); | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Most of Chapel's standard distributions support an optional | ||||||
|  | // targetLocales argument that permits you to pass in your own | ||||||
|  | // array of locales to be targeted.  In general, the targetLocales | ||||||
|  | // argument should match the rank of the distribution.  So for | ||||||
|  | // example, to map a Block to a [numLocales x 1] view of the | ||||||
|  | // locale set, one could do something like this: | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // We start by creating our own array of the locale values.  Here | ||||||
|  | // we use the standard array reshape function for convenience, | ||||||
|  | // but more generally, this array could be accessed/assigned like any | ||||||
|  | // other. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | var MyLocaleView = {0..#numLocales, 1..1}; | ||||||
|  | var MyLocales: [MyLocaleView] locale = reshape(Locales, MyLocaleView); | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Then we'll declare a distributed domain/array that targets | ||||||
|  | // this view of the locales: | ||||||
|  | //  | ||||||
|  |  | ||||||
|  | const BlockSpace2 = Space dmapped Block(boundingBox=Space, | ||||||
|  |                                         targetLocales=MyLocales); | ||||||
|  | var BA2: [BlockSpace2] int; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Then we'll do a similar computation as before to verify where | ||||||
|  | // everything ended up: | ||||||
|  | // | ||||||
|  | forall ba in BA2 do | ||||||
|  |   ba = here.id; | ||||||
|  |  | ||||||
|  | writeln("Block Array Index Map"); | ||||||
|  | writeln(BA2); | ||||||
|  | writeln(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Next, we'll perform a similar computation for the Cyclic distribution. | ||||||
|  | // Cyclic distributions start at a designated n-dimensional index and | ||||||
|  | // distribute the n-dimensional space across an n-dimensional array | ||||||
|  | // of locales in a round-robin fashion (in each dimension).  As with | ||||||
|  | // the Block distribution, domains may be declared using the | ||||||
|  | // distribution who have lower indices that the starting index; that | ||||||
|  | // value should just be considered a parameterization of how the | ||||||
|  | // distribution is defined. | ||||||
|  | // | ||||||
|  | const CyclicSpace = Space dmapped Cyclic(startIdx=Space.low); | ||||||
|  | var CA: [CyclicSpace] int; | ||||||
|  |  | ||||||
|  | forall ca in CA do | ||||||
|  |   ca = here.id; | ||||||
|  |  | ||||||
|  | writeln("Cyclic Array Index Map"); | ||||||
|  | writeln(CA); | ||||||
|  | writeln(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Next, we'll declare a Block-Cyclic distribution.  These | ||||||
|  | // distributions also deal out indices in a round-robin fashion, | ||||||
|  | // but rather than dealing out singleton indices, they deal out blocks | ||||||
|  | // of indices.  Thus, the BlockCyclic distribution is parameterized | ||||||
|  | // by a starting index (as with Cyclic) and a block size (per | ||||||
|  | // dimension) specifying how large the chunks to be dealt out are. | ||||||
|  | //  | ||||||
|  | const BlkCycSpace = Space dmapped BlockCyclic(startIdx=Space.low,  | ||||||
|  |                                               blocksize=(2, 3)); | ||||||
|  | var BCA: [BlkCycSpace] int; | ||||||
|  |  | ||||||
|  | forall bca in BCA do | ||||||
|  |   bca = here.id; | ||||||
|  |  | ||||||
|  | writeln("Block-Cyclic Array Index Map"); | ||||||
|  | writeln(BCA); | ||||||
|  | writeln(); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // The ReplicatedDist distribution is different: each of the | ||||||
|  | // original domain's indices - and the corresponding array elements - | ||||||
|  | // is replicated onto each locale. (Note: consistency among these | ||||||
|  | // array replicands is NOT maintained automatically.) | ||||||
|  | // | ||||||
|  | // This replication is observable in some cases but not others, | ||||||
|  | // as shown below. Note: this behavior may change in the future. | ||||||
|  | // | ||||||
|  | const ReplicatedSpace = Space dmapped ReplicatedDist(); | ||||||
|  | var RA: [ReplicatedSpace] int; | ||||||
|  |  | ||||||
|  | // The replication is observable - this visits each replicand. | ||||||
|  | forall ra in RA do | ||||||
|  |   ra = here.id; | ||||||
|  |  | ||||||
|  | writeln("Replicated Array Index Map, ", RA.numElements, " elements total"); | ||||||
|  | writeln(RA); | ||||||
|  | writeln(); | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // The replication is observable when the replicated array is | ||||||
|  | // on the left-hand side. If the right-hand side is not replicated, | ||||||
|  | // it is copied into each replicand. | ||||||
|  | // We illustrate this using a non-distributed array. | ||||||
|  | // | ||||||
|  | var A: [Space] int = [(i,j) in Space] i*100 + j; | ||||||
|  | RA = A; | ||||||
|  | writeln("Replicated Array after being array-assigned into"); | ||||||
|  | writeln(RA); | ||||||
|  | writeln(); | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Analogously, each replicand will be visited and | ||||||
|  | // other participated expressions will be computed on each locale | ||||||
|  | // (a) when the replicated array is assigned a scalar: | ||||||
|  | //       RA = 5; | ||||||
|  | // (b) when it appears first in a zippered forall loop: | ||||||
|  | //       forall (ra, a) in zip(RA, A) do ...; | ||||||
|  | // (c) when it appears in a for loop: | ||||||
|  | //       for ra in RA do ...; | ||||||
|  | // | ||||||
|  | // Zippering (RA,A) or (A,RA) in a 'for' loop will generate | ||||||
|  | // an error due to their different number of elements. | ||||||
|  |  | ||||||
|  | // Let RA store the Index Map again, for the examples below. | ||||||
|  | forall ra in RA do | ||||||
|  |   ra = here.id; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Only the local replicand is accessed - replication is NOT observable | ||||||
|  | // and consistency is NOT maintained - when: | ||||||
|  | // (a) the replicated array is indexed - an individual element is read... | ||||||
|  | // | ||||||
|  | on Locales(0) do | ||||||
|  |   writeln("on ", here, ": ", RA(Space.low)); | ||||||
|  | on Locales(LocaleSpace.high) do | ||||||
|  |   writeln("on ", here, ": ", RA(Space.low)); | ||||||
|  | writeln(); | ||||||
|  |  | ||||||
|  | // ...or an individual element is written; | ||||||
|  | on Locales(LocaleSpace.high) do | ||||||
|  |   RA(Space.low) = 7777; | ||||||
|  |  | ||||||
|  | writeln("Replicated Array after being indexed into"); | ||||||
|  | writeln(RA); | ||||||
|  | writeln(); | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // (b) the replicated array is on the right-hand side of an assignment... | ||||||
|  | // | ||||||
|  | on Locales(LocaleSpace.high) do | ||||||
|  |   A = RA + 4; | ||||||
|  | writeln("Non-Replicated Array after assignment from Replicated Array + 4"); | ||||||
|  | writeln(A); | ||||||
|  | writeln(); | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // (c) ...or, generally, the replicated array or domain participates | ||||||
|  | //     in a zippered forall loop, but not in the first position. | ||||||
|  | //     The loop could look like: | ||||||
|  | // | ||||||
|  | //       forall (a, (i,j), ra) in (A, ReplicatedSpace, RA) do ...; | ||||||
|  | // | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // The DimensionalDist2D distribution lets us build a 2D distribution | ||||||
|  | // as a composition of specifiers for individual dimensions. | ||||||
|  | // Under such a "dimensional" distribution each dimension is handled | ||||||
|  | // independently of the other. | ||||||
|  | // | ||||||
|  | // The dimension specifiers are similar to the corresponding multi-dimensional | ||||||
|  | // distributions in constructor arguments and index-to-locale mapping rules. | ||||||
|  | // However, instead of an array of locales, a specifier constructor | ||||||
|  | // accepts just the number of locales that the indices in the corresponding | ||||||
|  | // dimension will be distributed across. | ||||||
|  | // | ||||||
|  | // The DimensionalDist2D constructor requires: | ||||||
|  | // * an [0..nl1-1, 0..nl2-1] array of locales, where | ||||||
|  | //   nl1 and nl2 are the number of locales in each dimension, and | ||||||
|  | // * two dimension specifiers, created for nl1 and nl2 locale counts, resp. | ||||||
|  | // | ||||||
|  | // Presently, the following dimension specifiers are available | ||||||
|  | // (shown here with their constructor arguments): | ||||||
|  | // | ||||||
|  | // * ReplicatedDim(numLocales) | ||||||
|  | // * BlockDim(numLocales, boundingBoxLow, boundingBoxHigh) | ||||||
|  | // * BlockCyclicDim(lowIdx, blockSize, numLocales) | ||||||
|  | // | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // The following example creates a dimensional distribution that | ||||||
|  | // replicates over 2 locales (when available) in the first dimemsion | ||||||
|  | // and distributes using block-cyclic distribution in the second dimension. | ||||||
|  | // The example computes nl1 and nl2 and reshapes MyLocales correspondingly. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | var (nl1, nl2) = if numLocales == 1 then (1, 1) else (2, numLocales/2); | ||||||
|  | MyLocaleView = {0..#nl1, 0..#nl2}; | ||||||
|  | MyLocales = reshape(Locales[0..#nl1*nl2], MyLocaleView); | ||||||
|  |  | ||||||
|  | const DimReplicatedBlockcyclicSpace = Space | ||||||
|  |   dmapped DimensionalDist2D(MyLocales, | ||||||
|  |                             new ReplicatedDim(numLocales = nl1), | ||||||
|  |                             new BlockCyclicDim(numLocales = nl2, | ||||||
|  |                                                lowIdx = 1, blockSize = 2)); | ||||||
|  |  | ||||||
|  | var DRBA: [DimReplicatedBlockcyclicSpace] int; | ||||||
|  |  | ||||||
|  | // The ReplicatedDim specifier always accesses the local replicand. | ||||||
|  | // (This differs from how the ReplicatedDist distribution works.) | ||||||
|  | // | ||||||
|  | // This example visits each replicand. The behavior is the same | ||||||
|  | // regardless of the second index into MyLocales below. | ||||||
|  |  | ||||||
|  | for locId1 in 0..#nl1 do on MyLocales[locId1, 0] { | ||||||
|  |  | ||||||
|  |   forall drba in DRBA do | ||||||
|  |     drba = here.id; | ||||||
|  |  | ||||||
|  |   writeln("Dimensional2D(Replicated,BlockCyclic) Array Index Map", | ||||||
|  |           " from ", here); | ||||||
|  |  | ||||||
|  |   // Technicality: 'writeln(DRBA)' would read DRBA always on Locale 0. | ||||||
|  |   // Since we want to see what DRBA contains on the current locale, | ||||||
|  |   // we use 'Helper' that is mapped using the default distribution. | ||||||
|  |   // 'Helper = DRBA' captures the view of DRBA on the current locale, | ||||||
|  |   // which we then print out. | ||||||
|  |  | ||||||
|  |   const Helper: [Space] int = DRBA; | ||||||
|  |   writeln(Helper); | ||||||
|  |   writeln(); | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										1
									
								
								samples/Chapel/hello.chpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								samples/Chapel/hello.chpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | writeln("Hello, world!");    // print 'Hello, world!' to the console | ||||||
							
								
								
									
										1692
									
								
								samples/Chapel/lulesh.chpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1692
									
								
								samples/Chapel/lulesh.chpl
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										147
									
								
								samples/Chapel/nbody.chpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								samples/Chapel/nbody.chpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | |||||||
|  | /* The Computer Language Benchmarks Game | ||||||
|  |    http://benchmarksgame.alioth.debian.org/ | ||||||
|  |  | ||||||
|  |    contributed by Albert Sidelnik | ||||||
|  |    modified by Brad Chamberlain | ||||||
|  | */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // The number of timesteps to simulate; may be set via the command-line | ||||||
|  | // | ||||||
|  | config const n = 10000; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // Constants representing pi, the solar mass, and the number of days per year | ||||||
|  | // | ||||||
|  | const pi = 3.141592653589793, | ||||||
|  |       solarMass = 4 * pi**2, | ||||||
|  |       daysPerYear = 365.24; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // a record representing one of the bodies in the solar system | ||||||
|  | // | ||||||
|  | record body { | ||||||
|  |   var pos: 3*real; | ||||||
|  |   var v: 3*real; | ||||||
|  |   var mass: real;  // does not change after it is set up | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // the array of bodies that we'll be simulating | ||||||
|  | // | ||||||
|  | var bodies = [/* sun */ | ||||||
|  |               new body(mass = solarMass), | ||||||
|  |  | ||||||
|  |               /* jupiter */ | ||||||
|  |               new body(pos = ( 4.84143144246472090e+00, | ||||||
|  |                               -1.16032004402742839e+00, | ||||||
|  |                               -1.03622044471123109e-01), | ||||||
|  |                          v = ( 1.66007664274403694e-03 * daysPerYear, | ||||||
|  |                                7.69901118419740425e-03 * daysPerYear, | ||||||
|  |                               -6.90460016972063023e-05 * daysPerYear), | ||||||
|  |                       mass =   9.54791938424326609e-04 * solarMass), | ||||||
|  |    | ||||||
|  |               /* saturn */ | ||||||
|  |               new body(pos = ( 8.34336671824457987e+00, | ||||||
|  |                                4.12479856412430479e+00, | ||||||
|  |                               -4.03523417114321381e-01), | ||||||
|  |                          v = (-2.76742510726862411e-03 * daysPerYear, | ||||||
|  |                                4.99852801234917238e-03 * daysPerYear, | ||||||
|  |                                2.30417297573763929e-05 * daysPerYear), | ||||||
|  |                       mass =   2.85885980666130812e-04 * solarMass), | ||||||
|  |  | ||||||
|  |               /* uranus */ | ||||||
|  |               new body(pos = ( 1.28943695621391310e+01, | ||||||
|  |                               -1.51111514016986312e+01, | ||||||
|  |                               -2.23307578892655734e-01), | ||||||
|  |                          v = ( 2.96460137564761618e-03 * daysPerYear, | ||||||
|  |                                2.37847173959480950e-03 * daysPerYear, | ||||||
|  |                               -2.96589568540237556e-05 * daysPerYear), | ||||||
|  |                       mass =   4.36624404335156298e-05 * solarMass), | ||||||
|  |  | ||||||
|  |               /* neptune */ | ||||||
|  |               new body(pos = ( 1.53796971148509165e+01, | ||||||
|  |                               -2.59193146099879641e+01, | ||||||
|  |                                1.79258772950371181e-01), | ||||||
|  |                          v = ( 2.68067772490389322e-03 * daysPerYear, | ||||||
|  |                                1.62824170038242295e-03 * daysPerYear, | ||||||
|  |                               -9.51592254519715870e-05 * daysPerYear), | ||||||
|  |                       mass =   5.15138902046611451e-05 * solarMass) | ||||||
|  |               ]; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // the number of bodies to be simulated | ||||||
|  | // | ||||||
|  | const numbodies = bodies.numElements; | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // The computation involves initializing the sun's velocity, | ||||||
|  | // writing the initial energy, advancing the system through 'n' | ||||||
|  | // timesteps, and writing the final energy. | ||||||
|  | // | ||||||
|  | proc main() { | ||||||
|  |   initSun(); | ||||||
|  |  | ||||||
|  |   writef("%.9r\n", energy()); | ||||||
|  |   for 1..n do | ||||||
|  |     advance(0.01); | ||||||
|  |   writef("%.9r\n", energy()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // compute the sun's initial velocity | ||||||
|  | // | ||||||
|  | proc initSun() { | ||||||
|  |   const p = + reduce (for b in bodies do (b.v * b.mass)); | ||||||
|  |   bodies[1].v = -p / solarMass; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // advance the positions and velocities of all the bodies | ||||||
|  | // | ||||||
|  | proc advance(dt) { | ||||||
|  |   for i in 1..numbodies { | ||||||
|  |     for j in i+1..numbodies { | ||||||
|  |       updateVelocities(bodies[i], bodies[j]); | ||||||
|  |        | ||||||
|  |       inline proc updateVelocities(ref b1, ref b2) { | ||||||
|  |         const dpos = b1.pos - b2.pos, | ||||||
|  |                mag = dt / sqrt(sumOfSquares(dpos))**3; | ||||||
|  |          | ||||||
|  |         b1.v -= dpos * b2.mass * mag; | ||||||
|  |         b2.v += dpos * b1.mass * mag; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   for b in bodies do | ||||||
|  |     b.pos += dt * b.v; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // compute the energy of the bodies | ||||||
|  | // | ||||||
|  | proc energy() { | ||||||
|  |   var e = 0.0; | ||||||
|  |    | ||||||
|  |   for i in 1..numbodies { | ||||||
|  |     const b1 = bodies[i]; | ||||||
|  |      | ||||||
|  |     e += 0.5 * b1.mass * sumOfSquares(b1.v); | ||||||
|  |      | ||||||
|  |     for j in i+1..numbodies { | ||||||
|  |       const b2 = bodies[j]; | ||||||
|  |        | ||||||
|  |       e -= (b1.mass * b2.mass) / sqrt(sumOfSquares(b1.pos - b2.pos)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   return e; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // a helper routine to compute the sum of squares of a 3-tuple's components | ||||||
|  | // | ||||||
|  | inline proc sumOfSquares(x) | ||||||
|  |   return x(1)**2 + x(2)**2 + x(3)**2; | ||||||
							
								
								
									
										145
									
								
								samples/Chapel/quicksort.chpl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								samples/Chapel/quicksort.chpl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,145 @@ | |||||||
|  | // | ||||||
|  | // An example of a parallel quick sort implementation that uses | ||||||
|  | // "cobegin" to make each recursive call in parallel and "serial" to | ||||||
|  | // limit the number of threads. | ||||||
|  | // | ||||||
|  |  | ||||||
|  | use Random, Time; // for random number generation and the Timer class | ||||||
|  |  | ||||||
|  | var timer: Timer; // to time the sort | ||||||
|  |  | ||||||
|  | config var n: int = 2**15;      // the size of the array to be sorted | ||||||
|  | config var thresh: int = 1;     // the recursive depth to serialize | ||||||
|  | config var verbose: int = 0;    // print out this many elements in array | ||||||
|  | config var timing: bool = true; // set timing to false to disable timer | ||||||
|  |  | ||||||
|  | var A: [1..n] real; // array of real numbers | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // initialize array with random numbers | ||||||
|  | // | ||||||
|  | fillRandom(A); | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // print out front of array if verbose flag is set | ||||||
|  | // | ||||||
|  | if verbose > 0 then | ||||||
|  |   writeln("A[1..", verbose, "] = ", A[1..verbose]); | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // start timer, call parallel quick sort routine, stop timer | ||||||
|  | // | ||||||
|  | if timing then timer.start(); | ||||||
|  | pqsort(A, thresh); | ||||||
|  | if timing then timer.stop(); | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // report sort time | ||||||
|  | // | ||||||
|  | if timing then writeln("sorted in ", timer.elapsed(), " seconds"); | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // print out front of array if verbose flag is set | ||||||
|  | //   values should now be in sorted order | ||||||
|  | // | ||||||
|  | if verbose > 0 then | ||||||
|  |   writeln("A[1..", verbose, "] = ", A[1..verbose]); | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // verify that array is sorted or halt | ||||||
|  | // | ||||||
|  | for i in 2..n do | ||||||
|  |   if A(i) < A(i-1) then | ||||||
|  |     halt("A(", i-1, ") == ", A(i-1), " > A(", i, ") == ", A(i)); | ||||||
|  |  | ||||||
|  | writeln("verification success"); | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // pqsort -- parallel quick sort | ||||||
|  | // | ||||||
|  | //   arr: generic 1D array of values (real, int, ...) | ||||||
|  | //   thresh: number of recursive calls to make before serializing | ||||||
|  | //   low: lower bound of array to start sort at, defaults to whole array | ||||||
|  | //   high: upper bound of array to stop sort at, defaults to whole array | ||||||
|  | // | ||||||
|  | proc pqsort(arr: [], | ||||||
|  |            thresh: int, | ||||||
|  |            low: int = arr.domain.low, | ||||||
|  |            high: int = arr.domain.high) where arr.rank == 1 { | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // base case: arr[low..high] is small enough to bubble sort | ||||||
|  |   // | ||||||
|  |   if high - low < 8 { | ||||||
|  |     bubbleSort(arr, low, high); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // determine pivot and partition arr[low..high] | ||||||
|  |   // | ||||||
|  |   const pivotVal = findPivot(); | ||||||
|  |   const pivotLoc = partition(pivotVal); | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // make recursive calls to parallel quick sort each unsorted half of | ||||||
|  |   // the array; if thresh is 0 or less, start executing conquer tasks | ||||||
|  |   // serially | ||||||
|  |   // | ||||||
|  |   serial thresh <= 0 do cobegin { | ||||||
|  |     pqsort(arr, thresh-1, low, pivotLoc-1); | ||||||
|  |     pqsort(arr, thresh-1, pivotLoc+1, high); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // findPivot -- helper routine to find pivot value using simple | ||||||
|  |   //              median-of-3 method, returns pivot value | ||||||
|  |   // | ||||||
|  |   proc findPivot() { | ||||||
|  |     const mid = low + (high-low+1) / 2; | ||||||
|  |  | ||||||
|  |     if arr(mid) < arr(low) then arr(mid) <=> arr(low); | ||||||
|  |     if arr(high) < arr(low) then arr(high) <=> arr(low); | ||||||
|  |     if arr(high) < arr(mid) then arr(high) <=> arr(mid); | ||||||
|  |  | ||||||
|  |     const pivotVal = arr(mid); | ||||||
|  |     arr(mid) = arr(high-1); | ||||||
|  |     arr(high-1) = pivotVal; | ||||||
|  |  | ||||||
|  |     return pivotVal; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // | ||||||
|  |   // partition -- helper routine to partition array such that all | ||||||
|  |   //              values less than pivot are to its left and all | ||||||
|  |   //              values greater than pivot are to its right, returns | ||||||
|  |   //              pivot location | ||||||
|  |   // | ||||||
|  |   proc partition(pivotVal) { | ||||||
|  |     var ilo = low, ihi = high-1; | ||||||
|  |     while (ilo < ihi) { | ||||||
|  |       do { ilo += 1; } while arr(ilo) < pivotVal; | ||||||
|  |       do { ihi -= 1; } while pivotVal < arr(ihi); | ||||||
|  |       if (ilo < ihi) { | ||||||
|  |         arr(ilo) <=> arr(ihi); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     arr(high-1) = arr(ilo); | ||||||
|  |     arr(ilo) = pivotVal; | ||||||
|  |     return ilo; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | // | ||||||
|  | // bubbleSort -- bubble sort for base case of quick sort | ||||||
|  | // | ||||||
|  | //   arr: generic 1D array of values (real, int, ...) | ||||||
|  | //   low: lower bound of array to start sort at | ||||||
|  | //   high: upper bound of array to stop sort at | ||||||
|  | // | ||||||
|  | proc bubbleSort(arr: [], low: int, high: int) where arr.rank == 1 { | ||||||
|  |   for i in low..high do | ||||||
|  |     for j in low..high-1 do | ||||||
|  |       if arr(j) > arr(j+1) then | ||||||
|  |         arr(j) <=> arr(j+1); | ||||||
|  | } | ||||||
							
								
								
									
										11
									
								
								samples/Clean/GenHylo.dcl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								samples/Clean/GenHylo.dcl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | definition module GenHylo | ||||||
|  |  | ||||||
|  | import StdGeneric, GenMap | ||||||
|  |  | ||||||
|  | :: Fix f = In (f .(Fix f)) | ||||||
|  | Out :: !u:(Fix v:a) -> v:(a w:(Fix v:a)), [u <= w] | ||||||
|  |  | ||||||
|  | hylo :: ((.f .b) -> .b) (.a -> (.f .a)) -> (.a -> .b) | gMap{|*->*|} f | ||||||
|  | cata :: (u:(f .a) -> .a) -> (Fix u:f) -> .a | gMap{|*->*|} f | ||||||
|  | ana :: (.a -> u:(f .a)) -> .a -> (Fix u:f) | gMap{|*->*|} f | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								samples/Clean/GenMap.dcl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								samples/Clean/GenMap.dcl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | definition module GenMap | ||||||
|  |  | ||||||
|  | import StdGeneric | ||||||
|  |  | ||||||
|  | generic gMap a b :: .a -> .b | ||||||
|  | derive gMap c, UNIT, PAIR, EITHER, CONS, FIELD, OBJECT, {}, {!}  | ||||||
|  |  | ||||||
|  | derive gMap [], (,), (,,),  (,,,), (,,,,), (,,,,,), (,,,,,,), (,,,,,,,) | ||||||
|  |  | ||||||
							
								
								
									
										19
									
								
								samples/Clean/GenMap.icl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								samples/Clean/GenMap.icl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | |||||||
|  | implementation module GenMap | ||||||
|  |  | ||||||
|  | import StdClass, StdArray, StdInt, StdFunc | ||||||
|  | import StdGeneric, _Array | ||||||
|  |  | ||||||
|  | generic gMap a b :: .a -> .b | ||||||
|  | gMap{|c|} x 					= x | ||||||
|  | gMap{|UNIT|} x 					= x | ||||||
|  | gMap{|PAIR|} fx fy (PAIR x y) 	= PAIR (fx x) (fy y)  | ||||||
|  | gMap{|EITHER|} fl fr (LEFT x) 	= LEFT (fl x) | ||||||
|  | gMap{|EITHER|} fl fr (RIGHT x) 	= RIGHT (fr x) | ||||||
|  | gMap{|CONS|} f (CONS x) 		= CONS (f x) | ||||||
|  | gMap{|FIELD|} f (FIELD x) 		= FIELD (f x) | ||||||
|  | gMap{|OBJECT|} f (OBJECT x) 	= OBJECT (f x) | ||||||
|  | gMap{|{}|} f xs 				= mapArray f xs | ||||||
|  | gMap{|{!}|} f xs				= mapArray f xs | ||||||
|  |  | ||||||
|  | derive gMap [], (,), (,,),  (,,,), (,,,,), (,,,,,), (,,,,,,), (,,,,,,,) | ||||||
|  |  | ||||||
							
								
								
									
										54
									
								
								samples/Clean/fsieve.icl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								samples/Clean/fsieve.icl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | |||||||
|  | module fsieve | ||||||
|  |  | ||||||
|  | /* | ||||||
|  | The Fast Sieve of Eratosthenes. | ||||||
|  |  | ||||||
|  | A sequential and optimized version of the sieve of Eratosthenes. | ||||||
|  | The program calculates a list of the first NrOfPrime primes. | ||||||
|  | The result of the program is the NrOfPrimes'th prime. | ||||||
|  |  | ||||||
|  | Strictness annotations have been added because the strictness analyser | ||||||
|  | is not able to deduce all strictness information. Removal of these !'s | ||||||
|  | will make the program about 20% slower. | ||||||
|  |  | ||||||
|  | On a machine without a math coprocessor the execution of this | ||||||
|  | program might take a (very) long time. Set NrOfPrimes to a smaller value. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | import StdClass; // RWS | ||||||
|  | import StdInt, StdReal | ||||||
|  |       | ||||||
|  | NrOfPrimes :== 3000  | ||||||
|  | 	 | ||||||
|  | //	The sieve algorithm: generate an infinite list of all primes. | ||||||
|  |  | ||||||
|  | Primes::[Int] | ||||||
|  | Primes = pr where pr = [5 : Sieve 7 4 pr] | ||||||
|  |  | ||||||
|  | Sieve::Int !Int [Int] -> [Int] | ||||||
|  | Sieve g i prs | ||||||
|  | 	| IsPrime prs g (toInt (sqrt (toReal g)))	=  [g : Sieve` g i prs] | ||||||
|  | 												=  Sieve (g + i) (6 - i) prs | ||||||
|  |  | ||||||
|  | Sieve`::Int Int [Int] -> [Int] | ||||||
|  | Sieve` g i prs =  Sieve (g + i) (6 - i) prs | ||||||
|  |  | ||||||
|  | IsPrime::[Int] !Int Int -> Bool | ||||||
|  | IsPrime [f:r] pr bd | f>bd 			=  True | ||||||
|  | 					| pr rem f==0	=  False | ||||||
|  | 									=  IsPrime r pr bd | ||||||
|  | 								   | ||||||
|  | //	Select is used to get the NrOfPrimes'th prime from the infinite list. | ||||||
|  |  | ||||||
|  | Select::[x] Int -> x | ||||||
|  | Select [f:r] 1 =  f | ||||||
|  | Select [f:r] n =  Select r (n - 1) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /*	The Start rule: Select the NrOfPrimes'th prime from the list of primes | ||||||
|  | 	generated by Primes. | ||||||
|  | */ | ||||||
|  |  | ||||||
|  | Start::Int | ||||||
|  | Start = Select [2, 3 : Primes] NrOfPrimes | ||||||
|  |  | ||||||
							
								
								
									
										99
									
								
								samples/Clean/sem.icl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								samples/Clean/sem.icl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | |||||||
|  | module monadicSemantics | ||||||
|  |  | ||||||
|  | import StdEnv, StdGeneric, GenMap, GenHylo | ||||||
|  |  | ||||||
|  | /* For fun I implemented the recursive datastructre Exp and Stm as fixpoints | ||||||
|  |    This helps us define recursive functions on them (only a little bit though) | ||||||
|  |    However deriving gMap for Fix did not works out of the box | ||||||
|  |    I had to remove some uniqueness typing in GenMap and GenHylo */ | ||||||
|  | :: Op      = Plus | Minus | Times | Rem | Equal | LessThan | ||||||
|  | :: Var     :== String | ||||||
|  |  | ||||||
|  | :: ExpP a  = Int Int | Var Var | Op Op a a | ||||||
|  | :: Exp     :== Fix ExpP | ||||||
|  |  | ||||||
|  | :: StmP a  = Assign Var Exp | If Exp a a | While Exp a | Seq a a | Cont | ||||||
|  | :: Stm     :== Fix StmP | ||||||
|  |  | ||||||
|  | derive gMap ExpP, StmP, Fix | ||||||
|  |  | ||||||
|  | // Environment. Semantics is basically Env -> Env | ||||||
|  | :: Env :== Var -> Int | ||||||
|  | :: Sem :== Env -> (Int, Env) | ||||||
|  | empty = \v . 0 | ||||||
|  |  | ||||||
|  | // return | ||||||
|  | rtn :: Int -> Sem | ||||||
|  | rtn i = \e. (i, e) | ||||||
|  |  | ||||||
|  | // the usual bind | ||||||
|  | (>>=) infixl 1 :: Sem (Int->Sem) -> Sem | ||||||
|  | (>>=) x y = \e. (\(i,e2).y i e2) (x e) | ||||||
|  | (>>|) infixl 1 :: Sem Sem -> Sem | ||||||
|  | (>>|) x y = x >>= \_. y | ||||||
|  |  | ||||||
|  | // read variable from environment | ||||||
|  | read :: Var -> Sem | ||||||
|  | read v = \e. (e v, e) | ||||||
|  |  | ||||||
|  | // assign value to give variable in environment | ||||||
|  | write :: Var Int -> Sem | ||||||
|  | write v i = \e. (i, \w. if (w==v) i (e w)) | ||||||
|  |  | ||||||
|  | // semantics | ||||||
|  | class sem a :: a -> Sem | ||||||
|  |  | ||||||
|  | operator :: Op -> Int -> Int -> Int | ||||||
|  | operator Plus     = (+) | ||||||
|  | operator Minus    = (-) | ||||||
|  | operator Times    = (*) | ||||||
|  | operator Rem      = rem | ||||||
|  | operator Equal    = \x y . if (x==y) 1 0 | ||||||
|  | operator LessThan = \x y . if (x< y)  1 0 | ||||||
|  |  | ||||||
|  | // semantics of expressions | ||||||
|  | instance sem Exp where | ||||||
|  | 	sem x = cata phi x where | ||||||
|  | 		phi (Int n)     = rtn n | ||||||
|  | 		phi (Var v)     = read v | ||||||
|  | 		phi (Op op x y) = x >>= \v1. y >>= return o (operator op v1) | ||||||
|  |  | ||||||
|  | // semantics of statments | ||||||
|  | // NOTE: while will always return 0, as it might not even be executed | ||||||
|  | instance sem Stm where | ||||||
|  | 	sem x = cata phi x where | ||||||
|  | 		phi (Assign v e)     = sem e >>= write v | ||||||
|  | 		phi (If e s1 s2)     = sem e >>= \b . if (b<>0) s1 s2 | ||||||
|  | 		phi stm=:(While e s) = sem e >>= \b . if (b<>0) (s >>| phi stm) (phi Cont) | ||||||
|  | 		phi (Seq s1 s2)      = s1 >>| s2    // Here the cata *finally* pays off :D | ||||||
|  | 		phi Cont             = rtn 0 | ||||||
|  |  | ||||||
|  | // convenience functions | ||||||
|  | int    = In o Int | ||||||
|  | var    = In o Var | ||||||
|  | op o   = In o2 (Op o) | ||||||
|  | assign = In o2 Assign | ||||||
|  | ifte e = In o2 (If e) | ||||||
|  | while  = In o2 While | ||||||
|  | seq    = In o2 Seq | ||||||
|  | cont   = In Cont | ||||||
|  |  | ||||||
|  | // test case, also testing the new operator < | ||||||
|  | pEuclides = | ||||||
|  | 	while (op LessThan (int 0) (var "b"))( | ||||||
|  | 		seq (assign "r" (op Rem (var "a") (var "b"))) | ||||||
|  | 		(seq (assign "a" (var "b")) | ||||||
|  | 		( (assign "b" (var "r"))) | ||||||
|  | 		) | ||||||
|  | 	) | ||||||
|  |  | ||||||
|  | Start = fst (program start) where | ||||||
|  | 	program = sem pEuclides >>| read "a" | ||||||
|  | 	start "a" = 9 | ||||||
|  | 	start "b" = 12 | ||||||
|  | 	start _ = 0 | ||||||
|  |  | ||||||
|  | // Helper | ||||||
|  | (o2) infixr 9 | ||||||
|  | (o2) f g x :== f o (g x) | ||||||
|  |  | ||||||
							
								
								
									
										14
									
								
								samples/Clean/stack.dcl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								samples/Clean/stack.dcl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | definition module stack | ||||||
|  |  | ||||||
|  | :: Stack a | ||||||
|  |  | ||||||
|  | newStack :: (Stack a) | ||||||
|  | push :: a (Stack a) -> Stack a | ||||||
|  | pushes :: [a] (Stack a) -> Stack a | ||||||
|  | pop :: (Stack a) -> Stack a | ||||||
|  | popn :: Int (Stack a) -> Stack a | ||||||
|  | top :: (Stack a) -> a | ||||||
|  | topn :: Int (Stack a) -> [a] | ||||||
|  | elements :: (Stack a) -> [a] | ||||||
|  | count :: (Stack a) -> Int | ||||||
|  |  | ||||||
							
								
								
									
										33
									
								
								samples/Clean/stack.icl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								samples/Clean/stack.icl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | implementation module stack | ||||||
|  | import StdEnv | ||||||
|  |  | ||||||
|  | :: Stack a :== [a] | ||||||
|  |  | ||||||
|  | newStack :: (Stack a) | ||||||
|  | newStack = [] | ||||||
|  |  | ||||||
|  | push :: a (Stack a) -> Stack a | ||||||
|  | push x s = [x:s] | ||||||
|  |  | ||||||
|  | pushes :: [a] (Stack a) -> Stack a | ||||||
|  | pushes x s = x ++ s | ||||||
|  |  | ||||||
|  | pop :: (Stack a) -> Stack a | ||||||
|  | pop [] = abort "Cannot use pop on an empty stack" | ||||||
|  | pop [e:s] = s | ||||||
|  |  | ||||||
|  | popn :: Int (Stack a) -> Stack a | ||||||
|  | popn n s  = drop n s | ||||||
|  |  | ||||||
|  | top :: (Stack a) -> a | ||||||
|  | top [] = abort "Cannot use top on an empty stack" | ||||||
|  | top [e:s] = e | ||||||
|  |  | ||||||
|  | topn :: Int (Stack a) -> [a] | ||||||
|  | topn n s = take n s | ||||||
|  | elements :: (Stack a) -> [a] | ||||||
|  | elements s = s | ||||||
|  |  | ||||||
|  | count :: (Stack a) -> Int | ||||||
|  | count s = length s | ||||||
|  |  | ||||||
							
								
								
									
										16
									
								
								samples/Clean/streams.dcl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								samples/Clean/streams.dcl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | definition module streams | ||||||
|  |  | ||||||
|  | import StdEnv | ||||||
|  |  | ||||||
|  | instance zero [Real] | ||||||
|  | instance one [Real] | ||||||
|  | instance + [Real]         | ||||||
|  | instance - [Real] | ||||||
|  | instance * [Real] | ||||||
|  | instance / [Real] | ||||||
|  |  | ||||||
|  | X :: [Real] | ||||||
|  | invert :: [Real] -> [Real] | ||||||
|  | pow :: [Real] Int -> [Real] | ||||||
|  | (shuffle) infixl 7 :: [Real] [Real] -> [Real] | ||||||
|  |  | ||||||
							
								
								
									
										49
									
								
								samples/Clean/streams.icl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								samples/Clean/streams.icl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,49 @@ | |||||||
|  | implementation module streams | ||||||
|  |  | ||||||
|  | import StdEnv | ||||||
|  |  | ||||||
|  | instance zero [Real] | ||||||
|  | where | ||||||
|  |         zero = [] //Infinite row of zeroes represented as empty list to ease computation | ||||||
|  |  | ||||||
|  | instance one [Real] | ||||||
|  | where | ||||||
|  |         one = [1.0:zero] | ||||||
|  |  | ||||||
|  | instance + [Real] | ||||||
|  | where | ||||||
|  |         (+) [s:s`] [t:t`] = [s+t:s`+t`] | ||||||
|  |         (+) [s:s`] [] = [s:s`] | ||||||
|  |         (+) [] [t:t`] = [t:t`] | ||||||
|  |         (+) [] [] = [] | ||||||
|  |          | ||||||
|  | instance - [Real] | ||||||
|  | where | ||||||
|  |         (-) [s:s`] [t:t`] = [s-t:s`-t`] | ||||||
|  |         (-) [s:s`] [] = [s:s`] | ||||||
|  |         (-) [] [t:t`] = [-1.0] * [t:t`] | ||||||
|  |         (-) [] [] = [] | ||||||
|  |  | ||||||
|  | instance * [Real] | ||||||
|  | where | ||||||
|  |         (*) [s:s`] [t:t`] = [s*t:s`*[t:t`]+[s]*t`] | ||||||
|  |         (*) _ _ = [] | ||||||
|  |  | ||||||
|  | instance / [Real] | ||||||
|  | where | ||||||
|  |         (/) s t = s * (invert t) | ||||||
|  |  | ||||||
|  | X :: [Real] | ||||||
|  | X = [0.0:one] | ||||||
|  |  | ||||||
|  | invert :: [Real] -> [Real] | ||||||
|  | invert [s:s`] = [1.0/s:(invert [s:s`]) * s` * [-1.0/s]] | ||||||
|  |  | ||||||
|  | pow :: [Real] Int -> [Real] | ||||||
|  | pow s 0 = one | ||||||
|  | pow s n = s * pow s (n-1) | ||||||
|  |  | ||||||
|  | (shuffle) infixl 7 :: [Real] [Real] -> [Real] | ||||||
|  | (shuffle) [s:s`] [t:t`] = [s*t:s` shuffle [t:t`] + [s:s`] shuffle t`] | ||||||
|  | (shuffle) _ _ = [] | ||||||
|  |  | ||||||
							
								
								
									
										146
									
								
								samples/Clojure/index.cljs.hl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								samples/Clojure/index.cljs.hl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | |||||||
|  | ;; Copyright (c) Alan Dipert and Micha Niskin. All rights reserved. | ||||||
|  | ;; The use and distribution terms for this software are covered by the | ||||||
|  | ;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) | ||||||
|  | ;; which can be found in the file epl-v10.html at the root of this distribution. | ||||||
|  | ;; By using this software in any fashion, you are agreeing to be bound by | ||||||
|  | ;; the terms of this license. | ||||||
|  | ;; You must not remove this notice, or any other, from this software. | ||||||
|  |  | ||||||
|  | (page "index.html" | ||||||
|  |   (:refer-clojure :exclude [nth]) | ||||||
|  |   (:require | ||||||
|  |    [tailrecursion.hoplon.reload        :refer [reload-all]] | ||||||
|  |    [tailrecursion.hoplon.util          :refer [nth name pluralize]] | ||||||
|  |    [tailrecursion.hoplon.storage-atom  :refer [local-storage]])) | ||||||
|  |  | ||||||
|  | ;; utility functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  |  | ||||||
|  | (declare route state editing) | ||||||
|  |  | ||||||
|  | (reload-all) | ||||||
|  |  | ||||||
|  | (def mapvi  (comp vec map-indexed)) | ||||||
|  |  | ||||||
|  | (defn dissocv [v i] | ||||||
|  |   (let [z (- (dec (count v)) i)] | ||||||
|  |     (cond (neg?  z) v | ||||||
|  |           (zero? z) (pop v) | ||||||
|  |           (pos?  z) (into (subvec v 0 i) (subvec v (inc i)))))) | ||||||
|  |  | ||||||
|  | (defn decorate [todo route editing i] | ||||||
|  |   (let [{done? :completed text :text} todo] | ||||||
|  |     (-> todo (assoc :editing (= editing i) | ||||||
|  |                     :visible (and (not (empty? text)) | ||||||
|  |                                   (or (= "#/" route) | ||||||
|  |                                       (and (= "#/active" route) (not done?)) | ||||||
|  |                                       (and (= "#/completed" route) done?))))))) | ||||||
|  |  | ||||||
|  | ;; persisted state cell (AKA: stem cell) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  |  | ||||||
|  | (def   state        (-> (cell []) (local-storage ::store))) | ||||||
|  |  | ||||||
|  | ;; local state cells ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  |  | ||||||
|  | (defc  loaded?      false) | ||||||
|  | (defc  editing      nil) | ||||||
|  | (def   route        (route-cell "#/")) | ||||||
|  |  | ||||||
|  | ;; formula cells (computed state) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  |  | ||||||
|  | (defc= completed    (filter :completed state)) | ||||||
|  | (defc= active       (remove :completed state)) | ||||||
|  | (defc= plural-item  (pluralize "item" (count active))) | ||||||
|  | (defc= todos        (mapvi #(list %1 (decorate %2 route editing %1)) state)) | ||||||
|  |  | ||||||
|  | ;; state transition functions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  |  | ||||||
|  | (defn  todo        [t]   {:completed false :text t}) | ||||||
|  | (defn  destroy!    [i]   (swap! state dissocv i)) | ||||||
|  | (defn  done!       [i v] (swap! state assoc-in [i :completed] v)) | ||||||
|  | (defn  clear-done! [& _] (swap! state #(vec (remove :completed %)))) | ||||||
|  | (defn  new!        [t]   (when (not (empty? t)) (swap! state conj (todo t)))) | ||||||
|  | (defn  all-done!   [v]   (swap! state #(mapv (fn [x] (assoc x :completed v)) %))) | ||||||
|  | (defn  editing!    [i v] (reset! editing (if v i nil))) | ||||||
|  | (defn  text!       [i v] (if (empty? v) (destroy! i) (swap! state assoc-in [i :text] v))) | ||||||
|  |  | ||||||
|  | ;; page ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  |  | ||||||
|  | (html :lang "en" | ||||||
|  |   (head | ||||||
|  |     (meta :charset "utf-8") | ||||||
|  |     (meta :http-equiv "X-UA-Compatible" :content "IE=edge,chrome=1") | ||||||
|  |     (link :rel "stylesheet" :href "base.css") | ||||||
|  |     (title "Hoplon • TodoMVC")) | ||||||
|  |   (body | ||||||
|  |     (noscript | ||||||
|  |       (div :id "noscript" | ||||||
|  |         (p "JavaScript is required to view this page."))) | ||||||
|  |     (div | ||||||
|  |       (section :id "todoapp" | ||||||
|  |         (header :id "header" | ||||||
|  |           (h1 "todos") | ||||||
|  |           (form :on-submit #(do (new! (val-id :new-todo)) | ||||||
|  |                                 (do! (by-id :new-todo) :value "")) | ||||||
|  |             (input | ||||||
|  |               :id "new-todo" | ||||||
|  |               :type "text" | ||||||
|  |               :autofocus true | ||||||
|  |               :placeholder "What needs to be done?" | ||||||
|  |               :on-blur #(do! (by-id :new-todo) :value "")))) | ||||||
|  |         (section | ||||||
|  |           :id "main" | ||||||
|  |           :do-toggle (cell= (not (and (empty? active) (empty? completed)))) | ||||||
|  |           (input | ||||||
|  |             :id "toggle-all" | ||||||
|  |             :type "checkbox" | ||||||
|  |             :do-attr (cell= {:checked (empty? active)})  | ||||||
|  |             :on-click #(all-done! (val-id :toggle-all))) | ||||||
|  |           (label :for "toggle-all" | ||||||
|  |             "Mark all as complete") | ||||||
|  |           (ul :id "todo-list" | ||||||
|  |             (loop-tpl | ||||||
|  |               :reverse true | ||||||
|  |               :bind-ids [done# edit#] | ||||||
|  |               :bindings [[i {edit? :editing done? :completed todo-text :text show? :visible}] todos]  | ||||||
|  |               (li | ||||||
|  |                 :do-class (cell= {:completed done? :editing edit?})  | ||||||
|  |                 :do-toggle show? | ||||||
|  |                 (div :class "view" :on-dblclick #(editing! @i true) | ||||||
|  |                   (input | ||||||
|  |                     :id done#  | ||||||
|  |                     :type "checkbox" | ||||||
|  |                     :class "toggle" | ||||||
|  |                     :do-attr (cell= {:checked done?})  | ||||||
|  |                     :on-click #(done! @i (val-id done#))) | ||||||
|  |                   (label (text "~{todo-text}")) | ||||||
|  |                   (button | ||||||
|  |                     :type "submit" | ||||||
|  |                     :class "destroy" | ||||||
|  |                     :on-click  #(destroy! @i))) | ||||||
|  |                 (form :on-submit #(editing! @i false) | ||||||
|  |                   (input | ||||||
|  |                     :id edit# | ||||||
|  |                     :type "text" | ||||||
|  |                     :class "edit" | ||||||
|  |                     :do-value todo-text | ||||||
|  |                     :do-focus edit? | ||||||
|  |                     :on-blur #(when @edit? (editing! @i false)) | ||||||
|  |                     :on-change #(when @edit? (text! @i (val-id edit#))))))))) | ||||||
|  |         (footer  | ||||||
|  |           :id "footer" | ||||||
|  |           :do-toggle (cell= (not (and (empty? active) (empty? completed)))) | ||||||
|  |           (span :id "todo-count" | ||||||
|  |             (strong (text "~(count active) ")) | ||||||
|  |             (span (text "~{plural-item} left"))) | ||||||
|  |           (ul :id "filters" | ||||||
|  |             (li (a :href "#/"          :do-class (cell= {:selected (= "#/" route)})          "All")) | ||||||
|  |             (li (a :href "#/active"    :do-class (cell= {:selected (= "#/active" route)})    "Active")) | ||||||
|  |             (li (a :href "#/completed" :do-class (cell= {:selected (= "#/completed" route)}) "Completed"))) | ||||||
|  |           (button | ||||||
|  |             :type      "submit" | ||||||
|  |             :id        "clear-completed" | ||||||
|  |             :on-click  #(clear-done!) | ||||||
|  |             (text "Clear completed (~(count completed))")))) | ||||||
|  |       (footer :id "info"  | ||||||
|  |         (p "Double-click to edit a todo") | ||||||
|  |         (p "Part of " (a :href "http://github.com/tailrecursion/hoplon-demos/" "hoplon-demos"))))))  | ||||||
							
								
								
									
										239
									
								
								samples/ColdFusion CFC/exampleScript.cfc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										239
									
								
								samples/ColdFusion CFC/exampleScript.cfc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,239 @@ | |||||||
|  | /** | ||||||
|  | ******************************************************************************** | ||||||
|  | ContentBox - A Modular Content Platform | ||||||
|  | Copyright 2012 by Luis Majano and Ortus Solutions, Corp | ||||||
|  | www.gocontentbox.org | www.luismajano.com | www.ortussolutions.com | ||||||
|  | ******************************************************************************** | ||||||
|  | Apache License, Version 2.0 | ||||||
|  |  | ||||||
|  | Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] | ||||||
|  |  | ||||||
|  | Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  | you may not use this file except in compliance with the License. | ||||||
|  | You may obtain a copy of the License at | ||||||
|  |  | ||||||
|  | http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  | ||||||
|  | Unless required by applicable law or agreed to in writing, software | ||||||
|  | distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  | See the License for the specific language governing permissions and | ||||||
|  | limitations under the License. | ||||||
|  | ******************************************************************************** | ||||||
|  | * A generic content service for content objects | ||||||
|  | */ | ||||||
|  | component extends="coldbox.system.orm.hibernate.VirtualEntityService" singleton{ | ||||||
|  |  | ||||||
|  | 	// DI | ||||||
|  | 	property name="settingService"			inject="id:settingService@cb"; | ||||||
|  | 	property name="cacheBox"				inject="cachebox"; | ||||||
|  | 	property name="log"						inject="logbox:logger:{this}"; | ||||||
|  | 	property name="customFieldService" 	 	inject="customFieldService@cb"; | ||||||
|  | 	property name="categoryService" 	 	inject="categoryService@cb"; | ||||||
|  | 	property name="commentService" 	 		inject="commentService@cb"; | ||||||
|  | 	property name="contentVersionService"	inject="contentVersionService@cb"; | ||||||
|  | 	property name="authorService"			inject="authorService@cb"; | ||||||
|  | 	property name="populator"				inject="wirebox:populator"; | ||||||
|  | 	property name="systemUtil"				inject="SystemUtil@cb"; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 	* Constructor | ||||||
|  | 	* @entityName.hint The content entity name to bind this service to. | ||||||
|  | 	*/ | ||||||
|  | 	ContentService function init(entityName="cbContent"){ | ||||||
|  | 		// init it | ||||||
|  | 		super.init(entityName=arguments.entityName, useQueryCaching=true); | ||||||
|  |  | ||||||
|  | 		// Test scope coloring in pygments | ||||||
|  | 		this.colorTestVar = "Just for testing pygments!"; | ||||||
|  | 		cookie.colorTestVar = ""; | ||||||
|  | 		client.colorTestVar = "" | ||||||
|  | 		session.colorTestVar = ""; | ||||||
|  | 		application.colorTestVar = ""; | ||||||
|  |  | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	* Clear all content caches | ||||||
|  | 	* @async.hint Run it asynchronously or not, defaults to false | ||||||
|  | 	*/ | ||||||
|  | 	function clearAllCaches(boolean async=false){ | ||||||
|  | 		var settings = settingService.getAllSettings(asStruct=true); | ||||||
|  | 		// Get appropriate cache provider | ||||||
|  | 		var cache = cacheBox.getCache( settings.cb_content_cacheName ); | ||||||
|  | 		cache.clearByKeySnippet(keySnippet="cb-content",async=arguments.async); | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	* Clear all page wrapper caches | ||||||
|  | 	* @async.hint Run it asynchronously or not, defaults to false | ||||||
|  | 	*/ | ||||||
|  | 	function clearAllPageWrapperCaches(boolean async=false){ | ||||||
|  | 		var settings = settingService.getAllSettings(asStruct=true); | ||||||
|  | 		// Get appropriate cache provider | ||||||
|  | 		var cache = cacheBox.getCache( settings.cb_content_cacheName ); | ||||||
|  | 		cache.clearByKeySnippet(keySnippet="cb-content-pagewrapper",async=arguments.async); | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	* Clear all page wrapper caches | ||||||
|  | 	* @slug.hint The slug partial to clean on | ||||||
|  | 	* @async.hint Run it asynchronously or not, defaults to false | ||||||
|  | 	*/ | ||||||
|  | 	function clearPageWrapperCaches(required any slug, boolean async=false){ | ||||||
|  | 		var settings = settingService.getAllSettings(asStruct=true); | ||||||
|  | 		// Get appropriate cache provider | ||||||
|  | 		var cache = cacheBox.getCache( settings.cb_content_cacheName ); | ||||||
|  | 		cache.clearByKeySnippet(keySnippet="cb-content-pagewrapper-#arguments.slug#",async=arguments.async); | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	* Clear a page wrapper cache | ||||||
|  | 	* @slug.hint The slug to clean | ||||||
|  | 	* @async.hint Run it asynchronously or not, defaults to false | ||||||
|  | 	*/ | ||||||
|  | 	function clearPageWrapper(required any slug, boolean async=false){ | ||||||
|  | 		var settings = settingService.getAllSettings(asStruct=true); | ||||||
|  | 		// Get appropriate cache provider | ||||||
|  | 		var cache = cacheBox.getCache( settings.cb_content_cacheName ); | ||||||
|  | 		cache.clear("cb-content-pagewrapper-#arguments.slug#/"); | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	* Searches published content with cool paramters, remember published content only | ||||||
|  | 	* @searchTerm.hint The search term to search | ||||||
|  | 	* @max.hint The maximum number of records to paginate | ||||||
|  | 	* @offset.hint The offset in the pagination | ||||||
|  | 	* @asQuery.hint Return as query or array of objects, defaults to array of objects | ||||||
|  | 	* @sortOrder.hint The sorting of the search results, defaults to publishedDate DESC | ||||||
|  | 	* @isPublished.hint Search for published, non-published or both content objects [true, false, 'all'] | ||||||
|  | 	* @searchActiveContent.hint Search only content titles or both title and active content. Defaults to both. | ||||||
|  | 	*/ | ||||||
|  | 	function searchContent( | ||||||
|  | 		any searchTerm="",  | ||||||
|  | 		numeric max=0,  | ||||||
|  | 		numeric offset=0,  | ||||||
|  | 		boolean asQuery=false,  | ||||||
|  | 		any sortOrder="publishedDate DESC",  | ||||||
|  | 		any isPublished=true,  | ||||||
|  | 		boolean searchActiveContent=true){ | ||||||
|  |  | ||||||
|  | 		var results = {}; | ||||||
|  | 		var c = newCriteria(); | ||||||
|  |  | ||||||
|  | 		// only published content | ||||||
|  | 		if( isBoolean( arguments.isPublished ) ){ | ||||||
|  | 			// Published bit | ||||||
|  | 			c.isEq( "isPublished", javaCast( "Boolean", arguments.isPublished ) ); | ||||||
|  | 			// Published eq true evaluate other params | ||||||
|  | 			if( arguments.isPublished ){ | ||||||
|  | 				c.isLt("publishedDate", now() ) | ||||||
|  | 				.$or( c.restrictions.isNull("expireDate"), c.restrictions.isGT("expireDate", now() ) ) | ||||||
|  | 				.isEq("passwordProtection",""); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// Search Criteria | ||||||
|  | 		if( len( arguments.searchTerm ) ){ | ||||||
|  | 			// like disjunctions | ||||||
|  | 			c.createAlias("activeContent","ac"); | ||||||
|  | 			// Do we search title and active content or just title? | ||||||
|  | 			if( arguments.searchActiveContent ){ | ||||||
|  | 				c.$or( c.restrictions.like("title","%#arguments.searchTerm#%"), | ||||||
|  | 				  	  c.restrictions.like("ac.content", "%#arguments.searchTerm#%") ); | ||||||
|  | 			} | ||||||
|  | 			else{ | ||||||
|  | 				c.like( "title", "%#arguments.searchTerm#%" );  | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		// run criteria query and projections count | ||||||
|  | 		results.count = c.count( "contentID" ); | ||||||
|  | 		results.content = c.resultTransformer( c.DISTINCT_ROOT_ENTITY ) | ||||||
|  | 							.list(offset=arguments.offset, max=arguments.max, sortOrder=arguments.sortOrder, asQuery=arguments.asQuery); | ||||||
|  | 	 | ||||||
|  | 		return results; | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | /********************************************* PRIVATE *********************************************/ | ||||||
|  | 	 | ||||||
|  |  | ||||||
|  | 	/** | ||||||
|  | 	* Update the content hits | ||||||
|  | 	* @contentID.hint The content id to update | ||||||
|  | 	*/ | ||||||
|  | 	private function syncUpdateHits(required contentID){ | ||||||
|  | 		var q = new Query(sql="UPDATE cb_content SET hits = hits + 1 WHERE contentID = #arguments.contentID#").execute(); | ||||||
|  | 		return this; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	 | ||||||
|  | 	private function closureTest(){ | ||||||
|  | 		methodCall( | ||||||
|  | 			param1, | ||||||
|  | 			function( arg1, required arg2 ){ | ||||||
|  | 				var settings = settingService.getAllSettings(asStruct=true); | ||||||
|  | 				// Get appropriate cache provider | ||||||
|  | 				var cache = cacheBox.getCache( settings.cb_content_cacheName ); | ||||||
|  | 				cache.clear("cb-content-pagewrapper-#arguments.slug#/"); | ||||||
|  | 				return this; | ||||||
|  | 			}, | ||||||
|  | 			param1 | ||||||
|  | 		); | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	private function StructliteralTest(){ | ||||||
|  | 		return { | ||||||
|  | 			foo = bar, | ||||||
|  | 			brad = 'Wood', | ||||||
|  | 			func = function( arg1, required arg2 ){ | ||||||
|  | 				var settings = settingService.getAllSettings(asStruct=true); | ||||||
|  | 				// Get appropriate cache provider | ||||||
|  | 				var cache = cacheBox.getCache( settings.cb_content_cacheName ); | ||||||
|  | 				cache.clear("cb-content-pagewrapper-#arguments.slug#/"); | ||||||
|  | 				return this; | ||||||
|  | 			}, | ||||||
|  | 			array = [ | ||||||
|  | 				1, | ||||||
|  | 				2, | ||||||
|  | 				3, | ||||||
|  | 				4, | ||||||
|  | 				5, | ||||||
|  | 				'test', | ||||||
|  | 				'testing', | ||||||
|  | 				'testerton', | ||||||
|  | 				{ | ||||||
|  | 					foo = true, | ||||||
|  | 					brad = false, | ||||||
|  | 					wood = null | ||||||
|  | 				} | ||||||
|  | 			], | ||||||
|  | 			last = "final" | ||||||
|  | 		}; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	private function arrayliteralTest(){ | ||||||
|  | 		return [ | ||||||
|  | 			1, | ||||||
|  | 			2, | ||||||
|  | 			3, | ||||||
|  | 			4, | ||||||
|  | 			5, | ||||||
|  | 			'test', | ||||||
|  | 			'testing', | ||||||
|  | 			'testerton', | ||||||
|  | 			{ | ||||||
|  | 				foo = true, | ||||||
|  | 				brad = false, | ||||||
|  | 				wood = null | ||||||
|  | 			}, | ||||||
|  | 			'testy-von-testavich' | ||||||
|  | 		]; | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								samples/ColdFusion CFC/exampleTag.cfc
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								samples/ColdFusion CFC/exampleTag.cfc
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | <cfcomponent> | ||||||
|  | 	 | ||||||
|  | 	<cffunction name="init" access="public" returntype="any"> | ||||||
|  | 		<cfargument name="arg1" type="any" required="true"> | ||||||
|  | 		<cfset this.myVariable = arguments.arg1> | ||||||
|  |  | ||||||
|  | 		<cfreturn this> | ||||||
|  | 	</cffunction> | ||||||
|  |  | ||||||
|  | 	<cffunction name="testFunc" access="private" returntype="void"> | ||||||
|  | 		<cfargument name="arg1" type="any" required="false"> | ||||||
|  | 		 | ||||||
|  | 		<cfif structKeyExists(arguments, "arg1")> | ||||||
|  | 			<cfset writeoutput("Argument exists")> | ||||||
|  | 		</cfif> | ||||||
|  | 	</cffunction> | ||||||
|  | 	 | ||||||
|  | </cfcomponent> | ||||||
							
								
								
									
										50
									
								
								samples/ColdFusion/example.cfm
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								samples/ColdFusion/example.cfm
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | |||||||
|  | <!--- cfcomment ---> | ||||||
|  | <!--- nested <!--- cfcomment ---> ---> | ||||||
|  | <!--- multi-line | ||||||
|  | nested | ||||||
|  | <!--- | ||||||
|  | cfcomment | ||||||
|  | ---> | ||||||
|  | ---> | ||||||
|  | <!-- html comment --> | ||||||
|  | <html> | ||||||
|  | <head> | ||||||
|  | <title>Date Functions</title> | ||||||
|  | </head> | ||||||
|  | <body> | ||||||
|  | <cfset RightNow = Now()> | ||||||
|  | <cfoutput> | ||||||
|  |  #RightNow#<br /> | ||||||
|  |  #DateFormat(RightNow)#<br /> | ||||||
|  |  #DateFormat(RightNow,"mm/dd/yy")#<br /> | ||||||
|  |  #TimeFormat(RightNow)#<br /> | ||||||
|  |  #TimeFormat(RightNow,"hh:mm tt")#<br /> | ||||||
|  |  #IsDate(RightNow)#<br /> | ||||||
|  |  #IsDate("January 31, 2007")#<br /> | ||||||
|  |  #IsDate("foo")#<br /> | ||||||
|  |  #DaysInMonth(RightNow)# | ||||||
|  | </cfoutput> | ||||||
|  | <cfset x="x"> | ||||||
|  | <cfset y="y"> | ||||||
|  | <cfset z="z"> | ||||||
|  | <cfoutput group="x"> | ||||||
|  |     #x# | ||||||
|  |     <cfoutput>#y#</cfoutput> | ||||||
|  |     #z# | ||||||
|  | </cfoutput> | ||||||
|  | </body> | ||||||
|  | </html> | ||||||
|  |  | ||||||
|  | <cfset person = "Paul"> | ||||||
|  | <cfset greeting = "Hello #person#"> | ||||||
|  |  | ||||||
|  | <cfset greeting = "Hello" & " world!"> | ||||||
|  | <cfset a = 5> | ||||||
|  | <cfset b = 10> | ||||||
|  | <cfset c = a^b> | ||||||
|  | <cfset c = a MOD b> | ||||||
|  | <cfset c = a / b> | ||||||
|  | <cfset c = a * b> | ||||||
|  | <cfset c = a + b> | ||||||
|  | <cfset c = a - b> | ||||||
|  | <!--- <!-- another <!--- nested --> ---> comment ---> | ||||||
							
								
								
									
										82
									
								
								samples/Common Lisp/macros-advanced.cl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								samples/Common Lisp/macros-advanced.cl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | |||||||
|  | ;; @file macros-advanced.cl | ||||||
|  | ;; | ||||||
|  | ;; @breif Advanced macro practices - defining your own macros | ||||||
|  | ;; | ||||||
|  | ;; Macro definition skeleton: | ||||||
|  | ;; (defmacro name (parameter*) | ||||||
|  | ;;   "Optional documentation string" | ||||||
|  | ;;   body-form*) | ||||||
|  | ;; | ||||||
|  | ;; Note that backquote expression is most often used in the `body-form` | ||||||
|  | ;; | ||||||
|  |  | ||||||
|  | ; `primep` test a number for prime | ||||||
|  | (defun primep (n) | ||||||
|  |   "test a number for prime" | ||||||
|  |   (if (< n 2) (return-from primep)) | ||||||
|  |   (do ((i 2 (1+ i)) (p t (not (zerop (mod n i))))) | ||||||
|  |       ((> i (sqrt n)) p) | ||||||
|  |     (when (not p) (return)))) | ||||||
|  | ; `next-prime` return the next prime bigger than the specified number | ||||||
|  | (defun next-prime (n) | ||||||
|  |   "return the next prime bigger than the speicified number" | ||||||
|  |   (do ((i (1+ n) (1+ i))) | ||||||
|  |       ((primep i) i))) | ||||||
|  | ; | ||||||
|  | ; The recommended procedures to writting a new macro are as follows: | ||||||
|  | ; 1. Write a sample call to the macro and the code it should expand into | ||||||
|  | (do-primes (p 0 19) | ||||||
|  |   (format t "~d " p)) | ||||||
|  | ; Expected expanded codes | ||||||
|  | (do ((p (next-prime (- 0 1)) (next-prime p))) | ||||||
|  |     ((> p 19)) | ||||||
|  |   (format t "~d " p)) | ||||||
|  | ; 2. Write code that generate the hardwritten expansion from the arguments in | ||||||
|  | ; the sample call | ||||||
|  | (defmacro do-primes (var-and-range &rest body) | ||||||
|  |   (let ((var (first var-and-range)) | ||||||
|  |         (start (second var-and-range)) | ||||||
|  |         (end (third var-and-range))) | ||||||
|  |     `(do ((,var (next-prime (- ,start 1)) (next-prime ,var))) | ||||||
|  |          ((> ,var ,end)) | ||||||
|  |       ,@body))) | ||||||
|  | ; 2-1. More concise implementations with the 'parameter list destructuring' and | ||||||
|  | ; '&body' synonym, it also emits more friendly messages on incorrent input. | ||||||
|  | (defmacro do-primes ((var start end) &body body) | ||||||
|  |   `(do ((,var (next-prime (- ,start 1)) (next-prime ,var))) | ||||||
|  |        ((> ,var ,end)) | ||||||
|  |     ,@body)) | ||||||
|  | ; 2-2. Test the result of macro expansion with the `macroexpand-1` function | ||||||
|  | (macroexpand-1 '(do-primes (p 0 19) (format t "~d " p))) | ||||||
|  | ; 3. Make sure the macro abstraction does not "leak" | ||||||
|  | (defmacro do-primes ((var start end) &body body) | ||||||
|  |   (let ((end-value-name (gensym))) | ||||||
|  |     `(do ((,var (next-prime (- ,start 1)) (next-prime ,var)) | ||||||
|  |           (,end-value-name ,end)) | ||||||
|  |          ((> ,var ,end-value-name)) | ||||||
|  |       ,@body))) | ||||||
|  | ; 3-1. Rules to observe to avoid common and possible leaks | ||||||
|  | ;   a. include any subforms in the expansion in positions that will be evaluated | ||||||
|  | ;      in the same order as the subforms appear in the macro call | ||||||
|  | ;   b. make sure subforms are evaluated only once by creating a variable in the | ||||||
|  | ;      expansion to hold the value of evaluating the argument form, and then | ||||||
|  | ;      using that variable anywhere else the value is needed in the expansion | ||||||
|  | ;   c. use `gensym` at macro expansion time to create variable names used in the | ||||||
|  | ;      expansion | ||||||
|  | ; | ||||||
|  | ; Appendix I. Macro-writting macros, 'with-gensyms', to guranttee that rule c | ||||||
|  | ; gets observed. | ||||||
|  | ; Example usage of `with-gensyms` | ||||||
|  | (defmacro do-primes-a ((var start end) &body body) | ||||||
|  |   "do-primes implementation with macro-writting macro 'with-gensyms'" | ||||||
|  |   (with-gensyms (end-value-name) | ||||||
|  |     `(do ((,var (next-prime (- ,start 1)) (next-prime ,var)) | ||||||
|  |           (,end-value-name ,end)) | ||||||
|  |          ((> ,var ,end-value-name)) | ||||||
|  |       ,@body))) | ||||||
|  | ; Define the macro, note how comma is used to interpolate the value of the loop | ||||||
|  | ; expression | ||||||
|  | (defmacro with-gensyms ((&rest names) &body body) | ||||||
|  |   `(let ,(loop for n in names collect `(,n (gensym))) | ||||||
|  |     ,@body) | ||||||
|  | ) | ||||||
							
								
								
									
										475
									
								
								samples/Common Lisp/motor-inferencia.cl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										475
									
								
								samples/Common Lisp/motor-inferencia.cl
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,475 @@ | |||||||
|  | #| | ||||||
|  | ESCUELA POLITECNICA SUPERIOR - UNIVERSIDAD AUTONOMA DE MADRID | ||||||
|  | INTELIGENCIA ARTIFICIAL | ||||||
|  |  | ||||||
|  | Motor de inferencia | ||||||
|  | Basado en parte en "Paradigms of AI Programming: Case Studies | ||||||
|  | in Common Lisp", de Peter Norvig, 1992 | ||||||
|  | |# | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ;;;;;;;;;;;;;;;;;;;;; | ||||||
|  | ;;;; Global variables | ||||||
|  | ;;;;;;;;;;;;;;;;;;;;; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | (defvar *hypothesis-list*) | ||||||
|  | (defvar *rule-list*) | ||||||
|  | (defvar *fact-list*) | ||||||
|  |  | ||||||
|  | ;;;;;;;;;;;;;;;;;;;;; | ||||||
|  | ;;;; Constants | ||||||
|  | ;;;;;;;;;;;;;;;;;;;;; | ||||||
|  |  | ||||||
|  | (defconstant +fail+ nil "Indicates unification failure") | ||||||
|  |  | ||||||
|  | (defconstant +no-bindings+ '((nil)) | ||||||
|  |   "Indicates unification success, with no variables.") | ||||||
|  |  | ||||||
|  | (defconstant *mundo-abierto* nil) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  | ;;;; Functions for the user | ||||||
|  | ;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ;; Resets *fact-list* to NIL | ||||||
|  | (defun erase-facts () (setq *fact-list* nil)) | ||||||
|  |  | ||||||
|  | (defun set-hypothesis-list (h) (setq *hypothesis-list* h)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ;; Returns a list of solutions, each one satisfying all the hypothesis contained | ||||||
|  | ;; in *hypothesis-list* | ||||||
|  | (defun motor-inferencia () | ||||||
|  |   (consulta *hypothesis-list*)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  | ;;;; Auxiliary functions | ||||||
|  | ;;;;;;;;;;;;;;;;;;;;;;;; | ||||||
|  |  | ||||||
|  | #|____________________________________________________________________________ | ||||||
|  | FUNCTION: CONSULTA | ||||||
|  |  | ||||||
|  | COMMENTS: | ||||||
|  | CONSULTA receives a list of hypothesis (variable <hypotheses>), and returns | ||||||
|  | a list of binding lists (each binding list being a solution). | ||||||
|  |  | ||||||
|  | EXAMPLES: | ||||||
|  | hypotheses is: | ||||||
|  | ((brothers ?x ?y) (neighbours juan ?x)). | ||||||
|  |  | ||||||
|  | That is, we are searching the brothers of the possible neighbors of Juan. | ||||||
|  |  | ||||||
|  | The function can return in this case: | ||||||
|  |   | ||||||
|  | (((?x . sergio) (?y . javier)) ((?x . julian) (?y . mario)) ((?x . julian) (?y . pedro))). | ||||||
|  | That is, the neighbors of Juan (Sergio and Julian) have 3 brothers in total(Javier, Mario, Pedro) | ||||||
|  | ____________________________________________________________________________|# | ||||||
|  |  | ||||||
|  | (defun consulta (hypotheses) | ||||||
|  |   (if (null hypotheses) (list +no-bindings+) | ||||||
|  |     (mapcan #'(lambda (b) | ||||||
|  |                 (mapcar #'(lambda (x) (une-bindings-con-bindings b x)) | ||||||
|  |                   (consulta (subst-bindings b (rest hypotheses))))) | ||||||
|  |       (find-hypothesis-value (first hypotheses))))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #|____________________________________________________________________________ | ||||||
|  | FUNCTION: FIND-HYPOTHESIS-VALUE | ||||||
|  |  | ||||||
|  | COMMENTS: | ||||||
|  | This function manages the query a single query (only one hypothesis) given a binding list. | ||||||
|  | It tries (in the following order) to: | ||||||
|  | - Answer the query from *fact-list* | ||||||
|  | - Answer the query from the rules in *rule-list* | ||||||
|  | - Ask the user | ||||||
|  |  | ||||||
|  | The function returns a list of solutions (list of binding lists). | ||||||
|  |  | ||||||
|  | EXAMPLES: | ||||||
|  | If hypothesis is (brothers ?x ?y) | ||||||
|  | and the function returns: | ||||||
|  | (((?x . sergio) (?y . javier)) ((?x . julian) (?y . maria)) ((?x . alberto) (?y . pedro))). | ||||||
|  |  | ||||||
|  | Means that Sergio and Javier and brothers, Julian and Mario are brothers, and Alberto and Pedro are brothers. | ||||||
|  | ____________________________________________________________________________|# | ||||||
|  |  | ||||||
|  | (defun find-hypothesis-value (hypothesis) | ||||||
|  |   (let (rules) | ||||||
|  |    (cond | ||||||
|  |     ((equality? hypothesis)  | ||||||
|  |      (value-from-equality hypothesis)) | ||||||
|  |     ((value-from-facts hypothesis)) | ||||||
|  |     ((setq good-rules (find-rules hypothesis))  | ||||||
|  |      (value-from-rules hypothesis good-rules)) | ||||||
|  |     (t (ask-user hypothesis))))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ; une-bindings-con-bindings takes two binding lists and returns a binding list | ||||||
|  | ; Assumes that b1 and b2 are not +fail+ | ||||||
|  | (defun une-bindings-con-bindings (b1 b2) | ||||||
|  |   (cond | ||||||
|  |    ((equal b1 +no-bindings+) b2) | ||||||
|  |    ((equal b2 +no-bindings+) b1) | ||||||
|  |    (T (append b1 b2)))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #|____________________________________________________________________________ | ||||||
|  | FUNCTION: VALUE-FROM-FACTS | ||||||
|  |  | ||||||
|  | COMMENTS: | ||||||
|  | Returns all the solutions of <hypothesis> obtained directly from *fact-list* | ||||||
|  |  | ||||||
|  | EXAMPLES: | ||||||
|  | > (setf *fact-list* '((man luis) (man pedro)(woman mart)(man daniel)(woman laura))) | ||||||
|  |  | ||||||
|  | > (value-from-facts '(man ?x)) | ||||||
|  | returns: | ||||||
|  |  | ||||||
|  | (((?X . LUIS)) ((?X . PEDRO)) ((?X . DANIEL))) | ||||||
|  | ____________________________________________________________________________|# | ||||||
|  |  | ||||||
|  | (defun value-from-facts (hypothesis) | ||||||
|  |   (mapcan #'(lambda(x) (let ((aux (unify hypothesis x))) | ||||||
|  |                          (when aux (list aux)))) *fact-list*)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #|____________________________________________________________________________ | ||||||
|  | FUNCTION: FIND-RULES | ||||||
|  |  | ||||||
|  | COMMENTS: | ||||||
|  | Returns the rules in *rule-list* whose THENs unify with the term given in <hypothesis> | ||||||
|  | The variables in the rules that satisfy this requirement are renamed. | ||||||
|  |  | ||||||
|  | EXAMPLES: | ||||||
|  | > (setq *rule-list* | ||||||
|  |       '((R1 (pertenece ?E (?E . ?_))) | ||||||
|  |         (R2 (pertenece ?E (?_ . ?Xs)) :- ((pertenece ?E ?Xs))))) | ||||||
|  |  | ||||||
|  | Then: | ||||||
|  | > (FIND-RULES (PERTENECE 1 (2 5))) | ||||||
|  | returns: | ||||||
|  | ((R2 (PERTENECE ?E.1 (?_ . ?XS.2)) :- ((PERTENECE ?E.1 ?XS.2)))) | ||||||
|  | That is, only the THEN of rule R2 unify with <hypothesis> | ||||||
|  |  | ||||||
|  | However, | ||||||
|  | > (FIND-RULES (PERTENECE 1 (1 6 7))) | ||||||
|  |  | ||||||
|  | returns: | ||||||
|  | ((R1 (PERTENECE ?E.6 (?E.6 . ?_))) | ||||||
|  |  (R2 (PERTENECE ?E.7 (?_ . ?XS.8)) :- ((PERTENECE ?E.7 ?XS.8)))) | ||||||
|  | So the THEN of both rules unify with <hypothesis> | ||||||
|  | ____________________________________________________________________________|# | ||||||
|  |  | ||||||
|  | (defun find-rules (hypothesis) | ||||||
|  |   (mapcan #'(lambda(b) (let ((renamed-rule (rename-variables b))) | ||||||
|  |                          (when (in-then? hypothesis renamed-rule) | ||||||
|  |                            (list renamed-rule)))) *rule-list*)) | ||||||
|  |  | ||||||
|  | (defun in-then? (hypothesis rule) | ||||||
|  |   (unless (null (rule-then rule)) | ||||||
|  |     (not (equal +fail+ (unify hypothesis (rule-then rule)))))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #|____________________________________________________________________________ | ||||||
|  | FUNCTION: VALUE-FROM-RULES | ||||||
|  |  | ||||||
|  | COMMENTS: | ||||||
|  | Returns all the solutions to <hypothesis> found using all the rules given in | ||||||
|  | the list <rules>. Note that a single rule can have multiple solutions. | ||||||
|  | ____________________________________________________________________________|# | ||||||
|  | (defun value-from-rules (hypothesis rules) | ||||||
|  |   (mapcan #'(lambda (r) (eval-rule hypothesis r)) rules)) | ||||||
|  |  | ||||||
|  | (defun limpia-vinculos (termino bindings) | ||||||
|  |   (unify termino (subst-bindings bindings termino))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #|____________________________________________________________________________ | ||||||
|  | FUNCTION: EVAL-RULE | ||||||
|  |  | ||||||
|  | COMMENTS: | ||||||
|  | Returns all the solutions found using the rule given as input argument. | ||||||
|  |  | ||||||
|  | EXAMPLES: | ||||||
|  | > (setq *rule-list* | ||||||
|  |       '((R1 (pertenece ?E (?E . ?_))) | ||||||
|  |         (R2 (pertenece ?E (?_ . ?Xs)) :- ((pertenece ?E ?Xs))))) | ||||||
|  | Then: | ||||||
|  | > (EVAL-RULE  | ||||||
|  |    (PERTENECE 1 (1 6 7))  | ||||||
|  |    (R1 (PERTENECE ?E.42 (?E.42 . ?_)))) | ||||||
|  | returns: | ||||||
|  | (((NIL))) | ||||||
|  | That is, the query (PERTENECE 1 (1 6 7)) can be proven from the given rule, and | ||||||
|  | no binding in the variables in the query is necessary (in fact, the query has no variables). | ||||||
|  | On the other hand: | ||||||
|  | > (EVAL-RULE  | ||||||
|  |    (PERTENECE 1 (7))  | ||||||
|  |    (R2 (PERTENECE ?E.49 (?_ . ?XS.50)) :- ((PERTENECE ?E.49 ?XS.50)))) | ||||||
|  | returns: | ||||||
|  | NIL | ||||||
|  | That is, the query can not be proven from the rule R2. | ||||||
|  | ____________________________________________________________________________|# | ||||||
|  |  | ||||||
|  | (defun eval-rule (hypothesis rule) | ||||||
|  |   (let ((bindings-then  | ||||||
|  |           (unify (rule-then rule) hypothesis))) | ||||||
|  |     (unless (equal +fail+ bindings-then) | ||||||
|  |       (if (rule-ifs rule) | ||||||
|  |           (mapcar #'(lambda(b) (limpia-vinculos hypothesis (append bindings-then b))) | ||||||
|  |             (consulta (subst-bindings bindings-then (rule-ifs rule)))) | ||||||
|  |         (list (limpia-vinculos hypothesis bindings-then)))))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | (defun ask-user (hypothesis) | ||||||
|  |   (let ((question hypothesis)) | ||||||
|  |     (cond | ||||||
|  |      ((variables-in question) +fail+) | ||||||
|  |      ((not-in-fact-list? question) +fail+) | ||||||
|  |      (*mundo-abierto* | ||||||
|  |       (format t "~%Es cierto el hecho ~S? (T/nil)" question) | ||||||
|  |       (cond | ||||||
|  |        ((read) (add-fact question) +no-bindings+) | ||||||
|  |        (T (add-fact (list 'NOT question)) +fail+))) | ||||||
|  |      (T +fail+)))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ; value-from-equality: | ||||||
|  | (defun value-from-equality (hypothesis) | ||||||
|  |   (let ((new-bindings (unify (second hypothesis) (third hypothesis)))) | ||||||
|  |     (if (not (equal +fail+ new-bindings))  | ||||||
|  | 	(list new-bindings)))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #|____________________________________________________________________________ | ||||||
|  | FUNCTION: UNIFY | ||||||
|  |  | ||||||
|  | COMMENTS: | ||||||
|  | Finds the most general unifier of two input expressions, taking into account the | ||||||
|  | bindings specified in the input <bingings> | ||||||
|  | In case the two expressions can unify, the function returns the total bindings necessary | ||||||
|  | for that unification. Otherwise, returns +fail+ | ||||||
|  |  | ||||||
|  | EXAMPLES: | ||||||
|  | > (unify '1 '1) | ||||||
|  | ((NIL)) ;; which is the constant +no-bindings+ | ||||||
|  | > (unify 1 '2) | ||||||
|  | nil     ;; which is the constant +fail+ | ||||||
|  | > (unify '?x 1) | ||||||
|  | ((?x . 1)) | ||||||
|  | > (unify '(1 1) ?x) | ||||||
|  | ((? x 1 1)) | ||||||
|  | > (unify '?_ '?x) | ||||||
|  | ((NIL)) | ||||||
|  | > (unify '(p ?x 1 2) '(p ?y ?_ ?_)) | ||||||
|  | ((?x . ?y)) | ||||||
|  | > (unify '(?a . ?_) '(1 2 3))  | ||||||
|  | ((?a . 1))  | ||||||
|  | > (unify '(?_ ?_) '(1 2)) | ||||||
|  | ((nil)) | ||||||
|  | > (unify '(?a . ?b) '(1 2 3))  | ||||||
|  | ((?b 2 3) (?a . 1))  | ||||||
|  | > (unify '(?a . ?b) '(?v . ?d))  | ||||||
|  | ((?b . ?d) (?a . ?v))  | ||||||
|  | > (unify '(?eval (+ 1 1)) '1)  | ||||||
|  | nil | ||||||
|  | > (unify '(?eval (+ 1 1)) '2)  | ||||||
|  | (nil))  | ||||||
|  | ____________________________________________________________________________|# | ||||||
|  |  | ||||||
|  | (defun unify (x y &optional (bindings +no-bindings+)) | ||||||
|  |   "See if x and y match with given bindings.  If they do, | ||||||
|  |   return a binding list that would make them equal [p 303]." | ||||||
|  |   (cond ((eq bindings +fail+) +fail+) | ||||||
|  |         ((eql x y) bindings) | ||||||
|  |         ((eval? x) (unify-eval x y bindings)) | ||||||
|  |         ((eval? y) (unify-eval y x bindings)) | ||||||
|  |         ((variable? x) (unify-var x y bindings)) | ||||||
|  |         ((variable? y) (unify-var y x bindings)) | ||||||
|  |         ((and (consp x) (consp y)) | ||||||
|  |          (unify (rest x) (rest y)  | ||||||
|  |                 (unify (first x) (first y) bindings))) | ||||||
|  |         (t +fail+))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ;; rename-variables: renombra ?X por ?X.1, ?Y por ?Y.2 etc. salvo ?_ que no se renombra | ||||||
|  | (defun rename-variables (x) | ||||||
|  |   "Replace all variables in x with new ones. Excepto ?_" | ||||||
|  |   (sublis (mapcar #'(lambda (var)  | ||||||
|  | 		      (if (anonymous-var? var) | ||||||
|  | 			  (make-binding var var) | ||||||
|  | 			(make-binding var (new-variable var)))) | ||||||
|  | 		  (variables-in x)) | ||||||
|  | 	  x)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ;;;; Auxiliary Functions | ||||||
|  |  | ||||||
|  | (defun unify-var (var x bindings) | ||||||
|  |   "Unify var with x, using (and maybe extending) bindings [p 303]." | ||||||
|  |   (cond ((or (anonymous-var? var)(anonymous-var? x)) bindings) | ||||||
|  | 	((get-binding var bindings) | ||||||
|  | 	 (unify (lookup var bindings) x bindings)) | ||||||
|  | 	((and (variable? x) (get-binding x bindings)) | ||||||
|  | 	 (unify var (lookup x bindings) bindings)) | ||||||
|  | 	((occurs-in? var x bindings) | ||||||
|  | 	 +fail+) | ||||||
|  | 	(t (extend-bindings var x bindings)))) | ||||||
|  |  | ||||||
|  | (defun variable? (x) | ||||||
|  |   "Is x a variable (a symbol starting with ?)?" | ||||||
|  |   (and (symbolp x) (eql (char (symbol-name x) 0) #\?))) | ||||||
|  |  | ||||||
|  | (defun get-binding (var bindings) | ||||||
|  |   "Find a (variable . value) pair in a binding list." | ||||||
|  |   (assoc var bindings)) | ||||||
|  |  | ||||||
|  | (defun binding-var (binding) | ||||||
|  |   "Get the variable part of a single binding." | ||||||
|  |   (car binding)) | ||||||
|  |  | ||||||
|  | (defun binding-val (binding) | ||||||
|  |   "Get the value part of a single binding." | ||||||
|  |   (cdr binding)) | ||||||
|  |  | ||||||
|  | (defun make-binding (var val) (cons var val)) | ||||||
|  |  | ||||||
|  | (defun lookup (var bindings) | ||||||
|  |   "Get the value part (for var) from a binding list." | ||||||
|  |   (binding-val (get-binding var bindings))) | ||||||
|  |  | ||||||
|  | (defun extend-bindings (var val bindings) | ||||||
|  |   "Add a (var . value) pair to a binding list." | ||||||
|  |   (append  | ||||||
|  |    (unless (eq bindings +no-bindings+) bindings) | ||||||
|  |    (list (make-binding var val)))) | ||||||
|  |  | ||||||
|  | (defun occurs-in? (var x bindings) | ||||||
|  |   "Does var occur anywhere inside x?" | ||||||
|  |   (cond ((eq var x) t) | ||||||
|  |         ((and (variable? x) (get-binding x bindings)) | ||||||
|  |          (occurs-in? var (lookup x bindings) bindings)) | ||||||
|  |         ((consp x) (or (occurs-in? var (first x) bindings) | ||||||
|  |                        (occurs-in? var (rest x) bindings))) | ||||||
|  |         (t nil))) | ||||||
|  |  | ||||||
|  | (defun subst-bindings (bindings x) | ||||||
|  |   "Substitute the value of variables in bindings into x, | ||||||
|  |   taking recursively bound variables into account." | ||||||
|  |   (cond ((eq bindings +fail+) +fail+) | ||||||
|  |         ((eq bindings +no-bindings+) x) | ||||||
|  |         ((and (listp x) (eq '?eval (car x))) | ||||||
|  |          (subst-bindings-quote bindings x)) | ||||||
|  |         ((and (variable? x) (get-binding x bindings)) | ||||||
|  |          (subst-bindings bindings (lookup x bindings))) | ||||||
|  |         ((atom x) x) | ||||||
|  |         (t (cons (subst-bindings bindings (car x)) ;; s/reuse-cons/cons | ||||||
|  | 		 (subst-bindings bindings (cdr x)))))) | ||||||
|  |  | ||||||
|  | (defun unifier (x y) | ||||||
|  |  "Return something that unifies with both x and y (or fail)." | ||||||
|  |  (subst-bindings (unify x y) x)) | ||||||
|  |  | ||||||
|  | (defun variables-in (exp) | ||||||
|  |   "Return a list of all the variables in EXP." | ||||||
|  |   (unique-find-anywhere-if #'variable? exp)) | ||||||
|  |  | ||||||
|  | (defun unique-find-anywhere-if (predicate tree &optional found-so-far) | ||||||
|  |   "Return a list of leaves of tree satisfying predicate, | ||||||
|  |   with duplicates removed." | ||||||
|  |   (if (atom tree) | ||||||
|  |       (if (funcall predicate tree) | ||||||
|  |           (pushnew tree found-so-far) | ||||||
|  |           found-so-far) | ||||||
|  |     (unique-find-anywhere-if | ||||||
|  |         predicate | ||||||
|  |         (first tree) | ||||||
|  |         (unique-find-anywhere-if predicate (rest tree) | ||||||
|  |                                  found-so-far)))) | ||||||
|  |  | ||||||
|  | (defun find-anywhere-if (predicate tree) | ||||||
|  |   "Does predicate apply to any atom in the tree?"   | ||||||
|  |   (if (atom tree) | ||||||
|  |       (funcall predicate tree) | ||||||
|  |       (or (find-anywhere-if predicate (first tree)) | ||||||
|  |           (find-anywhere-if predicate (rest tree))))) | ||||||
|  |  | ||||||
|  | (defun new-variable (var) | ||||||
|  |   "Create a new variable.  Assumes user never types variables of form ?X.9" | ||||||
|  |   (gentemp (format nil "~S." var))) | ||||||
|  | ;  (gentemp "?") ) | ||||||
|  | ;;; | ||||||
|  |  | ||||||
|  | (defun anonymous-var? (x) | ||||||
|  |   (eq x '?_)) | ||||||
|  |  | ||||||
|  | (defun subst-bindings-quote (bindings x) | ||||||
|  |   "Substitute the value of variables in bindings into x, | ||||||
|  |   taking recursively bound variables into account." | ||||||
|  |   (cond ((eq bindings +fail+) +fail+) | ||||||
|  |         ((eq bindings +no-bindings+) x) | ||||||
|  |         ((and (variable? x) (get-binding x bindings)) | ||||||
|  |          (if (variable? (lookup x bindings)) | ||||||
|  |              (subst-bindings-quote bindings (lookup x bindings)) | ||||||
|  |              (subst-bindings-quote bindings (list 'quote (lookup x bindings))) | ||||||
|  |          ) | ||||||
|  |         )      | ||||||
|  |         ((atom x) x) | ||||||
|  |         (t (cons (subst-bindings-quote bindings (car x)) ;; s/reuse-cons/cons | ||||||
|  | 		 (subst-bindings-quote bindings (cdr x)))))) | ||||||
|  |  | ||||||
|  | (defun eval? (x) | ||||||
|  |   (and (consp x) (eq (first x) '?eval))) | ||||||
|  |  | ||||||
|  | (defun unify-eval (x y bindings) | ||||||
|  |   (let ((exp (subst-bindings-quote bindings (second x)))) | ||||||
|  |     (if (variables-in exp) | ||||||
|  | 	+fail+ | ||||||
|  |       (unify (eval exp) y bindings)))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | (defun rule-ifs (rule) (fourth rule)) | ||||||
|  | (defun rule-then (rule) (second rule)) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | (defun equality? (term) | ||||||
|  |   (and (consp term) (eql (first term) '?=))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | (defun in-fact-list? (expresion) | ||||||
|  |   (some #'(lambda(x) (equal x expresion)) *fact-list*)) | ||||||
|  |                       | ||||||
|  | (defun not-in-fact-list? (expresion) | ||||||
|  |   (if (eq (car expresion) 'NOT) | ||||||
|  |       (in-fact-list? (second expresion)) | ||||||
|  |     (in-fact-list? (list 'NOT expresion)))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ;; add-fact: | ||||||
|  |  | ||||||
|  | (defun add-fact (fact) | ||||||
|  |   (setq *fact-list* (cons fact *fact-list*))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | (defun variable? (x) | ||||||
|  |   "Is x a variable (a symbol starting with ?) except ?eval and ?=" | ||||||
|  |   (and (not (equal x '?eval)) (not (equal x '?=))  | ||||||
|  |        (symbolp x) (eql (char (symbol-name x) 0) #\?))) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ;; EOF | ||||||
							
								
								
									
										130
									
								
								samples/Component Pascal/Example.cp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								samples/Component Pascal/Example.cp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,130 @@ | |||||||
|  | MODULE ObxControls; | ||||||
|  | (** | ||||||
|  |     project         = "BlackBox" | ||||||
|  |     organization    = "www.oberon.ch" | ||||||
|  |     contributors    = "Oberon microsystems" | ||||||
|  |     version         = "System/Rsrc/About" | ||||||
|  |     copyright       = "System/Rsrc/About" | ||||||
|  |     license         = "Docu/BB-License" | ||||||
|  |     changes         = "" | ||||||
|  |     issues          = "" | ||||||
|  |  | ||||||
|  | **) | ||||||
|  |  | ||||||
|  | IMPORT Dialog, Ports, Properties, Views; | ||||||
|  |  | ||||||
|  | CONST beginner = 0; advanced = 1; expert = 2; guru = 3;    (* user classes *) | ||||||
|  |  | ||||||
|  | TYPE | ||||||
|  |     View = POINTER TO RECORD (Views.View) | ||||||
|  |         size: INTEGER    (* border size in mm *) | ||||||
|  |     END; | ||||||
|  |  | ||||||
|  | VAR | ||||||
|  |     data*: RECORD | ||||||
|  |         class*: INTEGER;    (* current user class *) | ||||||
|  |         list*: Dialog.List;    (* list of currently available sizes, derived from class *) | ||||||
|  |         width*: INTEGER    (* width of next view to be opened. Derived from | ||||||
|  |                                     class, or entered through a text entry field *) | ||||||
|  |     END; | ||||||
|  |  | ||||||
|  |     predef: ARRAY 6 OF INTEGER;    (* table of predefined sizes *) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | PROCEDURE SetList; | ||||||
|  | BEGIN | ||||||
|  |     IF data.class = beginner THEN | ||||||
|  |         data.list.SetLen(1); | ||||||
|  |         data.list.SetItem(0, "default") | ||||||
|  |     ELSIF data.class = advanced THEN | ||||||
|  |         data.list.SetLen(4); | ||||||
|  |         data.list.SetItem(0, "default"); | ||||||
|  |         data.list.SetItem(1, "small"); | ||||||
|  |         data.list.SetItem(2, "medium"); | ||||||
|  |         data.list.SetItem(3, "large"); | ||||||
|  |     ELSE | ||||||
|  |         data.list.SetLen(6); | ||||||
|  |         data.list.SetItem(0, "default"); | ||||||
|  |         data.list.SetItem(1, "small"); | ||||||
|  |         data.list.SetItem(2, "medium"); | ||||||
|  |         data.list.SetItem(3, "large"); | ||||||
|  |         data.list.SetItem(4, "tiny"); | ||||||
|  |         data.list.SetItem(5, "huge"); | ||||||
|  |     END | ||||||
|  | END SetList; | ||||||
|  |  | ||||||
|  | (* View *) | ||||||
|  |  | ||||||
|  | PROCEDURE (v: View) CopyFromSimpleView (source: Views.View); | ||||||
|  | BEGIN | ||||||
|  |     v.size := source(View).size | ||||||
|  | END CopyFromSimpleView; | ||||||
|  |  | ||||||
|  | PROCEDURE (v: View) Restore (f: Views.Frame; l, t, r, b: INTEGER); | ||||||
|  | BEGIN    (* fill view with a red square of size v.size *) | ||||||
|  |     IF v.size = 0 THEN v.size := predef[0] END;    (* lazy initialization of size *) | ||||||
|  |     f.DrawRect(0, 0, v.size, v.size, Ports.fill, Ports.red) | ||||||
|  | END Restore; | ||||||
|  |  | ||||||
|  | PROCEDURE (v: View) HandlePropMsg (VAR msg: Views.PropMessage); | ||||||
|  | BEGIN | ||||||
|  |     WITH msg: Properties.SizePref DO | ||||||
|  |         IF v.size = 0 THEN v.size := predef[0] END;    (* lazy initialization of size *) | ||||||
|  |         msg.w := v.size; msg.h := v.size    (* tell environment about desired width and height *) | ||||||
|  |     ELSE    (* ignore other messages *) | ||||||
|  |     END | ||||||
|  | END HandlePropMsg; | ||||||
|  |  | ||||||
|  | (* notifiers *) | ||||||
|  |  | ||||||
|  | PROCEDURE ClassNotify* (op, from, to: INTEGER); | ||||||
|  | BEGIN    (* react to change in data.class *) | ||||||
|  |     IF op = Dialog.changed THEN | ||||||
|  |         IF (to = beginner) OR (to = advanced) & (data.list.index > 3) THEN | ||||||
|  |             (* if class is reduced, make sure that selection contains legal elements *) | ||||||
|  |             data.list.index := 0; data.width := predef[0];    (* modify interactor *) | ||||||
|  |             Dialog.Update(data)    (* redraw controls where necessary *) | ||||||
|  |         END; | ||||||
|  |         SetList; | ||||||
|  |         Dialog.UpdateList(data.list)    (* reconstruct list box contents *) | ||||||
|  |     END | ||||||
|  | END ClassNotify; | ||||||
|  |  | ||||||
|  | PROCEDURE ListNotify* (op, from, to: INTEGER); | ||||||
|  | BEGIN    (* reacto to change in data.list (index to was selected) *) | ||||||
|  |     IF op = Dialog.changed THEN | ||||||
|  |         data.width := predef[to];    (* modify interactor *) | ||||||
|  |         Dialog.Update(data)    (* redraw controls where necessary *) | ||||||
|  |     END | ||||||
|  | END ListNotify; | ||||||
|  |  | ||||||
|  | (* guards *) | ||||||
|  |  | ||||||
|  | PROCEDURE ListGuard* (VAR par: Dialog.Par); | ||||||
|  | BEGIN    (* disable list box for a beginner *) | ||||||
|  |     par.disabled := data.class = beginner | ||||||
|  | END ListGuard; | ||||||
|  |  | ||||||
|  | PROCEDURE WidthGuard* (VAR par: Dialog.Par); | ||||||
|  | BEGIN    (* make text entry field read-only if user is not guru *) | ||||||
|  |     par.readOnly := data.class # guru | ||||||
|  | END WidthGuard; | ||||||
|  |  | ||||||
|  | (* commands *) | ||||||
|  |  | ||||||
|  | PROCEDURE Open*; | ||||||
|  |     VAR v: View; | ||||||
|  | BEGIN | ||||||
|  |     NEW(v);    (* create and initialize a new view *) | ||||||
|  |     v.size := data.width * Ports.mm;    (* define view's size in function of class *) | ||||||
|  |     Views.OpenAux(v, "Example")    (* open the view in a window *) | ||||||
|  | END Open; | ||||||
|  |  | ||||||
|  | BEGIN    (* initialization of global variables *) | ||||||
|  |     predef[0] := 40; predef[1] := 30; predef[2] := 50;    (* predefined sizes *) | ||||||
|  |     predef[3] := 70; predef[4] := 20; predef[5] := 100; | ||||||
|  |     data.class := beginner;    (* default values *) | ||||||
|  |     data.list.index := 0; | ||||||
|  |     data.width := predef[0]; | ||||||
|  |     SetList | ||||||
|  | END ObxControls. | ||||||
							
								
								
									
										71
									
								
								samples/Component Pascal/Example2.cps
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								samples/Component Pascal/Example2.cps
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | |||||||
|  | MODULE ObxFact; | ||||||
|  | (** | ||||||
|  |     project         = "BlackBox" | ||||||
|  |     organization    = "www.oberon.ch" | ||||||
|  |     contributors    = "Oberon microsystems" | ||||||
|  |     version         = "System/Rsrc/About" | ||||||
|  |     copyright       = "System/Rsrc/About" | ||||||
|  |     license         = "Docu/BB-License" | ||||||
|  |     changes         = "" | ||||||
|  |     issues          = "" | ||||||
|  |  | ||||||
|  | **) | ||||||
|  |  | ||||||
|  | IMPORT | ||||||
|  |     Stores, Models, TextModels, TextControllers, Integers; | ||||||
|  |  | ||||||
|  | PROCEDURE Read(r: TextModels.Reader; VAR x: Integers.Integer); | ||||||
|  |     VAR i, len, beg: INTEGER; ch: CHAR; buf: POINTER TO ARRAY OF CHAR; | ||||||
|  | BEGIN | ||||||
|  |     r.ReadChar(ch); | ||||||
|  |     WHILE ~r.eot & (ch <= " ") DO r.ReadChar(ch) END; | ||||||
|  |     ASSERT(~r.eot & (((ch >= "0") & (ch <= "9")) OR (ch = "-"))); | ||||||
|  |     beg := r.Pos() - 1; len := 0; | ||||||
|  |     REPEAT INC(len); r.ReadChar(ch) UNTIL r.eot OR (ch < "0") OR (ch > "9"); | ||||||
|  |     NEW(buf, len + 1); | ||||||
|  |     i := 0; r.SetPos(beg); | ||||||
|  |     REPEAT r.ReadChar(buf[i]); INC(i) UNTIL i = len; | ||||||
|  |     buf[i] := 0X; | ||||||
|  |     Integers.ConvertFromString(buf^, x) | ||||||
|  | END Read; | ||||||
|  |  | ||||||
|  | PROCEDURE Write(w: TextModels.Writer; x: Integers.Integer); | ||||||
|  |     VAR i: INTEGER; | ||||||
|  | BEGIN | ||||||
|  |     IF Integers.Sign(x) < 0 THEN w.WriteChar("-") END; | ||||||
|  |     i := Integers.Digits10Of(x); | ||||||
|  |     IF i # 0 THEN | ||||||
|  |         REPEAT DEC(i); w.WriteChar(Integers.ThisDigit10(x, i)) UNTIL i = 0 | ||||||
|  |     ELSE w.WriteChar("0") | ||||||
|  |     END | ||||||
|  | END Write; | ||||||
|  |  | ||||||
|  | PROCEDURE Compute*; | ||||||
|  |     VAR beg, end, i, n: INTEGER; ch: CHAR; | ||||||
|  |         s: Stores.Operation; | ||||||
|  |         r: TextModels.Reader; w: TextModels.Writer; attr: TextModels.Attributes; | ||||||
|  |         c: TextControllers.Controller; | ||||||
|  |         x: Integers.Integer; | ||||||
|  | BEGIN | ||||||
|  |     c := TextControllers.Focus(); | ||||||
|  |     IF (c # NIL) & c.HasSelection() THEN | ||||||
|  |         c.GetSelection(beg, end); | ||||||
|  |         r := c.text.NewReader(NIL); r.SetPos(beg); r.ReadChar(ch); | ||||||
|  |         WHILE ~r.eot & (beg < end) & (ch <= " ") DO r.ReadChar(ch); INC(beg) END; | ||||||
|  |         IF ~r.eot & (beg < end) THEN | ||||||
|  |             r.ReadPrev; Read(r, x); | ||||||
|  |             end := r.Pos(); r.ReadPrev; attr :=r.attr; | ||||||
|  |             IF (Integers.Sign(x) > 0) & (Integers.Compare(x, Integers.Long(MAX(LONGINT))) <= 0) THEN | ||||||
|  |                 n := SHORT(Integers.Short(x)); i := 2; x := Integers.Long(1); | ||||||
|  |                 WHILE i <= n DO x := Integers.Product(x, Integers.Long(i)); INC(i) END; | ||||||
|  |                 Models.BeginScript(c.text, "computation", s); | ||||||
|  |                 c.text.Delete(beg, end); | ||||||
|  |                 w := c.text.NewWriter(NIL); w.SetPos(beg); w.SetAttr(attr); | ||||||
|  |                 Write(w, x); | ||||||
|  |                 Models.EndScript(c.text, s) | ||||||
|  |             END | ||||||
|  |         END | ||||||
|  |     END | ||||||
|  | END Compute; | ||||||
|  |  | ||||||
|  | END ObxFact. | ||||||
							
								
								
									
										169
									
								
								samples/Crystal/const_spec.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								samples/Crystal/const_spec.cr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,169 @@ | |||||||
|  | #!/usr/bin/env bin/crystal --run | ||||||
|  | require "../../spec_helper" | ||||||
|  |  | ||||||
|  | describe "Codegen: const" do | ||||||
|  |   it "define a constant" do | ||||||
|  |     run("A = 1; A").to_i.should eq(1) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "support nested constant" do | ||||||
|  |     run("class B; A = 1; end; B::A").to_i.should eq(1) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "support constant inside a def" do | ||||||
|  |     run(" | ||||||
|  |       class Foo | ||||||
|  |         A = 1 | ||||||
|  |  | ||||||
|  |         def foo | ||||||
|  |           A | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       Foo.new.foo | ||||||
|  |     ").to_i.should eq(1) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "finds nearest constant first" do | ||||||
|  |     run(" | ||||||
|  |       A = 1 | ||||||
|  |  | ||||||
|  |       class Foo | ||||||
|  |         A = 2.5_f32 | ||||||
|  |  | ||||||
|  |         def foo | ||||||
|  |           A | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       Foo.new.foo | ||||||
|  |     ").to_f32.should eq(2.5) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "allows constants with same name" do | ||||||
|  |     run(" | ||||||
|  |       A = 1 | ||||||
|  |  | ||||||
|  |       class Foo | ||||||
|  |         A = 2.5_f32 | ||||||
|  |  | ||||||
|  |         def foo | ||||||
|  |           A | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       A | ||||||
|  |       Foo.new.foo | ||||||
|  |     ").to_f32.should eq(2.5) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "constants with expression" do | ||||||
|  |     run(" | ||||||
|  |       A = 1 + 1 | ||||||
|  |       A | ||||||
|  |     ").to_i.should eq(2) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "finds global constant" do | ||||||
|  |     run(" | ||||||
|  |       A = 1 | ||||||
|  |  | ||||||
|  |       class Foo | ||||||
|  |         def foo | ||||||
|  |           A | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       Foo.new.foo | ||||||
|  |     ").to_i.should eq(1) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "define a constant in lib" do | ||||||
|  |     run("lib Foo; A = 1; end; Foo::A").to_i.should eq(1) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "invokes block in const" do | ||||||
|  |     run("require \"prelude\"; A = [\"1\"].map { |x| x.to_i }; A[0]").to_i.should eq(1) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "declare constants in right order" do | ||||||
|  |     run("A = 1 + 1; B = true ? A : 0; B").to_i.should eq(2) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "uses correct types lookup" do | ||||||
|  |     run(" | ||||||
|  |       module A | ||||||
|  |         class B | ||||||
|  |           def foo | ||||||
|  |             1 | ||||||
|  |           end | ||||||
|  |         end | ||||||
|  |  | ||||||
|  |         C = B.new; | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       def foo | ||||||
|  |         A::C.foo | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       foo | ||||||
|  |       ").to_i.should eq(1) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "codegens variable assignment in const" do | ||||||
|  |     run(" | ||||||
|  |       class Foo | ||||||
|  |         def initialize(@x) | ||||||
|  |         end | ||||||
|  |  | ||||||
|  |         def x | ||||||
|  |           @x | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       A = begin | ||||||
|  |             f = Foo.new(1) | ||||||
|  |             f | ||||||
|  |           end | ||||||
|  |  | ||||||
|  |       def foo | ||||||
|  |         A.x | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       foo | ||||||
|  |       ").to_i.should eq(1) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "declaring var" do | ||||||
|  |     run(" | ||||||
|  |       BAR = begin | ||||||
|  |         a = 1 | ||||||
|  |         while 1 == 2 | ||||||
|  |           b = 2 | ||||||
|  |         end | ||||||
|  |         a | ||||||
|  |       end | ||||||
|  |       class Foo | ||||||
|  |         def compile | ||||||
|  |           BAR | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       Foo.new.compile | ||||||
|  |       ").to_i.should eq(1) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "initialize const that might raise an exception" do | ||||||
|  |     run(" | ||||||
|  |       require \"prelude\" | ||||||
|  |       CONST = (raise \"OH NO\" if 1 == 2) | ||||||
|  |  | ||||||
|  |       def doit | ||||||
|  |         CONST | ||||||
|  |       rescue | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       doit.nil? | ||||||
|  |     ").to_b.should be_true | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										79
									
								
								samples/Crystal/declare_var_spec.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								samples/Crystal/declare_var_spec.cr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | |||||||
|  | #!/usr/bin/env bin/crystal --run | ||||||
|  | require "../../spec_helper" | ||||||
|  |  | ||||||
|  | describe "Type inference: declare var" do | ||||||
|  |   it "types declare var" do | ||||||
|  |     assert_type("a :: Int32") { int32 } | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "types declare var and reads it" do | ||||||
|  |     assert_type("a :: Int32; a") { int32 } | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "types declare var and changes its type" do | ||||||
|  |     assert_type("a :: Int32; while 1 == 2; a = 'a'; end; a") { union_of(int32, char) } | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "declares instance var which appears in initialize" do | ||||||
|  |     result = assert_type(" | ||||||
|  |       class Foo | ||||||
|  |         @x :: Int32 | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       Foo.new") { types["Foo"] } | ||||||
|  |  | ||||||
|  |     mod = result.program | ||||||
|  |  | ||||||
|  |     foo = mod.types["Foo"] as NonGenericClassType | ||||||
|  |     foo.instance_vars["@x"].type.should eq(mod.int32) | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "declares instance var of generic class" do | ||||||
|  |     result = assert_type(" | ||||||
|  |       class Foo(T) | ||||||
|  |         @x :: T | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       Foo(Int32).new") do | ||||||
|  |         foo = types["Foo"] as GenericClassType | ||||||
|  |         foo_i32 = foo.instantiate([int32] of Type | ASTNode) | ||||||
|  |         foo_i32.lookup_instance_var("@x").type.should eq(int32) | ||||||
|  |         foo_i32 | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "declares instance var of generic class after reopen" do | ||||||
|  |     result = assert_type(" | ||||||
|  |       class Foo(T) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       f = Foo(Int32).new | ||||||
|  |  | ||||||
|  |       class Foo(T) | ||||||
|  |         @x :: T | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       f") do | ||||||
|  |         foo = types["Foo"] as GenericClassType | ||||||
|  |         foo_i32 = foo.instantiate([int32] of Type | ASTNode) | ||||||
|  |         foo_i32.lookup_instance_var("@x").type.should eq(int32) | ||||||
|  |         foo_i32 | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   it "declares an instance variable in initialize" do | ||||||
|  |     assert_type(" | ||||||
|  |       class Foo | ||||||
|  |         def initialize | ||||||
|  |           @x :: Int32 | ||||||
|  |         end | ||||||
|  |  | ||||||
|  |         def x | ||||||
|  |           @x | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       Foo.new.x | ||||||
|  |       ") { int32 } | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										515
									
								
								samples/Crystal/transformer.cr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										515
									
								
								samples/Crystal/transformer.cr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,515 @@ | |||||||
|  | module Crystal | ||||||
|  |   class ASTNode | ||||||
|  |     def transform(transformer) | ||||||
|  |       transformer.before_transform self | ||||||
|  |       node = transformer.transform self | ||||||
|  |       transformer.after_transform self | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  |  | ||||||
|  |   class Transformer | ||||||
|  |     def before_transform(node) | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def after_transform(node) | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Expressions) | ||||||
|  |       exps = [] of ASTNode | ||||||
|  |       node.expressions.each do |exp| | ||||||
|  |         new_exp = exp.transform(self) | ||||||
|  |         if new_exp | ||||||
|  |           if new_exp.is_a?(Expressions) | ||||||
|  |             exps.concat new_exp.expressions | ||||||
|  |           else | ||||||
|  |             exps << new_exp | ||||||
|  |           end | ||||||
|  |         end | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       if exps.length == 1 | ||||||
|  |         exps[0] | ||||||
|  |       else | ||||||
|  |         node.expressions = exps | ||||||
|  |         node | ||||||
|  |       end | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Call) | ||||||
|  |       if node_obj = node.obj | ||||||
|  |         node.obj = node_obj.transform(self) | ||||||
|  |       end | ||||||
|  |       transform_many node.args | ||||||
|  |  | ||||||
|  |       if node_block = node.block | ||||||
|  |         node.block = node_block.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       if node_block_arg = node.block_arg | ||||||
|  |         node.block_arg = node_block_arg.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : And) | ||||||
|  |       node.left = node.left.transform(self) | ||||||
|  |       node.right = node.right.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Or) | ||||||
|  |       node.left = node.left.transform(self) | ||||||
|  |       node.right = node.right.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : StringInterpolation) | ||||||
|  |       transform_many node.expressions | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : ArrayLiteral) | ||||||
|  |       transform_many node.elements | ||||||
|  |  | ||||||
|  |       if node_of = node.of | ||||||
|  |         node.of = node_of.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : HashLiteral) | ||||||
|  |       transform_many node.keys | ||||||
|  |       transform_many node.values | ||||||
|  |  | ||||||
|  |       if of_key = node.of_key | ||||||
|  |         node.of_key = of_key.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       if of_value = node.of_value | ||||||
|  |         node.of_value = of_value.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : If) | ||||||
|  |       node.cond = node.cond.transform(self) | ||||||
|  |       node.then = node.then.transform(self) | ||||||
|  |       node.else = node.else.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Unless) | ||||||
|  |       node.cond = node.cond.transform(self) | ||||||
|  |       node.then = node.then.transform(self) | ||||||
|  |       node.else = node.else.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : IfDef) | ||||||
|  |       node.cond = node.cond.transform(self) | ||||||
|  |       node.then = node.then.transform(self) | ||||||
|  |       node.else = node.else.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : MultiAssign) | ||||||
|  |       transform_many node.targets | ||||||
|  |       transform_many node.values | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : SimpleOr) | ||||||
|  |       node.left = node.left.transform(self) | ||||||
|  |       node.right = node.right.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Def) | ||||||
|  |       transform_many node.args | ||||||
|  |       node.body = node.body.transform(self) | ||||||
|  |  | ||||||
|  |       if receiver = node.receiver | ||||||
|  |         node.receiver = receiver.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       if block_arg = node.block_arg | ||||||
|  |         node.block_arg = block_arg.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Macro) | ||||||
|  |       transform_many node.args | ||||||
|  |       node.body = node.body.transform(self) | ||||||
|  |  | ||||||
|  |       if receiver = node.receiver | ||||||
|  |         node.receiver = receiver.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       if block_arg = node.block_arg | ||||||
|  |         node.block_arg = block_arg.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : PointerOf) | ||||||
|  |       node.exp = node.exp.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : SizeOf) | ||||||
|  |       node.exp = node.exp.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : InstanceSizeOf) | ||||||
|  |       node.exp = node.exp.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : IsA) | ||||||
|  |       node.obj = node.obj.transform(self) | ||||||
|  |       node.const = node.const.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : RespondsTo) | ||||||
|  |       node.obj = node.obj.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Case) | ||||||
|  |       node.cond = node.cond.transform(self) | ||||||
|  |       transform_many node.whens | ||||||
|  |  | ||||||
|  |       if node_else = node.else | ||||||
|  |         node.else = node_else.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : When) | ||||||
|  |       transform_many node.conds | ||||||
|  |       node.body = node.body.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : ImplicitObj) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : ClassDef) | ||||||
|  |       node.body = node.body.transform(self) | ||||||
|  |  | ||||||
|  |       if superclass = node.superclass | ||||||
|  |         node.superclass = superclass.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : ModuleDef) | ||||||
|  |       node.body = node.body.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : While) | ||||||
|  |       node.cond = node.cond.transform(self) | ||||||
|  |       node.body = node.body.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Generic) | ||||||
|  |       node.name = node.name.transform(self) | ||||||
|  |       transform_many node.type_vars | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : ExceptionHandler) | ||||||
|  |       node.body = node.body.transform(self) | ||||||
|  |       transform_many node.rescues | ||||||
|  |  | ||||||
|  |       if node_ensure = node.ensure | ||||||
|  |         node.ensure = node_ensure.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Rescue) | ||||||
|  |       node.body = node.body.transform(self) | ||||||
|  |       transform_many node.types | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Union) | ||||||
|  |       transform_many node.types | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Hierarchy) | ||||||
|  |       node.name = node.name.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Metaclass) | ||||||
|  |       node.name = node.name.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Arg) | ||||||
|  |       if default_value = node.default_value | ||||||
|  |         node.default_value = default_value.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       if restriction = node.restriction | ||||||
|  |         node.restriction = restriction.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : BlockArg) | ||||||
|  |       node.fun = node.fun.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Fun) | ||||||
|  |       transform_many node.inputs | ||||||
|  |  | ||||||
|  |       if output = node.output | ||||||
|  |         node.output = output.transform(self) | ||||||
|  |       end | ||||||
|  |  | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Block) | ||||||
|  |       node.args.map! { |exp| exp.transform(self) as Var } | ||||||
|  |       node.body = node.body.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : FunLiteral) | ||||||
|  |       node.def.body = node.def.body.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : FunPointer) | ||||||
|  |       if obj = node.obj | ||||||
|  |         node.obj = obj.transform(self) | ||||||
|  |       end | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Return) | ||||||
|  |       transform_many node.exps | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Break) | ||||||
|  |       transform_many node.exps | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Next) | ||||||
|  |       transform_many node.exps | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Yield) | ||||||
|  |       if scope = node.scope | ||||||
|  |         node.scope = scope.transform(self) | ||||||
|  |       end | ||||||
|  |       transform_many node.exps | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Include) | ||||||
|  |       node.name = node.name.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Extend) | ||||||
|  |       node.name = node.name.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : RangeLiteral) | ||||||
|  |       node.from = node.from.transform(self) | ||||||
|  |       node.to = node.to.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Assign) | ||||||
|  |       node.target = node.target.transform(self) | ||||||
|  |       node.value = node.value.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Nop) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : NilLiteral) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : BoolLiteral) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : NumberLiteral) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : CharLiteral) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : StringLiteral) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : SymbolLiteral) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : RegexLiteral) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Var) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : MetaVar) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : InstanceVar) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : ClassVar) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Global) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Require) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Path) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : LibDef) | ||||||
|  |       node.body = node.body.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : FunDef) | ||||||
|  |       if body = node.body | ||||||
|  |         node.body = body.transform(self) | ||||||
|  |       end | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : TypeDef) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : StructDef) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : UnionDef) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : EnumDef) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : ExternalVar) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : IndirectRead) | ||||||
|  |       node.obj = node.obj.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : IndirectWrite) | ||||||
|  |       node.obj = node.obj.transform(self) | ||||||
|  |       node.value = node.value.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : TypeOf) | ||||||
|  |       transform_many node.expressions | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Primitive) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Not) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : TypeFilteredNode) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : TupleLiteral) | ||||||
|  |       transform_many node.exps | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Cast) | ||||||
|  |       node.obj = node.obj.transform(self) | ||||||
|  |       node.to = node.to.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : DeclareVar) | ||||||
|  |       node.var = node.var.transform(self) | ||||||
|  |       node.declared_type = node.declared_type.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Alias) | ||||||
|  |       node.value = node.value.transform(self) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : TupleIndexer) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform(node : Attribute) | ||||||
|  |       node | ||||||
|  |     end | ||||||
|  |  | ||||||
|  |     def transform_many(exps) | ||||||
|  |       exps.map! { |exp| exp.transform(self) } if exps | ||||||
|  |     end | ||||||
|  |   end | ||||||
|  | end | ||||||
							
								
								
									
										580
									
								
								samples/Cycript/utils.cy
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										580
									
								
								samples/Cycript/utils.cy
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,580 @@ | |||||||
|  | (function(utils) { | ||||||
|  | 	// Load C functions declared in utils.loadFuncs | ||||||
|  | 	var shouldLoadCFuncs = true; | ||||||
|  | 	// Expose the C functions to cycript's global scope | ||||||
|  | 	var shouldExposeCFuncs = true; | ||||||
|  | 	// Expose C constants to cycript's global scope | ||||||
|  | 	var shouldExposeConsts = true; | ||||||
|  | 	// Expose functions defined here to cycript's global scope | ||||||
|  | 	var shouldExposeFuncs = true; | ||||||
|  | 	// Which functions to expose | ||||||
|  | 	var funcsToExpose = ["exec", "include", "sizeof", "logify", "apply", "str2voidPtr", "voidPtr2str", "double2voidPtr", "voidPtr2double", "isMemoryReadable", "isObject", "makeStruct"]; | ||||||
|  | 	 | ||||||
|  | 	// C functions that utils.loadFuncs loads | ||||||
|  | 	var CFuncsDeclarations = [ | ||||||
|  | 		// <stdlib.h> | ||||||
|  | 		"void *calloc(size_t num, size_t size)", | ||||||
|  | 		// <string.h> | ||||||
|  | 		"char *strcpy(char *restrict dst, const char *restrict src)", | ||||||
|  | 		"char *strdup(const char *s1)", | ||||||
|  | 		"void* memset(void* dest, int ch, size_t count)", | ||||||
|  | 		// <stdio.h> | ||||||
|  | 		"FILE *fopen(const char *, const char *)", | ||||||
|  | 		"int fclose(FILE *)", | ||||||
|  | 		"size_t fread(void *restrict, size_t, size_t, FILE *restrict)", | ||||||
|  | 		"size_t fwrite(const void *restrict, size_t, size_t, FILE *restrict)", | ||||||
|  | 		// <mach.h> | ||||||
|  | 		"mach_port_t mach_task_self()", | ||||||
|  | 		"kern_return_t task_for_pid(mach_port_name_t target_tport, int pid, mach_port_name_t *tn)", | ||||||
|  | 		"kern_return_t mach_vm_protect(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, boolean_t set_maximum, vm_prot_t new_protection)", | ||||||
|  | 		"kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, vm_offset_t data, mach_msg_type_number_t dataCnt)", | ||||||
|  | 		"kern_return_t mach_vm_read(vm_map_t target_task, mach_vm_address_t address, mach_vm_size_t size, vm_offset_t *data, mach_msg_type_number_t *dataCnt)", | ||||||
|  | 	]; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		Replacement for eval that can handle @encode etc. | ||||||
|  | 		 | ||||||
|  | 		Usage: | ||||||
|  | 			cy# utils.exec("@encode(void *(int, char))") | ||||||
|  | 			@encode(void*(int,char)) | ||||||
|  | 	*/ | ||||||
|  | 	utils.exec = function(str) { | ||||||
|  | 		var mkdir = @encode(int (const char *, int))(dlsym(RTLD_DEFAULT, "mkdir")); | ||||||
|  | 		var tempnam = @encode(char *(const char *, const char *))(dlsym(RTLD_DEFAULT, "tempnam")); | ||||||
|  | 		var fopen = @encode(void *(const char *, const char *))(dlsym(RTLD_DEFAULT, "fopen")); | ||||||
|  | 		var fclose = @encode(int (void *))(dlsym(RTLD_DEFAULT, "fclose")); | ||||||
|  | 		var fwrite = @encode(int (const char *, int, int, void *))(dlsym(RTLD_DEFAULT, "fwrite")); | ||||||
|  | 		var symlink = @encode(int (const char *, const char *))(dlsym(RTLD_DEFAULT, "symlink")); | ||||||
|  | 		var unlink = @encode(int (const char *))(dlsym(RTLD_DEFAULT, "unlink")); | ||||||
|  | 		var getenv = @encode(const char *(const char *))(dlsym(RTLD_DEFAULT, "getenv")); | ||||||
|  | 		var setenv = @encode(int (const char *, const char *, int))(dlsym(RTLD_DEFAULT, "setenv")); | ||||||
|  | 		 | ||||||
|  | 		var libdir = "/usr/lib/cycript0.9"; | ||||||
|  | 		var dir = libdir + "/tmp"; | ||||||
|  |  | ||||||
|  | 		mkdir(dir, 0777); | ||||||
|  | 		 | ||||||
|  | 		// This is needed because tempnam seems to ignore the first argument on i386 | ||||||
|  | 		var old_tmpdir = getenv("TMPDIR"); | ||||||
|  | 		setenv("TMPDIR", dir, 1); | ||||||
|  |  | ||||||
|  | 		// No freeing :( | ||||||
|  | 		var f = tempnam(dir, "exec-"); | ||||||
|  | 		setenv("TMPDIR", old_tmpdir, 1); | ||||||
|  | 		if(!f) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		symlink(f, f + ".cy"); | ||||||
|  | 		 | ||||||
|  | 		str = "exports.result = " + str; | ||||||
|  |  | ||||||
|  | 		var handle = fopen(f, "w"); | ||||||
|  | 		fwrite(str, str.length, 1, handle); | ||||||
|  | 		fclose(handle); | ||||||
|  | 		 | ||||||
|  | 		var r; | ||||||
|  | 		var except = null; | ||||||
|  | 		try { | ||||||
|  | 			r = require(f.replace(libdir + "/", "")); | ||||||
|  | 		} catch(e) { | ||||||
|  | 			except = e; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		unlink(f + ".cy"); | ||||||
|  | 		unlink(f); | ||||||
|  | 		 | ||||||
|  | 		if(except !== null) { | ||||||
|  | 			throw except; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return r.result; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		Applies known typedefs | ||||||
|  | 		Used in utils.include and utils.makeStruct | ||||||
|  | 		 | ||||||
|  | 		Usage: | ||||||
|  | 			cy# utils.applyTypedefs("mach_vm_address_t") | ||||||
|  | 			"uint64_t" | ||||||
|  | 	*/ | ||||||
|  | 	utils.applyTypedefs = function(str) { | ||||||
|  | 		var typedefs = { | ||||||
|  | 			"struct": "", | ||||||
|  | 			"restrict": "", | ||||||
|  | 			"FILE": "void", | ||||||
|  | 			"size_t": "uint64_t", | ||||||
|  | 			"uintptr_t": "unsigned long", | ||||||
|  | 			"kern_return_t": "int", | ||||||
|  | 			"mach_port_t": "unsigned int", | ||||||
|  | 			"mach_port_name_t": "unsigned int", | ||||||
|  | 			"vm_offset_t": "unsigned long", | ||||||
|  | 			"vm_size_t": "unsigned long", | ||||||
|  | 			"mach_vm_address_t": "uint64_t", | ||||||
|  | 			"mach_vm_offset_t": "uint64_t", | ||||||
|  | 			"mach_vm_size_t": "uint64_t", | ||||||
|  | 			"vm_map_offset_t": "uint64_t", | ||||||
|  | 			"vm_map_address_t": "uint64_t", | ||||||
|  | 			"vm_map_size_t": "uint64_t", | ||||||
|  | 			"mach_port_context_t": "uint64_t", | ||||||
|  | 			"vm_map_t": "unsigned int", | ||||||
|  | 			"boolean_t": "unsigned int", | ||||||
|  | 			"vm_prot_t": "int", | ||||||
|  | 			"mach_msg_type_number_t": "unsigned int", | ||||||
|  | 			"cpu_type_t": "int", | ||||||
|  | 			"cpu_subtype_t": "int", | ||||||
|  | 			"cpu_threadtype_t": "int", | ||||||
|  | 		}; | ||||||
|  | 		 | ||||||
|  | 		for(var k in typedefs) { | ||||||
|  | 			str = str.replace(new RegExp("(\\s|\\*|,|\\(|^)" + k + "(\\s|\\*|,|\\)|$)", "g"), "$1" + typedefs[k] + "$2"); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		return str; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		Parses a C function declaration and returns the function name and cycript type | ||||||
|  | 		If load is true, tries to load it into cycript using utils.exec | ||||||
|  | 		 | ||||||
|  | 		Usage: | ||||||
|  | 			cy# var str = "void *calloc(size_t num, size_t size)"; | ||||||
|  | 			"void *calloc(size_t num, size_t size)" | ||||||
|  | 			cy# utils.include(str) | ||||||
|  | 			["calloc","@encode(void *(uint64_t num,  uint64_t size))(140735674376857)"] | ||||||
|  | 			cy# var ret = utils.include(str, true) | ||||||
|  | 			["calloc",0x7fff93e0e299] | ||||||
|  | 			cy# ret[1].type | ||||||
|  | 			@encode(void*(unsigned long long int,unsigned long long int)) | ||||||
|  | 			cy# ret[1](100, 1) | ||||||
|  | 			0x100444100 | ||||||
|  | 	*/ | ||||||
|  | 	utils.include = function(str, load) { | ||||||
|  | 		var re = /^\s*([^(]*(?:\s+|\*))(\w*)\s*\(([^)]*)\)\s*;?\s*$/; | ||||||
|  | 		var match = re.exec(str); | ||||||
|  | 		if(!match) { | ||||||
|  | 			return -1; | ||||||
|  | 		} | ||||||
|  | 		var rType = utils.applyTypedefs(match[1]); | ||||||
|  | 		var name = match[2]; | ||||||
|  | 		var args = match[3]; | ||||||
|  |  | ||||||
|  | 		var argsRe = /([^,]+)(?:,|$)/g; | ||||||
|  | 		var argsTypes = []; | ||||||
|  | 		while((match = argsRe.exec(args)) !== null) { | ||||||
|  | 			var type = utils.applyTypedefs(match[1]); | ||||||
|  | 			argsTypes.push(type); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		var encodeString = "@encode("; | ||||||
|  | 		encodeString += rType + "("; | ||||||
|  | 		encodeString += argsTypes.join(", ") + "))"; | ||||||
|  |  | ||||||
|  | 		var fun = dlsym(RTLD_DEFAULT, name); | ||||||
|  | 		if(fun !== null) { | ||||||
|  | 			encodeString += "(" + fun + ")"; | ||||||
|  | 			if(load) { | ||||||
|  | 				return [name, utils.exec(encodeString)]; | ||||||
|  | 			} | ||||||
|  | 		} else if(load) { | ||||||
|  | 			throw "Function couldn't be found with dlsym!"; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return [name, encodeString]; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		Loads the function declaration in the defs array using utils.exec and exposes to cycript's global scope | ||||||
|  | 		Is automatically called if shouldLoadCFuncs is true | ||||||
|  | 	*/ | ||||||
|  | 	utils.funcs = {}; | ||||||
|  | 	utils.loadfuncs = function(expose) { | ||||||
|  | 		for(var i = 0; i < CFuncsDeclarations.length; i++) { | ||||||
|  | 			try { | ||||||
|  | 				var o = utils.include(CFuncsDeclarations[i], true); | ||||||
|  | 				utils.funcs[o[0]] = o[1]; | ||||||
|  | 				if(expose) { | ||||||
|  | 					Cycript.all[o[0]] = o[1]; | ||||||
|  | 				} | ||||||
|  | 			} catch(e) { | ||||||
|  | 				system.print("Failed to load function: " + i); | ||||||
|  | 				try { | ||||||
|  | 					system.print(utils.include(CFuncsDeclarations[i])); | ||||||
|  | 				} catch(e2) { | ||||||
|  | 					 | ||||||
|  | 				} | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		Calculates the size of a type like the C operator sizeof | ||||||
|  | 		 | ||||||
|  | 		Usage: | ||||||
|  | 			cy# utils.sizeof(int) | ||||||
|  | 			4 | ||||||
|  | 			cy# utils.sizeof(@encode(void *)) | ||||||
|  | 			8 | ||||||
|  | 			cy# utils.sizeof("mach_vm_address_t") | ||||||
|  | 			8 | ||||||
|  | 	*/ | ||||||
|  | 	utils.sizeof = function(type) { | ||||||
|  | 		if(typeof type === "string") { | ||||||
|  | 			type = utils.applyTypedefs(type); | ||||||
|  | 			type = utils.exec("@encode(" + type + ")"); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		// (const) char * has "infinite" preceision | ||||||
|  | 		if(type.toString().slice(-1) === "*") { | ||||||
|  | 			return utils.sizeof(@encode(void *)); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		// float and double | ||||||
|  | 		if(type.toString() === @encode(float).toString()) { | ||||||
|  | 			return 4; | ||||||
|  | 		} else if (type.toString() === @encode(double).toString()) { | ||||||
|  | 			return 8; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		var typeInstance = type(0); | ||||||
|  | 		 | ||||||
|  | 		if(typeInstance instanceof Object) { | ||||||
|  | 			// Arrays | ||||||
|  | 			if("length" in typeInstance) { | ||||||
|  | 				return typeInstance.length * utils.sizeof(typeInstance.type); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			// Structs | ||||||
|  | 			if(typeInstance.toString() === "[object Struct]") { | ||||||
|  | 				var typeStr = type.toString(); | ||||||
|  | 				var arrayTypeStr = "[2" + typeStr + "]"; | ||||||
|  | 				var arrayType = new Type(arrayTypeStr); | ||||||
|  | 				 | ||||||
|  | 				var arrayInstance = new arrayType; | ||||||
|  | 				 | ||||||
|  | 				return @encode(void *)(&(arrayInstance[1])) - @encode(void *)(&(arrayInstance[0])); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		for(var i = 0; i < 5; i++) { | ||||||
|  | 			var maxSigned = Math.pow(2, 8 * Math.pow(2, i) - 1) - 1; | ||||||
|  | 			if(i === 3) { | ||||||
|  | 				// Floating point fix ;^) | ||||||
|  | 				maxSigned /= 1000; | ||||||
|  | 			} | ||||||
|  |  | ||||||
|  | 			// can't use !== or sizeof(void *) === 0.5 | ||||||
|  | 			if(type(maxSigned) != maxSigned) { | ||||||
|  | 				return Math.pow(2, i - 1); | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		Logs a specific message sent to an instance of a class like logify.pl in theos | ||||||
|  | 		Requires Cydia Substrate (com.saurik.substrate.MS) and NSLog (org.cycript.NSLog) modules | ||||||
|  | 		Returns the old message returned by MS.hookMessage (Note: this is not just the old message!) | ||||||
|  | 		 | ||||||
|  | 		Usage: | ||||||
|  | 			cy# var oldm = utils.logify(objc_getMetaClass(NSNumber), @selector(numberWithDouble:)) | ||||||
|  | 			... | ||||||
|  | 			cy# var n = [NSNumber numberWithDouble:1.5] | ||||||
|  | 			2014-07-28 02:26:39.805 cycript[71213:507] +[<NSNumber: 0x10032d0c4> numberWithDouble:1.5] | ||||||
|  | 			2014-07-28 02:26:39.806 cycript[71213:507]  = 1.5 | ||||||
|  | 			@1.5 | ||||||
|  | 	*/ | ||||||
|  | 	utils.logify = function(cls, sel) { | ||||||
|  | 		@import com.saurik.substrate.MS; | ||||||
|  | 		@import org.cycript.NSLog; | ||||||
|  | 		 | ||||||
|  | 		var oldm = {}; | ||||||
|  | 		 | ||||||
|  | 		MS.hookMessage(cls, sel, function() { | ||||||
|  | 			var args = [].slice.call(arguments); | ||||||
|  | 			 | ||||||
|  | 			var selFormat = sel.toString().replace(/:/g, ":%@ ").trim(); | ||||||
|  | 			var logFormat = "%@[<%@: 0x%@> " + selFormat + "]"; | ||||||
|  | 			 | ||||||
|  | 			var standardArgs = [logFormat, class_isMetaClass(cls)? "+": "-", cls.toString(), (&this).valueOf().toString(16)]; | ||||||
|  | 			var logArgs = standardArgs.concat(args); | ||||||
|  | 			 | ||||||
|  | 			NSLog.apply(null, logArgs); | ||||||
|  | 			 | ||||||
|  | 			var r = oldm->apply(this, arguments); | ||||||
|  | 			 | ||||||
|  | 			if(r !== undefined) { | ||||||
|  | 				NSLog(" = %@", r); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			return r; | ||||||
|  | 		}, oldm); | ||||||
|  | 		 | ||||||
|  | 		return oldm; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		Calls a C function by providing its name and arguments | ||||||
|  | 		Doesn't support structs | ||||||
|  | 		Return value is always a void pointer | ||||||
|  | 		 | ||||||
|  | 		Usage: | ||||||
|  | 			cy# utils.apply("printf", ["%s %.3s, %d -> %c, float: %f\n", "foo", "barrrr", 97, 97, 1.5]) | ||||||
|  | 			foo bar, 97 -> a, float: 1.500000 | ||||||
|  | 			0x22 | ||||||
|  | 	*/ | ||||||
|  | 	utils.apply = function(fun, args) { | ||||||
|  | 		if(!(args instanceof Array)) { | ||||||
|  | 			throw "Args needs to be an array!"; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		var argc = args.length; | ||||||
|  | 		var voidPtr = @encode(void *); | ||||||
|  | 		var argTypes = []; | ||||||
|  | 		for(var i = 0; i < argc; i++) { | ||||||
|  | 			var argType = voidPtr; | ||||||
|  | 			 | ||||||
|  | 			var arg = args[i]; | ||||||
|  | 			if(typeof arg === "string") { | ||||||
|  | 				argType = @encode(char *); | ||||||
|  | 			} | ||||||
|  | 			if(typeof arg === "number" && arg % 1 !== 0) { | ||||||
|  | 				argType = @encode(double); | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			argTypes.push(argType); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		var type = voidPtr.functionWith.apply(voidPtr, argTypes); | ||||||
|  | 		 | ||||||
|  | 		if(typeof fun === "string") { | ||||||
|  | 			fun = dlsym(RTLD_DEFAULT, fun); | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if(!fun) { | ||||||
|  | 			throw "Function not found!"; | ||||||
|  | 		} | ||||||
|  |  | ||||||
|  | 		return type(fun).apply(null, args); | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		Converts a string (char *) to a void pointer (void *) | ||||||
|  | 		You can't cast to strings to void pointers and vice versa in cycript. Blame saurik. | ||||||
|  | 		 | ||||||
|  | 		Usage: | ||||||
|  | 			cy# var voidPtr = utils.str2voidPtr("foobar") | ||||||
|  | 			0x100331590 | ||||||
|  | 			cy# utils.voidPtr2str(voidPtr) | ||||||
|  | 			"foobar" | ||||||
|  | 	*/ | ||||||
|  | 	utils.str2voidPtr = function(str) { | ||||||
|  | 		var strdup = @encode(void *(char *))(dlsym(RTLD_DEFAULT, "strdup")); | ||||||
|  | 		return strdup(str); | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		The inverse function of str2voidPtr | ||||||
|  | 	*/ | ||||||
|  | 	utils.voidPtr2str = function(voidPtr) { | ||||||
|  | 		var strdup = @encode(char *(void *))(dlsym(RTLD_DEFAULT, "strdup")); | ||||||
|  | 		return strdup(voidPtr); | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		Converts a double into a void pointer | ||||||
|  | 		This can be used to view the binary representation of a floating point number | ||||||
|  | 		 | ||||||
|  | 		Usage: | ||||||
|  | 			cy# var n = utils.double2voidPtr(-1.5) | ||||||
|  | 			0xbff8000000000000 | ||||||
|  | 			cy# utils.voidPtr2double(n) | ||||||
|  | 			-1.5 | ||||||
|  | 	*/ | ||||||
|  | 	utils.double2voidPtr = function(n) { | ||||||
|  | 		var doublePtr = new double; | ||||||
|  | 		*doublePtr = n; | ||||||
|  | 		 | ||||||
|  | 		var voidPtrPtr = @encode(void **)(doublePtr); | ||||||
|  | 		 | ||||||
|  | 		return *voidPtrPtr; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		The inverse function of double2voidPtr | ||||||
|  | 	*/ | ||||||
|  | 	utils.voidPtr2double = function(voidPtr) { | ||||||
|  | 		var voidPtrPtr = new @encode(void **); | ||||||
|  | 		*voidPtrPtr = voidPtr; | ||||||
|  | 		 | ||||||
|  | 		var doublePtr = @encode(double *)(voidPtrPtr); | ||||||
|  | 		 | ||||||
|  | 		return *doublePtr; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		Determines in a safe way if a memory location is readable | ||||||
|  | 		 | ||||||
|  | 		Usage: | ||||||
|  | 			cy# utils.isMemoryReadable(0) | ||||||
|  | 			false | ||||||
|  | 			cy# utils.isMemoryReadable(0x1337) | ||||||
|  | 			false | ||||||
|  | 			cy# utils.isMemoryReadable(NSObject) | ||||||
|  | 			true | ||||||
|  | 			cy# var a = malloc(100); utils.isMemoryReadable(a) | ||||||
|  | 			true | ||||||
|  | 	*/ | ||||||
|  | 	utils.isMemoryReadable = function(ptr) { | ||||||
|  | 		if(typeof ptr === "string") { | ||||||
|  | 			return true; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		var fds = new @encode(int [2]); | ||||||
|  | 		utils.apply("pipe", [fds]); | ||||||
|  | 		var result = utils.apply("write", [fds[1], ptr, 1]) == 1; | ||||||
|  | 		 | ||||||
|  | 		utils.apply("close", [fds[0]]); | ||||||
|  | 		utils.apply("close", [fds[1]]); | ||||||
|  | 		 | ||||||
|  | 		return result; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		Determines in a safe way if the memory location contains an Objective-C object | ||||||
|  |  | ||||||
|  | 		Usage: | ||||||
|  | 			cy# utils.isObject(0) | ||||||
|  | 			false | ||||||
|  | 			cy# utils.isObject(0x1337) | ||||||
|  | 			false | ||||||
|  | 			cy# utils.isObject(NSObject) | ||||||
|  | 			true | ||||||
|  | 			cy# utils.isObject(objc_getMetaClass(NSObject)) | ||||||
|  | 			true | ||||||
|  | 			cy# utils.isObject([new NSObject init]) | ||||||
|  | 			true | ||||||
|  | 			cy# var a = malloc(100); utils.isObject(a) | ||||||
|  | 			false | ||||||
|  | 			cy# *@encode(void **)(a) = NSObject; utils.isObject(a) | ||||||
|  | 			true | ||||||
|  | 	*/ | ||||||
|  | 	utils.isObject = function(obj) { | ||||||
|  | 		obj = @encode(void *)(obj); | ||||||
|  | 		var lastObj = -1; | ||||||
|  | 		 | ||||||
|  | 		function objc_isa_ptr(obj) { | ||||||
|  | 			// See http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html | ||||||
|  | 			var objc_debug_isa_class_mask = 0x00000001fffffffa; | ||||||
|  | 			obj = (obj & 1)? (obj & objc_debug_isa_class_mask): obj; | ||||||
|  | 			 | ||||||
|  | 			if((obj & (utils.sizeof(@encode(void *)) - 1)) != 0) { | ||||||
|  | 				return null; | ||||||
|  | 			} else { | ||||||
|  | 				return obj; | ||||||
|  | 			} | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		function ptrValue(obj) { | ||||||
|  | 			return obj? obj.valueOf(): null; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		var foundMetaClass = false; | ||||||
|  | 		 | ||||||
|  | 		for(obj = objc_isa_ptr(obj); utils.isMemoryReadable(obj); ) { | ||||||
|  | 			obj = *@encode(void **)(obj); | ||||||
|  | 			 | ||||||
|  | 			if(ptrValue(obj) == ptrValue(lastObj)) { | ||||||
|  | 				foundMetaClass = true; | ||||||
|  | 				break; | ||||||
|  | 			} | ||||||
|  | 			 | ||||||
|  | 			lastObj = obj; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if(!foundMetaClass) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		if(lastObj === -1 || lastObj === null) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		var obj_class = objc_isa_ptr(@encode(void **)(obj)[1]); | ||||||
|  | 		 | ||||||
|  | 		if(!utils.isMemoryReadable(obj_class)) { | ||||||
|  | 			return false; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		var metaclass = objc_isa_ptr(@encode(void **)(obj_class)[0]); | ||||||
|  | 		var superclass = objc_isa_ptr(@encode(void **)(obj_class)[1]); | ||||||
|  | 		 | ||||||
|  | 		return ptrValue(obj) == ptrValue(metaclass) && superclass == null; | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	/* | ||||||
|  | 		Creates a cycript struct type from a C struct definition | ||||||
|  | 		 | ||||||
|  | 		Usage: | ||||||
|  | 			cy# var foo = makeStruct("int a; short b; char c; uint64_t d; double e;", "foo"); | ||||||
|  | 			@encode(foo) | ||||||
|  | 			cy# var f = new foo | ||||||
|  | 			&{a:0,b:0,c:0,d:0,e:0} | ||||||
|  | 			cy# f->a = 100; f | ||||||
|  | 			&{a:100,b:0,c:0,d:0,e:0} | ||||||
|  | 			cy# *@encode(int *)(f) | ||||||
|  | 			100 | ||||||
|  | 	*/ | ||||||
|  | 	utils.makeStruct = function(str, name) {		 | ||||||
|  | 		var fieldRe = /(?:\s|\n)*([^;]+\s*(?:\s|\*))([^;]+)\s*;/g; | ||||||
|  | 		 | ||||||
|  | 		if(!name) { | ||||||
|  | 			name = "struct" + Math.floor(Math.random() * 100000); | ||||||
|  | 		} | ||||||
|  | 		var typeStr = "{" + name + "="; | ||||||
|  | 		 | ||||||
|  | 		while((match = fieldRe.exec(str)) !== null) { | ||||||
|  | 			var fieldType = utils.applyTypedefs(match[1]); | ||||||
|  | 			var fieldName = match[2]; | ||||||
|  | 			var encodedType = utils.exec("@encode(" + fieldType + ")").toString(); | ||||||
|  | 			 | ||||||
|  | 			typeStr += '"' + fieldName + '"' + encodedType; | ||||||
|  | 		} | ||||||
|  | 		 | ||||||
|  | 		typeStr += "}"; | ||||||
|  | 		 | ||||||
|  | 		return new Type(typeStr); | ||||||
|  | 	}; | ||||||
|  | 	 | ||||||
|  | 	// Various constants | ||||||
|  | 	utils.constants = { | ||||||
|  | 		VM_PROT_NONE:       0x0, | ||||||
|  | 		VM_PROT_READ:       0x1, | ||||||
|  | 		VM_PROT_WRITE:      0x2, | ||||||
|  | 		VM_PROT_EXECUTE:    0x4, | ||||||
|  | 		VM_PROT_NO_CHANGE:  0x8, | ||||||
|  | 		VM_PROT_COPY:       0x10, | ||||||
|  | 		VM_PROT_WANTS_COPY: 0x10, | ||||||
|  | 		VM_PROT_IS_MASK:    0x40, | ||||||
|  | 	}; | ||||||
|  | 	var c = utils.constants; | ||||||
|  | 	c.VM_PROT_DEFAULT = c.VM_PROT_READ | c.VM_PROT_WRITE; | ||||||
|  | 	c.VM_PROT_ALL =     c.VM_PROT_READ | c.VM_PROT_WRITE | c.VM_PROT_EXECUTE; | ||||||
|  | 	 | ||||||
|  | 	if(shouldExposeConsts) { | ||||||
|  | 		for(var k in c) { | ||||||
|  | 			Cycript.all[k] = c[k]; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if(shouldExposeFuncs) { | ||||||
|  | 		for(var i = 0; i < funcsToExpose.length; i++) { | ||||||
|  | 			var name = funcsToExpose[i]; | ||||||
|  | 			Cycript.all[name] = utils[name]; | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 	 | ||||||
|  | 	if(shouldLoadCFuncs) { | ||||||
|  | 		utils.loadfuncs(shouldExposeCFuncs); | ||||||
|  | 	} | ||||||
|  | })(exports); | ||||||
							
								
								
									
										16
									
								
								samples/Dogescript/example.djs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								samples/Dogescript/example.djs
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | quiet | ||||||
|  |  wow  | ||||||
|  |     such language | ||||||
|  |   very syntax | ||||||
|  |         github recognized wow | ||||||
|  | loud | ||||||
|  |  | ||||||
|  | such language much friendly | ||||||
|  |     rly friendly is true | ||||||
|  |         plz console.loge with 'such friend, very inclusive' | ||||||
|  |     but | ||||||
|  |         plz console.loge with 'no love for doge' | ||||||
|  |     wow | ||||||
|  | wow | ||||||
|  |  | ||||||
|  | module.exports is language | ||||||
							
								
								
									
										31
									
								
								samples/E/Extends.E
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								samples/E/Extends.E
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | # from | ||||||
|  | # http://wiki.erights.org/wiki/Walnut/Ordinary_Programming/Objects_and_Functions | ||||||
|  | def makeVehicle(self) { | ||||||
|  |     def vehicle { | ||||||
|  |         to milesTillEmpty() { | ||||||
|  |             return self.milesPerGallon() * self.getFuelRemaining() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return vehicle | ||||||
|  | } | ||||||
|  |  | ||||||
|  | def makeCar() { | ||||||
|  |     var fuelRemaining := 20 | ||||||
|  |     def car extends makeVehicle(car) { | ||||||
|  |         to milesPerGallon() {return 19} | ||||||
|  |         to getFuelRemaining() {return fuelRemaining} | ||||||
|  |     } | ||||||
|  |     return car | ||||||
|  | } | ||||||
|  |  | ||||||
|  | def makeJet() { | ||||||
|  |     var fuelRemaining := 2000 | ||||||
|  |     def jet extends makeVehicle(jet) { | ||||||
|  |         to milesPerGallon() {return 2} | ||||||
|  |         to getFuelRemaining() {return fuelRemaining} | ||||||
|  |     } | ||||||
|  |     return jet | ||||||
|  | } | ||||||
|  |  | ||||||
|  | def car := makeCar() | ||||||
|  | println(`The car can go ${car.milesTillEmpty()} miles.`) | ||||||
							
								
								
									
										21
									
								
								samples/E/Functions.E
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								samples/E/Functions.E
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | # from | ||||||
|  | # http://wiki.erights.org/wiki/Walnut/Ordinary_Programming/Objects_and_Functions | ||||||
|  | def makeCar(var name) { | ||||||
|  |     var x := 0 | ||||||
|  |     var y := 0 | ||||||
|  |     def car { | ||||||
|  |         to moveTo(newX,newY) { | ||||||
|  |             x := newX | ||||||
|  |             y := newY | ||||||
|  |         } | ||||||
|  |         to getX() {return x} | ||||||
|  |         to getY() {return y} | ||||||
|  |         to setName(newName) {name := newName} | ||||||
|  |         to getName() {return name} | ||||||
|  |     }  | ||||||
|  |     return car | ||||||
|  | } | ||||||
|  | # Now use the makeCar function to make a car, which we will move and print | ||||||
|  | def sportsCar := makeCar("Ferrari") | ||||||
|  | sportsCar.moveTo(10,20) | ||||||
|  | println(`The car ${sportsCar.getName()} is at X location ${sportsCar.getX()}`) | ||||||
							
								
								
									
										69
									
								
								samples/E/Guards.E
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								samples/E/Guards.E
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | # from | ||||||
|  | # http://wiki.erights.org/wiki/Walnut/Advanced_Topics/Build_your_Own_Guards | ||||||
|  | def makeVOCPair(brandName :String) :near { | ||||||
|  |  | ||||||
|  |     var myTempContents := def none {} | ||||||
|  |  | ||||||
|  |     def brand { | ||||||
|  |         to __printOn(out :TextWriter) :void { | ||||||
|  |             out.print(brandName) | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     def ProveAuth { | ||||||
|  |         to __printOn(out :TextWriter) :void { | ||||||
|  |             out.print(`<$brandName prover>`) | ||||||
|  |         } | ||||||
|  |         to getBrand() :near { return brand } | ||||||
|  |         to coerce(specimen, optEjector) :near { | ||||||
|  |             def sealedBox { | ||||||
|  |                 to getBrand() :near { return brand } | ||||||
|  |                 to offerContent() :void { | ||||||
|  |                     myTempContents := specimen | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return sealedBox | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     def CheckAuth { | ||||||
|  |         to __printOn(out :TextWriter) :void { | ||||||
|  |             out.print(`<$brandName checker template>`) | ||||||
|  |         } | ||||||
|  |         to getBrand() :near { return brand } | ||||||
|  |         match [`get`, authList :any[]] { | ||||||
|  |             def checker { | ||||||
|  |                 to __printOn(out :TextWriter) :void { | ||||||
|  |                     out.print(`<$brandName checker>`) | ||||||
|  |                 } | ||||||
|  |                 to getBrand() :near { return brand } | ||||||
|  |                 to coerce(specimenBox, optEjector) :any { | ||||||
|  |                     myTempContents := null | ||||||
|  |                     if (specimenBox.__respondsTo("offerContent", 0)) { | ||||||
|  |                       # XXX Using __respondsTo/2 here is a kludge | ||||||
|  |                         specimenBox.offerContent() | ||||||
|  |                     } else { | ||||||
|  |                         myTempContents := specimenBox | ||||||
|  |                     } | ||||||
|  |                     for auth in authList { | ||||||
|  |                         if (auth == myTempContents) { | ||||||
|  |                             return auth | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                     myTempContents := none | ||||||
|  |                     throw.eject(optEjector, | ||||||
|  |                                 `Unmatched $brandName authorization`) | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         match [`__respondsTo`, [`get`, _]] { | ||||||
|  |             true | ||||||
|  |         } | ||||||
|  |         match [`__respondsTo`, [_, _]] { | ||||||
|  |             false | ||||||
|  |         } | ||||||
|  |         match [`__getAllegedType`, []] { | ||||||
|  |             null.__getAllegedType() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return [ProveAuth, CheckAuth] | ||||||
|  | } | ||||||
							
								
								
									
										14
									
								
								samples/E/IO.E
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								samples/E/IO.E
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | # E sample from | ||||||
|  | # http://wiki.erights.org/wiki/Walnut/Ordinary_Programming/InputOutput | ||||||
|  | #File objects for hardwired files: | ||||||
|  | def file1 := <file:myFile.txt> | ||||||
|  | def file2 := <file:/home/marcs/myFile.txt> | ||||||
|  |  | ||||||
|  | #Using a variable for a file name: | ||||||
|  | def filePath := "c:\\docs\\myFile.txt" | ||||||
|  | def file3 := <file>[filePath] | ||||||
|  |  | ||||||
|  | #Using a single character to specify a Windows drive | ||||||
|  | def file4 := <file:c:/docs/myFile.txt> | ||||||
|  | def file5 := <c:/docs/myFile.txt> | ||||||
|  | def file6 := <c:\docs\myFile.txt> | ||||||
							
								
								
									
										9
									
								
								samples/E/Promises.E
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								samples/E/Promises.E
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | # E snippet from | ||||||
|  | # http://wiki.erights.org/wiki/Walnut/Distributed_Computing/Promises | ||||||
|  | when (tempVow) -> { | ||||||
|  |     #...use tempVow | ||||||
|  | } catch prob { | ||||||
|  |     #.... report problem | ||||||
|  | } finally { | ||||||
|  |     #....log event | ||||||
|  | } | ||||||
							
								
								
									
										18
									
								
								samples/E/minChat.E
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								samples/E/minChat.E
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | # from | ||||||
|  | # http://wiki.erights.org/wiki/Walnut/Secure_Distributed_Computing/Auditing_minChat | ||||||
|  | pragma.syntax("0.9") | ||||||
|  | to send(message) { | ||||||
|  |     when (friend<-receive(message)) -> { | ||||||
|  |         chatUI.showMessage("self", message) | ||||||
|  |     } catch prob {chatUI.showMessage("system", "connection lost")} | ||||||
|  | } | ||||||
|  | to receive(message) {chatUI.showMessage("friend", message)} | ||||||
|  | to receiveFriend(friendRcvr) { | ||||||
|  |     bind friend := friendRcvr         | ||||||
|  |     chatUI.showMessage("system", "friend has arrived") | ||||||
|  | } | ||||||
|  | to save(file) {file.setText(makeURIFromObject(chatController))} | ||||||
|  | to load(file) { | ||||||
|  |     bind friend := getObjectFromURI(file.getText()) | ||||||
|  |     friend <- receiveFriend(chatController) | ||||||
|  | } | ||||||
							
								
								
									
										1396
									
								
								samples/Eagle/Eagle.brd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1396
									
								
								samples/Eagle/Eagle.brd
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										3612
									
								
								samples/Eagle/Eagle.sch
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3612
									
								
								samples/Eagle/Eagle.sch
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										23
									
								
								samples/EmberScript/momentComponent.em
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								samples/EmberScript/momentComponent.em
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | class App.FromNowView extends Ember.View | ||||||
|  |     tagName: 'time' | ||||||
|  |     template: Ember.Handlebars.compile '{{view.output}}' | ||||||
|  |     output: ~> | ||||||
|  |         return moment(@value).fromNow() | ||||||
|  |  | ||||||
|  |     didInsertElement: -> | ||||||
|  |         @tick() | ||||||
|  |  | ||||||
|  |     tick: -> | ||||||
|  |         f = -> | ||||||
|  |             @notifyPropertyChange 'output' | ||||||
|  |             @tick() | ||||||
|  |  | ||||||
|  |         nextTick = Ember.run.later(this, f, 1000) | ||||||
|  |         @set 'nextTick', nextTick | ||||||
|  |  | ||||||
|  |     willDestroyElement: -> | ||||||
|  |         nextTick = @nextTick | ||||||
|  |         Ember.run.cancel nextTick | ||||||
|  |  | ||||||
|  | Ember.Handlebars.helper 'fromNow', App.FromNowView | ||||||
|  |  | ||||||
							
								
								
									
										8
									
								
								samples/Forth/bitmap.frt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								samples/Forth/bitmap.frt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | \ Bit arrays. | ||||||
|  | : bits ( u1 -- u2 ) 7 + 3 rshift ; | ||||||
|  | : bitmap ( u "name" -- ) create bits here over erase allot | ||||||
|  |    does> ( u -- a x ) over 3 rshift +  1 rot 7 and lshift ; | ||||||
|  | : bit@ ( a x -- f ) swap c@ and ; | ||||||
|  | : 1bit ( a x -- ) over c@ or swap c! ; | ||||||
|  | : 0bit ( a x -- ) invert over c@ and swap c! ; | ||||||
|  | : bit! ( f a x -- ) rot if 1bit else 0bit then ; | ||||||
							
								
								
									
										7
									
								
								samples/Forth/enum.frt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								samples/Forth/enum.frt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | |||||||
|  | \ Implements ENUM. | ||||||
|  |  | ||||||
|  | \ Double DOES>! | ||||||
|  | : enum   create 0 ,  does> create dup @ 1 rot +! ,  does> @ ; | ||||||
|  |  | ||||||
|  | \ But this is simpler. | ||||||
|  | : enum   create 0 ,  does> dup @ constant 1 swap +! ; | ||||||
							
								
								
									
										8
									
								
								samples/Forth/macros.frt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								samples/Forth/macros.frt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | |||||||
|  | \ Simplifies compiling words. | ||||||
|  |  | ||||||
|  | : [[     ; immediate | ||||||
|  | : '<>    >in @ ' swap >in ! <> ; | ||||||
|  | : (]])   begin dup '<> while postpone postpone repeat drop ; | ||||||
|  | : ]]     ['] [[ (]]) ; immediate | ||||||
|  |  | ||||||
|  | ( Usage:   : foo ]] dup * [[ ; immediate   : bar 42 foo . ; ) | ||||||
							
								
								
									
										44
									
								
								samples/Frege/CommandLineClock.fr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								samples/Frege/CommandLineClock.fr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | {--  | ||||||
|  |     This program displays the | ||||||
|  |     current time on stdandard output | ||||||
|  |     every other second. | ||||||
|  |     -} | ||||||
|  |      | ||||||
|  | module examples.CommandLineClock where | ||||||
|  |  | ||||||
|  | data Date = native java.util.Date where | ||||||
|  |     native new :: () -> IO (MutableIO Date)     -- new Date() | ||||||
|  |     native toString :: Mutable s Date -> ST s String    -- d.toString() | ||||||
|  |  | ||||||
|  | --- 'IO' action to give us the current time as 'String' | ||||||
|  | current :: IO String | ||||||
|  | current = do | ||||||
|  |     d <- Date.new () | ||||||
|  |     d.toString | ||||||
|  |  | ||||||
|  | {-  | ||||||
|  |     "java.lang.Thread.sleep" takes a "long" and | ||||||
|  |     returns nothing, but may throw an InterruptedException. | ||||||
|  |     This is without doubt an IO action. | ||||||
|  |      | ||||||
|  |     public static void sleep(long millis) | ||||||
|  |                   throws InterruptedException | ||||||
|  |      | ||||||
|  |     Encoded in Frege: | ||||||
|  |     - argument type  long   Long | ||||||
|  |     - result         void   () | ||||||
|  |     - does IO               IO () | ||||||
|  |     - throws ...            throws .... | ||||||
|  |       | ||||||
|  | -} | ||||||
|  | -- .... defined in frege.java.Lang | ||||||
|  | -- native sleep java.lang.Thread.sleep :: Long -> IO () throws InterruptedException | ||||||
|  |  | ||||||
|  |        | ||||||
|  | main args =   | ||||||
|  |     forever do | ||||||
|  |         current >>= print | ||||||
|  |         print "\r" | ||||||
|  |         stdout.flush | ||||||
|  |         Thread.sleep 999 | ||||||
|  |                  | ||||||
							
								
								
									
										147
									
								
								samples/Frege/Concurrent.fr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								samples/Frege/Concurrent.fr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | |||||||
|  | module examples.Concurrent where | ||||||
|  |  | ||||||
|  | import System.Random | ||||||
|  | import Java.Net (URL) | ||||||
|  | import Control.Concurrent as C | ||||||
|  |  | ||||||
|  | main2 args = do | ||||||
|  |     m <- newEmptyMVar | ||||||
|  |     forkIO do | ||||||
|  |         m.put 'x' | ||||||
|  |         m.put 'y'  | ||||||
|  |         m.put 'z' | ||||||
|  |     replicateM_ 3 do | ||||||
|  |         c <- m.take | ||||||
|  |         print "got: " | ||||||
|  |         println c   | ||||||
|  |          | ||||||
|  |              | ||||||
|  | example1 = do | ||||||
|  |     forkIO (replicateM_ 100000 (putChar 'a')) | ||||||
|  |     replicateM_ 100000 (putChar 'b') | ||||||
|  |  | ||||||
|  | example2 =  do | ||||||
|  |     s <- getLine | ||||||
|  |     case s.long of | ||||||
|  |         Right n -> forkIO (setReminder n) >> example2 | ||||||
|  |         Left _  -> println ("exiting ...") | ||||||
|  |      | ||||||
|  | setReminder :: Long -> IO () | ||||||
|  | setReminder n = do | ||||||
|  |         println ("Ok, I remind you in " ++ show n ++ " seconds") | ||||||
|  |         Thread.sleep (1000L*n) | ||||||
|  |         println (show n ++ " seconds is up!") | ||||||
|  |  | ||||||
|  | table = "table" | ||||||
|  |              | ||||||
|  | mainPhil _ = do | ||||||
|  |     [fork1,fork2,fork3,fork4,fork5] <- mapM MVar.new [1..5] | ||||||
|  |     forkIO (philosopher "Kant" fork5 fork1) | ||||||
|  |     forkIO (philosopher "Locke" fork1 fork2) | ||||||
|  |     forkIO (philosopher "Wittgenstein" fork2 fork3) | ||||||
|  |     forkIO (philosopher "Nozick" fork3 fork4) | ||||||
|  |     forkIO (philosopher "Mises" fork4 fork5) | ||||||
|  |     return ()     | ||||||
|  |  | ||||||
|  | philosopher :: String -> MVar Int -> MVar Int -> IO () | ||||||
|  | philosopher me left right = do | ||||||
|  |     g <- Random.newStdGen | ||||||
|  |     let phil g  = do | ||||||
|  |             let (tT,g1) = Random.randomR (60L, 120L) g | ||||||
|  |                 (eT, g2)  = Random.randomR (80L, 160L) g1 | ||||||
|  |                 thinkTime = 300L * tT | ||||||
|  |                 eatTime   = 300L * eT | ||||||
|  |      | ||||||
|  |             println(me ++ " is going to the dining room and takes his seat.")  | ||||||
|  |             fl <- left.take             | ||||||
|  |             println (me ++ " takes up left fork (" ++ show fl ++ ")") | ||||||
|  |             rFork <- right.poll | ||||||
|  |             case rFork of | ||||||
|  |                 Just fr -> do  | ||||||
|  |                     println (me ++ " takes up right fork. (" ++ show fr ++ ")")  | ||||||
|  |                     println (me ++ " is going to eat for " ++ show eatTime ++ "ms") | ||||||
|  |                     Thread.sleep eatTime | ||||||
|  |                     println (me ++ " finished eating.") | ||||||
|  |                     right.put fr | ||||||
|  |                     println (me ++ " took down right fork.") | ||||||
|  |                     left.put fl | ||||||
|  |                     println (me ++ " took down left fork.") | ||||||
|  |                     table.notifyAll  | ||||||
|  |                     println(me ++ " is going to think for " ++ show thinkTime ++ "ms.") | ||||||
|  |                     Thread.sleep thinkTime | ||||||
|  |                     phil g2 | ||||||
|  |                 Nothing -> do | ||||||
|  |                     println (me ++ " finds right fork is already in use.") | ||||||
|  |                     left.put fl | ||||||
|  |                     println (me ++ " took down left fork.") | ||||||
|  |                     table.notifyAll | ||||||
|  |                     println (me ++ " is going to the bar to await notifications from table.") | ||||||
|  |                     table.wait | ||||||
|  |                     println (me ++ " got notice that something changed at the table.") | ||||||
|  |                     phil g2 | ||||||
|  |              | ||||||
|  |         inter :: InterruptedException -> IO () | ||||||
|  |         inter _ = return ()         | ||||||
|  |      | ||||||
|  |     phil g `catch` inter | ||||||
|  |  | ||||||
|  |      | ||||||
|  | getURL xx = do | ||||||
|  |         url <- URL.new xx  | ||||||
|  |         con <- url.openConnection | ||||||
|  |         con.connect | ||||||
|  |         is  <- con.getInputStream | ||||||
|  |         typ <- con.getContentType | ||||||
|  |         -- stderr.println ("content-type is " ++ show typ)  | ||||||
|  |         ir  <- InputStreamReader.new is (fromMaybe "UTF-8" (charset typ)) | ||||||
|  |             `catch` unsupportedEncoding is  | ||||||
|  |         br  <- BufferedReader.new ir | ||||||
|  |         br.getLines | ||||||
|  |     where | ||||||
|  |         unsupportedEncoding :: InputStream -> UnsupportedEncodingException -> IO InputStreamReader | ||||||
|  |         unsupportedEncoding is x = do | ||||||
|  |             stderr.println x.catched | ||||||
|  |             InputStreamReader.new is "UTF-8" | ||||||
|  |              | ||||||
|  |         charset ctyp = do | ||||||
|  |             typ <- ctyp | ||||||
|  |             case typ of | ||||||
|  |                 m~´charset=(\S+)´ -> m.group 1 | ||||||
|  |                 _ -> Nothing | ||||||
|  |  | ||||||
|  |      | ||||||
|  | type SomeException = Throwable | ||||||
|  |  | ||||||
|  | main ["dining"] = mainPhil [] | ||||||
|  |          | ||||||
|  | main _ =  do | ||||||
|  |     m1 <- MVar.newEmpty | ||||||
|  |     m2 <- MVar.newEmpty | ||||||
|  |     m3 <- MVar.newEmpty | ||||||
|  |      | ||||||
|  |     forkIO do | ||||||
|  |         r <- (catchAll . getURL) "http://www.wikipedia.org/wiki/Haskell" | ||||||
|  |         m1.put r | ||||||
|  |      | ||||||
|  |     forkIO do | ||||||
|  |         r <- (catchAll . getURL) "htto://www.wikipedia.org/wiki/Java" | ||||||
|  |         m2.put r | ||||||
|  |      | ||||||
|  |     forkIO do | ||||||
|  |         r <- (catchAll . getURL) "http://www.wikipedia.org/wiki/Frege" | ||||||
|  |         m3.put r | ||||||
|  |      | ||||||
|  |     r1 <- m1.take | ||||||
|  |     r2 <- m2.take | ||||||
|  |     r3 <- m3.take | ||||||
|  |     println (result r1, result r2, result r3) | ||||||
|  |     -- case r3 of | ||||||
|  |     --     Right ss -> mapM_ putStrLn ss | ||||||
|  |     --     Left _   -> return () | ||||||
|  |   where | ||||||
|  |     result :: (SomeException|[String]) -> (String|Int) | ||||||
|  |     result (Left x)  = Left x.getClass.getName | ||||||
|  |     result (Right y) = (Right . sum . map length)  y | ||||||
|  |     -- mapM_ putStrLn r2 | ||||||
|  |  | ||||||
|  |          | ||||||
							
								
								
									
										561
									
								
								samples/Frege/Sudoku.fr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										561
									
								
								samples/Frege/Sudoku.fr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,561 @@ | |||||||
|  | package examples.Sudoku where | ||||||
|  |  | ||||||
|  | import Data.TreeMap (Tree, keys) | ||||||
|  | import Data.List as DL hiding (find, union) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | type Element    = Int           -- 1,2,3,4,5,6,7,8,9 | ||||||
|  | type Zelle      = [Element]     -- set of candidates | ||||||
|  | type Position   = Int           -- 0..80 | ||||||
|  | type Feld       = (Position, Zelle) | ||||||
|  | type Brett      = [Feld] | ||||||
|  |  | ||||||
|  | --- data type for assumptions and conclusions | ||||||
|  | data Assumption = | ||||||
|  |               !ISNOT Position Element | ||||||
|  |             | !IS    Position Element | ||||||
|  |  | ||||||
|  |  | ||||||
|  | derive Eq Assumption | ||||||
|  | derive Ord Assumption | ||||||
|  | instance Show Assumption where | ||||||
|  |     show (IS p e)    = pname p ++ "=" ++ e.show | ||||||
|  |     show (ISNOT p e) = pname p ++ "/" ++ e.show | ||||||
|  |  | ||||||
|  | showcs cs = joined " " (map Assumption.show cs) | ||||||
|  |  | ||||||
|  | elements :: [Element]           -- all possible elements | ||||||
|  | elements = [1 .. 9] | ||||||
|  |  | ||||||
|  | {- | ||||||
|  |     a  b  c   d  e  f   g  h  i | ||||||
|  |      0  1  2 | 3  4  5 | 6  7  8    1 | ||||||
|  |      9 10 11 |12 13 14 |15 16 17    2 | ||||||
|  |     18 19 20 |21 22 23 |24 25 26    3 | ||||||
|  |     ---------|---------|-------- | ||||||
|  |     27 28 29 |30 31 32 |33 34 35    4 | ||||||
|  |     36 37 38 |39 40 41 |42 43 44    5 | ||||||
|  |     45 46 47 |48 49 50 |51 52 53    6 | ||||||
|  |     ---------|---------|-------- | ||||||
|  |     54 55 56 |57 58 59 |60 61 62    7 | ||||||
|  |     63 64 65 |66 67 68 |69 70 71    8 | ||||||
|  |     72 73 74 |75 76 77 |78 79 80    9 | ||||||
|  | -} | ||||||
|  |  | ||||||
|  | positions :: [Position]         -- all possible positions | ||||||
|  | positions = [0..80] | ||||||
|  | rowstarts :: [Position]         -- all positions where a row is starting | ||||||
|  | rowstarts =  [0,9,18,27,36,45,54,63,72] | ||||||
|  | colstarts :: [Position]         -- all positions where a column is starting | ||||||
|  | colstarts =  [0,1,2,3,4,5,6,7,8] | ||||||
|  | boxstarts :: [Position]         -- all positions where a box is starting | ||||||
|  | boxstarts =  [0,3,6,27,30,33,54,57,60] | ||||||
|  | boxmuster :: [Position]         -- pattern for a box, by adding upper left position results in real box | ||||||
|  | boxmuster =  [0,1,2,9,10,11,18,19,20] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | --- extract field for position | ||||||
|  | getf :: Brett -> Position  -> Feld | ||||||
|  | getf (f:fs) p | ||||||
|  |     | fst f == p = f | ||||||
|  |     | otherwise  = getf fs p | ||||||
|  | getf [] p = (p,[]) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | --- extract cell for position | ||||||
|  | getc :: Brett -> Position -> Zelle | ||||||
|  | getc b p = snd (getf b p) | ||||||
|  |  | ||||||
|  | --- compute the list of all positions that belong to the same row as a given position | ||||||
|  | row :: Position -> [Position] | ||||||
|  | row p = [z..(z+8)] where z = (p `quot` 9) * 9 | ||||||
|  |  | ||||||
|  | --- compute the list of all positions that belong to the same col as a given position | ||||||
|  | col :: Position -> [Position] | ||||||
|  | col p = map (c+) rowstarts where c = p `mod` 9 | ||||||
|  |  | ||||||
|  | --- compute the list of all positions that belong to the same box as a given position | ||||||
|  | box :: Position -> [Position] | ||||||
|  | box p  = map (z+) boxmuster where | ||||||
|  |     ri = p `div` 27 * 27    -- 0, 27 or 54, depending on row | ||||||
|  |     ci = p `mod` 9          -- column index 0..8, 0,1,2 is left, 3,4,5 is middle, 6,7,8 is right | ||||||
|  |     cs = ci `div` 3 * 3     -- 0, 3 or 6 | ||||||
|  |     z  = ri + cs | ||||||
|  |  | ||||||
|  | --- check if candidate set has exactly one member, i.e. field has been solved | ||||||
|  | single :: Zelle -> Bool | ||||||
|  | single [_] = true | ||||||
|  | single _   = false | ||||||
|  |  | ||||||
|  | unsolved :: Zelle -> Bool | ||||||
|  | unsolved [_] = false | ||||||
|  | unsolved _   = true | ||||||
|  |  | ||||||
|  | -- list of rows, cols, boxes | ||||||
|  | allrows = map row rowstarts | ||||||
|  | allcols = map col colstarts | ||||||
|  | allboxs = map box boxstarts | ||||||
|  | allrcb  = zip (repeat "row") allrows | ||||||
|  |           ++ zip (repeat "col") allcols | ||||||
|  |           ++ zip (repeat "box") allboxs | ||||||
|  |  | ||||||
|  |  | ||||||
|  | containers :: [(Position -> [Position], String)] | ||||||
|  | containers = [(row, "row"), (col, "col"), (box, "box")] | ||||||
|  |  | ||||||
|  | -- ----------------- PRINTING ------------------------------------ | ||||||
|  | -- printable coordinate of field, upper left is a1, lower right is i9 | ||||||
|  | pname p = packed [chr (ord 'a' + p `mod` 9), chr (ord '1' + p `div` 9)] | ||||||
|  |  | ||||||
|  | -- print board | ||||||
|  | printb b = mapM_ p1line allrows >> println "" | ||||||
|  |     where | ||||||
|  |         p1line row = do | ||||||
|  |                 print (joined "" (map pfld line)) | ||||||
|  |             where line = map (getc b) row | ||||||
|  |  | ||||||
|  | -- print field (brief) | ||||||
|  | --   ? = no candidate | ||||||
|  | --   5 = field is 5 | ||||||
|  | --   . = some candidates | ||||||
|  | pfld [] = "?" | ||||||
|  | pfld [x] = show x | ||||||
|  | pfld zs = "0" | ||||||
|  |  | ||||||
|  | -- print initial/final board | ||||||
|  | result msg b = do | ||||||
|  |         println ("Result: " ++ msg) | ||||||
|  |         print   ("Board: ") | ||||||
|  |         printb b | ||||||
|  |         return b | ||||||
|  |  | ||||||
|  | res012 b = case concatMap (getc b) [0,1,2] of | ||||||
|  |     [a,b,c] -> a*100+b*10+c | ||||||
|  |     _ -> 9999999 | ||||||
|  |  | ||||||
|  | -- -------------------------- BOARD ALTERATION ACTIONS --------------------------------- | ||||||
|  | -- print a message about what is done to the board and return the new board | ||||||
|  | turnoff1 :: Position -> Zelle -> Brett -> IO Brett | ||||||
|  | turnoff1 i off b | ||||||
|  |     | single nc = do | ||||||
|  |             -- print (pname i) | ||||||
|  |             -- print ": set to " | ||||||
|  |             -- print (head nc) | ||||||
|  |             -- println " (naked single)" | ||||||
|  |             return newb | ||||||
|  |     | otherwise = return newb | ||||||
|  |     where | ||||||
|  |         cell   = getc b i | ||||||
|  |         nc     = filter (`notElem` off) cell | ||||||
|  |         newb   = (i, nc) : [ f | f <- b, fst f != i ] | ||||||
|  |  | ||||||
|  | turnoff :: Int -> Zelle -> String -> Brett -> IO Brett | ||||||
|  | turnoff i off msg b = do | ||||||
|  |         -- print (pname i) | ||||||
|  |         -- print ": set to " | ||||||
|  |         -- print nc | ||||||
|  |         -- print " by clearing " | ||||||
|  |         -- print off | ||||||
|  |         -- print " " | ||||||
|  |         -- println  msg | ||||||
|  |         return newb | ||||||
|  |     where | ||||||
|  |         cell   = getc b i | ||||||
|  |         nc     = filter (`notElem` off) cell | ||||||
|  |         newb   = (i, nc) : [ f | f <- b, fst f != i ] | ||||||
|  |  | ||||||
|  | turnoffh ps off msg b = foldM toh b ps | ||||||
|  |     where | ||||||
|  |         toh b p = turnoff p off msg b | ||||||
|  |  | ||||||
|  | setto :: Position -> Element -> String -> Brett -> IO Brett | ||||||
|  | setto i n cname b = do | ||||||
|  |         -- print (pname i) | ||||||
|  |         -- print ": set to " | ||||||
|  |         -- print n | ||||||
|  |         -- print " (hidden single in " | ||||||
|  |         -- print cname | ||||||
|  |         -- println ")" | ||||||
|  |         return newb | ||||||
|  |     where | ||||||
|  |         nf     = [n] | ||||||
|  |         newb   = (i, nf) : [ f | f <- b, fst f != i ] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ----------------------------- SOLVING STRATEGIES --------------------------------------------- | ||||||
|  | -- reduce candidate sets that contains numbers already in same row, col or box | ||||||
|  | -- This finds (and logs) NAKED SINGLEs in passing. | ||||||
|  | reduce b = [  turnoff1 p sss | (p,cell) <- b,               -- for each field | ||||||
|  |                 unsolved cell,                              --  with more than 1 candidate | ||||||
|  |                 --       single fields in containers that are candidates of that field | ||||||
|  |                 sss = [ s | (rcb, _) <- containers, [s] <- map (getc b) (rcb p), s `elem` cell], | ||||||
|  |                 sss != [] ]                                     -- collect field index, elements to remove from candidate set | ||||||
|  |  | ||||||
|  | -- look for a number that appears in exactly 1 candidate set of a container | ||||||
|  | -- this number can go in no other place (HIDDEN SINGLE) | ||||||
|  | hiddenSingle b = [ setto i n cname |                     -- select index, number, containername | ||||||
|  |             (cname, rcb) <- allrcb,                 -- FOR rcb IN allrcb | ||||||
|  |             n <- elements,                          --  FOR n IN elements | ||||||
|  |             fs     = filter (unsolved • snd) (map (getf b) rcb), | ||||||
|  |             occurs  = filter ((n `elem`) • snd) fs, | ||||||
|  |             length occurs == 1, | ||||||
|  |             (i, _) <- occurs ] | ||||||
|  |  | ||||||
|  | -- look for NAKED PAIRS, TRIPLES, QUADS | ||||||
|  | nakedPair n b = [ turnoff p t ("(naked tuple in " ++ nm ++ ")") |           -- SELECT pos, tuple, name | ||||||
|  |             -- n <- [2,3,4],                    //  FOR n IN [2,3,4] | ||||||
|  |             (nm, rcb) <- allrcb,             --    FOR rcb IN containers | ||||||
|  |             fs = map (getf b) rcb,              --      let fs = fields for rcb positions | ||||||
|  |             u  = (fold union [] . filter unsolved . map snd) fs,   -- let u = union of non single candidates | ||||||
|  |             t <- n `outof` u,                   --      FOR t IN n-tuples | ||||||
|  |             hit = (filter ((`subset` t) . snd) . filter (unsolved . snd)) fs, | ||||||
|  |             length hit == n, | ||||||
|  |             (p, cell) <- fs, | ||||||
|  |             p `notElem` map fst hit, | ||||||
|  |             any (`elem` cell) t | ||||||
|  |             ] | ||||||
|  |  | ||||||
|  | -- look for HIDDEN PAIRS, TRIPLES or QUADS | ||||||
|  | hiddenPair n b = [ turnoff p off ("(hidden " ++ show t ++ " in " ++ nm ++ ")") |           -- SELECT pos, tuple, name | ||||||
|  |             -- n <- [2,3,4],                    //  FOR n IN [2,3,4] | ||||||
|  |             (nm, rcb) <- allrcb,             --    FOR rcb IN containers | ||||||
|  |             fs = map (getf b) rcb,              --      let fs = fields for rcb positions | ||||||
|  |             u  = (fold union [] . filter ((>1) . length) . map snd) fs,   -- let u = union of non single candidates | ||||||
|  |             t <- n `outof` u,                   --      FOR t IN n-tuples | ||||||
|  |             hit = (filter (any ( `elem` t) . snd) . filter (unsolved . snd)) fs, | ||||||
|  |             length hit == n, | ||||||
|  |             off = (fold union [] . map snd) hit `minus` t, | ||||||
|  |             off != [], | ||||||
|  |             (p, cell) <- hit, | ||||||
|  |             ! (cell `subset` t) | ||||||
|  |             ] | ||||||
|  |  | ||||||
|  | a `subset` b = all (`elem` b) a | ||||||
|  | a `union`  b = uniq (sort (a ++ b)) | ||||||
|  | a `minus`  b = filter (`notElem` b) a | ||||||
|  | a `common` b = filter (`elem` b) a | ||||||
|  | n `outof` as | ||||||
|  |     | length as < n = [] | ||||||
|  |     | [] <- as      = [] | ||||||
|  |     | 1 >= n        = map (:[]) as | ||||||
|  |     | (a:bs) <- as  = map (a:) ((n-1) `outof` bs) ++ (n `outof` bs) | ||||||
|  |     | otherwise     = undefined  -- cannot happen because either as is empty or not | ||||||
|  |  | ||||||
|  | same f a b = b `elem` f a | ||||||
|  |  | ||||||
|  | intersectionlist = [(allboxs, row, "box/row intersection"), (allboxs, col, "box/col intersection"), | ||||||
|  |                     (allrows ++ allcols, box, "line/box intersection")] | ||||||
|  | intersections b = [ | ||||||
|  |     turnoff pos [c] reason |    -- SELECT position, candidate, reson | ||||||
|  |         (from, container, reason) <- intersectionlist, | ||||||
|  |         rcb <- from, | ||||||
|  |         fs = (filter (unsolved . snd) . map (getf b)) rcb,        -- fs = fields in from with more than 1 candidate | ||||||
|  |         c <- (fold union [] • map snd) fs,                          -- FOR c IN union of candidates | ||||||
|  |         cpos = (map fst • filter ((c `elem`) • snd)) fs,            -- cpos = positions where c occurs | ||||||
|  |         cpos != [],                                                 -- WHERE cpos is not empty | ||||||
|  |         all (same container (head cpos)) (tail cpos),               -- WHERE all positions are in the intersection | ||||||
|  |         -- we can remove all occurences of c that are in container, but not in from | ||||||
|  |         (pos, cell) <- map (getf b) (container (head cpos)), | ||||||
|  |         c `elem` cell, | ||||||
|  |         pos `notElem` rcb ] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- look for an XY Wing | ||||||
|  | --  - there exists a cell A with candidates X and Y | ||||||
|  | --  - there exists a cell B with candidates X and Z that shares a container with A | ||||||
|  | --  - there exists a cell C with candidates Y and Z that shares a container with A | ||||||
|  | -- reasoning | ||||||
|  | --  - if A is X, B will be Z | ||||||
|  | --  - if A is Y, C will be Z | ||||||
|  | --  - since A will indeed be X or Y -> B or C will be Z | ||||||
|  | --  - thus, no cell that can see B and C can be Z | ||||||
|  | xyWing board = [ turnoff p [z] ("xy wing " ++ pname b ++ " " ++ pname c ++ " because of " ++ pname a) | | ||||||
|  |         (a, [x,y]) <- board,                            -- there exists a cell a with candidates x and y | ||||||
|  |         rcba = map (getf board) (row a ++ col a ++ box a),  -- rcba = all fields that share a container with a | ||||||
|  |         (b, [b1, b2]) <- rcba, | ||||||
|  |         b != a, | ||||||
|  |         b1 == x && b2 != y || b2 == x && b1 != y,       -- there exists a cell B with candidates x and z | ||||||
|  |         z = if b1 == x then b2 else b1, | ||||||
|  |         (c, [c1, c2]) <- rcba, | ||||||
|  |         c != a, c!= b, | ||||||
|  |         c1 == y && c2 == z || c1 == z && c2 == y,       -- there exists a cell C with candidates y and z | ||||||
|  |         ps = (uniq . sort) ((row b ++ col b ++ box b) `common` (row c ++ col c ++ box c)), | ||||||
|  |         -- remove z in ps | ||||||
|  |         (p, cs) <- map (getf board) ps, | ||||||
|  |         p != b, p != c, | ||||||
|  |         z `elem` cs ] | ||||||
|  |  | ||||||
|  | -- look for a N-Fish (2: X-Wing, 3: Swordfish, 4: Jellyfish) | ||||||
|  | -- When all candidates for a particular digit in N rows are located | ||||||
|  | -- in only N columns, we can eliminate all candidates from those N columns | ||||||
|  | --  which are not located on those N rows | ||||||
|  | fish n board = fish "row" allrows row col ++ fish "col" allcols col row where | ||||||
|  |     fishname 2 = "X-Wing" | ||||||
|  |     fishname 3 = "Swordfish" | ||||||
|  |     fishname 4 = "Jellyfish" | ||||||
|  |     fishname _ = "unknown fish" | ||||||
|  |     fish nm allrows row col = [ turnoff p [x] (fishname n ++ " in " ++ nm ++ " " ++ show (map (pname . head) rset)) | | ||||||
|  |         rset <- n `outof` allrows,          -- take n rows (or cols) | ||||||
|  |         x <- elements,                      -- look for certain number | ||||||
|  |         rflds = map (filter ((>1) . length . snd) . map (getf board)) rset,       -- unsolved fields in the rowset | ||||||
|  |         colss  = (map (map (head . col . fst) . filter ((x `elem`) . snd)) rflds),   -- where x occurs in candidates | ||||||
|  |         all ((>1) . length) colss,         -- x must appear in at least 2 cols | ||||||
|  |         cols = fold union [] colss, | ||||||
|  |         length cols == n, | ||||||
|  |         cstart <- cols, | ||||||
|  |         (p, cell) <- map (getf board) (col cstart), | ||||||
|  |         x `elem` cell, | ||||||
|  |         all (p `notElem`) rset] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- compute immediate consequences of an assumption of the form (p `IS` e) or (p `ISNOT` e) | ||||||
|  | conseq board (IS p e) = uniq (sort ([ p `ISNOT` x | x <- getc board p, x != e ] ++ | ||||||
|  |     [ a `ISNOT` e | | ||||||
|  |         (a,cs) <- map (getf board) (row p ++ col p ++ box p), | ||||||
|  |         a != p, | ||||||
|  |         e `elem` cs | ||||||
|  |     ])) | ||||||
|  | conseq board (ISNOT p  e) = uniq (sort ([ p `IS` x | cs = getc board p, length cs == 2, x <- cs, x != e ] ++ | ||||||
|  |     [ a `IS` e | | ||||||
|  |         cp <- [row p, box p, col p], | ||||||
|  |         as = (filter ((e `elem`) . getc board) . filter (p!=)) cp, | ||||||
|  |         length as == 1, | ||||||
|  |         a = head as | ||||||
|  |     ])) | ||||||
|  |  | ||||||
|  | -- check if two assumptions contradict each other | ||||||
|  | contradicts (IS a x)    (IS b y)    = a==b && x!=y | ||||||
|  | contradicts (IS a x)    (ISNOT b y) = a==b && x==y | ||||||
|  | contradicts (ISNOT a x) (IS b y)    = a==b && x==y | ||||||
|  | contradicts (ISNOT _ _) (ISNOT _ _) = false | ||||||
|  |  | ||||||
|  | -- get the Position of an Assumption | ||||||
|  | aPos (IS p _)    = p | ||||||
|  | aPos (ISNOT p _) = p | ||||||
|  |  | ||||||
|  | -- get List of elements that must be turned off when assumption is true/false | ||||||
|  | toClear board true  (IS p x)    = filter (x!=) (getc board p) | ||||||
|  | toClear board false (IS p x)    = [x] | ||||||
|  | toClear board true  (ISNOT p x) = [x] | ||||||
|  | toClear board false (ISNOT p x) = filter (x!=) (getc board p) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- look for assumptions whose implications contradict themself | ||||||
|  | chain board paths = [ solution a (head cs) (reverse cs) | | ||||||
|  |         (a, css) <-  paths, | ||||||
|  |         cs <- take 1 [ cs | cs <- css, contradicts a (head cs) ] | ||||||
|  |         ] | ||||||
|  |     where | ||||||
|  |         solution a c cs = turnoff (aPos a) (toClear board false a) reason where | ||||||
|  |             reason = "Assumption " ++ show a ++ " implies " ++ show c ++ "\n\t" | ||||||
|  |                 ++ showcs cs ++ "\n\t" | ||||||
|  |                 ++ "Therefore, " ++ show a ++ " must be false." | ||||||
|  |  | ||||||
|  | -- look for an assumption that yields to contradictory implications | ||||||
|  | -- this assumption must be false | ||||||
|  | chainContra board paths = [ solution a (reverse pro) (reverse contra) | | ||||||
|  |         (a, css) <- paths,          -- FOR ALL assumptions "a" with list of conlusions "css" | ||||||
|  |         (pro, contra) <- take 1 [ (pro, contra) | | ||||||
|  |             pro <- (uniqBy (using head) . sortBy (comparing head)) css,                 -- FOR ALL conslusion chains "pro" | ||||||
|  |             c = head pro,               -- LET "c" BE the final conclusion | ||||||
|  |             contra <- take 1 (filter ((contradicts c) . head) css)   -- THE FIRST conclusion that contradicts c | ||||||
|  |         ] | ||||||
|  |       ] | ||||||
|  |     where | ||||||
|  |         solution a pro con = turnoff (aPos a) (toClear board false a) reason where | ||||||
|  |             reason = ("assumption " ++ show a ++ " leads to contradictory conclusions\n\t" | ||||||
|  |                         ++ showcs pro ++ "\n\t" ++ showcs con) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- look for a common implication c of some assumptions ai, where at least 1 ai is true | ||||||
|  | -- so that (a0 OR a1 OR a2 OR ...) IMPLIES c | ||||||
|  | -- For all cells pi in same container that have x as candidate, we can construct (p0==x OR p1==x OR ... OR pi==x) | ||||||
|  | -- For a cell p with candidates ci, we can construct (p==c0 OR p==c1) | ||||||
|  | cellRegionChain board paths = [ solution b as (map head os) | | ||||||
|  |         as <- cellas ++ regionas,           -- one of as must be true | ||||||
|  |         iss = filter ((`elem` as) . fst) paths,    -- the implications for as | ||||||
|  |         (a, ass) <- take 1 iss,             -- implications for first assumption | ||||||
|  |         fs <- (uniqBy (using head) . sortBy (comparing head)) ass, | ||||||
|  |         b = head fs,                        -- final conclusions of first assumption | ||||||
|  |         os = [fs] : map (take 1 . filter ((b==) . head) . snd) (tail iss), -- look for implications with same conclusion | ||||||
|  |         all ([]!=) os] | ||||||
|  |     where | ||||||
|  |         cellas   = [ map (p `IS`) candidates | (p, candidates@(_:_:_)) <- board ] | ||||||
|  |         regionas = [ map (`IS` e) ps | | ||||||
|  |             region <- map (map (getf board)) (allrows ++ allcols ++ allboxs), | ||||||
|  |             e <- elements, | ||||||
|  |             ps = map fst (filter ((e `elem`) . snd) region), | ||||||
|  |             length ps > 1 ] | ||||||
|  |         solution b as oss = turnoff (aPos b) (toClear board true b) reason where | ||||||
|  |             reason = "all of the assumptions " ++ joined ", " (map show as) ++ " imply " ++ show b ++ "\n\t" | ||||||
|  |                 ++ joined "\n\t" (map (showcs . reverse) oss) ++ "\n\t" | ||||||
|  |                 ++ "One of them must be true, so " ++ show b ++ " must be true." | ||||||
|  |  | ||||||
|  |  | ||||||
|  | {- | ||||||
|  |     Wir brauchen für einige Funktionen eine Datenstruktur wie | ||||||
|  |         [ (Assumption, [[Assumption]]) ] | ||||||
|  |     d.i. eine Liste von möglichen Annahmen samt aller Schlußketten. | ||||||
|  |     Idealerweise sollte die Schlußkette in umgekehrter Reihenfolge vorliegen, | ||||||
|  |     dann kann man einfach finden: | ||||||
|  |     - Annahmen, die zum Selbstwiderspruch führen. | ||||||
|  |     - alles, was aus einer bestimmten Annahme folgt (map (map head) [[a]]) | ||||||
|  |     -... | ||||||
|  | -} | ||||||
|  | --- Liste aller Annahmen für ein bestimmtes Brett | ||||||
|  | assumptions :: Brett -> [Assumption] | ||||||
|  | assumptions board = [ a | | ||||||
|  |                 (p, cs) <- board, | ||||||
|  |                 !(single cs), | ||||||
|  |                 a <- map (ISNOT p) cs ++ map (IS p) cs ] | ||||||
|  |  | ||||||
|  | consequences :: Brett -> [Assumption] -> [[Assumption]] | ||||||
|  | consequences board as = map (conseq board) as | ||||||
|  |  | ||||||
|  | acstree :: Brett -> Tree Assumption [Assumption] | ||||||
|  | acstree board = Tree.fromList (zip as cs) | ||||||
|  |     where | ||||||
|  |         as = assumptions  board | ||||||
|  |         cs = consequences board as | ||||||
|  |  | ||||||
|  | -- bypass maybe on tree lookup | ||||||
|  | find :: Tree Assumption [Assumption] -> Assumption -> [Assumption] | ||||||
|  | find t a | ||||||
|  |     | Just cs <- t.lookup a = cs | ||||||
|  |     | otherwise = error ("no consequences for " ++ show a) | ||||||
|  |  | ||||||
|  | -- for performance resons, we confine ourselves to implication chains of length 20 per assumption | ||||||
|  | mkPaths :: Tree Assumption [Assumption] -> [ (Assumption, [[Assumption]]) ] | ||||||
|  | mkPaths acst = map impl  (keys acst)   -- {[a1], [a2], [a3] ] | ||||||
|  |     where | ||||||
|  |         -- [Assumption] -> [(a, [chains, ordered by length] | ||||||
|  |         impl a = (a, impls [[a]]) | ||||||
|  |         impls ns = (take 1000 • concat • takeUntil null • iterate expandchain) ns | ||||||
|  |         -- expandchain :: [[Assumption]] -> [[Assumption]] | ||||||
|  |         expandchain css = [ (n:a:as) | | ||||||
|  |             (a : as) <- css,               -- list of assumptions | ||||||
|  |             n <- find acst a,              -- consequences of a | ||||||
|  |             n `notElem` as                 -- avoid loops | ||||||
|  |           ] | ||||||
|  |         -- uni (a:as) = a : uni (filter ((head a !=) • head) as) | ||||||
|  |         -- uni [] = empty | ||||||
|  |         -- empty = [] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | -- ------------------ SOLVE A SUDOKU -------------------------- | ||||||
|  | -- Apply all available strategies until nothing changes anymore | ||||||
|  | -- Strategy functions are supposed to return a list of | ||||||
|  | -- functions, which, when applied to a board, give a changed board. | ||||||
|  | -- When a strategy does not find anything to alter, | ||||||
|  | -- it returns [], and the next strategy can be tried. | ||||||
|  | solve b | ||||||
|  |     | all (single . snd) b       = result "Solved" b | ||||||
|  |     | any (([]==) . snd) b       = result "not solvable" b | ||||||
|  |     | res@(_:_) <- reduce b       = apply b res >>=solve       -- compute smallest candidate sets | ||||||
|  |     -- comment "candidate sets are up to date" = () | ||||||
|  |     | res@(_:_) <- hiddenSingle b  = apply b res >>= solve     -- find HIDDEN SINGLES | ||||||
|  |     -- comment "no more hidden singles" = () | ||||||
|  |     | res@(_:_) <- intersections b = apply b res >>= solve     -- find locked candidates | ||||||
|  |     -- comment "no more intersections" = () | ||||||
|  |     | res@(_:_) <- nakedPair 2 b     = apply b res >>= solve     -- find NAKED PAIRS, TRIPLES or QUADRUPELS | ||||||
|  |     -- comment "no more naked pairs" = () | ||||||
|  |     | res@(_:_) <- hiddenPair  2 b   = apply b res >>= solve      -- find HIDDEN PAIRS, TRIPLES or QUADRUPELS | ||||||
|  |     -- comment "no more hidden pairs" = () | ||||||
|  |     -- res@(_:_) <- nakedPair 3 b     = apply b res >>= solve       // find NAKED PAIRS, TRIPLES or QUADRUPELS | ||||||
|  |     -- | comment "no more naked triples" = () | ||||||
|  |     -- res@(_:_) <- hiddenPair  3 b    = apply b res >>= solve      // find HIDDEN PAIRS, TRIPLES or QUADRUPELS | ||||||
|  |     -- | comment "no more hidden triples" = () | ||||||
|  |     -- res@(_:_) <- nakedPair 4 b     = apply b res >>=solve       // find NAKED PAIRS, TRIPLES or QUADRUPELS | ||||||
|  |     -- | comment "no more naked quadruples" = () | ||||||
|  |     -- res@(_:_) <- hiddenPair  4 b    = apply b res >>=solve      // find HIDDEN PAIRS, TRIPLES or QUADRUPELS | ||||||
|  |     -- | comment "no more hidden quadruples" = () | ||||||
|  |     | res@(_:_) <- xyWing b            = apply b res >>=solve      -- find XY WINGS | ||||||
|  |     -- comment "no more xy wings"       = () | ||||||
|  |     | res@(_:_) <- fish 2 b            = apply b res >>=solve      -- find 2-FISH | ||||||
|  |     -- comment "no more x-wings"        = () | ||||||
|  |     -- res@(_:_) <- fish 3 b            = apply b res >>=solve      // find 3-FISH | ||||||
|  |     -- | comment "no more swordfish"      = () | ||||||
|  |     -- res@(_:_) <- fish 4 b            = apply b res >>=solve      // find 4-FISH | ||||||
|  |     -- | comment "no more jellyfish"      = () | ||||||
|  |     -- | comment pcomment                 = () | ||||||
|  |     | res@(_:_) <- chain b paths             = apply b (take 9 res) >>= solve  -- find forcing chains | ||||||
|  |     | res@(_:_) <- cellRegionChain b paths   = apply b (take 9 res) >>= solve  -- find common conclusion for true assumption | ||||||
|  |     | res@(_:_) <- chainContra b paths       = apply b (take 9 res) >>= solve  -- find assumptions that allow to infer both a and !a | ||||||
|  |     -- comment "consistent conclusions only"       = () | ||||||
|  |  | ||||||
|  |     | otherwise = result "ambiguous" b | ||||||
|  |     where | ||||||
|  |         apply brd fs = foldM (\b\f -> f b) brd fs | ||||||
|  |         paths = mkPaths (acstree b) | ||||||
|  |         -- pcomment = show (length paths) ++ " assumptions with " ++ show (fold (+) 0 (map (length <~ snd) paths)) | ||||||
|  |         --    ++ " implication chains" | ||||||
|  |  | ||||||
|  | -- comment com = do stderr << com << "\n" for false | ||||||
|  | -- log com     = do stderr << com << "\n" for true | ||||||
|  |  | ||||||
|  | --- turn a string into a row | ||||||
|  | mkrow :: String -> [Zelle] | ||||||
|  | mkrow s = mkrow1 xs | ||||||
|  |     where | ||||||
|  |         xs = s ++ "---------" -- make sure at least 9 elements | ||||||
|  |         mkrow1 xs = (take 9 • filter ([]!=) • map f • unpacked) xs | ||||||
|  |         f x | x >= '1' && x <= '9'  =  [ord x - ord '0'] | ||||||
|  |             | x == ' '  = []    -- ignored | ||||||
|  |             | otherwise = elements | ||||||
|  |  | ||||||
|  | main ["-h"]    = main [] | ||||||
|  | main ["-help"] = main [] | ||||||
|  | main [] = do | ||||||
|  |         mapM_ stderr.println [ | ||||||
|  |             "usage: java Sudoku file ...", | ||||||
|  |             "       java Sudoku position", | ||||||
|  |             "where position is a 81 char string consisting of digits", | ||||||
|  |             "One can get such a string by going to", | ||||||
|  |             "http://www.sudokuoftheday.com/pages/s-o-t-d.php", | ||||||
|  |             "Right click on the puzzle and open it in new tab", | ||||||
|  |             "Copy the 81 digits from the URL in the address field of your browser.", | ||||||
|  |             "", | ||||||
|  |             "There is also a file with hard sudokus in examples/top95.txt\n"] | ||||||
|  |         return () | ||||||
|  |  | ||||||
|  |  | ||||||
|  | main [s@#^[0-9\W]{81}$#] = solve board >> return () | ||||||
|  |     where | ||||||
|  |         board = zip positions felder | ||||||
|  |         felder = decode s | ||||||
|  |  | ||||||
|  | main files = forM_ files sudoku | ||||||
|  |     where | ||||||
|  |         sudoku file = do | ||||||
|  |             br <- openReader file | ||||||
|  |             lines <- BufferedReader.getLines br | ||||||
|  |             bs <- process lines | ||||||
|  |             ss <- mapM (\b -> print "Puzzle: " >> printb b >> solve b) bs | ||||||
|  |             println ("Euler: " ++ show (sum (map res012 ss))) | ||||||
|  |             return () | ||||||
|  |  | ||||||
|  | -- "--3-" => [1..9, 1..9, [3], 1..9] | ||||||
|  | decode s = map candi (unpacked s) where | ||||||
|  |         candi c | c >= '1' && c <= '9'  = [(ord c - ord '0')] | ||||||
|  |                 | otherwise = elements | ||||||
|  | process [] = return [] | ||||||
|  | process (s:ss) | ||||||
|  |     | length s == 81 = consider b1 | ||||||
|  |     | length s == 9, | ||||||
|  |       length acht == 8, | ||||||
|  |       all ((9==) • length) acht = consider b2 | ||||||
|  |     | otherwise = do | ||||||
|  |             stderr.println ("skipped line: " ++ s) | ||||||
|  |             process ss | ||||||
|  |     where | ||||||
|  |         acht = take 8 ss | ||||||
|  |         neun = fold (++) "" (s:acht) | ||||||
|  |         b1 = zip positions (decode s) | ||||||
|  |         b2 = zip positions (decode neun) | ||||||
|  |         consider b = do | ||||||
|  |             -- print "Puzzle: " | ||||||
|  |             -- printb b | ||||||
|  |             bs <- process ss | ||||||
|  |             return (b:bs) | ||||||
|  |  | ||||||
							
								
								
									
										79
									
								
								samples/Frege/SwingExamples.fr
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								samples/Frege/SwingExamples.fr
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | |||||||
|  | package examples.SwingExamples where | ||||||
|  |  | ||||||
|  | import Java.Awt  (ActionListener) | ||||||
|  | import Java.Swing | ||||||
|  |  | ||||||
|  |  | ||||||
|  | main _ = do | ||||||
|  |     rs <- mapM Runnable.new [helloWorldGUI, buttonDemoGUI, celsiusConverterGUI] | ||||||
|  |     mapM_ invokeLater rs | ||||||
|  |     println "Hit enter to end ...." | ||||||
|  |     s <- getLine | ||||||
|  |     return () | ||||||
|  |  | ||||||
|  | celsiusConverterGUI = do | ||||||
|  |     tempTextField   <- JTextField.new() | ||||||
|  |     celsiusLabel    <- JLabel.new () | ||||||
|  |     convertButton   <- JButton.new () | ||||||
|  |     fahrenheitLabel <- JLabel.new ()  | ||||||
|  |     frame           <- JFrame.new () | ||||||
|  |     frame.setDefaultCloseOperation JFrame.dispose_on_close | ||||||
|  |     frame.setTitle "Celsius Converter" | ||||||
|  |     celsiusLabel.setText  "Celsius" | ||||||
|  |     convertButton.setText "Convert" | ||||||
|  |     let convertButtonActionPerformed _ = do | ||||||
|  |             celsius <- tempTextField.getText | ||||||
|  |             case celsius.double of | ||||||
|  |                 Left _  -> fahrenheitLabel.setText ("not a valid number: " ++ celsius) | ||||||
|  |                 Right c -> fahrenheitLabel.setText (show (c*1.8 + 32.0).long ++ " Fahrenheit")  | ||||||
|  |             return () | ||||||
|  |     ActionListener.new convertButtonActionPerformed >>= convertButton.addActionListener | ||||||
|  |     fahrenheitLabel.setText "Fahrenheit" | ||||||
|  |     contentPane <- frame.getContentPane | ||||||
|  |     layout      <- GroupLayout.new contentPane | ||||||
|  |     contentPane.setLayout layout | ||||||
|  |     -- TODO continue | ||||||
|  |     -- http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/learn/CelsiusConverterProject/src/learn/CelsiusConverterGUI.java | ||||||
|  |     frame.pack | ||||||
|  |     frame.setVisible true | ||||||
|  |  | ||||||
|  | helloWorldGUI = do | ||||||
|  |     frame <- JFrame.new "Hello World Frege" | ||||||
|  |     frame.setDefaultCloseOperation(JFrame.dispose_on_close) | ||||||
|  |     label <- JLabel.new "Hello World!" | ||||||
|  |     cp <- frame.getContentPane | ||||||
|  |     cp.add label | ||||||
|  |     frame.pack | ||||||
|  |     frame.setVisible true | ||||||
|  |  | ||||||
|  | buttonDemoGUI = do | ||||||
|  |     frame <- JFrame.new "Button Demo" | ||||||
|  |     frame.setDefaultCloseOperation(JFrame.dispose_on_close) | ||||||
|  |     newContentPane <- JPanel.new () | ||||||
|  |     b1::JButton <- JButton.new "Disable middle button" | ||||||
|  |     b1.setVerticalTextPosition   SwingConstants.center | ||||||
|  |     b1.setHorizontalTextPosition SwingConstants.leading | ||||||
|  |     b2::JButton <- JButton.new "Middle button" | ||||||
|  |     b2.setVerticalTextPosition   SwingConstants.center | ||||||
|  |     b2.setHorizontalTextPosition SwingConstants.leading | ||||||
|  |     b3::JButton <- JButton.new "Enable middle button" | ||||||
|  |     b3.setVerticalTextPosition   SwingConstants.center | ||||||
|  |     b3.setHorizontalTextPosition SwingConstants.leading | ||||||
|  |     b3.setEnabled false | ||||||
|  |     let action1 _ = do | ||||||
|  |             b2.setEnabled false | ||||||
|  |             b1.setEnabled false | ||||||
|  |             b3.setEnabled true | ||||||
|  |         action3 _ = do | ||||||
|  |             b2.setEnabled true | ||||||
|  |             b1.setEnabled true | ||||||
|  |             b3.setEnabled false | ||||||
|  |     ActionListener.new action1  >>= b1.addActionListener | ||||||
|  |     ActionListener.new action3  >>= b3.addActionListener  | ||||||
|  |     newContentPane.add b1 | ||||||
|  |     newContentPane.add b2 | ||||||
|  |     newContentPane.add b3 | ||||||
|  |     newContentPane.setOpaque true | ||||||
|  |     frame.setContentPane newContentPane | ||||||
|  |     frame.pack | ||||||
|  |     frame.setVisible true | ||||||
							
								
								
									
										57
									
								
								samples/G-code/duettest.g
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								samples/G-code/duettest.g
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | ; RepRapPro Ormerod | ||||||
|  | ; Board test GCodes | ||||||
|  | M111 S1; Debug on | ||||||
|  | G21 ; mm | ||||||
|  | G90 ; Absolute positioning | ||||||
|  | M83 ; Extrusion relative | ||||||
|  | M906 X800 Y800 Z800 E800 ; Motor currents (mA) | ||||||
|  | T0 ; Extruder 0 | ||||||
|  | G1 X50 F500 | ||||||
|  | G1 X0 | ||||||
|  | G4 P500 | ||||||
|  | G1 Y50 F500 | ||||||
|  | G1 Y0 | ||||||
|  | G4 P500 | ||||||
|  | G1 Z20 F200 | ||||||
|  | G1 Z0 | ||||||
|  | G4 P500 | ||||||
|  | G1 E20 F200 | ||||||
|  | G1 E-20 | ||||||
|  | G4 P500 | ||||||
|  | M106 S255 | ||||||
|  | G4 P500 | ||||||
|  | M106 S0 | ||||||
|  | G4 P500 | ||||||
|  | M105 | ||||||
|  | G10 P0 S100 | ||||||
|  | T0 | ||||||
|  | M140 S100 | ||||||
|  | G4 P5000 | ||||||
|  | M105 | ||||||
|  | G4 P5000 | ||||||
|  | M105 | ||||||
|  | G4 P5000 | ||||||
|  | M105 | ||||||
|  | G4 P5000 | ||||||
|  | M105 | ||||||
|  | G4 P5000 | ||||||
|  | M105 | ||||||
|  | G4 P5000 | ||||||
|  | M105 | ||||||
|  | G4 P5000 | ||||||
|  | M105 | ||||||
|  | G4 P5000 | ||||||
|  | M105 | ||||||
|  | G4 P5000 | ||||||
|  | M105 | ||||||
|  | G4 P5000 | ||||||
|  | M105 | ||||||
|  | G4 P5000 | ||||||
|  | M105 | ||||||
|  | G4 P5000 | ||||||
|  | M105 | ||||||
|  | M0 | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										25912
									
								
								samples/G-code/lm.g
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25912
									
								
								samples/G-code/lm.g
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										29735
									
								
								samples/G-code/rm.g
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29735
									
								
								samples/G-code/rm.g
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										13
									
								
								samples/G-code/square.g
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								samples/G-code/square.g
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | |||||||
|  | G28 X0 Y0 | ||||||
|  | G1 X55 Y5 F2000 | ||||||
|  | G1 Y180 | ||||||
|  | G1 X180 | ||||||
|  | G1 Y5 | ||||||
|  | G1 X55 | ||||||
|  | G1 Y180 | ||||||
|  | G1 X180 | ||||||
|  | G1 Y5 | ||||||
|  | G1 X55 | ||||||
|  | M0 | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										76
									
								
								samples/GAMS/transport.gms
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								samples/GAMS/transport.gms
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | |||||||
|  | *Basic example of transport model from GAMS model library | ||||||
|  |  | ||||||
|  | $Title  A Transportation Problem (TRNSPORT,SEQ=1) | ||||||
|  | $Ontext | ||||||
|  |  | ||||||
|  | This problem finds a least cost shipping schedule that meets | ||||||
|  | requirements at markets and supplies at factories. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Dantzig, G B, Chapter 3.3. In Linear Programming and Extensions. | ||||||
|  | Princeton University Press, Princeton, New Jersey, 1963. | ||||||
|  |  | ||||||
|  | This formulation is described in detail in: | ||||||
|  | Rosenthal, R E, Chapter 2: A GAMS Tutorial. In GAMS: A User's Guide. | ||||||
|  | The Scientific Press, Redwood City, California, 1988. | ||||||
|  |  | ||||||
|  | The line numbers will not match those in the book because of these | ||||||
|  | comments. | ||||||
|  |  | ||||||
|  | $Offtext | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   Sets | ||||||
|  |        i   canning plants   / seattle, san-diego / | ||||||
|  |        j   markets          / new-york, chicago, topeka / ; | ||||||
|  |   Parameters | ||||||
|  |        a(i)  capacity of plant i in cases | ||||||
|  |          /    seattle     350 | ||||||
|  |               san-diego   600  / | ||||||
|  |        b(j)  demand at market j in cases | ||||||
|  |          /    new-york    325 | ||||||
|  |               chicago     300 | ||||||
|  |               topeka      275  / ; | ||||||
|  |   Table d(i,j)  distance in thousands of miles | ||||||
|  |                     new-york       chicago      topeka | ||||||
|  |       seattle          2.5           1.7          1.8 | ||||||
|  |       san-diego        2.5           1.8          1.4  ; | ||||||
|  |   Scalar f  freight in dollars per case per thousand miles  /90/ ; | ||||||
|  |   Parameter c(i,j)  transport cost in thousands of dollars per case ; | ||||||
|  |             c(i,j) = f * d(i,j) / 1000 ; | ||||||
|  |   Variables | ||||||
|  |        x(i,j)  shipment quantities in cases | ||||||
|  |        z       total transportation costs in thousands of dollars ; | ||||||
|  |  | ||||||
|  |   Positive Variable x ; | ||||||
|  |  | ||||||
|  |   Equations | ||||||
|  |        cost        define objective function | ||||||
|  |        supply(i)   observe supply limit at plant i | ||||||
|  |        demand(j)   satisfy demand at market j ; | ||||||
|  |  | ||||||
|  |   cost ..        z  =e=  sum((i,j), c(i,j)*x(i,j)) ; | ||||||
|  |  | ||||||
|  |   supply(i) ..   sum(j, x(i,j))  =l=  a(i) ; | ||||||
|  |  | ||||||
|  |   demand(j) ..   sum(i, x(i,j))  =g=  b(j) ; | ||||||
|  |  | ||||||
|  |   Model transport /all/ ; | ||||||
|  |  | ||||||
|  |   Solve transport using lp minimizing z ; | ||||||
|  |  | ||||||
|  |   Display x.l, x.m ; | ||||||
|  |  | ||||||
|  | $ontext | ||||||
|  | #user model library stuff | ||||||
|  | Main topic Basic GAMS | ||||||
|  | Featured item 1 Trnsport model | ||||||
|  | Featured item 2 | ||||||
|  | Featured item 3 | ||||||
|  | Featured item 4 | ||||||
|  | Description | ||||||
|  | Basic example of transport model from GAMS model library | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | $offtext | ||||||
							
								
								
									
										307
									
								
								samples/GAP/Magic.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										307
									
								
								samples/GAP/Magic.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,307 @@ | |||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | ##  Magic.gd                                         AutoDoc package | ||||||
|  | ## | ||||||
|  | ##  Copyright 2013, Max Horn, JLU Giessen | ||||||
|  | ##                  Sebastian Gutsche, University of Kaiserslautern | ||||||
|  | ## | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #! @Description | ||||||
|  | #! This is the main function of the &AutoDoc; package. It can perform | ||||||
|  | #! any combination of the following three tasks: | ||||||
|  | #! <Enum> | ||||||
|  | #! <Item> | ||||||
|  | #!     It can (re)generate a scaffold for your package manual. | ||||||
|  | #!     That is, it can produce two XML files in &GAPDoc; format to be used as part | ||||||
|  | #!     of your manual: First, a file named <F>doc/PACKAGENAME.xml</F> | ||||||
|  | #!     (with your package's name substituted) which is used as | ||||||
|  | #!     main file for the package manual, i.e. this file sets the | ||||||
|  | #!     XML DOCTYPE and defines various XML entities, includes | ||||||
|  | #!     other XML files (both those generated by &AutoDoc; as well | ||||||
|  | #!     as additional files created by other means), tells &GAPDoc; | ||||||
|  | #!     to generate a table of content and an index, and more. | ||||||
|  | #!     Secondly, it creates a file <F>doc/title.xml</F> containing a title | ||||||
|  | #!     page for your documentation, with information about your package | ||||||
|  | #!     (name, description, version), its authors and more, based | ||||||
|  | #!     on the data in your <F>PackageInfo.g</F>. | ||||||
|  | #! </Item> | ||||||
|  | #! <Item> | ||||||
|  | #!     It can scan your package for &AutoDoc; based documentation (by using &AutoDoc; | ||||||
|  | #!     tags and the Autodoc command. | ||||||
|  | #!     This will | ||||||
|  | #!     produce further XML files to be used as part of the package manual. | ||||||
|  | #! </Item> | ||||||
|  | #! <Item> | ||||||
|  | #!     It can use &GAPDoc; to generate PDF, text and HTML (with | ||||||
|  | #!     MathJaX enabled) documentation from the &GAPDoc; XML files it | ||||||
|  | #!     generated as well as additional such files provided by you. For | ||||||
|  | #!     this, it invokes <Ref Func='MakeGAPDocDoc' BookName='gapdoc'/> | ||||||
|  | #!     to convert the XML sources, and it also instructs &GAPDoc; to copy | ||||||
|  | #!     supplementary files (such as CSS style files) into your doc directory | ||||||
|  | #!     (see <Ref Func='CopyHTMLStyleFiles' BookName='gapdoc'/>). | ||||||
|  | #! </Item> | ||||||
|  | #! </Enum> | ||||||
|  | #! For more information and some examples, please refer to Chapter <Ref Label='Tutorials'/>. | ||||||
|  | #! <P/> | ||||||
|  | #! The parameters have the following meanings: | ||||||
|  | #! <List> | ||||||
|  | #! | ||||||
|  | #! <Mark><A>package_name</A></Mark> | ||||||
|  | #! <Item> | ||||||
|  | #!     The name of the package whose documentation should be(re)generated. | ||||||
|  | #! </Item> | ||||||
|  | #! | ||||||
|  | #! | ||||||
|  | #! <Mark><A>option_record</A></Mark> | ||||||
|  | #! <Item> | ||||||
|  | #!     <A>option_record</A> can be a record with some additional options. | ||||||
|  | #!     The following are currently supported: | ||||||
|  | #!     <List> | ||||||
|  | #!     <Mark><A>dir</A></Mark> | ||||||
|  | #!     <Item> | ||||||
|  | #!         This should be a string containing a (relative) path or a | ||||||
|  | #!         Directory() object specifying where the package documentation | ||||||
|  | #!         (i.e. the &GAPDoc; XML files) are stored. | ||||||
|  | #!         <Br/> | ||||||
|  | #!         <E>Default value: <C>"doc/"</C>.</E> | ||||||
|  | #!     </Item> | ||||||
|  | #!     <Mark><A>scaffold</A></Mark> | ||||||
|  | #!     <Item> | ||||||
|  | #!         This controls whether and how to generate scaffold XML files | ||||||
|  | #!         for the main and title page of the package's documentation.  | ||||||
|  | #!         <P/> | ||||||
|  | #!         The value should be either <K>true</K>, <K>false</K> or a | ||||||
|  | #!         record. If it is a record or <K>true</K> (the latter is | ||||||
|  | #!         equivalent to specifying an empty record), then this feature is | ||||||
|  | #!         enabled. It is also enabled if <A>opt.scaffold</A> is missing but the | ||||||
|  | #!         package's info record in <F>PackageInfo.g</F> has an <C>AutoDoc</C> entry. | ||||||
|  | #!         In all other cases (in particular if <A>opt.scaffold</A> is | ||||||
|  | #!         <K>false</K>), scaffolding is disabled. | ||||||
|  | #!         <P/> | ||||||
|  | #! | ||||||
|  | #!         If <A>opt.scaffold</A> is a record, it may contain the following entries. | ||||||
|  | #! | ||||||
|  | #### TODO: mention merging with PackageInfo.AutoDoc! | ||||||
|  | #!         <List> | ||||||
|  | #! | ||||||
|  | #!         <Mark><A>includes</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             A list of XML files to be included in the body of the main XML file. | ||||||
|  | #!             If you specify this list and also are using &AutoDoc; to document | ||||||
|  | #!             your operations with &AutoDoc; comments, | ||||||
|  | #!             you can add <F>AutoDocMainFile.xml</F> to this list | ||||||
|  | #!             to control at which point the documentation produced by &AutoDoc; | ||||||
|  | #!             is inserted. If you do not do this, it will be added after the last | ||||||
|  | #!             of your own XML files. | ||||||
|  | #!         </Item> | ||||||
|  | #! | ||||||
|  | #!         <Mark><A>appendix</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             This entry is similar to <A>opt.scaffold.includes</A> but is used | ||||||
|  | #!             to specify files to include after the main body of the manual, | ||||||
|  | #!             i.e. typically appendices. | ||||||
|  | #!         </Item> | ||||||
|  | #! | ||||||
|  | #!         <Mark><A>bib</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             The name of a bibliography file, in Bibtex or XML format. | ||||||
|  | #!             If this key is not set, but there is a file <F>doc/PACKAGENAME.bib</F> | ||||||
|  | #!             then it is assumed that you want to use this as your bibliography. | ||||||
|  | #!         </Item> | ||||||
|  | #! | ||||||
|  | #### TODO: The 'entities' param is a bit strange. We should probably change it to be a bit more | ||||||
|  | #### general, as one might want to define other entities... For now, we do not document it | ||||||
|  | #### to leave us the choice of revising how it works. | ||||||
|  | #### | ||||||
|  | ####                 <Mark><A>entities</A></Mark> | ||||||
|  | ####                 <Item> | ||||||
|  | ####                     A list of package names or other entities which are used to define corresponding XML entities. | ||||||
|  | ####                     For example, if set to a list containing the string <Q>SomePackage</Q>, | ||||||
|  | ####                     then the following is added to the XML preamble: | ||||||
|  | ####                     <Listing><![CDATA[<!ENTITY SomePackage '<Package>SomePackage</Package>'>]]></Listing> | ||||||
|  | ####                     This allows you to write <Q>&SomePackage;</Q> in your documentation | ||||||
|  | ####                     to reference that package. If another type of entity is desired, one can simply add, | ||||||
|  | ####                     instead of a string, add a two entry list <A>a</A> to the list. It will be handled as | ||||||
|  | ####                     <Listing><![CDATA[<!ENTITY a[ 2 ] '<a[ 1 ]>a[ 2 ]</a[ 1 ]>'>]]></Listing>, | ||||||
|  | ####                     so please be careful. | ||||||
|  | ####                 </Item> | ||||||
|  | #! | ||||||
|  | #!         <Mark><A>TitlePage</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             A record whose entries are used to embellish the generated titlepage | ||||||
|  | #!             for the package manual with extra information, such as a copyright | ||||||
|  | #!             statement or acknowledgments. To this end, the names of the record | ||||||
|  | #!             components are used as XML element names, and the values of the | ||||||
|  | #!             components are outputted as content of these XML elements. For | ||||||
|  | #!             example, you could pass the following record to set a custom | ||||||
|  | #!             acknowledgements text: | ||||||
|  | #!             <Listing><![CDATA[ | ||||||
|  | #!             rec( Acknowledgements := "Many thanks to ..." )]]></Listing> | ||||||
|  | #!             For a list of valid entries in the titlepage, please refer to the | ||||||
|  | #!             &GAPDoc; manual, specifically section <Ref Subsect='Title' BookName='gapdoc'/> | ||||||
|  | #!             and following. | ||||||
|  | #!         </Item> | ||||||
|  | #!         <Mark><A>document_class</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             Sets the document class of the resulting pdf. The value can either be a string | ||||||
|  | #!             which has to be the name of the new document class, a list containing this string, or | ||||||
|  | #!             a list of two strings. Then the first one has to be the document class name, the second one | ||||||
|  | #!             the option string ( contained in [ ] ) in LaTeX. | ||||||
|  | #!         </Item> | ||||||
|  | #!         <Mark><A>latex_header_file</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             Replaces the standard header from &GAPDoc; completely with the header in this LaTeX file. | ||||||
|  | #!             Please be careful here, and look at GAPDoc's latexheader.tex file for an example. | ||||||
|  | #!         </Item> | ||||||
|  | #!         <Mark><A>gapdoc_latex_options</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             Must be a record with entries which can be understood by SetGapDocLaTeXOptions. Each entry can be a string, which | ||||||
|  | #!             will be given to &GAPDoc; directly, or a list containing of two entries: The first one must be the string "file", | ||||||
|  | #!             the second one a filename. This file will be read and then its content is passed to &GAPDoc; as option with the name | ||||||
|  | #!             of the entry. | ||||||
|  | #!         </Item> | ||||||
|  | #! | ||||||
|  | #!         </List> | ||||||
|  | #!     </Item> | ||||||
|  | #! | ||||||
|  | #! | ||||||
|  | #!     <Mark><A>autodoc</A></Mark> | ||||||
|  | #!     <Item> | ||||||
|  | #!         This controls whether and how to generate addition XML documentation files | ||||||
|  | #!         by scanning for &AutoDoc; documentation comments. | ||||||
|  | #!         <P/> | ||||||
|  | #!         The value should be either <K>true</K>, <K>false</K> or a | ||||||
|  | #!         record. If it is a record or <K>true</K> (the latter is | ||||||
|  | #!         equivalent to specifying an empty record), then this feature is | ||||||
|  | #!         enabled. It is also enabled if <A>opt.autodoc</A> is missing but the | ||||||
|  | #!         package depends (directly) on the &AutoDoc; package. | ||||||
|  | #!         In all other cases (in particular if <A>opt.autodoc</A> is | ||||||
|  | #!         <K>false</K>), this feature is disabled. | ||||||
|  | #!         <P/> | ||||||
|  | #! | ||||||
|  | #!         If <A>opt.autodoc</A> is a record, it may contain the following entries. | ||||||
|  | #! | ||||||
|  | #!         <List> | ||||||
|  | #! | ||||||
|  | #!         <Mark><A>files</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             A list of files (given by paths relative to the package directory) | ||||||
|  | #!             to be scanned for &AutoDoc; documentation comments. | ||||||
|  | #!             Usually it is more convenient to use <A>autodoc.scan_dirs</A>, see below. | ||||||
|  | #!         </Item> | ||||||
|  | #! | ||||||
|  | #!         <Mark><A>scan_dirs</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             A list of subdirectories of the package directory (given as relative paths) | ||||||
|  | #!             which &AutoDoc; then scans for .gi, .gd and .g files; all of these files | ||||||
|  | #!             are then scanned for &AutoDoc; documentation comments. | ||||||
|  | #!             <Br/> | ||||||
|  | #!             <E>Default value: <C>[ "gap", "lib", "examples", "examples/doc" ]</C>.</E> | ||||||
|  | #!         </Item> | ||||||
|  | #! | ||||||
|  | #!         <Mark><A>level</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             This defines the level of the created documentation. The default value is 0. | ||||||
|  | #!             When parts of the manual are declared with a higher value | ||||||
|  | #!             they will not be printed into the manual. | ||||||
|  | #!         </Item> | ||||||
|  | #! | ||||||
|  | #### TODO: Document section_intros later on. | ||||||
|  | #### However, note that thanks to the new AutoDoc comment syntax, the only remaining | ||||||
|  | #### use for this seems to be the ability to specify the order of chapters and | ||||||
|  | #### sections. | ||||||
|  | ####                 <Mark><A>section_intros</A></Mark> | ||||||
|  | ####                 <Item> | ||||||
|  | ####                     TODO. | ||||||
|  | ####                 </Item> | ||||||
|  | #! | ||||||
|  | #!         </List> | ||||||
|  | #!     </Item> | ||||||
|  | #! | ||||||
|  | #! | ||||||
|  | #!     <Mark><A>gapdoc</A></Mark> | ||||||
|  | #!     <Item> | ||||||
|  | #!         This controls whether and how to invoke &GAPDoc; to create HTML, PDF and text | ||||||
|  | #!         files from your various XML files. | ||||||
|  | #!         <P/> | ||||||
|  | #!         The value should be either <K>true</K>, <K>false</K> or a | ||||||
|  | #!         record. If it is a record or <K>true</K> (the latter is | ||||||
|  | #!         equivalent to specifying an empty record), then this feature is | ||||||
|  | #!         enabled. It is also enabled if <A>opt.gapdoc</A> is missing. | ||||||
|  | #!         In all other cases (in particular if <A>opt.gapdoc</A> is | ||||||
|  | #!         <K>false</K>), this feature is disabled. | ||||||
|  | #!         <P/> | ||||||
|  | #! | ||||||
|  | #!         If <A>opt.gapdoc</A> is a record, it may contain the following entries. | ||||||
|  | #! | ||||||
|  | #!         <List> | ||||||
|  | #! | ||||||
|  | #! | ||||||
|  | #### Note: 'main' is strictly speaking also used for the scaffold. | ||||||
|  | #### However, if one uses the scaffolding mechanism, then it is not | ||||||
|  | #### really necessary to specify a custom name for the main XML file. | ||||||
|  | #### Thus, the purpose of this parameter is to cater for packages | ||||||
|  | #### that have existing documentation using a different XML name, | ||||||
|  | #### and which do not wish to use scaffolding. | ||||||
|  | #### | ||||||
|  | #### This explain why we only allow specifying gapdoc.main. | ||||||
|  | #### The scaffolding code will still honor it, though, just in case. | ||||||
|  | #!         <Mark><A>main</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             The name of the main XML file of the package manual. | ||||||
|  | #!             This exists primarily to support packages with existing manual | ||||||
|  | #!             which use a filename here which differs from the default. | ||||||
|  | #!             In particular, specifying this is unnecessary when using scaffolding. | ||||||
|  | #!             <Br/> | ||||||
|  | #!             <E>Default value: <C>PACKAGENAME.xml</C></E>. | ||||||
|  | #!         </Item> | ||||||
|  | #! | ||||||
|  | #!         <Mark><A>files</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             A list of files (given by paths relative to the package directory) | ||||||
|  | #!             to be scanned for &GAPDoc; documentation comments. | ||||||
|  | #!             Usually it is more convenient to use <A>gapdoc.scan_dirs</A>, see below. | ||||||
|  | #!         </Item> | ||||||
|  | #! | ||||||
|  | #!         <Mark><A>scan_dirs</A></Mark> | ||||||
|  | #!         <Item> | ||||||
|  | #!             A list of subdirectories of the package directory (given as relative paths) | ||||||
|  | #!             which &AutoDoc; then scans for .gi, .gd and .g files; all of these files | ||||||
|  | #!             are then scanned for &GAPDoc; documentation comments. | ||||||
|  | #!             <Br/> | ||||||
|  | #!             <E>Default value: <C>[ "gap", "lib", "examples", "examples/doc" ]</C>.</E> | ||||||
|  | #!         </Item> | ||||||
|  | #! | ||||||
|  | #!         </List> | ||||||
|  | #!     </Item> | ||||||
|  | ## This is the maketest part. Still under construction. | ||||||
|  | #!        <Mark><A>maketest</A></Mark> | ||||||
|  | #!        <Item> | ||||||
|  | #!          The maketest item can be true or a record. When it is true, | ||||||
|  | #!          a simple maketest.g is created in the main package directory, | ||||||
|  | #!          which can be used to test the examples from the manual. As a record, | ||||||
|  | #!          the entry can have the following entries itself, to specify some options. | ||||||
|  | #!          <List> | ||||||
|  | #!          <Mark>filename</Mark> | ||||||
|  | #!          <Item> | ||||||
|  | #!            Sets the name of the test file. | ||||||
|  | #!          </Item> | ||||||
|  | #!          <Mark>commands</Mark> | ||||||
|  | #!          <Item> | ||||||
|  | #!            A list of strings, each one a command, which | ||||||
|  | #!            will be executed at the beginning of the test file. | ||||||
|  | #!          </Item> | ||||||
|  | #!          </List> | ||||||
|  | #!        </Item> | ||||||
|  | #! | ||||||
|  | #!     </List> | ||||||
|  | #! </Item> | ||||||
|  | #! </List> | ||||||
|  | #! | ||||||
|  | #! @Returns nothing | ||||||
|  | #! @Arguments package_name[, option_record ] | ||||||
|  | #! @ChapterInfo AutoDoc, The AutoDoc() function | ||||||
|  | DeclareGlobalFunction( "AutoDoc" ); | ||||||
|  |  | ||||||
							
								
								
									
										534
									
								
								samples/GAP/Magic.gi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										534
									
								
								samples/GAP/Magic.gi
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,534 @@ | |||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | ##  Magic.gi                                         AutoDoc package | ||||||
|  | ## | ||||||
|  | ##  Copyright 2013, Max Horn, JLU Giessen | ||||||
|  | ##                  Sebastian Gutsche, University of Kaiserslautern | ||||||
|  | ## | ||||||
|  | ############################################################################# | ||||||
|  |  | ||||||
|  | # Check if a string has the given suffix or not. Another | ||||||
|  | # name for this would "StringEndsWithOtherString". | ||||||
|  | # For example, AUTODOC_HasSuffix("file.gi", ".gi") returns | ||||||
|  | # true while AUTODOC_HasSuffix("file.txt", ".gi") returns false. | ||||||
|  | BindGlobal( "AUTODOC_HasSuffix", | ||||||
|  | function(str, suffix) | ||||||
|  |     local n, m; | ||||||
|  |     n := Length(str); | ||||||
|  |     m := Length(suffix); | ||||||
|  |     return n >= m and str{[n-m+1..n]} = suffix; | ||||||
|  | end ); | ||||||
|  |  | ||||||
|  | # Given a string containing a ".", , return its suffix, | ||||||
|  | # i.e. the bit after the last ".". For example, given "test.txt", | ||||||
|  | # it returns "txt". | ||||||
|  | BindGlobal( "AUTODOC_GetSuffix", | ||||||
|  | function(str) | ||||||
|  |     local i; | ||||||
|  |     i := Length(str); | ||||||
|  |     while i > 0 and str[i] <> '.' do i := i - 1; od; | ||||||
|  |     if i < 0 then return ""; fi; | ||||||
|  |     return str{[i+1..Length(str)]}; | ||||||
|  | end ); | ||||||
|  |  | ||||||
|  | # Check whether the given directory exists, and if not, attempt | ||||||
|  | # to create it. | ||||||
|  | BindGlobal( "AUTODOC_CreateDirIfMissing", | ||||||
|  | function(d) | ||||||
|  |     local tmp; | ||||||
|  |     if not IsDirectoryPath(d) then | ||||||
|  |         tmp := CreateDir(d); # Note: CreateDir is currently undocumented | ||||||
|  |         if tmp = fail then | ||||||
|  |             Error("Cannot create directory ", d, "\n", | ||||||
|  |                   "Error message: ", LastSystemError().message, "\n"); | ||||||
|  |             return false; | ||||||
|  |         fi; | ||||||
|  |     fi; | ||||||
|  |     return true; | ||||||
|  | end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # Scan the given (by name) subdirs of a package dir for | ||||||
|  | # files with one of the given extensions, and return the corresponding | ||||||
|  | # filenames, as relative paths (relative to the package dir). | ||||||
|  | # | ||||||
|  | # For example, the invocation | ||||||
|  | #   AUTODOC_FindMatchingFiles("AutoDoc", [ "gap/" ], [ "gi", "gd" ]); | ||||||
|  | # might return a list looking like | ||||||
|  | #  [ "gap/AutoDocMainFunction.gd", "gap/AutoDocMainFunction.gi", ... ] | ||||||
|  | BindGlobal( "AUTODOC_FindMatchingFiles", | ||||||
|  | function (pkg, subdirs, extensions) | ||||||
|  |     local d_rel, d, tmp, files, result; | ||||||
|  |  | ||||||
|  |     result := []; | ||||||
|  |  | ||||||
|  |     for d_rel in subdirs do | ||||||
|  |         # Get the absolute path to the directory in side the package... | ||||||
|  |         d := DirectoriesPackageLibrary( pkg, d_rel ); | ||||||
|  |         if IsEmpty( d ) then | ||||||
|  |             continue; | ||||||
|  |         fi; | ||||||
|  |         d := d[1]; | ||||||
|  |         # ... but also keep the relative path (such as "gap") | ||||||
|  |         d_rel := Directory( d_rel ); | ||||||
|  |  | ||||||
|  |         files := DirectoryContents( d ); | ||||||
|  |         Sort( files ); | ||||||
|  |         for tmp in files do | ||||||
|  |             if not AUTODOC_GetSuffix( tmp ) in [ "g", "gi", "gd", "autodoc" ] then | ||||||
|  |                 continue; | ||||||
|  |             fi; | ||||||
|  |             if not IsReadableFile( Filename( d, tmp ) ) then | ||||||
|  |                 continue; | ||||||
|  |             fi; | ||||||
|  |             Add( result, Filename( d_rel, tmp ) ); | ||||||
|  |         od; | ||||||
|  |     od; | ||||||
|  |     return result; | ||||||
|  | end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # AutoDoc(pkg[, opt]) | ||||||
|  | # | ||||||
|  | ## Make this function callable with the package_name AutoDocWorksheet. | ||||||
|  | ## Which will then create a worksheet! | ||||||
|  | InstallGlobalFunction( AutoDoc, | ||||||
|  | function( arg ) | ||||||
|  |     local pkg, package_info, opt, scaffold, gapdoc, maketest, | ||||||
|  |           autodoc, pkg_dir, doc_dir, doc_dir_rel, d, tmp, | ||||||
|  |           title_page, tree, is_worksheet, position_document_class, i, gapdoc_latex_option_record; | ||||||
|  |      | ||||||
|  |     pkg := arg[1]; | ||||||
|  |      | ||||||
|  |     if LowercaseString( pkg ) = "autodocworksheet" then | ||||||
|  |         is_worksheet := true; | ||||||
|  |         package_info := rec( ); | ||||||
|  |         pkg_dir := DirectoryCurrent( ); | ||||||
|  |     else | ||||||
|  |         is_worksheet := false; | ||||||
|  |         package_info := PackageInfo( pkg )[ 1 ]; | ||||||
|  |         pkg_dir := DirectoriesPackageLibrary( pkg, "" )[1]; | ||||||
|  |     fi; | ||||||
|  |  | ||||||
|  |     if Length(arg) >= 2 then | ||||||
|  |         opt := arg[2]; | ||||||
|  |     else | ||||||
|  |         opt := rec(); | ||||||
|  |     fi; | ||||||
|  |  | ||||||
|  |     # Check for certain user supplied options, and if present, add them | ||||||
|  |     # to the opt record. | ||||||
|  |     tmp := function( key ) | ||||||
|  |         local val; | ||||||
|  |         val := ValueOption( key ); | ||||||
|  |         if val <> fail then | ||||||
|  |             opt.(key) := val; | ||||||
|  |         fi; | ||||||
|  |     end; | ||||||
|  |      | ||||||
|  |     tmp( "dir" ); | ||||||
|  |     tmp( "scaffold" ); | ||||||
|  |     tmp( "autodoc" ); | ||||||
|  |     tmp( "gapdoc" ); | ||||||
|  |     tmp( "maketest" ); | ||||||
|  |      | ||||||
|  |     # | ||||||
|  |     # Setup the output directory | ||||||
|  |     # | ||||||
|  |     if not IsBound( opt.dir ) then | ||||||
|  |         doc_dir := "doc"; | ||||||
|  |     elif IsString( opt.dir ) or IsDirectory( opt.dir ) then | ||||||
|  |         doc_dir := opt.dir; | ||||||
|  |     else | ||||||
|  |         Error( "opt.dir must be a string containing a path, or a directory object" ); | ||||||
|  |     fi; | ||||||
|  |      | ||||||
|  |     if IsString( doc_dir ) then | ||||||
|  |         # Record the relative version of the path | ||||||
|  |         doc_dir_rel := Directory( doc_dir ); | ||||||
|  |  | ||||||
|  |         # We intentionally do not use | ||||||
|  |         #   DirectoriesPackageLibrary( pkg, "doc" ) | ||||||
|  |         # because it returns an empty list if the subdirectory is missing. | ||||||
|  |         # But we want to handle that case by creating the directory. | ||||||
|  |         doc_dir := Filename(pkg_dir, doc_dir); | ||||||
|  |         doc_dir := Directory(doc_dir); | ||||||
|  |  | ||||||
|  |     else | ||||||
|  |         # TODO: doc_dir_rel = ... ? | ||||||
|  |     fi; | ||||||
|  |  | ||||||
|  |     # Ensure the output directory exists, create it if necessary | ||||||
|  |     AUTODOC_CreateDirIfMissing(Filename(doc_dir, "")); | ||||||
|  |      | ||||||
|  |     # Let the developer know where we are generating the documentation. | ||||||
|  |     # This helps diagnose problems where multiple instances of a package | ||||||
|  |     # are visible to GAP and the wrong one is used for generating the | ||||||
|  |     # documentation. | ||||||
|  |     # TODO: Using Info() instead of Print? | ||||||
|  |     Print( "Generating documentation in ", doc_dir, "\n" ); | ||||||
|  |  | ||||||
|  |     # | ||||||
|  |     # Extract scaffolding settings, which can be controlled via | ||||||
|  |     # opt.scaffold or package_info.AutoDoc. The former has precedence. | ||||||
|  |     # | ||||||
|  |     if not IsBound(opt.scaffold) then | ||||||
|  |         # Default: enable scaffolding if and only if package_info.AutoDoc is present | ||||||
|  |         if IsBound( package_info.AutoDoc ) then | ||||||
|  |             scaffold := rec( ); | ||||||
|  |         fi; | ||||||
|  |     elif IsRecord(opt.scaffold) then | ||||||
|  |         scaffold := opt.scaffold; | ||||||
|  |     elif IsBool(opt.scaffold) then | ||||||
|  |         if opt.scaffold = true then | ||||||
|  |             scaffold := rec(); | ||||||
|  |         fi; | ||||||
|  |     else | ||||||
|  |         Error("opt.scaffold must be a bool or a record"); | ||||||
|  |     fi; | ||||||
|  |  | ||||||
|  |     # Merge package_info.AutoDoc into scaffold | ||||||
|  |     if IsBound(scaffold) and IsBound( package_info.AutoDoc ) then | ||||||
|  |         AUTODOC_APPEND_RECORD_WRITEONCE( scaffold, package_info.AutoDoc ); | ||||||
|  |     fi; | ||||||
|  |      | ||||||
|  |     if IsBound( scaffold ) then | ||||||
|  |         AUTODOC_WriteOnce( scaffold, "TitlePage", true ); | ||||||
|  |         AUTODOC_WriteOnce( scaffold, "MainPage", true ); | ||||||
|  |     fi; | ||||||
|  |  | ||||||
|  |      | ||||||
|  |     # | ||||||
|  |     # Extract AutoDoc settings | ||||||
|  |     # | ||||||
|  |     if not IsBound(opt.autodoc) and not is_worksheet then | ||||||
|  |         # Enable AutoDoc support if the package depends on AutoDoc. | ||||||
|  |         tmp := Concatenation( package_info.Dependencies.NeededOtherPackages, | ||||||
|  |                               package_info.Dependencies.SuggestedOtherPackages ); | ||||||
|  |         if ForAny( tmp, x -> LowercaseString(x[1]) = "autodoc" ) then | ||||||
|  |             autodoc := rec(); | ||||||
|  |         fi; | ||||||
|  |     elif IsRecord(opt.autodoc) then | ||||||
|  |         autodoc := opt.autodoc; | ||||||
|  |     elif IsBool(opt.autodoc) and opt.autodoc = true then | ||||||
|  |         autodoc := rec(); | ||||||
|  |     fi; | ||||||
|  |      | ||||||
|  |     if IsBound(autodoc) then | ||||||
|  |         if not IsBound( autodoc.files ) then | ||||||
|  |             autodoc.files := [ ]; | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         if not IsBound( autodoc.scan_dirs ) and not is_worksheet then | ||||||
|  |             autodoc.scan_dirs := [ "gap", "lib", "examples", "examples/doc" ]; | ||||||
|  |         elif not IsBound( autodoc.scan_dirs ) and is_worksheet then | ||||||
|  |             autodoc.scan_dirs := [ ]; | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         if not IsBound( autodoc.level ) then | ||||||
|  |             autodoc.level := 0; | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         PushOptions( rec( level_value := autodoc.level ) ); | ||||||
|  |          | ||||||
|  |         if not is_worksheet then | ||||||
|  |             Append( autodoc.files, AUTODOC_FindMatchingFiles(pkg, autodoc.scan_dirs, [ "g", "gi", "gd" ]) ); | ||||||
|  |         fi; | ||||||
|  |     fi; | ||||||
|  |  | ||||||
|  |     # | ||||||
|  |     # Extract GAPDoc settings | ||||||
|  |     # | ||||||
|  |     if not IsBound( opt.gapdoc ) then | ||||||
|  |         # Enable GAPDoc support by default | ||||||
|  |         gapdoc := rec(); | ||||||
|  |     elif IsRecord( opt.gapdoc ) then | ||||||
|  |         gapdoc := opt.gapdoc; | ||||||
|  |     elif IsBool( opt.gapdoc ) and opt.gapdoc = true then | ||||||
|  |         gapdoc := rec(); | ||||||
|  |     fi; | ||||||
|  |      | ||||||
|  |     # | ||||||
|  |     # Extract test settings | ||||||
|  |     # | ||||||
|  |      | ||||||
|  |     if IsBound( opt.maketest ) then | ||||||
|  |         if IsRecord( opt.maketest ) then | ||||||
|  |             maketest := opt.maketest; | ||||||
|  |         elif opt.maketest = true then | ||||||
|  |             maketest := rec( ); | ||||||
|  |         fi; | ||||||
|  |     fi; | ||||||
|  |      | ||||||
|  |     if IsBound( gapdoc ) then | ||||||
|  |  | ||||||
|  |         if not IsBound( gapdoc.main ) then | ||||||
|  |             gapdoc.main := pkg; | ||||||
|  |         fi; | ||||||
|  |  | ||||||
|  |         # FIXME: the following may break if a package uses more than one book | ||||||
|  |         if IsBound( package_info.PackageDoc ) and IsBound( package_info.PackageDoc[1].BookName ) then | ||||||
|  |             gapdoc.bookname := package_info.PackageDoc[1].BookName; | ||||||
|  |         elif not is_worksheet then | ||||||
|  |             # Default: book name = package name | ||||||
|  |             gapdoc.bookname := pkg; | ||||||
|  |  | ||||||
|  |             Print("\n"); | ||||||
|  |             Print("WARNING: PackageInfo.g is missing a PackageDoc entry!\n"); | ||||||
|  |             Print("Without this, your package manual will not be recognized by the GAP help system.\n"); | ||||||
|  |             Print("You can correct this by adding the following to your PackageInfo.g:\n"); | ||||||
|  |             Print("PackageDoc := rec(\n"); | ||||||
|  |             Print("  BookName  := ~.PackageName,\n"); | ||||||
|  |             #Print("  BookName  := \"", pkg, "\",\n"); | ||||||
|  |             Print("  ArchiveURLSubset := [\"doc\"],\n"); | ||||||
|  |             Print("  HTMLStart := \"doc/chap0.html\",\n"); | ||||||
|  |             Print("  PDFFile   := \"doc/manual.pdf\",\n"); | ||||||
|  |             Print("  SixFile   := \"doc/manual.six\",\n"); | ||||||
|  |             Print("  LongTitle := ~.Subtitle,\n"); | ||||||
|  |             Print("),\n"); | ||||||
|  |             Print("\n"); | ||||||
|  |         fi; | ||||||
|  |  | ||||||
|  |         if not IsBound( gapdoc.files ) then | ||||||
|  |             gapdoc.files := []; | ||||||
|  |         fi; | ||||||
|  |  | ||||||
|  |         if not IsBound( gapdoc.scan_dirs ) and not is_worksheet then | ||||||
|  |             gapdoc.scan_dirs := [ "gap", "lib", "examples", "examples/doc" ]; | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         if not is_worksheet then | ||||||
|  |             Append( gapdoc.files, AUTODOC_FindMatchingFiles(pkg, gapdoc.scan_dirs, [ "g", "gi", "gd" ]) ); | ||||||
|  |         fi; | ||||||
|  |  | ||||||
|  |         # Attempt to weed out duplicates as they may confuse GAPDoc (this | ||||||
|  |         # won't work if there are any non-normalized paths in the list). | ||||||
|  |         gapdoc.files := Set( gapdoc.files ); | ||||||
|  |          | ||||||
|  |         # Convert the file paths in gapdoc.files, which are relative to | ||||||
|  |         # the package directory, to paths which are relative to the doc directory. | ||||||
|  |         # For this, we assume that doc_dir_rel is normalized (e.g. | ||||||
|  |         # it does not contains '//') and relative. | ||||||
|  |         d := Number( Filename( doc_dir_rel, "" ), x -> x = '/' ); | ||||||
|  |         d := Concatenation( ListWithIdenticalEntries(d, "../") ); | ||||||
|  |         gapdoc.files := List( gapdoc.files, f -> Concatenation( d, f ) ); | ||||||
|  |     fi; | ||||||
|  |      | ||||||
|  |      | ||||||
|  |     # read tree | ||||||
|  |     # FIXME: shouldn't tree be declared inside of an 'if IsBound(autodoc)' section? | ||||||
|  |     tree := DocumentationTree( ); | ||||||
|  |      | ||||||
|  |     if IsBound( autodoc ) then | ||||||
|  |         if IsBound( autodoc.section_intros ) then | ||||||
|  |             AUTODOC_PROCESS_INTRO_STRINGS( autodoc.section_intros : Tree := tree ); | ||||||
|  |         fi; | ||||||
|  |      | ||||||
|  |         AutoDocScanFiles( autodoc.files : PackageName := pkg, Tree := tree ); | ||||||
|  |     fi; | ||||||
|  |      | ||||||
|  |     if is_worksheet then | ||||||
|  |         # FIXME: We use scaffold and autodoc here without checking whether | ||||||
|  |         # they are bound. Does that mean worksheets always use them? | ||||||
|  |         if IsRecord( scaffold.TitlePage ) and IsBound( scaffold.TitlePage.Title ) then | ||||||
|  |             pkg := scaffold.TitlePage.Title; | ||||||
|  |  | ||||||
|  |         elif IsBound( tree!.TitlePage.Title ) then | ||||||
|  |             pkg := tree!.TitlePage.Title; | ||||||
|  |  | ||||||
|  |         elif IsBound( autodoc.files ) and Length( autodoc.files ) > 0  then | ||||||
|  |             pkg := autodoc.files[ 1 ]; | ||||||
|  |              | ||||||
|  |             while Position( pkg, '/' ) <> fail do | ||||||
|  |                 Remove( pkg, 1 ); | ||||||
|  |             od; | ||||||
|  |              | ||||||
|  |             while Position( pkg, '.' ) <> fail do | ||||||
|  |                 Remove( pkg, Length( pkg ) ); | ||||||
|  |             od; | ||||||
|  |  | ||||||
|  |         else | ||||||
|  |             Error( "could not figure out a title." ); | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         if not IsString( pkg ) then | ||||||
|  |             pkg := JoinStringsWithSeparator( pkg, " " ); | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         gapdoc.main := ReplacedString( pkg, " ", "_" ); | ||||||
|  |         gapdoc.bookname := ReplacedString( pkg, " ", "_" ); | ||||||
|  |     fi; | ||||||
|  |      | ||||||
|  |     # | ||||||
|  |     # Generate scaffold | ||||||
|  |     # | ||||||
|  |     gapdoc_latex_option_record := rec( ); | ||||||
|  |      | ||||||
|  |     if IsBound( scaffold ) then | ||||||
|  |         ## Syntax is [ "class", [ "options" ] ] | ||||||
|  |         if IsBound( scaffold.document_class ) then | ||||||
|  |             position_document_class := PositionSublist( GAPDoc2LaTeXProcs.Head, "documentclass" ); | ||||||
|  |              | ||||||
|  |             if IsString( scaffold.document_class ) then | ||||||
|  |                 scaffold.document_class := [ scaffold.document_class ]; | ||||||
|  |             fi; | ||||||
|  |              | ||||||
|  |             if position_document_class = fail then | ||||||
|  |                 Error( "something is wrong with the LaTeX header" ); | ||||||
|  |             fi; | ||||||
|  |              | ||||||
|  |             GAPDoc2LaTeXProcs.Head := Concatenation( | ||||||
|  |                   GAPDoc2LaTeXProcs.Head{[ 1 .. PositionSublist( GAPDoc2LaTeXProcs.Head, "{", position_document_class ) ]}, | ||||||
|  |                   scaffold.document_class[ 1 ], | ||||||
|  |                   GAPDoc2LaTeXProcs.Head{[ PositionSublist( GAPDoc2LaTeXProcs.Head, "}", position_document_class ) .. Length( GAPDoc2LaTeXProcs.Head ) ]} ); | ||||||
|  |              | ||||||
|  |             if Length( scaffold.document_class ) = 2 then | ||||||
|  |                  | ||||||
|  |                 GAPDoc2LaTeXProcs.Head := Concatenation( | ||||||
|  |                       GAPDoc2LaTeXProcs.Head{[ 1 .. PositionSublist( GAPDoc2LaTeXProcs.Head, "[", position_document_class ) ]}, | ||||||
|  |                       scaffold.document_class[ 2 ], | ||||||
|  |                       GAPDoc2LaTeXProcs.Head{[ PositionSublist( GAPDoc2LaTeXProcs.Head, "]", position_document_class ) .. Length( GAPDoc2LaTeXProcs.Head ) ]} ); | ||||||
|  |             fi; | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         if IsBound( scaffold.latex_header_file ) then | ||||||
|  |             GAPDoc2LaTeXProcs.Head := StringFile( scaffold.latex_header_file ); | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         if IsBound( scaffold.gapdoc_latex_options ) then | ||||||
|  |             if IsRecord( scaffold.gapdoc_latex_options ) then | ||||||
|  |                 for i in RecNames( scaffold.gapdoc_latex_options ) do | ||||||
|  |                     if not IsString( scaffold.gapdoc_latex_options.( i ) ) | ||||||
|  |                        and IsList( scaffold.gapdoc_latex_options.( i ) ) | ||||||
|  |                        and LowercaseString( scaffold.gapdoc_latex_options.( i )[ 1 ] ) = "file" then | ||||||
|  |                         scaffold.gapdoc_latex_options.( i ) := StringFile( scaffold.gapdoc_latex_options.( i )[ 2 ] ); | ||||||
|  |                     fi; | ||||||
|  |                 od; | ||||||
|  |                  | ||||||
|  |                 gapdoc_latex_option_record := scaffold.gapdoc_latex_options; | ||||||
|  |             fi; | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         if not IsBound( scaffold.includes ) then | ||||||
|  |             scaffold.includes := [ ]; | ||||||
|  |         fi; | ||||||
|  |  | ||||||
|  |         if IsBound( autodoc ) then | ||||||
|  |             # If scaffold.includes is already set, then we add | ||||||
|  |             # AutoDocMainFile.xml to it, but *only* if it not already | ||||||
|  |             # there. This way, package authors can control where | ||||||
|  |             # it is put in their includes list. | ||||||
|  |             if not "AutoDocMainFile.xml" in scaffold.includes then | ||||||
|  |                 Add( scaffold.includes, "AutoDocMainFile.xml" ); | ||||||
|  |             fi; | ||||||
|  |         fi; | ||||||
|  |  | ||||||
|  |         if IsBound( scaffold.bib ) and IsBool( scaffold.bib ) then | ||||||
|  |             if scaffold.bib = true then | ||||||
|  |                 scaffold.bib := Concatenation( pkg, ".bib" ); | ||||||
|  |             else | ||||||
|  |                 Unbind( scaffold.bib ); | ||||||
|  |             fi; | ||||||
|  |         elif not IsBound( scaffold.bib ) then | ||||||
|  |             # If there is a doc/PKG.bib file, assume that we want to reference it in the scaffold. | ||||||
|  |             if IsReadableFile( Filename( doc_dir, Concatenation( pkg, ".bib" ) ) ) then | ||||||
|  |                 scaffold.bib := Concatenation( pkg, ".bib" ); | ||||||
|  |             fi; | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         AUTODOC_WriteOnce( scaffold, "index", true ); | ||||||
|  |  | ||||||
|  |         if IsBound( gapdoc ) then | ||||||
|  |             if AUTODOC_GetSuffix( gapdoc.main ) = "xml" then | ||||||
|  |                 scaffold.main_xml_file := gapdoc.main; | ||||||
|  |             else | ||||||
|  |                 scaffold.main_xml_file := Concatenation( gapdoc.main, ".xml" ); | ||||||
|  |             fi; | ||||||
|  |         fi; | ||||||
|  |  | ||||||
|  |         # TODO: It should be possible to only rebuild the title page. (Perhaps also only the main page? but this is less important) | ||||||
|  |         if IsBound( scaffold.TitlePage ) then | ||||||
|  |             if IsRecord( scaffold.TitlePage ) then | ||||||
|  |                 title_page := scaffold.TitlePage; | ||||||
|  |             else | ||||||
|  |                 title_page := rec( ); | ||||||
|  |             fi; | ||||||
|  |              | ||||||
|  |             AUTODOC_WriteOnce( title_page, "dir", doc_dir ); | ||||||
|  |             AUTODOC_APPEND_RECORD_WRITEONCE( title_page, tree!.TitlePage ); | ||||||
|  |              | ||||||
|  |             if not is_worksheet then | ||||||
|  |                 AUTODOC_APPEND_RECORD_WRITEONCE( title_page, ExtractTitleInfoFromPackageInfo( pkg ) ); | ||||||
|  |             fi; | ||||||
|  |              | ||||||
|  |             CreateTitlePage( title_page ); | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         if IsBound( scaffold.MainPage ) and scaffold.MainPage <> false then | ||||||
|  |             scaffold.dir := doc_dir; | ||||||
|  |             scaffold.book_name := pkg; | ||||||
|  |             CreateMainPage( scaffold ); | ||||||
|  |         fi; | ||||||
|  |     fi; | ||||||
|  |      | ||||||
|  |     # | ||||||
|  |     # Run AutoDoc | ||||||
|  |     # | ||||||
|  |     if IsBound( autodoc ) then | ||||||
|  |         WriteDocumentation( tree, doc_dir ); | ||||||
|  |     fi; | ||||||
|  |      | ||||||
|  |      | ||||||
|  |     # | ||||||
|  |     # Run GAPDoc | ||||||
|  |     # | ||||||
|  |     if IsBound( gapdoc ) then | ||||||
|  |  | ||||||
|  |         # Ask GAPDoc to use UTF-8 as input encoding for LaTeX, as the XML files | ||||||
|  |         # of the documentation are also in UTF-8 encoding, and may contain characters | ||||||
|  |         # not contained in the default Latin 1 encoding. | ||||||
|  |         SetGapDocLaTeXOptions( "utf8", gapdoc_latex_option_record ); | ||||||
|  |  | ||||||
|  |         MakeGAPDocDoc( doc_dir, gapdoc.main, gapdoc.files, gapdoc.bookname, "MathJax" ); | ||||||
|  |  | ||||||
|  |         CopyHTMLStyleFiles( Filename( doc_dir, "" ) ); | ||||||
|  |  | ||||||
|  |         # The following (undocumented) API is there for compatibility | ||||||
|  |         # with old-style gapmacro.tex based package manuals. It | ||||||
|  |         # produces a manual.lab file which those packages can use if | ||||||
|  |         # they wish to link to things in the manual we are currently | ||||||
|  |         # generating. This can probably be removed eventually, but for | ||||||
|  |         # now, doing it does not hurt. | ||||||
|  |          | ||||||
|  |         # FIXME: It seems that this command does not work if pdflatex | ||||||
|  |         #        is not present. Maybe we should remove it. | ||||||
|  |          | ||||||
|  |         if not is_worksheet then | ||||||
|  |             GAPDocManualLab( pkg ); | ||||||
|  |         fi; | ||||||
|  |  | ||||||
|  |     fi; | ||||||
|  |      | ||||||
|  |     if IsBound( maketest ) then | ||||||
|  |          | ||||||
|  |         AUTODOC_WriteOnce( maketest, "filename", "maketest.g" ); | ||||||
|  |         AUTODOC_WriteOnce( maketest, "folder", pkg_dir ); | ||||||
|  |         AUTODOC_WriteOnce( maketest, "scan_dir", doc_dir ); | ||||||
|  |         AUTODOC_WriteOnce( maketest, "files_to_scan", gapdoc.files ); | ||||||
|  |  | ||||||
|  |         if IsString( maketest.folder ) then | ||||||
|  |             maketest.folder := Directory( maketest.folder ); | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         if IsString( maketest.scan_dir ) then | ||||||
|  |             maketest.scan_dir := Directory( maketest.scan_dir ); | ||||||
|  |         fi; | ||||||
|  |          | ||||||
|  |         AUTODOC_WriteOnce( maketest, "commands", [ ] ); | ||||||
|  |         AUTODOC_WriteOnce( maketest, "book_name", gapdoc.main ); | ||||||
|  |          | ||||||
|  |         CreateMakeTest( maketest ); | ||||||
|  |     fi; | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  | end ); | ||||||
							
								
								
									
										115
									
								
								samples/GAP/PackageInfo.g
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								samples/GAP/PackageInfo.g
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,115 @@ | |||||||
|  | ############################################################################# | ||||||
|  | ##   | ||||||
|  | ##  PackageInfo.g for the package `cvec'                      Max Neunhoeffer | ||||||
|  | ## | ||||||
|  | ##  (created from Frank Lübeck's PackageInfo.g template file) | ||||||
|  | ##   | ||||||
|  |  | ||||||
|  | SetPackageInfo( rec( | ||||||
|  |  | ||||||
|  | PackageName := "cvec", | ||||||
|  | Subtitle := "Compact vectors over finite fields", | ||||||
|  | Version := "2.5.1", | ||||||
|  | Date := "04/04/2014", # dd/mm/yyyy format | ||||||
|  |  | ||||||
|  | ##  Information about authors and maintainers. | ||||||
|  | Persons := [ | ||||||
|  |   rec(  | ||||||
|  |     LastName      := "Neunhoeffer", | ||||||
|  |     FirstNames    := "Max", | ||||||
|  |     IsAuthor      := true, | ||||||
|  |     IsMaintainer  := false, | ||||||
|  |     Email         := "neunhoef@mcs.st-and.ac.uk", | ||||||
|  |     WWWHome       := "http://www-groups.mcs.st-and.ac.uk/~neunhoef/", | ||||||
|  |     PostalAddress := Concatenation( [ | ||||||
|  |                        "School of Mathematics and Statistics\n", | ||||||
|  |                        "University of St Andrews\n", | ||||||
|  |                        "Mathematical Institute\n", | ||||||
|  |                        "North Haugh\n", | ||||||
|  |                        "St Andrews, Fife KY16 9SS\n", | ||||||
|  |                        "Scotland, UK" ] ), | ||||||
|  |     Place         := "St Andrews", | ||||||
|  |     Institution   := "University of St Andrews" | ||||||
|  |   ), | ||||||
|  | ], | ||||||
|  |  | ||||||
|  | ##  Status information. Currently the following cases are recognized: | ||||||
|  | ##    "accepted"      for successfully refereed packages | ||||||
|  | ##    "deposited"     for packages for which the GAP developers agreed  | ||||||
|  | ##                    to distribute them with the core GAP system | ||||||
|  | ##    "dev"           for development versions of packages  | ||||||
|  | ##    "other"         for all other packages | ||||||
|  | ## | ||||||
|  | # Status := "accepted", | ||||||
|  | Status := "deposited", | ||||||
|  |  | ||||||
|  | ##  You must provide the next two entries if and only if the status is  | ||||||
|  | ##  "accepted" because is was successfully refereed: | ||||||
|  | # format: 'name (place)' | ||||||
|  | # CommunicatedBy := "Mike Atkinson (St. Andrews)", | ||||||
|  | #CommunicatedBy := "", | ||||||
|  | # format: mm/yyyy | ||||||
|  | # AcceptDate := "08/1999", | ||||||
|  | #AcceptDate := "", | ||||||
|  |  | ||||||
|  | PackageWWWHome := "http://neunhoef.github.io/cvec/", | ||||||
|  | README_URL     := Concatenation(~.PackageWWWHome, "README"), | ||||||
|  | PackageInfoURL := Concatenation(~.PackageWWWHome, "PackageInfo.g"), | ||||||
|  | ArchiveURL     := Concatenation("https://github.com/neunhoef/cvec/", | ||||||
|  |                                 "releases/download/v", ~.Version, | ||||||
|  |                                 "/cvec-", ~.Version), | ||||||
|  | ArchiveFormats := ".tar.gz .tar.bz2", | ||||||
|  |  | ||||||
|  | ##  Here you  must provide a short abstract explaining the package content  | ||||||
|  | ##  in HTML format (used on the package overview Web page) and an URL  | ||||||
|  | ##  for a Webpage with more detailed information about the package | ||||||
|  | ##  (not more than a few lines, less is ok): | ||||||
|  | ##  Please, use '<span class="pkgname">GAP</span>' and | ||||||
|  | ##  '<span class="pkgname">MyPKG</span>' for specifing package names. | ||||||
|  | ##   | ||||||
|  | AbstractHTML :=  | ||||||
|  |   "This package provides an implementation of compact vectors over finite\ | ||||||
|  |    fields. Contrary to earlier implementations no table lookups are used\ | ||||||
|  |    but only word-based processor arithmetic. This allows for bigger finite\ | ||||||
|  |    fields and higher speed.", | ||||||
|  |  | ||||||
|  | PackageDoc := rec( | ||||||
|  |   BookName  := "cvec", | ||||||
|  |   ArchiveURLSubset := ["doc"], | ||||||
|  |   HTMLStart := "doc/chap0.html", | ||||||
|  |   PDFFile   := "doc/manual.pdf", | ||||||
|  |   SixFile   := "doc/manual.six", | ||||||
|  |   LongTitle := "Compact vectors over finite fields", | ||||||
|  | ), | ||||||
|  |  | ||||||
|  | Dependencies := rec( | ||||||
|  |   GAP := ">=4.5.5", | ||||||
|  |   NeededOtherPackages := [ | ||||||
|  |     ["GAPDoc", ">= 1.2"], | ||||||
|  |     ["IO", ">= 4.1"], | ||||||
|  |     ["orb", ">= 4.2"], | ||||||
|  |   ], | ||||||
|  |   SuggestedOtherPackages := [], | ||||||
|  |   ExternalConditions := [] | ||||||
|  | ), | ||||||
|  |  | ||||||
|  | AvailabilityTest := function() | ||||||
|  |   if not "cvec" in SHOW_STAT() and | ||||||
|  |      Filename(DirectoriesPackagePrograms("cvec"), "cvec.so") = fail then | ||||||
|  |     #Info(InfoWarning, 1, "cvec: kernel cvec functions not available."); | ||||||
|  |     return fail; | ||||||
|  |   fi; | ||||||
|  |   return true; | ||||||
|  | end, | ||||||
|  |  | ||||||
|  | ##  *Optional*, but recommended: path relative to package root to a file which  | ||||||
|  | ##  contains as many tests of the package functionality as sensible. | ||||||
|  | #TestFile := "tst/testall.g", | ||||||
|  |  | ||||||
|  | ##  *Optional*: Here you can list some keyword related to the topic  | ||||||
|  | ##  of the package. | ||||||
|  | Keywords := [] | ||||||
|  |  | ||||||
|  | )); | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										23
									
								
								samples/GAP/example.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								samples/GAP/example.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #W  example.gd | ||||||
|  | ## | ||||||
|  | ##  This file contains a sample of a GAP declaration file. | ||||||
|  | ## | ||||||
|  | DeclareProperty( "SomeProperty", IsLeftModule ); | ||||||
|  | DeclareGlobalFunction( "SomeGlobalFunction" ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #C  IsQuuxFrobnicator(<R>) | ||||||
|  | ## | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Filt Name="IsQuuxFrobnicator" Arg='R' Type='Category'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  Tests whether R is a quux frobnicator. | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ## | ||||||
|  | DeclareSynonym( "IsQuuxFrobnicator", IsField and IsGroup ); | ||||||
							
								
								
									
										64
									
								
								samples/GAP/example.gi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								samples/GAP/example.gi
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | |||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #W  example.gd | ||||||
|  | ## | ||||||
|  | ##  This file contains a sample of a GAP implementation file. | ||||||
|  | ## | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  SomeOperation( <val> ) | ||||||
|  | ## | ||||||
|  | ##  performs some operation on <val> | ||||||
|  | ## | ||||||
|  | InstallMethod( SomeProperty, | ||||||
|  |     "for left modules", | ||||||
|  |     [ IsLeftModule ], 0, | ||||||
|  |     function( M ) | ||||||
|  |     if IsFreeLeftModule( M ) and not IsTrivial( M ) then | ||||||
|  |       return true; | ||||||
|  |     fi; | ||||||
|  |     TryNextMethod(); | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  SomeGlobalFunction( ) | ||||||
|  | ## | ||||||
|  | ##  A global variadic funfion. | ||||||
|  | ## | ||||||
|  | InstallGlobalFunction( SomeGlobalFunction, function( arg ) | ||||||
|  |     if Length( arg ) = 3 then | ||||||
|  |       return arg[1] + arg[2] * arg[3]; | ||||||
|  |     elif Length( arg ) = 2 then | ||||||
|  |       return arg[1] - arg[2] | ||||||
|  |     else | ||||||
|  |       Error( "usage: SomeGlobalFunction( <x>, <y>[, <z>] )" ); | ||||||
|  |     fi; | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # | ||||||
|  | # A plain function. | ||||||
|  | # | ||||||
|  | SomeFunc := function(x, y) | ||||||
|  |     local z, func, tmp, j; | ||||||
|  |     z := x * 1.0; | ||||||
|  |     y := 17^17 - y; | ||||||
|  |     func := a -> a mod 5; | ||||||
|  |     tmp := List( [1..50], func ); | ||||||
|  |     while y > 0 do | ||||||
|  |         for j in tmp do | ||||||
|  |             Print(j, "\n"); | ||||||
|  |         od; | ||||||
|  |         repeat | ||||||
|  |             y := y - 1; | ||||||
|  |         until 0 < 1; | ||||||
|  |         y := y -1; | ||||||
|  |     od; | ||||||
|  |     return z; | ||||||
|  | end; | ||||||
|  |          | ||||||
							
								
								
									
										822
									
								
								samples/GAP/vspc.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										822
									
								
								samples/GAP/vspc.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,822 @@ | |||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #W  vspc.gd                     GAP library                     Thomas Breuer | ||||||
|  | ## | ||||||
|  | ## | ||||||
|  | #Y  Copyright (C)  1997,  Lehrstuhl D für Mathematik,  RWTH Aachen,  Germany | ||||||
|  | #Y  (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland | ||||||
|  | #Y  Copyright (C) 2002 The GAP Group | ||||||
|  | ## | ||||||
|  | ##  This file declares the operations for vector spaces. | ||||||
|  | ## | ||||||
|  | ##  The operations for bases of free left modules can be found in the file | ||||||
|  | ##  <F>lib/basis.gd<F>. | ||||||
|  | ## | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #C  IsLeftOperatorRing(<R>) | ||||||
|  | ## | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Filt Name="IsLeftOperatorRing" Arg='R' Type='Category'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ## | ||||||
|  | DeclareSynonym( "IsLeftOperatorRing", | ||||||
|  |     IsLeftOperatorAdditiveGroup and IsRing and IsAssociativeLOpDProd ); | ||||||
|  | #T really? | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #C  IsLeftOperatorRingWithOne(<R>) | ||||||
|  | ## | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Filt Name="IsLeftOperatorRingWithOne" Arg='R' Type='Category'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ## | ||||||
|  | DeclareSynonym( "IsLeftOperatorRingWithOne", | ||||||
|  |     IsLeftOperatorAdditiveGroup and IsRingWithOne | ||||||
|  |     and IsAssociativeLOpDProd ); | ||||||
|  | #T really? | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #C  IsLeftVectorSpace( <V> ) | ||||||
|  | #C  IsVectorSpace( <V> ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="IsLeftVectorSpace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Filt Name="IsLeftVectorSpace" Arg='V' Type='Category'/> | ||||||
|  | ##  <Filt Name="IsVectorSpace" Arg='V' Type='Category'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  A <E>vector space</E> in &GAP; is a free left module | ||||||
|  | ##  (see <Ref Func="IsFreeLeftModule"/>) over a division ring | ||||||
|  | ##  (see Chapter <Ref Chap="Fields and Division Rings"/>). | ||||||
|  | ##  <P/> | ||||||
|  | ##  Whenever we talk about an <M>F</M>-vector space <A>V</A> then <A>V</A> is | ||||||
|  | ##  an additive group (see <Ref Func="IsAdditiveGroup"/>) on which the | ||||||
|  | ##  division ring <M>F</M> acts via multiplication from the left such that | ||||||
|  | ##  this action and the addition in <A>V</A> are left and right distributive. | ||||||
|  | ##  The division ring <M>F</M> can be accessed as value of the attribute | ||||||
|  | ##  <Ref Func="LeftActingDomain"/>. | ||||||
|  | ##  <P/> | ||||||
|  | ##  Vector spaces in &GAP; are always <E>left</E> vector spaces, | ||||||
|  | ##  <Ref Filt="IsLeftVectorSpace"/> and <Ref Filt="IsVectorSpace"/> are | ||||||
|  | ##  synonyms. | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareSynonym( "IsLeftVectorSpace", | ||||||
|  |     IsLeftModule and IsLeftActedOnByDivisionRing ); | ||||||
|  |  | ||||||
|  | DeclareSynonym( "IsVectorSpace", IsLeftVectorSpace ); | ||||||
|  |  | ||||||
|  | InstallTrueMethod( IsFreeLeftModule, | ||||||
|  |     IsLeftModule and IsLeftActedOnByDivisionRing ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  IsGaussianSpace( <V> ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="IsGaussianSpace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="IsGaussianSpace" Arg='V'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  The filter <Ref Filt="IsGaussianSpace"/> (see <Ref Sect="Filters"/>) | ||||||
|  | ##  for the row space (see <Ref Func="IsRowSpace"/>) | ||||||
|  | ##  or matrix space (see <Ref Func="IsMatrixSpace"/>) <A>V</A> | ||||||
|  | ##  over the field <M>F</M>, say, | ||||||
|  | ##  indicates that the entries of all row vectors or matrices in <A>V</A>, | ||||||
|  | ##  respectively, are all contained in <M>F</M>. | ||||||
|  | ##  In this case, <A>V</A> is called a <E>Gaussian</E> vector space. | ||||||
|  | ##  Bases for Gaussian spaces can be computed using Gaussian elimination for | ||||||
|  | ##  a given list of vector space generators. | ||||||
|  | ##  <Example><![CDATA[ | ||||||
|  | ##  gap> mats:= [ [[1,1],[2,2]], [[3,4],[0,1]] ];; | ||||||
|  | ##  gap> V:= VectorSpace( Rationals, mats );; | ||||||
|  | ##  gap> IsGaussianSpace( V ); | ||||||
|  | ##  true | ||||||
|  | ##  gap> mats[1][1][1]:= E(4);;   # an element in an extension field | ||||||
|  | ##  gap> V:= VectorSpace( Rationals, mats );; | ||||||
|  | ##  gap> IsGaussianSpace( V ); | ||||||
|  | ##  false | ||||||
|  | ##  gap> V:= VectorSpace( Field( Rationals, [ E(4) ] ), mats );; | ||||||
|  | ##  gap> IsGaussianSpace( V ); | ||||||
|  | ##  true | ||||||
|  | ##  ]]></Example> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareFilter( "IsGaussianSpace", IsVectorSpace ); | ||||||
|  |  | ||||||
|  | InstallTrueMethod( IsGaussianSpace, | ||||||
|  |     IsVectorSpace and IsFullMatrixModule ); | ||||||
|  |  | ||||||
|  | InstallTrueMethod( IsGaussianSpace, | ||||||
|  |     IsVectorSpace and IsFullRowModule ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #C  IsDivisionRing( <D> ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="IsDivisionRing"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Filt Name="IsDivisionRing" Arg='D' Type='Category'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  A <E>division ring</E> in &GAP; is a nontrivial associative algebra | ||||||
|  | ##  <A>D</A> with a multiplicative inverse for each nonzero element. | ||||||
|  | ##  In &GAP; every division ring is a vector space over a division ring | ||||||
|  | ##  (possibly over itself). | ||||||
|  | ##  Note that being a division ring is thus not a property that a ring can | ||||||
|  | ##  get, because a ring is usually not represented as a vector space. | ||||||
|  | ##  <P/> | ||||||
|  | ##  The field of coefficients is stored as the value of the attribute | ||||||
|  | ##  <Ref Func="LeftActingDomain"/> of <A>D</A>. | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareSynonymAttr( "IsDivisionRing", | ||||||
|  |         IsMagmaWithInversesIfNonzero | ||||||
|  |     and IsLeftOperatorRingWithOne | ||||||
|  |     and IsLeftVectorSpace | ||||||
|  |     and IsNonTrivial | ||||||
|  |     and IsAssociative | ||||||
|  |     and IsEuclideanRing ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #A  GeneratorsOfLeftVectorSpace( <V> ) | ||||||
|  | #A  GeneratorsOfVectorSpace( <V> ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="GeneratorsOfLeftVectorSpace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Attr Name="GeneratorsOfLeftVectorSpace" Arg='V'/> | ||||||
|  | ##  <Attr Name="GeneratorsOfVectorSpace" Arg='V'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  For an <M>F</M>-vector space <A>V</A>, | ||||||
|  | ##  <Ref Attr="GeneratorsOfLeftVectorSpace"/> returns a list of vectors in | ||||||
|  | ##  <A>V</A> that generate <A>V</A> as an <M>F</M>-vector space. | ||||||
|  | ##  <Example><![CDATA[ | ||||||
|  | ##  gap> GeneratorsOfVectorSpace( FullRowSpace( Rationals, 3 ) ); | ||||||
|  | ##  [ [ 1, 0, 0 ], [ 0, 1, 0 ], [ 0, 0, 1 ] ] | ||||||
|  | ##  ]]></Example> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareSynonymAttr( "GeneratorsOfLeftVectorSpace", | ||||||
|  |     GeneratorsOfLeftOperatorAdditiveGroup ); | ||||||
|  |  | ||||||
|  | DeclareSynonymAttr( "GeneratorsOfVectorSpace", | ||||||
|  |     GeneratorsOfLeftOperatorAdditiveGroup ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #A  CanonicalBasis( <V> ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="CanonicalBasis"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Attr Name="CanonicalBasis" Arg='V'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  If the vector space <A>V</A> supports a <E>canonical basis</E> then | ||||||
|  | ##  <Ref Attr="CanonicalBasis"/> returns this basis, | ||||||
|  | ##  otherwise <K>fail</K> is returned. | ||||||
|  | ##  <P/> | ||||||
|  | ##  The defining property of a canonical basis is that its vectors are | ||||||
|  | ##  uniquely determined by the vector space. | ||||||
|  | ##  If canonical bases exist for two vector spaces over the same left acting | ||||||
|  | ##  domain (see <Ref Func="LeftActingDomain"/>) then the equality of | ||||||
|  | ##  these vector spaces can be decided by comparing the canonical bases. | ||||||
|  | ##  <P/> | ||||||
|  | ##  The exact meaning of a canonical basis depends on the type of <A>V</A>. | ||||||
|  | ##  Canonical bases are defined for example for Gaussian row and matrix | ||||||
|  | ##  spaces (see <Ref Sect="Row and Matrix Spaces"/>). | ||||||
|  | ##  <P/> | ||||||
|  | ##  If one designs a new kind of vector spaces | ||||||
|  | ##  (see <Ref Sect="How to Implement New Kinds of Vector Spaces"/>) and | ||||||
|  | ##  defines a canonical basis for these spaces then the | ||||||
|  | ##  <Ref Attr="CanonicalBasis"/> method one installs | ||||||
|  | ##  (see <Ref Func="InstallMethod"/>) | ||||||
|  | ##  must <E>not</E> call <Ref Func="Basis"/>. | ||||||
|  | ##  On the other hand, one probably should install a <Ref Func="Basis"/> | ||||||
|  | ##  method that simply calls <Ref Attr="CanonicalBasis"/>, | ||||||
|  | ##  the value of the method | ||||||
|  | ##  (see <Ref Sect="Method Installation"/> and | ||||||
|  | ##  <Ref Sect="Applicable Methods and Method Selection"/>) | ||||||
|  | ##  being <C>CANONICAL_BASIS_FLAGS</C>. | ||||||
|  | ##  <Example><![CDATA[ | ||||||
|  | ##  gap> vecs:= [ [ 1, 2, 3 ], [ 1, 1, 1 ], [ 1, 1, 1 ] ];; | ||||||
|  | ##  gap> V:= VectorSpace( Rationals, vecs );; | ||||||
|  | ##  gap> B:= CanonicalBasis( V ); | ||||||
|  | ##  CanonicalBasis( <vector space over Rationals, with 3 generators> ) | ||||||
|  | ##  gap> BasisVectors( B ); | ||||||
|  | ##  [ [ 1, 0, -1 ], [ 0, 1, 2 ] ] | ||||||
|  | ##  ]]></Example> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareAttribute( "CanonicalBasis", IsFreeLeftModule ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  IsRowSpace( <V> ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="IsRowSpace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="IsRowSpace" Arg='V'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  A <E>row space</E> in &GAP; is a vector space that consists of | ||||||
|  | ##  row vectors (see Chapter <Ref Chap="Row Vectors"/>). | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareSynonym( "IsRowSpace", IsRowModule and IsVectorSpace ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  IsGaussianRowSpace( <V> ) | ||||||
|  | ## | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="IsGaussianRowSpace" Arg='V'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  A row space is <E>Gaussian</E> if the left acting domain contains all | ||||||
|  | ##  scalars that occur in the vectors. | ||||||
|  | ##  Thus one can use Gaussian elimination in the calculations. | ||||||
|  | ##  <P/> | ||||||
|  | ##  (Otherwise the space is non-Gaussian. | ||||||
|  | ##  We will need a flag for this to write down methods that delegate from | ||||||
|  | ##  non-Gaussian spaces to Gaussian ones.) | ||||||
|  | ##  <!-- reformulate this when it becomes documented --> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ## | ||||||
|  | DeclareSynonym( "IsGaussianRowSpace", IsGaussianSpace and IsRowSpace ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  IsNonGaussianRowSpace( <V> ) | ||||||
|  | ## | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="IsNonGaussianRowSpace" Arg='V'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  If an <M>F</M>-vector space <A>V</A> is in the filter | ||||||
|  | ##  <Ref Func="IsNonGaussianRowSpace"/> then this expresses that <A>V</A> | ||||||
|  | ##  consists of row vectors (see <Ref Func="IsRowVector"/>) such | ||||||
|  | ##  that not all entries in these row vectors are contained in <M>F</M> | ||||||
|  | ##  (so Gaussian elimination cannot be used to compute an <M>F</M>-basis | ||||||
|  | ##  from a list of vector space generators), | ||||||
|  | ##  and that <A>V</A> is handled via the mechanism of nice bases | ||||||
|  | ##  (see <Ref ???="..."/>) in the following way. | ||||||
|  | ##  Let <M>K</M> be the field spanned by the entries of all vectors in | ||||||
|  | ##  <A>V</A>. | ||||||
|  | ##  Then the <Ref Attr="NiceFreeLeftModuleInfo"/> value of <A>V</A> is | ||||||
|  | ##  a basis <M>B</M> of the field extension <M>K / ( K \cap F )</M>, | ||||||
|  | ##  and the <Ref Func="NiceVector"/> value of <M>v \in <A>V</A></M> | ||||||
|  | ##  is defined by replacing each entry of <M>v</M> by the list of its | ||||||
|  | ##  <M>B</M>-coefficients, and then forming the concatenation. | ||||||
|  | ##  <P/> | ||||||
|  | ##  So the associated nice vector space is a Gaussian row space | ||||||
|  | ##  (see <Ref Func="IsGaussianRowSpace"/>). | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ## | ||||||
|  | DeclareHandlingByNiceBasis( "IsNonGaussianRowSpace", | ||||||
|  |     "for non-Gaussian row spaces" ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  IsMatrixSpace( <V> ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="IsMatrixSpace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="IsMatrixSpace" Arg='V'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  A <E>matrix space</E> in &GAP; is a vector space that consists of matrices | ||||||
|  | ##  (see Chapter <Ref Chap="Matrices"/>). | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareSynonym( "IsMatrixSpace", IsMatrixModule and IsVectorSpace ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  IsGaussianMatrixSpace( <V> ) | ||||||
|  | ## | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="IsGaussianMatrixSpace" Arg='V'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  A matrix space is Gaussian if the left acting domain contains all | ||||||
|  | ##  scalars that occur in the vectors. | ||||||
|  | ##  Thus one can use Gaussian elimination in the calculations. | ||||||
|  | ##  <P/> | ||||||
|  | ##  (Otherwise the space is non-Gaussian. | ||||||
|  | ##  We will need a flag for this to write down methods that delegate from | ||||||
|  | ##  non-Gaussian spaces to Gaussian ones.) | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ## | ||||||
|  | DeclareSynonym( "IsGaussianMatrixSpace", IsGaussianSpace and IsMatrixSpace ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  IsNonGaussianMatrixSpace( <V> ) | ||||||
|  | ## | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="IsNonGaussianMatrixSpace" Arg='V'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  If an <M>F</M>-vector space <A>V</A> is in the filter | ||||||
|  | ##  <Ref Func="IsNonGaussianMatrixSpace"/> | ||||||
|  | ##  then this expresses that <A>V</A> consists of matrices | ||||||
|  | ##  (see <Ref Func="IsMatrix"/>) | ||||||
|  | ##  such that not all entries in these matrices are contained in <M>F</M> | ||||||
|  | ##  (so Gaussian elimination cannot be used to compute an <M>F</M>-basis | ||||||
|  | ##  from a list of vector space generators), | ||||||
|  | ##  and that <A>V</A> is handled via the mechanism of nice bases | ||||||
|  | ##  (see <Ref ???="..."/>) in the following way. | ||||||
|  | ##  Let <M>K</M> be the field spanned by the entries of all vectors in <A>V</A>. | ||||||
|  | ##  The <Ref Attr="NiceFreeLeftModuleInfo"/> value of <A>V</A> is irrelevant, | ||||||
|  | ##  and the <Ref Func="NiceVector"/> value of <M>v \in <A>V</A></M> | ||||||
|  | ##  is defined as the concatenation of the rows of <M>v</M>. | ||||||
|  | ##  <P/> | ||||||
|  | ##  So the associated nice vector space is a (not necessarily Gaussian) | ||||||
|  | ##  row space (see <Ref Func="IsRowSpace"/>). | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ## | ||||||
|  | DeclareHandlingByNiceBasis( "IsNonGaussianMatrixSpace", | ||||||
|  |     "for non-Gaussian matrix spaces" ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #A  NormedRowVectors( <V> ) . . .  normed vectors in a Gaussian row space <V> | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="NormedRowVectors"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Attr Name="NormedRowVectors" Arg='V'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  For a finite Gaussian row space <A>V</A> | ||||||
|  | ##  (see <Ref Func="IsRowSpace"/>, <Ref Func="IsGaussianSpace"/>), | ||||||
|  | ##  <Ref Attr="NormedRowVectors"/> returns a list of those nonzero | ||||||
|  | ##  vectors in <A>V</A> that have a one in the first nonzero component. | ||||||
|  | ##  <P/> | ||||||
|  | ##  The result list can be used as action domain for the action of a matrix | ||||||
|  | ##  group via <Ref Func="OnLines"/>, which yields the natural action on | ||||||
|  | ##  one-dimensional subspaces of <A>V</A> | ||||||
|  | ##  (see also <Ref Func="Subspaces"/>). | ||||||
|  | ##  <Example><![CDATA[ | ||||||
|  | ##  gap> vecs:= NormedRowVectors( GF(3)^2 ); | ||||||
|  | ##  [ [ 0*Z(3), Z(3)^0 ], [ Z(3)^0, 0*Z(3) ], [ Z(3)^0, Z(3)^0 ],  | ||||||
|  | ##    [ Z(3)^0, Z(3) ] ] | ||||||
|  | ##  gap> Action( GL(2,3), vecs, OnLines ); | ||||||
|  | ##  Group([ (3,4), (1,2,4) ]) | ||||||
|  | ##  ]]></Example> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareAttribute( "NormedRowVectors", IsGaussianSpace ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #A  TrivialSubspace( <V> ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="TrivialSubspace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Attr Name="TrivialSubspace" Arg='V'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  For a vector space <A>V</A>, <Ref Attr="TrivialSubspace"/> returns the | ||||||
|  | ##  subspace of <A>V</A> that consists of the zero vector in <A>V</A>. | ||||||
|  | ##  <Example><![CDATA[ | ||||||
|  | ##  gap> V:= GF(3)^3;; | ||||||
|  | ##  gap> triv:= TrivialSubspace( V ); | ||||||
|  | ##  <vector space over GF(3), with 0 generators> | ||||||
|  | ##  gap> AsSet( triv ); | ||||||
|  | ##  [ [ 0*Z(3), 0*Z(3), 0*Z(3) ] ] | ||||||
|  | ##  ]]></Example> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareSynonymAttr( "TrivialSubspace", TrivialSubmodule ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  VectorSpace( <F>, <gens>[, <zero>][, "basis"] ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="VectorSpace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="VectorSpace" Arg='F, gens[, zero][, "basis"]'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  For a field <A>F</A> and a collection <A>gens</A> of vectors, | ||||||
|  | ##  <Ref Func="VectorSpace"/> returns the <A>F</A>-vector space spanned by | ||||||
|  | ##  the elements in <A>gens</A>. | ||||||
|  | ##  <P/> | ||||||
|  | ##  The optional argument <A>zero</A> can be used to specify the zero element | ||||||
|  | ##  of the space; <A>zero</A> <E>must</E> be given if <A>gens</A> is empty. | ||||||
|  | ##  The optional string <C>"basis"</C> indicates that <A>gens</A> is known to | ||||||
|  | ##  be linearly independent over <A>F</A>, in particular the dimension of the | ||||||
|  | ##  vector space is immediately set; | ||||||
|  | ##  note that <Ref Func="Basis"/> need <E>not</E> return the basis formed by | ||||||
|  | ##  <A>gens</A> if the string <C>"basis"</C> is given as an argument. | ||||||
|  | ##  <!-- crossref. to <C>FreeLeftModule</C> as soon as the modules chapter | ||||||
|  | ##       is reliable!--> | ||||||
|  | ##  <Example><![CDATA[ | ||||||
|  | ##  gap> V:= VectorSpace( Rationals, [ [ 1, 2, 3 ], [ 1, 1, 1 ] ] ); | ||||||
|  | ##  <vector space over Rationals, with 2 generators> | ||||||
|  | ##  ]]></Example> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareGlobalFunction( "VectorSpace" ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  Subspace( <V>, <gens>[, "basis"] )  . subspace of <V> generated by <gens> | ||||||
|  | #F  SubspaceNC( <V>, <gens>[, "basis"] ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="Subspace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="Subspace" Arg='V, gens[, "basis"]'/> | ||||||
|  | ##  <Func Name="SubspaceNC" Arg='V, gens[, "basis"]'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  For an <M>F</M>-vector space <A>V</A> and a list or collection | ||||||
|  | ##  <A>gens</A> that is a subset of <A>V</A>, | ||||||
|  | ##  <Ref Func="Subspace"/> returns the <M>F</M>-vector space spanned by | ||||||
|  | ##  <A>gens</A>; if <A>gens</A> is empty then the trivial subspace | ||||||
|  | ##  (see <Ref Func="TrivialSubspace"/>) of <A>V</A> is returned. | ||||||
|  | ##  The parent (see <Ref Sect="Parents"/>) of the returned vector space | ||||||
|  | ##  is set to <A>V</A>. | ||||||
|  | ##  <P/> | ||||||
|  | ##  <Ref Func="SubspaceNC"/> does the same as <Ref Func="Subspace"/>, | ||||||
|  | ##  except that it omits the check whether <A>gens</A> is a subset of | ||||||
|  | ##  <A>V</A>. | ||||||
|  | ##  <P/> | ||||||
|  | ##  The optional string <A>"basis"</A> indicates that <A>gens</A> is known to | ||||||
|  | ##  be linearly independent over <M>F</M>. | ||||||
|  | ##  In this case the dimension of the subspace is immediately set, | ||||||
|  | ##  and both <Ref Func="Subspace"/> and <Ref Func="SubspaceNC"/> do | ||||||
|  | ##  <E>not</E> check whether <A>gens</A> really is linearly independent and | ||||||
|  | ##  whether <A>gens</A> is a subset of <A>V</A>. | ||||||
|  | ##  <!-- crossref. to <C>Submodule</C> as soon as the modules chapter | ||||||
|  | ##       is reliable!--> | ||||||
|  | ##  <Example><![CDATA[ | ||||||
|  | ##  gap> V:= VectorSpace( Rationals, [ [ 1, 2, 3 ], [ 1, 1, 1 ] ] );; | ||||||
|  | ##  gap> W:= Subspace( V, [ [ 0, 1, 2 ] ] ); | ||||||
|  | ##  <vector space over Rationals, with 1 generators> | ||||||
|  | ##  ]]></Example> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareSynonym( "Subspace", Submodule ); | ||||||
|  |  | ||||||
|  | DeclareSynonym( "SubspaceNC", SubmoduleNC ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #O  AsVectorSpace( <F>, <D> ) . . . . . . . . .  view <D> as <F>-vector space | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="AsVectorSpace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Oper Name="AsVectorSpace" Arg='F, D'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  Let <A>F</A> be a division ring and <A>D</A> a domain. | ||||||
|  | ##  If the elements in <A>D</A> form an <A>F</A>-vector space then | ||||||
|  | ##  <Ref Oper="AsVectorSpace"/> returns this <A>F</A>-vector space, | ||||||
|  | ##  otherwise <K>fail</K> is returned. | ||||||
|  | ##  <P/> | ||||||
|  | ##  <Ref Oper="AsVectorSpace"/> can be used for example to view a given | ||||||
|  | ##  vector space as a vector space over a smaller or larger division ring. | ||||||
|  | ##  <Example><![CDATA[ | ||||||
|  | ##  gap> V:= FullRowSpace( GF( 27 ), 3 ); | ||||||
|  | ##  ( GF(3^3)^3 ) | ||||||
|  | ##  gap> Dimension( V );  LeftActingDomain( V ); | ||||||
|  | ##  3 | ||||||
|  | ##  GF(3^3) | ||||||
|  | ##  gap> W:= AsVectorSpace( GF( 3 ), V ); | ||||||
|  | ##  <vector space over GF(3), with 9 generators> | ||||||
|  | ##  gap> Dimension( W );  LeftActingDomain( W ); | ||||||
|  | ##  9 | ||||||
|  | ##  GF(3) | ||||||
|  | ##  gap> AsVectorSpace( GF( 9 ), V ); | ||||||
|  | ##  fail | ||||||
|  | ##  ]]></Example> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareSynonym( "AsVectorSpace", AsLeftModule ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #O  AsSubspace( <V>, <U> )  . . . . . . . . . . . view <U> as subspace of <V> | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="AsSubspace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Oper Name="AsSubspace" Arg='V, U'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  Let <A>V</A> be an <M>F</M>-vector space, and <A>U</A> a collection. | ||||||
|  | ##  If <A>U</A> is a subset of <A>V</A> such that the elements of <A>U</A> | ||||||
|  | ##  form an <M>F</M>-vector space then <Ref Oper="AsSubspace"/> returns this | ||||||
|  | ##  vector space, with parent set to <A>V</A> | ||||||
|  | ##  (see <Ref Func="AsVectorSpace"/>). | ||||||
|  | ##  Otherwise <K>fail</K> is returned. | ||||||
|  | ##  <Example><![CDATA[ | ||||||
|  | ##  gap> V:= VectorSpace( Rationals, [ [ 1, 2, 3 ], [ 1, 1, 1 ] ] );; | ||||||
|  | ##  gap> W:= VectorSpace( Rationals, [ [ 1/2, 1/2, 1/2 ] ] );; | ||||||
|  | ##  gap> U:= AsSubspace( V, W ); | ||||||
|  | ##  <vector space over Rationals, with 1 generators> | ||||||
|  | ##  gap> Parent( U ) = V; | ||||||
|  | ##  true | ||||||
|  | ##  gap> AsSubspace( V, [ [ 1, 1, 1 ] ] ); | ||||||
|  | ##  fail | ||||||
|  | ##  ]]></Example> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareOperation( "AsSubspace", [ IsVectorSpace, IsCollection ] ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  Intersection2Spaces( <AsStruct>, <Substruct>, <Struct> ) | ||||||
|  | ## | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="Intersection2Spaces" Arg='AsStruct, Substruct, Struct'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  is a function that takes two arguments <A>V</A> and <A>W</A> which must | ||||||
|  | ##  be finite dimensional vector spaces, | ||||||
|  | ##  and returns the intersection of <A>V</A> and <A>W</A>. | ||||||
|  | ##  <P/> | ||||||
|  | ##  If the left acting domains are different then let <M>F</M> be their | ||||||
|  | ##  intersection. | ||||||
|  | ##  The intersection of <A>V</A> and <A>W</A> is computed as intersection of | ||||||
|  | ##  <C><A>AsStruct</A>( <A>F</A>, <A>V</A> )</C> and | ||||||
|  | ##  <C><A>AsStruct</A>( <A>F</A>, <A>V</A> )</C>. | ||||||
|  | ##  <P/> | ||||||
|  | ##  If the left acting domains are equal to <M>F</M> then the intersection of | ||||||
|  | ##  <A>V</A> and <A>W</A> is returned either as <M>F</M>-<A>Substruct</A> | ||||||
|  | ##  with the common parent of <A>V</A> and <A>W</A> or as | ||||||
|  | ##  <M>F</M>-<A>Struct</A>, in both cases with known basis. | ||||||
|  | ##  <P/> | ||||||
|  | ##  This function is used to handle the intersections of two vector spaces, | ||||||
|  | ##  two algebras, two algebras-with-one, two left ideals, two right ideals, | ||||||
|  | ##  two two-sided ideals. | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ## | ||||||
|  | DeclareGlobalFunction( "Intersection2Spaces" ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  FullRowSpace( <F>, <n> ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="FullRowSpace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="FullRowSpace" Arg='F, n'/> | ||||||
|  | ##  <Meth Name="\^" Arg='F, n' Label="for a field and an integer"/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  For a field <A>F</A> and a nonnegative integer <A>n</A>, | ||||||
|  | ##  <Ref Func="FullRowSpace"/> returns the <A>F</A>-vector space that | ||||||
|  | ##  consists of all row vectors (see <Ref Func="IsRowVector"/>) of | ||||||
|  | ##  length <A>n</A> with entries in <A>F</A>. | ||||||
|  | ##  <P/> | ||||||
|  | ##  An alternative to construct this vector space is via | ||||||
|  | ##  <A>F</A><C>^</C><A>n</A>. | ||||||
|  | ##  <Example><![CDATA[ | ||||||
|  | ##  gap> FullRowSpace( GF( 9 ), 3 ); | ||||||
|  | ##  ( GF(3^2)^3 ) | ||||||
|  | ##  gap> GF(9)^3;           # the same as above | ||||||
|  | ##  ( GF(3^2)^3 ) | ||||||
|  | ##  ]]></Example> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareSynonym( "FullRowSpace", FullRowModule ); | ||||||
|  | DeclareSynonym( "RowSpace", FullRowModule ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  FullMatrixSpace( <F>, <m>, <n> ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="FullMatrixSpace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="FullMatrixSpace" Arg='F, m, n'/> | ||||||
|  | ##  <Meth Name="\^" Arg='F, dims' | ||||||
|  | ##   Label="for a field and a pair of integers"/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  For a field <A>F</A> and two positive integers <A>m</A> and <A>n</A>, | ||||||
|  | ##  <Ref Func="FullMatrixSpace"/> returns the <A>F</A>-vector space that | ||||||
|  | ##  consists of all <A>m</A> by <A>n</A> matrices | ||||||
|  | ##  (see <Ref Func="IsMatrix"/>) with entries in <A>F</A>. | ||||||
|  | ##  <P/> | ||||||
|  | ##  If <A>m</A><C> = </C><A>n</A> then the result is in fact an algebra | ||||||
|  | ##  (see <Ref Func="FullMatrixAlgebra"/>). | ||||||
|  | ##  <P/> | ||||||
|  | ##  An alternative to construct this vector space is via | ||||||
|  | ##  <A>F</A><C>^[</C><A>m</A>,<A>n</A><C>]</C>. | ||||||
|  | ##  <Example><![CDATA[ | ||||||
|  | ##  gap> FullMatrixSpace( GF(2), 4, 5 ); | ||||||
|  | ##  ( GF(2)^[ 4, 5 ] ) | ||||||
|  | ##  gap> GF(2)^[ 4, 5 ];    # the same as above | ||||||
|  | ##  ( GF(2)^[ 4, 5 ] ) | ||||||
|  | ##  ]]></Example> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareSynonym( "FullMatrixSpace", FullMatrixModule ); | ||||||
|  | DeclareSynonym( "MatrixSpace", FullMatrixModule ); | ||||||
|  | DeclareSynonym( "MatSpace", FullMatrixModule ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #C  IsSubspacesVectorSpace( <D> ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="IsSubspacesVectorSpace"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Filt Name="IsSubspacesVectorSpace" Arg='D' Type='Category'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  The domain of all subspaces of a (finite) vector space or of all | ||||||
|  | ##  subspaces of fixed dimension, as returned by <Ref Func="Subspaces"/> | ||||||
|  | ##  (see <Ref Func="Subspaces"/>) lies in the category | ||||||
|  | ##  <Ref Filt="IsSubspacesVectorSpace"/>. | ||||||
|  | ##  <Example><![CDATA[ | ||||||
|  | ##  gap> D:= Subspaces( GF(3)^3 ); | ||||||
|  | ##  Subspaces( ( GF(3)^3 ) ) | ||||||
|  | ##  gap> Size( D ); | ||||||
|  | ##  28 | ||||||
|  | ##  gap> iter:= Iterator( D );; | ||||||
|  | ##  gap> NextIterator( iter ); | ||||||
|  | ##  <vector space over GF(3), with 0 generators> | ||||||
|  | ##  gap> NextIterator( iter ); | ||||||
|  | ##  <vector space of dimension 1 over GF(3)> | ||||||
|  | ##  gap> IsSubspacesVectorSpace( D ); | ||||||
|  | ##  true | ||||||
|  | ##  ]]></Example> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareCategory( "IsSubspacesVectorSpace", IsDomain ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  IsFinite( <D> ) . . . . . . . . . . . . . . . . .  for a subspaces domain | ||||||
|  | ## | ||||||
|  | ##  Returns `true' if <D> is finite. | ||||||
|  | ##  We allow subspaces domains in `IsSubspacesVectorSpace' only for finite | ||||||
|  | ##  vector spaces. | ||||||
|  | ## | ||||||
|  | InstallTrueMethod( IsFinite, IsSubspacesVectorSpace ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #A  Subspaces( <V>[, <k>] ) | ||||||
|  | ## | ||||||
|  | ##  <#GAPDoc Label="Subspaces"> | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Attr Name="Subspaces" Arg='V[, k]'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  Called with a finite vector space <A>v</A>, | ||||||
|  | ##  <Ref Oper="Subspaces"/> returns the domain of all subspaces of <A>V</A>. | ||||||
|  | ##  <P/> | ||||||
|  | ##  Called with <A>V</A> and a nonnegative integer <A>k</A>, | ||||||
|  | ##  <Ref Oper="Subspaces"/> returns the domain of all <A>k</A>-dimensional | ||||||
|  | ##  subspaces of <A>V</A>. | ||||||
|  | ##  <P/> | ||||||
|  | ##  Special <Ref Attr="Size"/> and <Ref Oper="Iterator"/> methods are | ||||||
|  | ##  provided for these domains. | ||||||
|  | ##  <!-- <C>Enumerator</C> would also be good ... | ||||||
|  | ##       (special treatment for full row spaces, | ||||||
|  | ##       other spaces delegate to this)--> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ##  <#/GAPDoc> | ||||||
|  | ## | ||||||
|  | DeclareAttribute( "Subspaces", IsLeftModule ); | ||||||
|  | DeclareOperation( "Subspaces", [ IsLeftModule, IsInt ] ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  IsSubspace( <V>, <U> ) | ||||||
|  | ## | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Func Name="IsSubspace" Arg='V, U'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  check that <A>U</A> is a vector space that is contained in <A>V</A> | ||||||
|  | ##  <!-- Must also <A>V</A> be a vector space? | ||||||
|  | ##       If yes then must <A>V</A> and <A>U</A> have same left acting domain? | ||||||
|  | ##       (Is this function useful at all?) --> | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ## | ||||||
|  | DeclareGlobalFunction( "IsSubspace" ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #A  OrthogonalSpaceInFullRowSpace( <U> ) | ||||||
|  | ## | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Attr Name="OrthogonalSpaceInFullRowSpace" Arg='U'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  For a Gaussian row space <A>U</A> over <M>F</M>, | ||||||
|  | ##  <Ref Attr="OrthogonalSpaceInFullRowSpace"/> | ||||||
|  | ##  returns a complement of <A>U</A> in the full row space of same vector | ||||||
|  | ##  dimension as <A>U</A> over <M>F</M>. | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ## | ||||||
|  | DeclareAttribute( "OrthogonalSpaceInFullRowSpace", IsGaussianSpace ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #P  IsVectorSpaceHomomorphism( <map> ) | ||||||
|  | ## | ||||||
|  | ##  <ManSection> | ||||||
|  | ##  <Prop Name="IsVectorSpaceHomomorphism" Arg='map'/> | ||||||
|  | ## | ||||||
|  | ##  <Description> | ||||||
|  | ##  A mapping <M>f</M> is a vector space homomorphism (or linear mapping) | ||||||
|  | ##  if the source and range are vector spaces | ||||||
|  | ##  (see <Ref Func="IsVectorSpace"/>) | ||||||
|  | ##  over the same division ring <M>D</M> | ||||||
|  | ##  (see <Ref Func="LeftActingDomain"/>), | ||||||
|  | ##  and if <M>f( a + b ) = f(a) + f(b)</M> and <M>f( s * a ) = s * f(a)</M> | ||||||
|  | ##  hold for all elements <M>a</M>, <M>b</M> in the source of <M>f</M> and | ||||||
|  | ##  <M>s \in D</M>. | ||||||
|  | ##  </Description> | ||||||
|  | ##  </ManSection> | ||||||
|  | ## | ||||||
|  | DeclareProperty( "IsVectorSpaceHomomorphism", IsGeneralMapping ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #E | ||||||
|  |  | ||||||
							
								
								
									
										651
									
								
								samples/GAP/vspc.gi
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										651
									
								
								samples/GAP/vspc.gi
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,651 @@ | |||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #W  vspc.gi                     GAP library                     Thomas Breuer | ||||||
|  | ## | ||||||
|  | ## | ||||||
|  | #Y  Copyright (C)  1997,  Lehrstuhl D für Mathematik,  RWTH Aachen,  Germany | ||||||
|  | #Y  (C) 1998 School Math and Comp. Sci., University of St Andrews, Scotland | ||||||
|  | #Y  Copyright (C) 2002 The GAP Group | ||||||
|  | ## | ||||||
|  | ##  This file contains generic methods for vector spaces. | ||||||
|  | ## | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  SetLeftActingDomain( <extL>, <D> ) | ||||||
|  | ## | ||||||
|  | ##  check whether the left acting domain <D> of the external left set <extL> | ||||||
|  | ##  knows that it is a division ring. | ||||||
|  | ##  This is used, e.g.,  to tell a free module over a division ring | ||||||
|  | ##  that it is a vector space. | ||||||
|  | ## | ||||||
|  | InstallOtherMethod( SetLeftActingDomain, | ||||||
|  |     "method to set also 'IsLeftActedOnByDivisionRing'", | ||||||
|  |     [ IsAttributeStoringRep and IsLeftActedOnByRing, IsObject ],0, | ||||||
|  |     function( extL, D ) | ||||||
|  |     if HasIsDivisionRing( D ) and IsDivisionRing( D ) then | ||||||
|  |       SetIsLeftActedOnByDivisionRing( extL, true ); | ||||||
|  |     fi; | ||||||
|  |     TryNextMethod(); | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  IsLeftActedOnByDivisionRing( <M> ) | ||||||
|  | ## | ||||||
|  | InstallMethod( IsLeftActedOnByDivisionRing, | ||||||
|  |     "method for external left set that is left acted on by a ring", | ||||||
|  |     [ IsExtLSet and IsLeftActedOnByRing ], | ||||||
|  |     function( M ) | ||||||
|  |     if IsIdenticalObj( M, LeftActingDomain( M ) ) then | ||||||
|  |       TryNextMethod(); | ||||||
|  |     else | ||||||
|  |       return IsDivisionRing( LeftActingDomain( M ) ); | ||||||
|  |     fi; | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  VectorSpace( <F>, <gens>[, <zero>][, "basis"] ) | ||||||
|  | ## | ||||||
|  | ##  The only difference between `VectorSpace' and `FreeLeftModule' shall be | ||||||
|  | ##  that the left acting domain of a vector space must be a division ring. | ||||||
|  | ## | ||||||
|  | InstallGlobalFunction( VectorSpace, function( arg ) | ||||||
|  |     if Length( arg ) = 0 or not IsDivisionRing( arg[1] ) then | ||||||
|  |       Error( "usage: VectorSpace( <F>, <gens>[, <zero>][, \"basis\"] )" ); | ||||||
|  |     fi; | ||||||
|  |     return CallFuncList( FreeLeftModule, arg ); | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  AsSubspace( <V>, <C> )  . . . . . . . for a vector space and a collection | ||||||
|  | ## | ||||||
|  | InstallMethod( AsSubspace, | ||||||
|  |     "for a vector space and a collection", | ||||||
|  |     [ IsVectorSpace, IsCollection ], | ||||||
|  |     function( V, C ) | ||||||
|  |     local newC; | ||||||
|  |  | ||||||
|  |     if not IsSubset( V, C ) then | ||||||
|  |       return fail; | ||||||
|  |     fi; | ||||||
|  |     newC:= AsVectorSpace( LeftActingDomain( V ), C ); | ||||||
|  |     if newC = fail then | ||||||
|  |       return fail; | ||||||
|  |     fi; | ||||||
|  |     SetParent( newC, V ); | ||||||
|  |     UseIsomorphismRelation( C, newC ); | ||||||
|  |     UseSubsetRelation( C, newC ); | ||||||
|  |  | ||||||
|  |     return newC; | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  AsLeftModule( <F>, <V> )  . . . . . .  for division ring and vector space | ||||||
|  | ## | ||||||
|  | ##  View the vector space <V> as a vector space over the division ring <F>. | ||||||
|  | ## | ||||||
|  | InstallMethod( AsLeftModule, | ||||||
|  |     "method for a division ring and a vector space", | ||||||
|  |     [ IsDivisionRing, IsVectorSpace ], | ||||||
|  |     function( F, V ) | ||||||
|  |  | ||||||
|  |     local W,        # the space, result | ||||||
|  |           base,     # basis vectors of field extension | ||||||
|  |           gen,      # loop over generators of 'V' | ||||||
|  |           b,        # loop over 'base' | ||||||
|  |           gens,     # generators of 'V' | ||||||
|  |           newgens;  # extended list of generators | ||||||
|  |  | ||||||
|  |     if Characteristic( F ) <> Characteristic( LeftActingDomain( V ) ) then | ||||||
|  |  | ||||||
|  |       # This is impossible. | ||||||
|  |       return fail; | ||||||
|  |  | ||||||
|  |     elif F = LeftActingDomain( V ) then | ||||||
|  |  | ||||||
|  |       # No change of the left acting domain is necessary. | ||||||
|  |       return V; | ||||||
|  |  | ||||||
|  |     elif IsSubset( F, LeftActingDomain( V ) ) then | ||||||
|  |  | ||||||
|  |       # Check whether 'V' is really a space over the bigger field, | ||||||
|  |       # that is, whether the set of elements does not change. | ||||||
|  |       base:= BasisVectors( Basis( AsField( LeftActingDomain( V ), F ) ) ); | ||||||
|  |       for gen in GeneratorsOfLeftModule( V ) do | ||||||
|  |         for b in base do | ||||||
|  |           if not b * gen in V then | ||||||
|  |  | ||||||
|  |             # The field extension would change the set of elements. | ||||||
|  |             return fail; | ||||||
|  |  | ||||||
|  |           fi; | ||||||
|  |         od; | ||||||
|  |       od; | ||||||
|  |  | ||||||
|  |       # Construct the space. | ||||||
|  |       W:= LeftModuleByGenerators( F, GeneratorsOfLeftModule(V), Zero(V) ); | ||||||
|  |  | ||||||
|  |     elif IsSubset( LeftActingDomain( V ), F ) then | ||||||
|  |  | ||||||
|  |       # View 'V' as a space over a smaller field. | ||||||
|  |       # For that, the list of generators must be extended. | ||||||
|  |       gens:= GeneratorsOfLeftModule( V ); | ||||||
|  |       if IsEmpty( gens ) then | ||||||
|  |         W:= LeftModuleByGenerators( F, [], Zero( V ) ); | ||||||
|  |       else | ||||||
|  |  | ||||||
|  |         base:= BasisVectors( Basis( AsField( F, LeftActingDomain( V ) ) ) ); | ||||||
|  |         newgens:= []; | ||||||
|  |         for b in base do | ||||||
|  |           for gen in gens do | ||||||
|  |             Add( newgens, b * gen ); | ||||||
|  |           od; | ||||||
|  |         od; | ||||||
|  |         W:= LeftModuleByGenerators( F, newgens ); | ||||||
|  |  | ||||||
|  |       fi; | ||||||
|  |  | ||||||
|  |     else | ||||||
|  |  | ||||||
|  |       # View 'V' first as space over the intersection of fields, | ||||||
|  |       # and then over the desired field. | ||||||
|  |       return AsLeftModule( F, | ||||||
|  |                  AsLeftModule( Intersection( F, | ||||||
|  |                      LeftActingDomain( V ) ), V ) ); | ||||||
|  |  | ||||||
|  |     fi; | ||||||
|  |  | ||||||
|  |     UseIsomorphismRelation( V, W ); | ||||||
|  |     UseSubsetRelation( V, W ); | ||||||
|  |     return W; | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  ViewObj( <V> )  . . . . . . . . . . . . . . . . . . . view a vector space | ||||||
|  | ## | ||||||
|  | ##  print left acting domain, if known also dimension or no. of generators | ||||||
|  | ## | ||||||
|  | InstallMethod( ViewObj, | ||||||
|  |     "for vector space with known generators", | ||||||
|  |     [ IsVectorSpace and HasGeneratorsOfLeftModule ], | ||||||
|  |     function( V ) | ||||||
|  |     Print( "<vector space over ", LeftActingDomain( V ), ", with ", | ||||||
|  |            Length( GeneratorsOfLeftModule( V ) ), " generators>" ); | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  | InstallMethod( ViewObj, | ||||||
|  |     "for vector space with known dimension", | ||||||
|  |     [ IsVectorSpace and HasDimension ], | ||||||
|  |     1, # override method for known generators | ||||||
|  |     function( V ) | ||||||
|  |     Print( "<vector space of dimension ", Dimension( V ), | ||||||
|  |            " over ", LeftActingDomain( V ), ">" ); | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  | InstallMethod( ViewObj, | ||||||
|  |     "for vector space", | ||||||
|  |     [ IsVectorSpace ], | ||||||
|  |     function( V ) | ||||||
|  |     Print( "<vector space over ", LeftActingDomain( V ), ">" ); | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  PrintObj( <V> ) . . . . . . . . . . . . . . . . . . .  for a vector space | ||||||
|  | ## | ||||||
|  | InstallMethod( PrintObj, | ||||||
|  |     "method for vector space with left module generators", | ||||||
|  |     [ IsVectorSpace and HasGeneratorsOfLeftModule ], | ||||||
|  |     function( V ) | ||||||
|  |     Print( "VectorSpace( ", LeftActingDomain( V ), ", ", | ||||||
|  |            GeneratorsOfLeftModule( V ) ); | ||||||
|  |     if IsEmpty( GeneratorsOfLeftModule( V ) ) and HasZero( V ) then | ||||||
|  |       Print( ", ", Zero( V ), " )" ); | ||||||
|  |     else | ||||||
|  |       Print( " )" ); | ||||||
|  |     fi; | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  | InstallMethod( PrintObj, | ||||||
|  |     "method for vector space", | ||||||
|  |     [ IsVectorSpace ], | ||||||
|  |     function( V ) | ||||||
|  |     Print( "VectorSpace( ", LeftActingDomain( V ), ", ... )" ); | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  \/( <V>, <W> )  . . . . . . . . .  factor of a vector space by a subspace | ||||||
|  | #M  \/( <V>, <vectors> )  . . . . . .  factor of a vector space by a subspace | ||||||
|  | ## | ||||||
|  | InstallOtherMethod( \/, | ||||||
|  |     "method for vector space and collection", | ||||||
|  |     IsIdenticalObj, | ||||||
|  |     [ IsVectorSpace, IsCollection ], | ||||||
|  |     function( V, vectors ) | ||||||
|  |     if IsVectorSpace( vectors ) then | ||||||
|  |       TryNextMethod(); | ||||||
|  |     else | ||||||
|  |       return V / Subspace( V, vectors ); | ||||||
|  |     fi; | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  | InstallOtherMethod( \/, | ||||||
|  |     "generic method for two vector spaces", | ||||||
|  |     IsIdenticalObj, | ||||||
|  |     [ IsVectorSpace, IsVectorSpace ], | ||||||
|  |     function( V, W ) | ||||||
|  |     return ImagesSource( NaturalHomomorphismBySubspace( V, W ) ); | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  Intersection2Spaces( <AsStruct>, <Substruct>, <Struct> ) | ||||||
|  | ## | ||||||
|  | InstallGlobalFunction( Intersection2Spaces, | ||||||
|  |     function( AsStructure, Substructure, Structure ) | ||||||
|  |     return function( V, W ) | ||||||
|  |     local inters,  # intersection, result | ||||||
|  |           F,       # coefficients field | ||||||
|  |           gensV,   # list of generators of 'V' | ||||||
|  |           gensW,   # list of generators of 'W' | ||||||
|  |           VW,      # sum of 'V' and 'W' | ||||||
|  |           B;       # basis of 'VW' | ||||||
|  |  | ||||||
|  |     if LeftActingDomain( V ) <> LeftActingDomain( W ) then | ||||||
|  |  | ||||||
|  |       # Compute the intersection as vector space over the intersection | ||||||
|  |       # of the coefficients fields. | ||||||
|  |       # (Note that the characteristic is the same.) | ||||||
|  |       F:= Intersection2( LeftActingDomain( V ), LeftActingDomain( W ) ); | ||||||
|  |       return Intersection2( AsStructure( F, V ), AsStructure( F, W ) ); | ||||||
|  |  | ||||||
|  |     elif IsFiniteDimensional( V ) and IsFiniteDimensional( W ) then | ||||||
|  |  | ||||||
|  |       # Compute the intersection of two spaces over the same field. | ||||||
|  |       gensV:= GeneratorsOfLeftModule( V ); | ||||||
|  |       gensW:= GeneratorsOfLeftModule( W ); | ||||||
|  |       if   IsEmpty( gensV ) then | ||||||
|  |         if Zero( V ) in W then | ||||||
|  |           inters:= V; | ||||||
|  |         else | ||||||
|  |           inters:= []; | ||||||
|  |         fi; | ||||||
|  |       elif IsEmpty( gensW ) then | ||||||
|  |         if Zero( V ) in W then | ||||||
|  |           inters:= W; | ||||||
|  |         else | ||||||
|  |           inters:= []; | ||||||
|  |         fi; | ||||||
|  |       else | ||||||
|  |         # Compute a common coefficient space. | ||||||
|  |         VW:= LeftModuleByGenerators( LeftActingDomain( V ), | ||||||
|  |                                      Concatenation( gensV, gensW ) ); | ||||||
|  |         B:= Basis( VW ); | ||||||
|  |  | ||||||
|  |         # Construct the coefficient subspaces corresponding to 'V' and 'W'. | ||||||
|  |         gensV:= List( gensV, x -> Coefficients( B, x ) ); | ||||||
|  |         gensW:= List( gensW, x -> Coefficients( B, x ) ); | ||||||
|  |  | ||||||
|  |         # Construct the intersection of row spaces, and carry back to VW. | ||||||
|  |         inters:= List( SumIntersectionMat( gensV, gensW )[2], | ||||||
|  |                        x -> LinearCombination( B, x ) ); | ||||||
|  |  | ||||||
|  |         # Construct the intersection space, if possible with a parent. | ||||||
|  |         if     HasParent( V ) and HasParent( W ) | ||||||
|  |            and IsIdenticalObj( Parent( V ), Parent( W ) ) then | ||||||
|  |           inters:= Substructure( Parent( V ), inters, "basis" ); | ||||||
|  |         elif IsEmpty( inters ) then | ||||||
|  |           inters:= Substructure( V, inters, "basis" ); | ||||||
|  |           SetIsTrivial( inters, true ); | ||||||
|  |         else | ||||||
|  |           inters:= Structure( LeftActingDomain( V ), inters, "basis" ); | ||||||
|  |         fi; | ||||||
|  |  | ||||||
|  |         # Run implications by the subset relation. | ||||||
|  |         UseSubsetRelation( V, inters ); | ||||||
|  |         UseSubsetRelation( W, inters ); | ||||||
|  |       fi; | ||||||
|  |  | ||||||
|  |       # Return the result. | ||||||
|  |       return inters; | ||||||
|  |  | ||||||
|  |     else | ||||||
|  |       TryNextMethod(); | ||||||
|  |     fi; | ||||||
|  |     end; | ||||||
|  | end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  Intersection2( <V>, <W> ) . . . . . . . . . . . . . for two vector spaces | ||||||
|  | ## | ||||||
|  | InstallMethod( Intersection2, | ||||||
|  |     "method for two vector spaces", | ||||||
|  |     IsIdenticalObj, | ||||||
|  |     [ IsVectorSpace, IsVectorSpace ], | ||||||
|  |     Intersection2Spaces( AsLeftModule, SubspaceNC, VectorSpace ) ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  ClosureLeftModule( <V>, <a> ) . . . . . . . . . closure of a vector space | ||||||
|  | ## | ||||||
|  | InstallMethod( ClosureLeftModule, | ||||||
|  |     "method for a vector space with basis, and a vector", | ||||||
|  |     IsCollsElms, | ||||||
|  |     [ IsVectorSpace and HasBasis, IsVector ], | ||||||
|  |     function( V, w ) | ||||||
|  |     local   B; # basis of 'V' | ||||||
|  |  | ||||||
|  |     # We can test membership easily. | ||||||
|  |     B:= Basis( V ); | ||||||
|  | #T why easily? | ||||||
|  |     if Coefficients( B, w ) = fail then | ||||||
|  |  | ||||||
|  |       # In the case of a vector space, we know a basis of the closure. | ||||||
|  |       B:= Concatenation( BasisVectors( B ), [ w ] ); | ||||||
|  |       V:= LeftModuleByGenerators( LeftActingDomain( V ), B ); | ||||||
|  |       UseBasis( V, B ); | ||||||
|  |  | ||||||
|  |     fi; | ||||||
|  |     return V; | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | ##  Methods for collections of subspaces of a vector space | ||||||
|  | ## | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #R  IsSubspacesVectorSpaceDefaultRep( <D> ) | ||||||
|  | ## | ||||||
|  | ##  is the representation of domains of subspaces of a vector space <V>, | ||||||
|  | ##  with the components 'structure' (with value <V>) and 'dimension' | ||||||
|  | ##  (with value either the dimension of the subspaces in the domain | ||||||
|  | ##  or the string '\"all\"', which means that the domain contains all | ||||||
|  | ##  subspaces of <V>). | ||||||
|  | ## | ||||||
|  | DeclareRepresentation( | ||||||
|  |     "IsSubspacesVectorSpaceDefaultRep", | ||||||
|  |     IsComponentObjectRep, | ||||||
|  |     [ "dimension", "structure" ] ); | ||||||
|  | #T not IsAttributeStoringRep? | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  PrintObj( <D> )  . . . . . . . . . . . . . . . . . for a subspaces domain | ||||||
|  | ## | ||||||
|  | InstallMethod( PrintObj, | ||||||
|  |     "method for a subspaces domain", | ||||||
|  |     [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], | ||||||
|  |     function( D ) | ||||||
|  |     if IsInt( D!.dimension ) then | ||||||
|  |       Print( "Subspaces( ", D!.structure, ", ", D!.dimension, " )" ); | ||||||
|  |     else | ||||||
|  |       Print( "Subspaces( ", D!.structure, " )" ); | ||||||
|  |     fi; | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  Size( <D> ) . . . . . . . . . . . . . . . . . . .  for a subspaces domain | ||||||
|  | ## | ||||||
|  | ##  The number of $k$-dimensional subspaces in a $n$-dimensional space over | ||||||
|  | ##  the field with $q$ elements is | ||||||
|  | ##  $$ | ||||||
|  | ##  a(n,k) = \prod_{i=0}^{k-1} \frac{q^n-q^i}{q^k-q^i} = | ||||||
|  | ##           \prod_{i=0}^{k-1} \frac{q^{n-i}-1}{q^{k-i}-1}. | ||||||
|  | ##  $$ | ||||||
|  | ##  We have the recursion | ||||||
|  | ##  $$ | ||||||
|  | ##  a(n,k+1) = a(n,k) \frac{q^{n-i}-1}{q^{i+1}-1}. | ||||||
|  | ##  $$ | ||||||
|  | ## | ||||||
|  | ##  (The number of all subspaces is $\sum_{k=0}^n a(n,k)$.) | ||||||
|  | ## | ||||||
|  | InstallMethod( Size, | ||||||
|  |     "method for a subspaces domain", | ||||||
|  |     [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], | ||||||
|  |     function( D ) | ||||||
|  |  | ||||||
|  |     local k, | ||||||
|  |           n, | ||||||
|  |           q, | ||||||
|  |           size, | ||||||
|  |           qn, | ||||||
|  |           qd, | ||||||
|  |           ank, | ||||||
|  |           i; | ||||||
|  |  | ||||||
|  |     if D!.dimension = "all" then | ||||||
|  |  | ||||||
|  |       # all subspaces of the space | ||||||
|  |       n:= Dimension( D!.structure ); | ||||||
|  |  | ||||||
|  |       q:= Size( LeftActingDomain( D!.structure ) ); | ||||||
|  |       size:= 1; | ||||||
|  |       qn:= q^n; | ||||||
|  |       qd:= q; | ||||||
|  |  | ||||||
|  |       # $a(n,0)$ | ||||||
|  |       ank:= 1; | ||||||
|  |  | ||||||
|  |       for k in [ 1 .. Int( (n-1)/2 ) ] do | ||||||
|  |  | ||||||
|  |         # Compute $a(n,k)$. | ||||||
|  |         ank:= ank * ( qn - 1 ) / ( qd - 1 ); | ||||||
|  |         qn:= qn / q; | ||||||
|  |         qd:= qd * q; | ||||||
|  |  | ||||||
|  |         size:= size + ank; | ||||||
|  |  | ||||||
|  |       od; | ||||||
|  |  | ||||||
|  |       size:= 2 * size; | ||||||
|  |  | ||||||
|  |       if n mod 2 = 0 then | ||||||
|  |  | ||||||
|  |         # Add the number of spaces of dimension $n/2$. | ||||||
|  |         size:= size + ank * ( qn - 1 ) / ( qd - 1 ); | ||||||
|  |       fi; | ||||||
|  |  | ||||||
|  |     else | ||||||
|  |  | ||||||
|  |       # number of spaces of dimension 'k' only | ||||||
|  |       n:= Dimension( D!.structure ); | ||||||
|  |       if   D!.dimension < 0 or | ||||||
|  |            n < D!.dimension then | ||||||
|  |         return 0; | ||||||
|  |       elif n / 2 < D!.dimension then | ||||||
|  |         k:= n - D!.dimension; | ||||||
|  |       else | ||||||
|  |         k:= D!.dimension; | ||||||
|  |       fi; | ||||||
|  |  | ||||||
|  |       q:= Size( LeftActingDomain( D!.structure ) ); | ||||||
|  |       size:= 1; | ||||||
|  |  | ||||||
|  |       qn:= q^n; | ||||||
|  |       qd:= q; | ||||||
|  |       for i in [ 1 .. k ] do | ||||||
|  |         size:= size * ( qn - 1 ) / ( qd - 1 ); | ||||||
|  |         qn:= qn / q; | ||||||
|  |         qd:= qd * q; | ||||||
|  |       od; | ||||||
|  |  | ||||||
|  |     fi; | ||||||
|  |  | ||||||
|  |     # Return the result. | ||||||
|  |     return size; | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  Enumerator( <D> ) . . . . . . . . . . . . . . . .  for a subspaces domain | ||||||
|  | ## | ||||||
|  | ##  Use the iterator to compute the elements list. | ||||||
|  | #T This is not allowed! | ||||||
|  | ## | ||||||
|  | InstallMethod( Enumerator, | ||||||
|  |     "method for a subspaces domain", | ||||||
|  |     [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], | ||||||
|  |     function( D ) | ||||||
|  |     local iter,    # iterator for 'D' | ||||||
|  |           elms;    # elements list, result | ||||||
|  |  | ||||||
|  |     iter:= Iterator( D ); | ||||||
|  |     elms:= []; | ||||||
|  |     while not IsDoneIterator( iter ) do | ||||||
|  |       Add( elms, NextIterator( iter ) ); | ||||||
|  |     od; | ||||||
|  |     return elms; | ||||||
|  |     end ); | ||||||
|  | #T necessary? | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  Iterator( <D> ) . . . . . . . . . . . . . . . . .  for a subspaces domain | ||||||
|  | ## | ||||||
|  | ##  uses the subspaces iterator for full row spaces and the mechanism of | ||||||
|  | ##  associated row spaces. | ||||||
|  | ## | ||||||
|  | BindGlobal( "IsDoneIterator_Subspaces", | ||||||
|  |     iter -> IsDoneIterator( iter!.associatedIterator ) ); | ||||||
|  |  | ||||||
|  | BindGlobal( "NextIterator_Subspaces", function( iter ) | ||||||
|  |     local next; | ||||||
|  |     next:= NextIterator( iter!.associatedIterator ); | ||||||
|  |     next:= List( GeneratorsOfLeftModule( next ), | ||||||
|  |                  x -> LinearCombination( iter!.basis, x ) ); | ||||||
|  |     return Subspace( iter!.structure, next, "basis" ); | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  | BindGlobal( "ShallowCopy_Subspaces", | ||||||
|  |     iter -> rec( structure          := iter!.structure, | ||||||
|  |                  basis              := iter!.basis, | ||||||
|  |                  associatedIterator := ShallowCopy( | ||||||
|  |                                            iter!.associatedIterator ) ) ); | ||||||
|  |  | ||||||
|  | InstallMethod( Iterator, | ||||||
|  |     "for a subspaces domain", | ||||||
|  |     [ IsSubspacesVectorSpace and IsSubspacesVectorSpaceDefaultRep ], | ||||||
|  |     function( D ) | ||||||
|  |     local V;      # the vector space | ||||||
|  |  | ||||||
|  |     V:= D!.structure; | ||||||
|  |     return IteratorByFunctions( rec( | ||||||
|  |                IsDoneIterator     := IsDoneIterator_Subspaces, | ||||||
|  |                NextIterator       := NextIterator_Subspaces, | ||||||
|  |                ShallowCopy        := ShallowCopy_Subspaces, | ||||||
|  |                structure          := V, | ||||||
|  |                basis              := Basis( V ), | ||||||
|  |                associatedIterator := Iterator( | ||||||
|  |                       Subspaces( FullRowSpace( LeftActingDomain( V ), | ||||||
|  |                                                Dimension( V ) ), | ||||||
|  |                                  D!.dimension ) ) ) ); | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  Subspaces( <V>, <dim> ) | ||||||
|  | ## | ||||||
|  | InstallMethod( Subspaces, | ||||||
|  |     "for a vector space, and an integer", | ||||||
|  |     [ IsVectorSpace, IsInt ], | ||||||
|  |     function( V, dim ) | ||||||
|  |     if IsFinite( V ) then | ||||||
|  |       return Objectify( NewType( CollectionsFamily( FamilyObj( V ) ), | ||||||
|  |                                      IsSubspacesVectorSpace | ||||||
|  |                                  and IsSubspacesVectorSpaceDefaultRep ), | ||||||
|  |                         rec( | ||||||
|  |                              structure  := V, | ||||||
|  |                              dimension  := dim | ||||||
|  |                            ) | ||||||
|  |                       ); | ||||||
|  |     else | ||||||
|  |       TryNextMethod(); | ||||||
|  |     fi; | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  Subspaces( <V> ) | ||||||
|  | ## | ||||||
|  | InstallMethod( Subspaces, | ||||||
|  |     "for a vector space", | ||||||
|  |     [ IsVectorSpace ], | ||||||
|  |     function( V ) | ||||||
|  |     if IsFinite( V ) then | ||||||
|  |       return Objectify( NewType( CollectionsFamily( FamilyObj( V ) ), | ||||||
|  |                                      IsSubspacesVectorSpace | ||||||
|  |                                  and IsSubspacesVectorSpaceDefaultRep ), | ||||||
|  |                         rec( | ||||||
|  |                              structure  := V, | ||||||
|  |                              dimension  := "all" | ||||||
|  |                            ) | ||||||
|  |                       ); | ||||||
|  |     else | ||||||
|  |       TryNextMethod(); | ||||||
|  |     fi; | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #F  IsSubspace( <V>, <U> ) . . . . . . . . . . . . . . . . . check <U> <= <V> | ||||||
|  | ## | ||||||
|  | InstallGlobalFunction( IsSubspace, function( V, U ) | ||||||
|  |     return IsVectorSpace( U ) and IsSubset( V, U ); | ||||||
|  | end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #M  IsVectorSpaceHomomorphism( <map> ) | ||||||
|  | ## | ||||||
|  | InstallMethod( IsVectorSpaceHomomorphism, | ||||||
|  |     [ IsGeneralMapping ], | ||||||
|  |     function( map ) | ||||||
|  |     local S, R, F; | ||||||
|  |     S:= Source( map ); | ||||||
|  |     if not IsVectorSpace( S ) then | ||||||
|  |       return false; | ||||||
|  |     fi; | ||||||
|  |     R:= Range( map ); | ||||||
|  |     if not IsVectorSpace( R ) then | ||||||
|  |       return false; | ||||||
|  |     fi; | ||||||
|  |     F:= LeftActingDomain( S ); | ||||||
|  |     return ( F = LeftActingDomain( R ) ) and IsLinearMapping( F, map ); | ||||||
|  |     end ); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ############################################################################# | ||||||
|  | ## | ||||||
|  | #E | ||||||
|  |  | ||||||
							
								
								
									
										57
									
								
								samples/GDScript/example.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										57
									
								
								samples/GDScript/example.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,57 @@ | |||||||
|  | # Taken from https://github.com/okamstudio/godot/wiki/gdscript | ||||||
|  | # a file is a class! | ||||||
|  |  | ||||||
|  | # inheritance | ||||||
|  |  | ||||||
|  | extends BaseClass | ||||||
|  |  | ||||||
|  | # member variables | ||||||
|  |  | ||||||
|  | var a = 5  | ||||||
|  | var s = "Hello" | ||||||
|  | var arr = [1, 2, 3] | ||||||
|  | var dict = {"key":"value", 2:3} | ||||||
|  |  | ||||||
|  | # constants | ||||||
|  |  | ||||||
|  | const answer = 42 | ||||||
|  | const thename = "Charly" | ||||||
|  |  | ||||||
|  | # built-in vector types | ||||||
|  |  | ||||||
|  | var v2 = Vector2(1, 2) | ||||||
|  | var v3 = Vector3(1, 2, 3) | ||||||
|  |  | ||||||
|  | # function | ||||||
|  |  | ||||||
|  | func some_function(param1, param2): | ||||||
|  |     var local_var = 5 | ||||||
|  |  | ||||||
|  |     if param1 < local_var: | ||||||
|  |         print(param1) | ||||||
|  |     elif param2 > 5: | ||||||
|  |         print(param2) | ||||||
|  |     else: | ||||||
|  |         print("fail!") | ||||||
|  |  | ||||||
|  |     for i in range(20): | ||||||
|  |         print(i) | ||||||
|  |  | ||||||
|  |     while(param2 != 0): | ||||||
|  |         param2 -= 1 | ||||||
|  |  | ||||||
|  |     var local_var2 = param1+3 | ||||||
|  |     return local_var2 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # subclass | ||||||
|  |  | ||||||
|  | class Something: | ||||||
|  |     var a = 10 | ||||||
|  |  | ||||||
|  | # constructor | ||||||
|  |  | ||||||
|  | func _init(): | ||||||
|  |     print("constructed!") | ||||||
|  |     var lv = Something.new() | ||||||
|  |     print(lv.a) | ||||||
							
								
								
									
										216
									
								
								samples/GDScript/grid.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										216
									
								
								samples/GDScript/grid.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,216 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
|  | extends Control | ||||||
|  |  | ||||||
|  | # Simple Tetris-like demo, (c) 2012 Juan Linietsky | ||||||
|  | # Implemented by using a regular Control and drawing on it during the _draw() callback. | ||||||
|  | # The drawing surface is updated only when changes happen (by calling update()) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | var score = 0 | ||||||
|  | var score_label=null | ||||||
|  |  | ||||||
|  | const MAX_SHAPES = 7 | ||||||
|  |  | ||||||
|  | var block = preload("block.png") | ||||||
|  |  | ||||||
|  | var block_colors=[ | ||||||
|  | 	Color(1,0.5,0.5), | ||||||
|  | 	Color(0.5,1,0.5), | ||||||
|  | 	Color(0.5,0.5,1), | ||||||
|  | 	Color(0.8,0.4,0.8), | ||||||
|  | 	Color(0.8,0.8,0.4), | ||||||
|  | 	Color(0.4,0.8,0.8), | ||||||
|  | 	Color(0.7,0.7,0.7)] | ||||||
|  |  | ||||||
|  | var	block_shapes=[ | ||||||
|  | 	[ Vector2(0,-1),Vector2(0,0),Vector2(0,1),Vector2(0,2) ], # I | ||||||
|  | 	[ Vector2(0,0),Vector2(1,0),Vector2(1,1),Vector2(0,1) ], # O | ||||||
|  | 	[ Vector2(-1,1),Vector2(0,1),Vector2(0,0),Vector2(1,0) ], # S | ||||||
|  | 	[ Vector2(1,1),Vector2(0,1),Vector2(0,0),Vector2(-1,0) ], # Z | ||||||
|  | 	[ Vector2(-1,1),Vector2(-1,0),Vector2(0,0),Vector2(1,0) ], # L | ||||||
|  | 	[ Vector2(1,1),Vector2(1,0),Vector2(0,0),Vector2(-1,0) ], # J | ||||||
|  | 	[ Vector2(0,1),Vector2(1,0),Vector2(0,0),Vector2(-1,0) ]] # T | ||||||
|  | 	 | ||||||
|  |  | ||||||
|  | var block_rotations=[ | ||||||
|  | 	Matrix32( Vector2(1,0),Vector2(0,1), Vector2() ), | ||||||
|  | 	Matrix32( Vector2(0,1),Vector2(-1,0), Vector2() ), | ||||||
|  | 	Matrix32( Vector2(-1,0),Vector2(0,-1), Vector2() ), | ||||||
|  | 	Matrix32( Vector2(0,-1),Vector2(1,0), Vector2() ) | ||||||
|  | ] | ||||||
|  | 	 | ||||||
|  |  | ||||||
|  | var width=0 | ||||||
|  | var height=0 | ||||||
|  |  | ||||||
|  | var cells={} | ||||||
|  |  | ||||||
|  | var piece_active=false | ||||||
|  | var piece_shape=0 | ||||||
|  | var piece_pos=Vector2() | ||||||
|  | var piece_rot=0 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | func piece_cell_xform(p,er=0): | ||||||
|  | 	var r = (4+er+piece_rot)%4 | ||||||
|  | 	return piece_pos+block_rotations[r].xform(p) | ||||||
|  |  | ||||||
|  | func _draw(): | ||||||
|  |  | ||||||
|  | 	var sb = get_stylebox("bg","Tree") # use line edit bg | ||||||
|  | 	draw_style_box(sb,Rect2(Vector2(),get_size()).grow(3)) | ||||||
|  | 	 | ||||||
|  | 	var bs = block.get_size() | ||||||
|  | 	for y in range(height): | ||||||
|  | 		for x in range(width): | ||||||
|  | 			if (Vector2(x,y) in cells): | ||||||
|  | 				draw_texture_rect(block,Rect2(Vector2(x,y)*bs,bs),false,block_colors[cells[Vector2(x,y)]]) | ||||||
|  | 				 | ||||||
|  | 	if (piece_active): | ||||||
|  | 		 | ||||||
|  | 		for c in block_shapes[piece_shape]: | ||||||
|  | 			draw_texture_rect(block,Rect2(piece_cell_xform(c)*bs,bs),false,block_colors[piece_shape]) | ||||||
|  | 			 | ||||||
|  |  | ||||||
|  | func piece_check_fit(ofs,er=0): | ||||||
|  |  | ||||||
|  | 	for c in block_shapes[piece_shape]: | ||||||
|  | 		var pos = piece_cell_xform(c,er)+ofs | ||||||
|  | 		if (pos.x < 0): | ||||||
|  | 			return false | ||||||
|  | 		if (pos.y < 0): | ||||||
|  | 			return false | ||||||
|  | 		if (pos.x >= width): | ||||||
|  | 			return false | ||||||
|  | 		if (pos.y >= height): | ||||||
|  | 			return false | ||||||
|  | 		if (pos in cells): | ||||||
|  | 			return false | ||||||
|  | 	 | ||||||
|  | 	return true	 | ||||||
|  |  | ||||||
|  | func new_piece(): | ||||||
|  |  | ||||||
|  | 	piece_shape = randi() % MAX_SHAPES	 | ||||||
|  | 	piece_pos = Vector2(width/2,0) | ||||||
|  | 	piece_active=true | ||||||
|  | 	piece_rot=0 | ||||||
|  | 	if (piece_shape==0): | ||||||
|  | 		piece_pos.y+=1 | ||||||
|  | 		 | ||||||
|  | 	if (not piece_check_fit(Vector2())): | ||||||
|  | 		#game over | ||||||
|  | 		#print("GAME OVER!") | ||||||
|  | 		game_over() | ||||||
|  | 		 | ||||||
|  | 	update() | ||||||
|  | 		 | ||||||
|  | 	 | ||||||
|  | func test_collapse_rows(): | ||||||
|  | 	var accum_down=0 | ||||||
|  | 	for i in range(height): | ||||||
|  | 		var y = height - i - 1 | ||||||
|  | 		var collapse = true | ||||||
|  | 		for x in range(width): | ||||||
|  | 			if (Vector2(x,y) in cells): | ||||||
|  | 				if (accum_down): | ||||||
|  | 					cells[ Vector2(x,y+accum_down) ] = cells[Vector2(x,y)] | ||||||
|  | 			else: | ||||||
|  | 				collapse=false | ||||||
|  | 				if (accum_down): | ||||||
|  | 					cells.erase( Vector2(x,y+accum_down) ) | ||||||
|  | 						 | ||||||
|  | 		if (collapse): | ||||||
|  | 			accum_down+=1 | ||||||
|  | 		 | ||||||
|  | 			 | ||||||
|  | 	score+=accum_down*100 | ||||||
|  | 	score_label.set_text(str(score)) | ||||||
|  | 			 | ||||||
|  | 		 | ||||||
|  | func game_over(): | ||||||
|  |  | ||||||
|  | 		piece_active=false | ||||||
|  | 		get_node("gameover").set_text("Game Over")		 | ||||||
|  | 		update() | ||||||
|  | 				 | ||||||
|  | 		 | ||||||
|  | func restart_pressed(): | ||||||
|  |  | ||||||
|  | 		score=0 | ||||||
|  | 		score_label.set_text("0") | ||||||
|  | 		cells.clear() | ||||||
|  | 		get_node("gameover").set_text("")		 | ||||||
|  | 		piece_active=true | ||||||
|  | 		update() | ||||||
|  | 		 | ||||||
|  | 		 | ||||||
|  |  | ||||||
|  | func piece_move_down(): | ||||||
|  |  | ||||||
|  | 	if (!piece_active): | ||||||
|  | 		return | ||||||
|  | 	if (piece_check_fit(Vector2(0,1))): | ||||||
|  | 		piece_pos.y+=1 | ||||||
|  | 		update()		 | ||||||
|  | 	else: | ||||||
|  |  | ||||||
|  | 		for c in block_shapes[piece_shape]: | ||||||
|  | 			var pos = piece_cell_xform(c) | ||||||
|  | 			cells[pos]=piece_shape | ||||||
|  | 		test_collapse_rows() | ||||||
|  | 		new_piece() | ||||||
|  | 		 | ||||||
|  |  | ||||||
|  | func piece_rotate(): | ||||||
|  |  | ||||||
|  | 	var adv = 1 | ||||||
|  | 	if (not piece_check_fit(Vector2(),1)): | ||||||
|  | 		return | ||||||
|  | 	piece_rot = (piece_rot + adv) % 4 | ||||||
|  | 	update() | ||||||
|  | 	 | ||||||
|  | 	 | ||||||
|  |  | ||||||
|  | func _input(ie): | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	if (not piece_active): | ||||||
|  | 		return | ||||||
|  | 	if (!ie.is_pressed()): | ||||||
|  | 		return | ||||||
|  |  | ||||||
|  | 	if (ie.is_action("move_left")): | ||||||
|  | 		if (piece_check_fit(Vector2(-1,0))): | ||||||
|  | 			piece_pos.x-=1 | ||||||
|  | 			update() | ||||||
|  | 	elif (ie.is_action("move_right")): | ||||||
|  | 		if (piece_check_fit(Vector2(1,0))): | ||||||
|  | 			piece_pos.x+=1 | ||||||
|  | 			update() | ||||||
|  | 	elif (ie.is_action("move_down")): | ||||||
|  | 		piece_move_down() | ||||||
|  | 	elif (ie.is_action("rotate")): | ||||||
|  | 		piece_rotate() | ||||||
|  | 		 | ||||||
|  | 		 | ||||||
|  | func setup(w,h): | ||||||
|  | 	width=w | ||||||
|  | 	height=h | ||||||
|  | 	set_size( Vector2(w,h)*block.get_size() ) | ||||||
|  | 	new_piece() | ||||||
|  | 	get_node("timer").start() | ||||||
|  | 	 | ||||||
|  |  | ||||||
|  | func _ready(): | ||||||
|  | 	# Initalization here | ||||||
|  |  | ||||||
|  | 	setup(10,20) | ||||||
|  | 	score_label = get_node("../score") | ||||||
|  |  | ||||||
|  | 	set_process_input(true) | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										243
									
								
								samples/GDScript/player.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										243
									
								
								samples/GDScript/player.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,243 @@ | |||||||
|  |  | ||||||
|  | extends RigidBody | ||||||
|  |  | ||||||
|  | # member variables here, example: | ||||||
|  | # var a=2 | ||||||
|  | # var b="textvar" | ||||||
|  |  | ||||||
|  | #var dir=Vector3() | ||||||
|  |  | ||||||
|  | const ANIM_FLOOR = 0 | ||||||
|  | const ANIM_AIR_UP = 1 | ||||||
|  | const ANIM_AIR_DOWN = 2 | ||||||
|  |  | ||||||
|  | const SHOOT_TIME = 1.5 | ||||||
|  | const SHOOT_SCALE = 2 | ||||||
|  |  | ||||||
|  | const CHAR_SCALE = Vector3(0.3,0.3,0.3) | ||||||
|  |  | ||||||
|  | var facing_dir = Vector3(1, 0, 0) | ||||||
|  | var movement_dir = Vector3() | ||||||
|  |  | ||||||
|  | var jumping=false | ||||||
|  |  | ||||||
|  | var turn_speed=40 | ||||||
|  | var keep_jump_inertia = true | ||||||
|  | var air_idle_deaccel = false | ||||||
|  | var accel=19.0 | ||||||
|  | var deaccel=14.0 | ||||||
|  | var sharp_turn_threshhold = 140 | ||||||
|  |  | ||||||
|  | var max_speed=3.1 | ||||||
|  | var on_floor = false | ||||||
|  |  | ||||||
|  | var prev_shoot = false | ||||||
|  |  | ||||||
|  | var last_floor_velocity = Vector3() | ||||||
|  |  | ||||||
|  | var shoot_blend = 0 | ||||||
|  |  | ||||||
|  | func adjust_facing(p_facing, p_target,p_step, p_adjust_rate,current_gn): | ||||||
|  |  | ||||||
|  | 	var n = p_target # normal | ||||||
|  | 	var t = n.cross(current_gn).normalized() | ||||||
|  | 	 | ||||||
|  | 	var x = n.dot(p_facing) | ||||||
|  | 	var y = t.dot(p_facing) | ||||||
|  | 	 | ||||||
|  | 	var ang = atan2(y,x) | ||||||
|  | 	 | ||||||
|  | 	if (abs(ang)<0.001): # too small | ||||||
|  | 		return p_facing | ||||||
|  | 	 | ||||||
|  | 	var s = sign(ang) | ||||||
|  | 	ang = ang * s | ||||||
|  | 	var turn = ang * p_adjust_rate * p_step | ||||||
|  | 	var a | ||||||
|  | 	if (ang<turn): | ||||||
|  | 		a=ang | ||||||
|  | 	else: | ||||||
|  | 		a=turn | ||||||
|  | 	ang = (ang - a) * s | ||||||
|  | 	 | ||||||
|  | 	return ((n * cos(ang)) + (t * sin(ang))) * p_facing.length() | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | func _integrate_forces( state ): | ||||||
|  |  | ||||||
|  | 	var lv = state.get_linear_velocity() # linear velocity | ||||||
|  | 	var g = state.get_total_gravity() | ||||||
|  | 	var delta = state.get_step() | ||||||
|  | 	var d = 1.0 - delta*state.get_total_density() | ||||||
|  | 	if (d<0): | ||||||
|  | 		d=0 | ||||||
|  | 	lv += g * delta #apply gravity | ||||||
|  |  | ||||||
|  | 	var anim = ANIM_FLOOR | ||||||
|  |  | ||||||
|  | 	var up = -g.normalized() # (up is against gravity) | ||||||
|  | 	var vv = up.dot(lv) # vertical velocity | ||||||
|  | 	var hv = lv - (up*vv) # horizontal velocity | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	var hdir = hv.normalized() # horizontal direction | ||||||
|  | 	var hspeed = hv.length()	#horizontal speed | ||||||
|  |  | ||||||
|  | 	var floor_velocity | ||||||
|  | 	var onfloor = false | ||||||
|  |  | ||||||
|  | 	if (state.get_contact_count() == 0): | ||||||
|  | 		floor_velocity = last_floor_velocity | ||||||
|  | 	else: | ||||||
|  | 		for i in range(state.get_contact_count()): | ||||||
|  | 			if (state.get_contact_local_shape(i) != 1): | ||||||
|  | 				continue | ||||||
|  | 			 | ||||||
|  | 			onfloor = true | ||||||
|  | 			floor_velocity = state.get_contact_collider_velocity_at_pos(i) | ||||||
|  | 			break | ||||||
|  | 		 | ||||||
|  |  | ||||||
|  | 	var dir = Vector3() #where does the player intend to walk to | ||||||
|  | 	var cam_xform = get_node("target/camera").get_global_transform() | ||||||
|  | 	 | ||||||
|  | 	if (Input.is_action_pressed("move_forward")): | ||||||
|  | 		dir+=-cam_xform.basis[2]  | ||||||
|  | 	if (Input.is_action_pressed("move_backwards")): | ||||||
|  | 		dir+=cam_xform.basis[2]  | ||||||
|  | 	if (Input.is_action_pressed("move_left")): | ||||||
|  | 		dir+=-cam_xform.basis[0]  | ||||||
|  | 	if (Input.is_action_pressed("move_right")): | ||||||
|  | 		dir+=cam_xform.basis[0]  | ||||||
|  | 		 | ||||||
|  | 	var jump_attempt = Input.is_action_pressed("jump") | ||||||
|  | 	var shoot_attempt = Input.is_action_pressed("shoot") | ||||||
|  | 		 | ||||||
|  | 	var target_dir = (dir - up*dir.dot(up)).normalized() | ||||||
|  | 	 | ||||||
|  | 	if (onfloor): | ||||||
|  |  | ||||||
|  | 		var sharp_turn = hspeed > 0.1 and rad2deg(acos(target_dir.dot(hdir))) > sharp_turn_threshhold | ||||||
|  |  | ||||||
|  | 		if (dir.length()>0.1 and !sharp_turn) : | ||||||
|  | 			if (hspeed > 0.001) : | ||||||
|  |  | ||||||
|  | 				#linear_dir = linear_h_velocity/linear_vel | ||||||
|  | 				#if (linear_vel > brake_velocity_limit and linear_dir.dot(ctarget_dir)<-cos(Math::deg2rad(brake_angular_limit))) | ||||||
|  | 				#	brake=true | ||||||
|  | 				#else | ||||||
|  | 				hdir = adjust_facing(hdir,target_dir,delta,1.0/hspeed*turn_speed,up) | ||||||
|  | 				facing_dir = hdir | ||||||
|  | 			else: | ||||||
|  |  | ||||||
|  | 				hdir = target_dir | ||||||
|  | 			 | ||||||
|  | 			if (hspeed<max_speed): | ||||||
|  | 				hspeed+=accel*delta | ||||||
|  |  | ||||||
|  | 		else: | ||||||
|  | 			hspeed-=deaccel*delta | ||||||
|  | 			if (hspeed<0): | ||||||
|  | 				hspeed=0 | ||||||
|  | 		 | ||||||
|  | 		hv = hdir*hspeed | ||||||
|  | 		 | ||||||
|  | 		var mesh_xform = get_node("Armature").get_transform()  | ||||||
|  | 		var facing_mesh=-mesh_xform.basis[0].normalized() | ||||||
|  | 		facing_mesh = (facing_mesh - up*facing_mesh.dot(up)).normalized() | ||||||
|  | 		facing_mesh = adjust_facing(facing_mesh,target_dir,delta,1.0/hspeed*turn_speed,up) | ||||||
|  | 		var m3 = Matrix3(-facing_mesh,up,-facing_mesh.cross(up).normalized()).scaled( CHAR_SCALE ) | ||||||
|  | 		 | ||||||
|  | 		get_node("Armature").set_transform(Transform(m3,mesh_xform.origin)) | ||||||
|  | 				 | ||||||
|  | 		if (not jumping and jump_attempt): | ||||||
|  | 			vv = 7.0 | ||||||
|  | 			jumping = true		 | ||||||
|  | 			get_node("sfx").play("jump") | ||||||
|  | 	else: | ||||||
|  |  | ||||||
|  | 		if (vv>0): | ||||||
|  | 			anim=ANIM_AIR_UP | ||||||
|  | 		else: | ||||||
|  | 			anim=ANIM_AIR_DOWN | ||||||
|  | 			 | ||||||
|  | 		var hs | ||||||
|  | 		if (dir.length()>0.1): | ||||||
|  |  | ||||||
|  | 			hv += target_dir * (accel * 0.2) * delta | ||||||
|  | 			if (hv.length() > max_speed): | ||||||
|  | 				hv = hv.normalized() * max_speed | ||||||
|  |  | ||||||
|  | 		else: | ||||||
|  |  | ||||||
|  | 			if (air_idle_deaccel): | ||||||
|  | 				hspeed = hspeed - (deaccel * 0.2) * delta | ||||||
|  | 				if (hspeed<0): | ||||||
|  | 					hspeed=0 | ||||||
|  |  | ||||||
|  | 				hv = hdir*hspeed | ||||||
|  | 			 | ||||||
|  | 		 | ||||||
|  | 	if (jumping and vv < 0): | ||||||
|  | 		jumping=false | ||||||
|  |  | ||||||
|  | 	lv = hv+up*vv | ||||||
|  | 	 | ||||||
|  | 	 | ||||||
|  |  | ||||||
|  | 	if (onfloor): | ||||||
|  |  | ||||||
|  | 		movement_dir = lv | ||||||
|  | 		#lv += floor_velocity | ||||||
|  | 		last_floor_velocity = floor_velocity | ||||||
|  | 	else: | ||||||
|  |  | ||||||
|  | 		if (on_floor) : | ||||||
|  |  | ||||||
|  | 			#if (keep_jump_inertia): | ||||||
|  | 			#	lv += last_floor_velocity | ||||||
|  | 			pass | ||||||
|  | 		 | ||||||
|  | 		last_floor_velocity = Vector3() | ||||||
|  | 		movement_dir = lv | ||||||
|  | 	 | ||||||
|  | 	on_floor = onfloor | ||||||
|  |  | ||||||
|  | 	state.set_linear_velocity(lv) | ||||||
|  | 	 | ||||||
|  | 	if (shoot_blend>0): | ||||||
|  | 		shoot_blend -= delta * SHOOT_SCALE | ||||||
|  | 		if (shoot_blend<0): | ||||||
|  | 			shoot_blend=0 | ||||||
|  | 	 | ||||||
|  | 	if (shoot_attempt and not prev_shoot): | ||||||
|  | 		shoot_blend = SHOOT_TIME		 | ||||||
|  | 		var bullet = preload("res://bullet.scn").instance() | ||||||
|  | 		bullet.set_transform( get_node("Armature/bullet").get_global_transform().orthonormalized() ) | ||||||
|  | 		get_parent().add_child( bullet ) | ||||||
|  | 		bullet.set_linear_velocity( get_node("Armature/bullet").get_global_transform().basis[2].normalized() * 20 ) | ||||||
|  | 		PS.body_add_collision_exception( bullet.get_rid(), get_rid() ) #add it to bullet | ||||||
|  | 		get_node("sfx").play("shoot") | ||||||
|  | 		 | ||||||
|  | 	prev_shoot = shoot_attempt | ||||||
|  | 	 | ||||||
|  | 	if (onfloor): | ||||||
|  | 		get_node("AnimationTreePlayer").blend2_node_set_amount("walk",hspeed / max_speed) | ||||||
|  | 		 | ||||||
|  | 	get_node("AnimationTreePlayer").transition_node_set_current("state",anim) | ||||||
|  | 	get_node("AnimationTreePlayer").blend2_node_set_amount("gun",min(shoot_blend,1.0)) | ||||||
|  | #	state.set_angular_velocity(Vector3())	 | ||||||
|  | 	 | ||||||
|  | 	 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | func _ready(): | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	# Initalization here | ||||||
|  | 	get_node("AnimationTreePlayer").set_active(true) | ||||||
|  | 	pass | ||||||
|  |  | ||||||
|  |  | ||||||
							
								
								
									
										73
									
								
								samples/GDScript/pong.gd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								samples/GDScript/pong.gd
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | |||||||
|  |  | ||||||
|  | extends Node2D | ||||||
|  |  | ||||||
|  | # member variables here, example: | ||||||
|  | # var a=2 | ||||||
|  | # var b="textvar" | ||||||
|  | const INITIAL_BALL_SPEED = 80 | ||||||
|  | var ball_speed = INITIAL_BALL_SPEED | ||||||
|  | var screen_size = Vector2(640,400) | ||||||
|  | #default ball direction | ||||||
|  | var direction = Vector2(-1,0) | ||||||
|  | var pad_size = Vector2(8,32) | ||||||
|  | const PAD_SPEED = 150 | ||||||
|  |  | ||||||
|  |  | ||||||
|  | func _process(delta): | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	# get ball positio and pad rectangles | ||||||
|  | 	var ball_pos = get_node("ball").get_pos() | ||||||
|  | 	var left_rect = Rect2( get_node("left").get_pos() - pad_size*0.5, pad_size ) | ||||||
|  | 	var right_rect = Rect2( get_node("right").get_pos() - pad_size*0.5, pad_size ) | ||||||
|  | 	 | ||||||
|  | 	#integrate new ball postion | ||||||
|  | 	ball_pos+=direction*ball_speed*delta | ||||||
|  | 	 | ||||||
|  | 	#flip when touching roof or floor | ||||||
|  | 	if ( (ball_pos.y<0 and direction.y <0) or (ball_pos.y>screen_size.y and direction.y>0)): | ||||||
|  | 		direction.y = -direction.y | ||||||
|  | 		 | ||||||
|  | 	#flip, change direction and increase speed when touching pads	 | ||||||
|  | 	if ( (left_rect.has_point(ball_pos) and direction.x < 0) or (right_rect.has_point(ball_pos) and direction.x > 0)): | ||||||
|  | 		direction.x=-direction.x | ||||||
|  | 		ball_speed*=1.1 | ||||||
|  | 		direction.y=randf()*2.0-1 | ||||||
|  | 		direction = direction.normalized() | ||||||
|  |  | ||||||
|  | 	#check gameover | ||||||
|  | 	if (ball_pos.x<0 or ball_pos.x>screen_size.x): | ||||||
|  | 		ball_pos=screen_size*0.5 | ||||||
|  | 		ball_speed=INITIAL_BALL_SPEED | ||||||
|  | 		direction=Vector2(-1,0) | ||||||
|  | 			 | ||||||
|  | 						 | ||||||
|  | 	get_node("ball").set_pos(ball_pos) | ||||||
|  |  | ||||||
|  | 	#move left pad	 | ||||||
|  | 	var left_pos = get_node("left").get_pos() | ||||||
|  | 	 | ||||||
|  | 	if (left_pos.y > 0 and Input.is_action_pressed("left_move_up")): | ||||||
|  | 		left_pos.y+=-PAD_SPEED*delta | ||||||
|  | 	if (left_pos.y < screen_size.y and Input.is_action_pressed("left_move_down")): | ||||||
|  | 		left_pos.y+=PAD_SPEED*delta | ||||||
|  | 		 | ||||||
|  | 	get_node("left").set_pos(left_pos) | ||||||
|  | 		 | ||||||
|  | 	#move right pad	 | ||||||
|  | 	var right_pos = get_node("right").get_pos() | ||||||
|  | 	 | ||||||
|  | 	if (right_pos.y > 0 and Input.is_action_pressed("right_move_up")): | ||||||
|  | 		right_pos.y+=-PAD_SPEED*delta | ||||||
|  | 	if (right_pos.y < screen_size.y and Input.is_action_pressed("right_move_down")): | ||||||
|  | 		right_pos.y+=PAD_SPEED*delta | ||||||
|  | 		 | ||||||
|  | 	get_node("right").set_pos(right_pos) | ||||||
|  | 	 | ||||||
|  | 	  | ||||||
|  |  | ||||||
|  | func _ready(): | ||||||
|  | 	screen_size = get_viewport_rect().size # get actual size | ||||||
|  | 	pad_size = get_node("left").get_texture().get_size() | ||||||
|  | 	set_process(true) | ||||||
|  |  | ||||||
							
								
								
									
										9
									
								
								samples/GLSL/SimpleLighting.gl2.frag
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								samples/GLSL/SimpleLighting.gl2.frag
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | |||||||
|  | static const char* SimpleFragmentShader = STRINGIFY( | ||||||
|  |  | ||||||
|  | varying vec4 FrontColor; | ||||||
|  |  | ||||||
|  | void main(void) | ||||||
|  | { | ||||||
|  |     gl_FragColor = FrontColor; | ||||||
|  | } | ||||||
|  | ); | ||||||
							
								
								
									
										6
									
								
								samples/GLSL/myfragment.frg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								samples/GLSL/myfragment.frg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | varying vec4 v_color; | ||||||
|  |  | ||||||
|  | void main() | ||||||
|  | { | ||||||
|  | 	gl_FragColor = v_color; | ||||||
|  | } | ||||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user