mirror of
https://github.com/KevinMidboe/linguist.git
synced 2025-10-29 17:50:22 +00:00
Compare commits
504 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31921838cd | ||
|
|
a707587182 | ||
|
|
bc482af999 | ||
|
|
6818744dae | ||
|
|
607185ac61 | ||
|
|
81b7a412c3 | ||
|
|
09b9a8b441 | ||
|
|
85479cc2de | ||
|
|
3ad4eb2b59 | ||
|
|
878fe95ec3 | ||
|
|
701e720ab8 | ||
|
|
e709ce7d56 | ||
|
|
32c89a5405 | ||
|
|
1735982a73 | ||
|
|
625e0aa1af | ||
|
|
00e1a3f8fd | ||
|
|
539256b08e | ||
|
|
ff791f5a39 | ||
|
|
304fc344a1 | ||
|
|
9d940755e7 | ||
|
|
bc04232f87 | ||
|
|
e17ebec098 | ||
|
|
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 | ||
|
|
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 | ||
|
|
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 | ||
|
|
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 | ||
|
|
0c6f4383a7 | ||
|
|
97908204a3 | ||
|
|
5606916d99 | ||
|
|
3d4b682d63 | ||
|
|
96561c24be | ||
|
|
0cd1566145 | ||
|
|
b6aa9f9b12 | ||
|
|
b6d0a41718 | ||
|
|
0240b76cc3 | ||
|
|
3f96bcc32b | ||
|
|
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 | ||
|
|
f39456ee47 | ||
|
|
911a532051 | ||
|
|
44910dbcd8 | ||
|
|
42cb8ec3cf | ||
|
|
957dd15d5b | ||
|
|
1e9435c999 | ||
|
|
dc1b0e3c48 | ||
|
|
2e731a1084 | ||
|
|
869cf8ba11 | ||
|
|
d394e8db21 | ||
|
|
a8b6267471 | ||
|
|
637682e452 | ||
|
|
38bd07a113 | ||
|
|
68b6152b42 | ||
|
|
a349f81e2d | ||
|
|
8c2e41cc99 | ||
|
|
6c0618f75a | ||
|
|
b1eed16422 | ||
|
|
432f27480e | ||
|
|
23addec9a9 | ||
|
|
e50cc9b210 | ||
|
|
58d865f293 | ||
|
|
b69fef2c39 | ||
|
|
f8fee56446 | ||
|
|
10903e7e38 | ||
|
|
645411e256 | ||
|
|
29510b26e0 | ||
|
|
e4c1cc572b | ||
|
|
7c85c11944 | ||
|
|
5318402be5 | ||
|
|
8323450958 | ||
|
|
68793b1f0f | ||
|
|
c6e3c8fab8 | ||
|
|
54c1d7c9d9 | ||
|
|
3a19ba4523 | ||
|
|
210ca9a86f | ||
|
|
ff9e0aedd6 | ||
|
|
cb9bef43a5 | ||
|
|
115ac6b999 | ||
|
|
4c500e1fb2 | ||
|
|
5715802999 | ||
|
|
a2690b7dac | ||
|
|
8b00872d36 | ||
|
|
c67c8a7482 | ||
|
|
ee370cbf43 | ||
|
|
78217e1cee | ||
|
|
86364da07e | ||
|
|
4ec878ba0d | ||
|
|
28a2b39a55 | ||
|
|
92e1b1eb40 | ||
|
|
3bea39eb10 | ||
|
|
a34398eb92 | ||
|
|
2f6035cd1e | ||
|
|
e437cf749d | ||
|
|
5218b60681 | ||
|
|
8afe123084 | ||
|
|
c60328383d | ||
|
|
69bfe73165 | ||
|
|
3429ddeaa1 | ||
|
|
9242a2f83b | ||
|
|
e2b1fe3641 | ||
|
|
0eebd42d72 | ||
|
|
b0894e20ef | ||
|
|
0cc47dd47d | ||
|
|
fdbfd8b806 | ||
|
|
9f3ee8dff6 | ||
|
|
166012dcf0 | ||
|
|
bb754d8849 | ||
|
|
0eaaa2bacc | ||
|
|
a1eab2a439 | ||
|
|
487cad7041 | ||
|
|
43f393a02d | ||
|
|
3c1f4c8ee1 | ||
|
|
81db880a7b | ||
|
|
277a71f6f6 | ||
|
|
0cfcb6917b | ||
|
|
681561229e | ||
|
|
43825c3426 | ||
|
|
f4fd6ed94e | ||
|
|
ef42680646 | ||
|
|
03ce24221e | ||
|
|
e9f9a9ef12 | ||
|
|
476b39c353 | ||
|
|
0eea2bd7bb | ||
|
|
f78ce5389e | ||
|
|
dd32b8f441 | ||
|
|
39a9c768c8 | ||
|
|
ff257175ac | ||
|
|
877ee775a3 | ||
|
|
19e151390e | ||
|
|
7da9038e79 | ||
|
|
1f8ef83657 | ||
|
|
2770e4e111 | ||
|
|
96dfbc71eb | ||
|
|
9076086d9b | ||
|
|
dc76ca7e37 | ||
|
|
7ee2b60762 | ||
|
|
e3a9395b4c | ||
|
|
83513977a4 | ||
|
|
42912141c5 | ||
|
|
8561ece4d7 | ||
|
|
028f2ab92c | ||
|
|
34c83d9495 | ||
|
|
e37f5b8df5 | ||
|
|
df342798b0 | ||
|
|
b91738721b | ||
|
|
123f4c26c3 | ||
|
|
1bbf75b5ab | ||
|
|
70e56303ab | ||
|
|
293ed8aa8d | ||
|
|
49fd25236e | ||
|
|
83a742621f | ||
|
|
63cb5aac20 | ||
|
|
00de2b011d | ||
|
|
bc923bb6b1 | ||
|
|
9cae54bb55 | ||
|
|
89795ebd1f | ||
|
|
5fb6f34d8a | ||
|
|
3ecc1f883c | ||
|
|
edf19a0941 | ||
|
|
dfeaaaa17e | ||
|
|
bcefa61fe0 | ||
|
|
f0ad498b93 | ||
|
|
a0aae8cdc1 | ||
|
|
a2d6b374da | ||
|
|
6df8bd62d3 | ||
|
|
d6e3bcc875 | ||
|
|
200473ba27 | ||
|
|
05fb0c35fa | ||
|
|
395f4375da | ||
|
|
bb348c4038 | ||
|
|
1a4be4dfa0 | ||
|
|
7c9e973082 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1 +1,3 @@
|
||||
Gemfile.lock
|
||||
.bundle/
|
||||
vendor/
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
before_install:
|
||||
- sudo apt-get install libicu-dev -y
|
||||
# Short-term fix addressing https://github.com/bundler/bundler/issues/2784
|
||||
- gem update --system 2.1.11
|
||||
rvm:
|
||||
- 1.8.7
|
||||
- 1.9.2
|
||||
- 1.9.3
|
||||
- 2.0.0
|
||||
- ree
|
||||
- 2.1.1
|
||||
notifications:
|
||||
disabled: true
|
||||
|
||||
5
Gemfile
5
Gemfile
@@ -1,7 +1,2 @@
|
||||
source 'https://rubygems.org'
|
||||
gemspec
|
||||
|
||||
if RUBY_VERSION < "1.9.3"
|
||||
# escape_utils 1.0.0 requires 1.9.3 and above
|
||||
gem "escape_utils", "0.3.2"
|
||||
end
|
||||
|
||||
51
README.md
51
README.md
@@ -6,12 +6,9 @@ We use this library at GitHub to detect blob languages, highlight code, ignore b
|
||||
|
||||
### Language detection
|
||||
|
||||
Linguist defines a list of all languages known to GitHub in a [yaml file](https://github.com/github/linguist/blob/master/lib/linguist/languages.yml). In order for a file to be highlighted, a language and lexer must be defined there.
|
||||
Linguist defines a list of all languages known to GitHub in a [yaml file](https://github.com/github/linguist/blob/master/lib/linguist/languages.yml). In order for a file to be highlighted, a language and a lexer must be defined there.
|
||||
|
||||
Most languages are detected by their file extension. This is the fastest and most common situation.
|
||||
|
||||
For disambiguating between files with common extensions, we first apply
|
||||
some common-sense heuristics to pick out obvious languages. After that, we use a
|
||||
Most languages are detected by their file extension. For disambiguating between files with common extensions, we first apply some common-sense heuristics to pick out obvious languages. After that, we use a
|
||||
[statistical
|
||||
classifier](https://github.com/github/linguist/blob/master/lib/linguist/classifier.rb).
|
||||
This process can help us tell the difference between, for example, `.h` files which could be either C, C++, or Obj-C.
|
||||
@@ -31,7 +28,7 @@ The actual syntax highlighting is handled by our Pygments wrapper, [pygments.rb]
|
||||
|
||||
### Stats
|
||||
|
||||
The Language stats bar that you see on every repository is built by aggregating the languages of each file in that repository. The top language in the graph determines the project's primary language. Collectively, these stats make up the [Top Languages](https://github.com/languages) page.
|
||||
The Language stats bar that you see on every repository is built by aggregating the languages of each file in that repository. The top language in the graph determines the project's primary language.
|
||||
|
||||
The repository stats API, accessed through `#languages`, can be used on a directory:
|
||||
|
||||
@@ -109,8 +106,50 @@ To update the `samples.json` after adding new files to [`samples/`](https://gith
|
||||
|
||||
bundle exec rake samples
|
||||
|
||||
### A note on language extensions
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
|
||||
### 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: `gem build github-linguist.gemspec`
|
||||
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-2.10.12.gem`
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
require File.expand_path('../lib/linguist/version', __FILE__)
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = 'github-linguist'
|
||||
s.version = '2.10.11'
|
||||
s.version = Linguist::VERSION
|
||||
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.'
|
||||
|
||||
@@ -11,10 +13,10 @@ Gem::Specification.new do |s|
|
||||
s.files = Dir['lib/**/*']
|
||||
s.executables << 'linguist'
|
||||
|
||||
s.add_dependency 'charlock_holmes', '~> 0.6.6'
|
||||
s.add_dependency 'escape_utils', '>= 0.3.1'
|
||||
s.add_dependency 'charlock_holmes', '~> 0.7.3'
|
||||
s.add_dependency 'escape_utils', '~> 1.0.1'
|
||||
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_development_dependency 'json'
|
||||
s.add_development_dependency 'mocha'
|
||||
|
||||
@@ -4,3 +4,4 @@ require 'linguist/heuristics'
|
||||
require 'linguist/language'
|
||||
require 'linguist/repository'
|
||||
require 'linguist/samples'
|
||||
require 'linguist/version'
|
||||
|
||||
@@ -112,6 +112,12 @@ module Linguist
|
||||
end
|
||||
end
|
||||
|
||||
def ruby_encoding
|
||||
if hash = detect_encoding
|
||||
hash[:ruby_encoding]
|
||||
end
|
||||
end
|
||||
|
||||
# Try to guess the encoding
|
||||
#
|
||||
# Returns: a Hash, with :encoding, :confidence, :type
|
||||
@@ -241,7 +247,31 @@ module Linguist
|
||||
def lines
|
||||
@lines ||=
|
||||
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
|
||||
[]
|
||||
end
|
||||
|
||||
@@ -62,7 +62,8 @@ module Linguist
|
||||
generated_protocol_buffer? ||
|
||||
generated_jni_header? ||
|
||||
composer_lock? ||
|
||||
node_modules?
|
||||
node_modules? ||
|
||||
vcr_cassette?
|
||||
end
|
||||
|
||||
# Internal: Is the blob an XCode project file?
|
||||
@@ -235,5 +236,15 @@ module Linguist
|
||||
def composer_lock?
|
||||
!!name.match(/composer.lock/)
|
||||
end
|
||||
|
||||
# Is the blob a VCR Cassette file?
|
||||
#
|
||||
# Returns true or false
|
||||
def vcr_cassette?
|
||||
return false unless extname == '.yml'
|
||||
return false unless lines.count > 2
|
||||
# VCR Cassettes have "recorded_with: VCR" in the second last line.
|
||||
return lines[-2].include?("recorded_with: VCR")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -19,9 +19,18 @@ module Linguist
|
||||
if languages.all? { |l| ["Perl", "Prolog"].include?(l) }
|
||||
disambiguate_pl(data, languages)
|
||||
end
|
||||
if languages.all? { |l| ["ECL", "Prolog"].include?(l) }
|
||||
disambiguate_ecl(data, languages)
|
||||
end
|
||||
if languages.all? { |l| ["TypeScript", "XML"].include?(l) }
|
||||
disambiguate_ts(data, languages)
|
||||
end
|
||||
if languages.all? { |l| ["Common Lisp", "OpenCL"].include?(l) }
|
||||
disambiguate_cl(data, languages)
|
||||
end
|
||||
if languages.all? { |l| ["Rebol", "R"].include?(l) }
|
||||
disambiguate_r(data, languages)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -43,6 +52,13 @@ module Linguist
|
||||
matches
|
||||
end
|
||||
|
||||
def self.disambiguate_ecl(data, languages)
|
||||
matches = []
|
||||
matches << Language["Prolog"] if data.include?(":-")
|
||||
matches << Language["ECL"] if data.include?(":=")
|
||||
matches
|
||||
end
|
||||
|
||||
def self.disambiguate_ts(data, languages)
|
||||
matches = []
|
||||
if (data.include?("</translation>"))
|
||||
@@ -53,6 +69,20 @@ module Linguist
|
||||
matches
|
||||
end
|
||||
|
||||
def self.disambiguate_cl(data, languages)
|
||||
matches = []
|
||||
matches << Language["Common Lisp"] if data.include?("(defun ")
|
||||
matches << Language["OpenCL"] if /\/\* |\/\/ |^\}/.match(data)
|
||||
matches
|
||||
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.active?
|
||||
!!ACTIVE
|
||||
end
|
||||
|
||||
@@ -24,7 +24,6 @@ module Linguist
|
||||
@extension_index = Hash.new { |h,k| h[k] = [] }
|
||||
@interpreter_index = Hash.new { |h,k| h[k] = [] }
|
||||
@filename_index = Hash.new { |h,k| h[k] = [] }
|
||||
@primary_extension_index = {}
|
||||
|
||||
# Valid Languages types
|
||||
TYPES = [:data, :markup, :programming, :prose]
|
||||
@@ -80,12 +79,6 @@ module Linguist
|
||||
@extension_index[extension] << language
|
||||
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|
|
||||
@interpreter_index[interpreter] << language
|
||||
end
|
||||
@@ -191,8 +184,7 @@ module Linguist
|
||||
# Returns all matching Languages or [] if none were found.
|
||||
def self.find_by_filename(filename)
|
||||
basename, extname = File.basename(filename), File.extname(filename)
|
||||
langs = [@primary_extension_index[extname]] +
|
||||
@filename_index[basename] +
|
||||
langs = @filename_index[basename] +
|
||||
@extension_index[extname]
|
||||
langs.compact.uniq
|
||||
end
|
||||
@@ -299,15 +291,6 @@ module Linguist
|
||||
@interpreters = attributes[:interpreters] || []
|
||||
@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
|
||||
@popular = attributes.key?(:popular) ? attributes[:popular] : false
|
||||
@searchable = attributes.key?(:searchable) ? attributes[:searchable] : true
|
||||
@@ -395,20 +378,6 @@ module Linguist
|
||||
# Returns the extensions Array
|
||||
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
|
||||
#
|
||||
# Examples
|
||||
@@ -426,6 +395,27 @@ module Linguist
|
||||
#
|
||||
# Returns the extensions Array
|
||||
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.
|
||||
#
|
||||
@@ -485,7 +475,7 @@ module Linguist
|
||||
#
|
||||
# Returns html String
|
||||
def colorize(text, options = {})
|
||||
lexer.highlight(text, options = {})
|
||||
lexer.highlight(text, options)
|
||||
end
|
||||
|
||||
# Public: Return name as String representation
|
||||
@@ -568,9 +558,8 @@ module Linguist
|
||||
:group_name => options['group'],
|
||||
:searchable => options.key?('searchable') ? options['searchable'] : true,
|
||||
:search_term => options['search_term'],
|
||||
:extensions => options['extensions'].sort,
|
||||
:extensions => [options['extensions'].first] + options['extensions'][1..-1].sort,
|
||||
:interpreters => options['interpreters'].sort,
|
||||
:primary_extension => options['primary_extension'],
|
||||
:filenames => options['filenames'],
|
||||
:popular => popular.include?(name)
|
||||
)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -10,7 +10,7 @@
|
||||
## Vendor Conventions ##
|
||||
|
||||
# Caches
|
||||
- cache/
|
||||
- (^|/)cache/
|
||||
|
||||
# Dependencies
|
||||
- ^[Dd]ependencies/
|
||||
@@ -47,6 +47,9 @@
|
||||
# Debian packaging
|
||||
- ^debian/
|
||||
|
||||
# Haxelib projects often contain a neko bytecode file named run.n
|
||||
- run.n$
|
||||
|
||||
## Commonly Bundled JavaScript frameworks ##
|
||||
|
||||
# jQuery
|
||||
@@ -63,6 +66,9 @@
|
||||
- (^|/)controls\.js$
|
||||
- (^|/)dragdrop\.js$
|
||||
|
||||
# Typescript definition files
|
||||
- (.*?)\.d\.ts$
|
||||
|
||||
# MooTools
|
||||
- (^|/)mootools([^.]*)\d+\.\d+.\d+([^.]*)\.js$
|
||||
|
||||
@@ -92,6 +98,16 @@
|
||||
# AngularJS
|
||||
- (^|/)angular([^.]*)(\.min)?\.js$
|
||||
|
||||
# D3.js
|
||||
- (^|\/)d3(\.v\d+)?([^.]*)(\.min)?\.js$
|
||||
|
||||
# React
|
||||
- (^|/)react(-[^.]*)?(\.min)?\.js$
|
||||
|
||||
# Modernizr
|
||||
- (^|/)modernizr\-\d\.\d+(\.\d+)?(\.min)?\.js$
|
||||
- (^|/)modernizr\.custom\.\d+\.js$
|
||||
|
||||
## Python ##
|
||||
|
||||
# django
|
||||
@@ -111,10 +127,18 @@
|
||||
# Sparkle
|
||||
- (^|/)Sparkle/
|
||||
|
||||
## Groovy ##
|
||||
|
||||
# Gradle
|
||||
- (^|/)gradlew$
|
||||
- (^|/)gradlew\.bat$
|
||||
- (^|/)gradle/wrapper/
|
||||
|
||||
## .NET ##
|
||||
|
||||
# Visual Studio IntelliSense
|
||||
- -vsdoc\.js$
|
||||
- \.intellisense\.js$
|
||||
|
||||
# jQuery validation plugin (MS bundles this with asp.net mvc)
|
||||
- (^|/)jquery([^.]*)\.validate(\.unobtrusive)?(\.min)?\.js$
|
||||
@@ -124,7 +148,7 @@
|
||||
- (^|/)[Mm]icrosoft([Mm]vc)?([Aa]jax|[Vv]alidation)(\.debug)?\.js$
|
||||
|
||||
# NuGet
|
||||
- ^[Pp]ackages/
|
||||
- ^[Pp]ackages\/.+\.\d+\/
|
||||
|
||||
# ExtJS
|
||||
- (^|/)extjs/.*?\.js$
|
||||
@@ -144,6 +168,9 @@
|
||||
- (^|/)extjs/src/
|
||||
- (^|/)extjs/welcome/
|
||||
|
||||
# Html5shiv
|
||||
- (^|/)html5shiv(\.min)?\.js$
|
||||
|
||||
# Samples folders
|
||||
- ^[Ss]amples/
|
||||
|
||||
@@ -169,3 +196,11 @@
|
||||
|
||||
# .DS_Store's
|
||||
- .[Dd][Ss]_[Ss]tore$
|
||||
|
||||
# Mercury --use-subdirs
|
||||
- Mercury/
|
||||
|
||||
# R packages
|
||||
- ^vignettes/
|
||||
- ^inst/extdata/
|
||||
|
||||
|
||||
3
lib/linguist/version.rb
Normal file
3
lib/linguist/version.rb
Normal file
@@ -0,0 +1,3 @@
|
||||
module Linguist
|
||||
VERSION = "2.12.0"
|
||||
end
|
||||
110
samples/ATS/CoYonedaLemma.dats
Normal file
110
samples/ATS/CoYonedaLemma.dats
Normal file
@@ -0,0 +1,110 @@
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// HX-2014-01
|
||||
// CoYoneda Lemma:
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
#include
|
||||
"share/atspre_staload.hats"
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
staload
|
||||
"libats/ML/SATS/basis.sats"
|
||||
staload
|
||||
"libats/ML/SATS/list0.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
staload _ = "libats/ML/DATS/list0.dats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
sortdef ftype = type -> type
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
infixr (->) ->>
|
||||
typedef ->> (a:type, b:type) = a -<cloref1> b
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
typedef
|
||||
functor(F:ftype) =
|
||||
{a,b:type} (a ->> b) ->> F(a) ->> F(b)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
typedef
|
||||
list0 (a:type) = list0 (a)
|
||||
extern
|
||||
val functor_list0 : functor (list0)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
functor_list0{a,b}
|
||||
(f) = lam xs => list0_map<a><b> (xs, f)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
datatype
|
||||
CoYoneda
|
||||
(F:ftype, r:type) = {a:type} CoYoneda of (a ->> r, F(a))
|
||||
// end of [CoYoneda]
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
extern
|
||||
fun CoYoneda_phi
|
||||
: {F:ftype}functor(F) -> {r:type} (F (r) ->> CoYoneda (F, r))
|
||||
extern
|
||||
fun CoYoneda_psi
|
||||
: {F:ftype}functor(F) -> {r:type} (CoYoneda (F, r) ->> F (r))
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
CoYoneda_phi(ftor) = lam (fx) => CoYoneda (lam x => x, fx)
|
||||
implement
|
||||
CoYoneda_psi(ftor) = lam (CoYoneda(f, fx)) => ftor (f) (fx)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
datatype int0 = I of (int)
|
||||
datatype bool = True | False // boxed boolean
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
fun bool2string
|
||||
(x:bool): string =
|
||||
(
|
||||
case+ x of True() => "True" | False() => "False"
|
||||
)
|
||||
//
|
||||
implement
|
||||
fprint_val<bool> (out, x) = fprint (out, bool2string(x))
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
fun int2bool (i: int0): bool =
|
||||
let val+I(i) = i in if i > 0 then True else False end
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
val myintlist0 = g0ofg1($list{int0}((I)1, (I)0, (I)1, (I)0, (I)0))
|
||||
val myboolist0 = CoYoneda{list0,bool}{int0}(lam (i) => int2bool(i), myintlist0)
|
||||
val myboolist0 = CoYoneda_psi{list0}(functor_list0){bool}(myboolist0)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
val ((*void*)) = fprintln! (stdout_ref, "myboolist0 = ", myboolist0)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement main0 () = ()
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
(* end of [CoYonedaLemma.dats] *)
|
||||
178
samples/ATS/DiningPhil2.dats
Normal file
178
samples/ATS/DiningPhil2.dats
Normal file
@@ -0,0 +1,178 @@
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// HX-2013-11
|
||||
//
|
||||
// Implementing a variant of
|
||||
// the problem of Dining Philosophers
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
#include
|
||||
"share/atspre_define.hats"
|
||||
#include
|
||||
"share/atspre_staload.hats"
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
staload
|
||||
UN = "prelude/SATS/unsafe.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
staload "libc/SATS/stdlib.sats"
|
||||
staload "libc/SATS/unistd.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
staload "{$LIBATSHWXI}/teaching/mythread/SATS/channel.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
staload _ = "libats/DATS/deqarray.dats"
|
||||
staload _ = "{$LIBATSHWXI}/teaching/mythread/DATS/channel.dats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
staload "./DiningPhil2.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement phil_left (n) = n
|
||||
implement phil_right (n) = (n+1) \nmod NPHIL
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
extern
|
||||
fun randsleep (n: intGte(1)): void
|
||||
//
|
||||
implement
|
||||
randsleep (n) =
|
||||
ignoret (sleep($UN.cast{uInt}(rand() mod n + 1)))
|
||||
// end of [randsleep]
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
phil_think (n) =
|
||||
{
|
||||
val () = println! ("phil_think(", n, ") starts")
|
||||
val () = randsleep (6)
|
||||
val () = println! ("phil_think(", n, ") finishes")
|
||||
}
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
phil_dine (n, lf, rf) =
|
||||
{
|
||||
val () = println! ("phil_dine(", n, ") starts")
|
||||
val () = randsleep (3)
|
||||
val () = println! ("phil_dine(", n, ") finishes")
|
||||
}
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
phil_loop (n) = let
|
||||
//
|
||||
val () = phil_think (n)
|
||||
//
|
||||
val nl = phil_left (n)
|
||||
val nr = phil_right (n)
|
||||
//
|
||||
val ch_lfork = fork_changet (nl)
|
||||
val ch_rfork = fork_changet (nr)
|
||||
//
|
||||
val lf = channel_takeout (ch_lfork)
|
||||
val () = println! ("phil_loop(", n, ") picks left fork")
|
||||
//
|
||||
val () = randsleep (2) // HX: try to actively induce deadlock
|
||||
//
|
||||
val rf = channel_takeout (ch_rfork)
|
||||
val () = println! ("phil_loop(", n, ") picks right fork")
|
||||
//
|
||||
val () = phil_dine (n, lf, rf)
|
||||
//
|
||||
val ch_forktray = forktray_changet ()
|
||||
val () = channel_insert (ch_forktray, lf)
|
||||
val () = channel_insert (ch_forktray, rf)
|
||||
//
|
||||
in
|
||||
phil_loop (n)
|
||||
end // end of [phil_loop]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
cleaner_wash (f) =
|
||||
{
|
||||
val f = fork_get_num (f)
|
||||
val () = println! ("cleaner_wash(", f, ") starts")
|
||||
val () = randsleep (1)
|
||||
val () = println! ("cleaner_wash(", f, ") finishes")
|
||||
}
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
cleaner_return (f) =
|
||||
{
|
||||
val n = fork_get_num (f)
|
||||
val ch = fork_changet (n)
|
||||
val () = channel_insert (ch, f)
|
||||
}
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
cleaner_loop () = let
|
||||
//
|
||||
val ch = forktray_changet ()
|
||||
val f0 = channel_takeout (ch)
|
||||
//
|
||||
val () = cleaner_wash (f0)
|
||||
val () = cleaner_return (f0)
|
||||
//
|
||||
in
|
||||
cleaner_loop ()
|
||||
end // end of [cleaner_loop]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
dynload "DiningPhil2.sats"
|
||||
dynload "DiningPhil2_fork.dats"
|
||||
dynload "DiningPhil2_thread.dats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
local
|
||||
//
|
||||
staload
|
||||
"{$LIBATSHWXI}/teaching/mythread/SATS/mythread.sats"
|
||||
//
|
||||
in (* in of [local] *)
|
||||
//
|
||||
val () = mythread_create_cloptr (llam () => phil_loop (0))
|
||||
val () = mythread_create_cloptr (llam () => phil_loop (1))
|
||||
val () = mythread_create_cloptr (llam () => phil_loop (2))
|
||||
val () = mythread_create_cloptr (llam () => phil_loop (3))
|
||||
val () = mythread_create_cloptr (llam () => phil_loop (4))
|
||||
//
|
||||
val () = mythread_create_cloptr (llam () => cleaner_loop ())
|
||||
//
|
||||
end // end of [local]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
main0 () =
|
||||
{
|
||||
//
|
||||
val () = println! ("DiningPhil2: starting")
|
||||
val ((*void*)) = while (true) ignoret (sleep(1))
|
||||
//
|
||||
} (* end of [main0] *)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
(* end of [DiningPhil2.dats] *)
|
||||
71
samples/ATS/DiningPhil2.sats
Normal file
71
samples/ATS/DiningPhil2.sats
Normal file
@@ -0,0 +1,71 @@
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// HX-2013-11
|
||||
//
|
||||
// Implementing a variant of
|
||||
// the problem of Dining Philosophers
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
#include
|
||||
"share/atspre_define.hats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
staload "{$LIBATSHWXI}/teaching/mythread/SATS/channel.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
%{#
|
||||
#define NPHIL 5
|
||||
%} // end of [%{#]
|
||||
#define NPHIL 5
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
typedef nphil = natLt(NPHIL)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun phil_left (n: nphil): nphil
|
||||
fun phil_right (n: nphil): nphil
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
fun phil_loop (n: nphil): void
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
fun cleaner_loop ((*void*)): void
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
absvtype fork_vtype = ptr
|
||||
vtypedef fork = fork_vtype
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun fork_get_num (!fork): nphil
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun phil_dine
|
||||
(n: nphil, lf: !fork, rf: !fork): void
|
||||
// end of [phil_dine]
|
||||
|
||||
fun phil_think (n: nphil): void
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun cleaner_wash (f: !fork): void
|
||||
fun cleaner_return (f: fork): void
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
fun fork_changet (n: nphil): channel(fork)
|
||||
//
|
||||
fun forktray_changet ((*void*)): channel(fork)
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
(* end of [DiningPhil2.sats] *)
|
||||
89
samples/ATS/DiningPhil2_fork.dats
Normal file
89
samples/ATS/DiningPhil2_fork.dats
Normal file
@@ -0,0 +1,89 @@
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// HX-2013-11
|
||||
//
|
||||
// Implementing a variant of
|
||||
// the problem of Dining Philosophers
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
#include
|
||||
"share/atspre_define.hats"
|
||||
#include
|
||||
"share/atspre_staload.hats"
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
staload
|
||||
UN = "prelude/SATS/unsafe.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
staload "{$LIBATSHWXI}/teaching/mythread/SATS/channel.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
staload _ = "libats/DATS/deqarray.dats"
|
||||
staload _ = "{$LIBATSHWXI}/teaching/mythread/DATS/channel.dats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
staload "./DiningPhil2.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
datavtype fork = FORK of (nphil)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
assume fork_vtype = fork
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
fork_get_num (f) = let val FORK(n) = f in n end
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
local
|
||||
|
||||
val
|
||||
the_forkarray = let
|
||||
//
|
||||
typedef t = channel(fork)
|
||||
//
|
||||
implement
|
||||
array_tabulate$fopr<t>
|
||||
(n) = ch where
|
||||
{
|
||||
val n = $UN.cast{nphil}(n)
|
||||
val ch = channel_create_exn<fork> (i2sz(2))
|
||||
val () = channel_insert (ch, FORK (n))
|
||||
}
|
||||
//
|
||||
in
|
||||
arrayref_tabulate<t> (i2sz(NPHIL))
|
||||
end // end of [val]
|
||||
|
||||
in (* in of [local] *)
|
||||
|
||||
implement fork_changet (n) = the_forkarray[n]
|
||||
|
||||
end // end of [local]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
local
|
||||
|
||||
val the_forktray =
|
||||
channel_create_exn<fork> (i2sz(NPHIL+1))
|
||||
|
||||
in (* in of [local] *)
|
||||
|
||||
implement forktray_changet () = the_forktray
|
||||
|
||||
end // end of [local]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
(* end of [DiningPhil2_fork.dats] *)
|
||||
43
samples/ATS/DiningPhil2_thread.dats
Normal file
43
samples/ATS/DiningPhil2_thread.dats
Normal file
@@ -0,0 +1,43 @@
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// HX-2013-11
|
||||
//
|
||||
// Implementing a variant of
|
||||
// the problem of Dining Philosophers
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
#include "share/atspre_define.hats"
|
||||
#include "share/atspre_staload.hats"
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
staload "{$LIBATSHWXI}/teaching/mythread/SATS/mythread.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
local
|
||||
//
|
||||
#include "{$LIBATSHWXI}/teaching/mythread/DATS/mythread.dats"
|
||||
//
|
||||
in (* in of [local] *)
|
||||
//
|
||||
// HX: it is intentionally left to be empty
|
||||
//
|
||||
end // end of [local]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
local
|
||||
//
|
||||
#include "{$LIBATSHWXI}/teaching/mythread/DATS/mythread_posix.dats"
|
||||
//
|
||||
in (* in of [local] *)
|
||||
//
|
||||
// HX: it is intentionally left to be empty
|
||||
//
|
||||
end // end of [local]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
(* end of [DiningPhil2_thread.dats] *)
|
||||
178
samples/ATS/YonedaLemma.dats
Normal file
178
samples/ATS/YonedaLemma.dats
Normal file
@@ -0,0 +1,178 @@
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// HX-2014-01
|
||||
// Yoneda Lemma:
|
||||
// The hardest "trivial" theorem :)
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
#include
|
||||
"share/atspre_staload.hats"
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
staload
|
||||
"libats/ML/SATS/basis.sats"
|
||||
staload
|
||||
"libats/ML/SATS/list0.sats"
|
||||
staload
|
||||
"libats/ML/SATS/option0.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
staload _ = "libats/ML/DATS/list0.dats"
|
||||
staload _ = "libats/ML/DATS/option0.dats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
sortdef ftype = type -> type
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
infixr (->) ->>
|
||||
typedef ->> (a:type, b:type) = a -<cloref1> b
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
typedef
|
||||
functor(F:ftype) =
|
||||
{a,b:type} (a ->> b) ->> F(a) ->> F(b)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
typedef
|
||||
list0 (a:type) = list0 (a)
|
||||
extern
|
||||
val functor_list0 : functor (list0)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
functor_list0{a,b}
|
||||
(f) = lam xs => list0_map<a><b> (xs, f)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
typedef
|
||||
option0 (a:type) = option0 (a)
|
||||
extern
|
||||
val functor_option0 : functor (option0)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
functor_option0{a,b}
|
||||
(f) = lam opt => option0_map<a><b> (opt, f)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
extern
|
||||
val functor_homres
|
||||
: {c:type} functor (lam(r:type) => c ->> r)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
functor_homres{c}{a,b} (f) = lam (r) => lam (x) => f (r(x))
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
extern
|
||||
fun Yoneda_phi : {F:ftype}functor(F) ->
|
||||
{a:type}F(a) ->> ({r:type}(a ->> r) ->> F(r))
|
||||
extern
|
||||
fun Yoneda_psi : {F:ftype}functor(F) ->
|
||||
{a:type}({r:type}(a ->> r) ->> F(r)) ->> F(a)
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
implement
|
||||
Yoneda_phi
|
||||
(ftor) = lam(fx) => lam (m) => ftor(m)(fx)
|
||||
//
|
||||
implement
|
||||
Yoneda_psi (ftor) = lam(mf) => mf(lam x => x)
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
(*
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// HX-2014-01-05:
|
||||
// Another version based on Natural Transformation
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
typedef
|
||||
natrans(F:ftype, G:ftype) = {x:type} (F(x) ->> G(x))
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
extern
|
||||
fun Yoneda_phi_nat : {F:ftype}functor(F) ->
|
||||
{a:type} F(a) ->> natrans(lam (r:type) => (a ->> r), F)
|
||||
extern
|
||||
fun Yoneda_psi_nat : {F:ftype}functor(F) ->
|
||||
{a:type} natrans(lam (r:type) => (a ->> r), F) ->> F(a)
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
implement
|
||||
Yoneda_phi_nat
|
||||
(ftor) = lam(fx) => lam (m) => ftor(m)(fx)
|
||||
//
|
||||
implement
|
||||
Yoneda_psi_nat (ftor) = lam(mf) => mf(lam x => x)
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
*)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
datatype bool = True | False // boxed boolean
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
fun bool2string
|
||||
(x:bool): string =
|
||||
(
|
||||
case+ x of True() => "True" | False() => "False"
|
||||
)
|
||||
//
|
||||
implement
|
||||
fprint_val<bool> (out, x) = fprint (out, bool2string(x))
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
val myboolist0 =
|
||||
$list_t{bool}(True, False, True, False, False)
|
||||
val myboolist0 = g0ofg1_list (myboolist0)
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
extern
|
||||
val Yoneda_bool_list0 : {r:type} (bool ->> r) ->> list0(r)
|
||||
//
|
||||
implement
|
||||
Yoneda_bool_list0 =
|
||||
Yoneda_phi(functor_list0){bool}(myboolist0)
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
val myboolist1 =
|
||||
Yoneda_psi(functor_list0){bool}(Yoneda_bool_list0)
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
val () = fprintln! (stdout_ref, "myboolist0 = ", myboolist0)
|
||||
val () = fprintln! (stdout_ref, "myboolist1 = ", myboolist1)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement main0 () = ()
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
(* end of [YonedaLemma.dats] *)
|
||||
187
samples/ATS/linset.hats
Normal file
187
samples/ATS/linset.hats
Normal file
@@ -0,0 +1,187 @@
|
||||
(***********************************************************************)
|
||||
(* *)
|
||||
(* Applied Type System *)
|
||||
(* *)
|
||||
(***********************************************************************)
|
||||
|
||||
(*
|
||||
** ATS/Postiats - Unleashing the Potential of Types!
|
||||
** Copyright (C) 2011-2013 Hongwei Xi, ATS Trustful Software, Inc.
|
||||
** All rights reserved
|
||||
**
|
||||
** ATS is free software; you can redistribute it and/or modify it under
|
||||
** the terms of the GNU GENERAL PUBLIC LICENSE (GPL) as published by the
|
||||
** Free Software Foundation; either version 3, or (at your option) any
|
||||
** later version.
|
||||
**
|
||||
** ATS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
** WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
** for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with ATS; see the file COPYING. If not, please write to the
|
||||
** Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
** 02110-1301, USA.
|
||||
*)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
(* Author: Hongwei Xi *)
|
||||
(* Authoremail: hwxi AT cs DOT bu DOT edu *)
|
||||
(* Start time: December, 2012 *)
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// HX: shared by linset_listord (* ordered list *)
|
||||
// HX: shared by linset_avltree (* AVL-tree-based *)
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// HX-2013-02:
|
||||
// for sets of nonlinear elements
|
||||
//
|
||||
absvtype set_vtype (a:t@ype+) = ptr
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
vtypedef set (a:t0p) = set_vtype (a)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun{a:t0p}
|
||||
compare_elt_elt (x1: a, x2: a):<> int
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun{} linset_nil{a:t0p} ():<> set(a)
|
||||
fun{} linset_make_nil{a:t0p} ():<> set(a)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun{a:t0p} linset_sing (x: a):<!wrt> set(a)
|
||||
fun{a:t0p} linset_make_sing (x: a):<!wrt> set(a)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun{a:t0p}
|
||||
linset_make_list (xs: List(INV(a))):<!wrt> set(a)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun{}
|
||||
linset_is_nil {a:t0p} (xs: !set(INV(a))):<> bool
|
||||
fun{}
|
||||
linset_isnot_nil {a:t0p} (xs: !set(INV(a))):<> bool
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun{a:t0p} linset_size (!set(INV(a))): size_t
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun{a:t0p}
|
||||
linset_is_member (xs: !set(INV(a)), x0: a):<> bool
|
||||
fun{a:t0p}
|
||||
linset_isnot_member (xs: !set(INV(a)), x0: a):<> bool
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun{a:t0p}
|
||||
linset_copy (!set(INV(a))):<!wrt> set(a)
|
||||
fun{a:t0p}
|
||||
linset_free (xs: set(INV(a))):<!wrt> void
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
fun{a:t0p}
|
||||
linset_insert
|
||||
(xs: &set(INV(a)) >> _, x0: a):<!wrt> bool
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
fun{a:t0p}
|
||||
linset_takeout
|
||||
(
|
||||
&set(INV(a)) >> _, a, res: &(a?) >> opt(a, b)
|
||||
) :<!wrt> #[b:bool] bool(b) // endfun
|
||||
fun{a:t0p}
|
||||
linset_takeout_opt (&set(INV(a)) >> _, a):<!wrt> Option_vt(a)
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
fun{a:t0p}
|
||||
linset_remove
|
||||
(xs: &set(INV(a)) >> _, x0: a):<!wrt> bool
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// HX: choosing an element in an unspecified manner
|
||||
//
|
||||
fun{a:t0p}
|
||||
linset_choose
|
||||
(
|
||||
xs: !set(INV(a)), x: &a? >> opt (a, b)
|
||||
) :<!wrt> #[b:bool] bool(b)
|
||||
//
|
||||
fun{a:t0p}
|
||||
linset_choose_opt (xs: !set(INV(a))):<!wrt> Option_vt(a)
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
fun{a:t0p}
|
||||
linset_takeoutmax
|
||||
(
|
||||
xs: &set(INV(a)) >> _, res: &a? >> opt(a, b)
|
||||
) :<!wrt> #[b:bool] bool (b)
|
||||
fun{a:t0p}
|
||||
linset_takeoutmax_opt (xs: &set(INV(a)) >> _):<!wrt> Option_vt(a)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun{a:t0p}
|
||||
linset_takeoutmin
|
||||
(
|
||||
xs: &set(INV(a)) >> _, res: &a? >> opt(a, b)
|
||||
) :<!wrt> #[b:bool] bool (b)
|
||||
fun{a:t0p}
|
||||
linset_takeoutmin_opt (xs: &set(INV(a)) >> _):<!wrt> Option_vt(a)
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
fun{}
|
||||
fprint_linset$sep (FILEref): void // ", "
|
||||
//
|
||||
fun{a:t0p}
|
||||
fprint_linset (out: FILEref, xs: !set(INV(a))): void
|
||||
//
|
||||
overload fprint with fprint_linset
|
||||
//
|
||||
(* ****** ****** *)
|
||||
//
|
||||
fun{
|
||||
a:t0p}{env:vt0p
|
||||
} linset_foreach$fwork
|
||||
(x: a, env: &(env) >> _): void
|
||||
//
|
||||
fun{a:t0p}
|
||||
linset_foreach (set: !set(INV(a))): void
|
||||
fun{
|
||||
a:t0p}{env:vt0p
|
||||
} linset_foreach_env
|
||||
(set: !set(INV(a)), env: &(env) >> _): void
|
||||
// end of [linset_foreach_env]
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
fun{a:t0p}
|
||||
linset_listize (xs: set(INV(a))): List0_vt (a)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
fun{a:t0p}
|
||||
linset_listize1 (xs: !set(INV(a))): List0_vt (a)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
(* end of [linset.hats] *)
|
||||
504
samples/ATS/linset_listord.dats
Normal file
504
samples/ATS/linset_listord.dats
Normal file
@@ -0,0 +1,504 @@
|
||||
(***********************************************************************)
|
||||
(* *)
|
||||
(* Applied Type System *)
|
||||
(* *)
|
||||
(***********************************************************************)
|
||||
|
||||
(*
|
||||
** ATS/Postiats - Unleashing the Potential of Types!
|
||||
** Copyright (C) 2011-2013 Hongwei Xi, ATS Trustful Software, Inc.
|
||||
** All rights reserved
|
||||
**
|
||||
** ATS is free software; you can redistribute it and/or modify it under
|
||||
** the terms of the GNU GENERAL PUBLIC LICENSE (GPL) as published by the
|
||||
** Free Software Foundation; either version 3, or (at your option) any
|
||||
** later version.
|
||||
**
|
||||
** ATS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
** WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
** for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with ATS; see the file COPYING. If not, please write to the
|
||||
** Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
** 02110-1301, USA.
|
||||
*)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
(* Author: Hongwei Xi *)
|
||||
(* Authoremail: hwxi AT cs DOT bu DOT edu *)
|
||||
(* Start time: February, 2013 *)
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// HX-2013-08:
|
||||
// a set is represented as a sorted list in descending order;
|
||||
// note that descending order is chosen to faciliate set comparison
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
staload
|
||||
UN = "prelude/SATS/unsafe.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
staload "libats/SATS/linset_listord.sats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
#include "./SHARE/linset.hats" // code reuse
|
||||
#include "./SHARE/linset_node.hats" // code reuse
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
assume
|
||||
set_vtype (elt:t@ype) = List0_vt (elt)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement{}
|
||||
linset_nil () = list_vt_nil ()
|
||||
implement{}
|
||||
linset_make_nil () = list_vt_nil ()
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
{a}(*tmp*)
|
||||
linset_sing
|
||||
(x) = list_vt_cons{a}(x, list_vt_nil)
|
||||
// end of [linset_sing]
|
||||
implement{a}
|
||||
linset_make_sing
|
||||
(x) = list_vt_cons{a}(x, list_vt_nil)
|
||||
// end of [linset_make_sing]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement{}
|
||||
linset_is_nil (xs) = list_vt_is_nil (xs)
|
||||
implement{}
|
||||
linset_isnot_nil (xs) = list_vt_is_cons (xs)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement{a}
|
||||
linset_size (xs) =
|
||||
let val n = list_vt_length(xs) in i2sz(n) end
|
||||
// end of [linset_size]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement{a}
|
||||
linset_is_member
|
||||
(xs, x0) = let
|
||||
//
|
||||
fun aux
|
||||
{n:nat} .<n>.
|
||||
(
|
||||
xs: !list_vt (a, n)
|
||||
) :<> bool = let
|
||||
in
|
||||
//
|
||||
case+ xs of
|
||||
| list_vt_cons (x, xs) => let
|
||||
val sgn = compare_elt_elt<a> (x0, x) in
|
||||
if sgn > 0 then false else (if sgn < 0 then aux (xs) else true)
|
||||
end // end of [list_vt_cons]
|
||||
| list_vt_nil ((*void*)) => false
|
||||
//
|
||||
end // end of [aux]
|
||||
//
|
||||
in
|
||||
aux (xs)
|
||||
end // end of [linset_is_member]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement{a}
|
||||
linset_copy (xs) = list_vt_copy<a> (xs)
|
||||
implement{a}
|
||||
linset_free (xs) = list_vt_free<a> (xs)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement{a}
|
||||
linset_insert
|
||||
(xs, x0) = let
|
||||
//
|
||||
fun
|
||||
mynode_cons
|
||||
{n:nat} .<>.
|
||||
(
|
||||
nx: mynode1 (a), xs: list_vt (a, n)
|
||||
) : list_vt (a, n+1) = let
|
||||
//
|
||||
val xs1 =
|
||||
$UN.castvwtp0{List1_vt(a)}(nx)
|
||||
val+@list_vt_cons (_, xs2) = xs1
|
||||
prval () = $UN.cast2void (xs2); val () = (xs2 := xs)
|
||||
//
|
||||
in
|
||||
fold@ (xs1); xs1
|
||||
end // end of [mynode_cons]
|
||||
//
|
||||
fun ins
|
||||
{n:nat} .<n>. // tail-recursive
|
||||
(
|
||||
xs: &list_vt (a, n) >> list_vt (a, n1)
|
||||
) : #[n1:nat | n <= n1; n1 <= n+1] bool =
|
||||
(
|
||||
case+ xs of
|
||||
| @list_vt_cons
|
||||
(x, xs1) => let
|
||||
val sgn =
|
||||
compare_elt_elt<a> (x0, x)
|
||||
// end of [val]
|
||||
in
|
||||
if sgn > 0 then let
|
||||
prval () = fold@ (xs)
|
||||
val nx = mynode_make_elt<a> (x0)
|
||||
val ((*void*)) = xs := mynode_cons (nx, xs)
|
||||
in
|
||||
false
|
||||
end else if sgn < 0 then let
|
||||
val ans = ins (xs1)
|
||||
prval () = fold@ (xs)
|
||||
in
|
||||
ans
|
||||
end else let // [x0] is found
|
||||
prval () = fold@ (xs)
|
||||
in
|
||||
true (* [x0] in [xs] *)
|
||||
end (* end of [if] *)
|
||||
end // end of [list_vt_cons]
|
||||
| list_vt_nil () => let
|
||||
val nx = mynode_make_elt<a> (x0)
|
||||
val ((*void*)) = xs := mynode_cons (nx, xs)
|
||||
in
|
||||
false
|
||||
end // end of [list_vt_nil]
|
||||
) (* end of [ins] *)
|
||||
//
|
||||
in
|
||||
$effmask_all (ins (xs))
|
||||
end // end of [linset_insert]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
(*
|
||||
//
|
||||
HX-2013-08:
|
||||
[linset_remove] moved up
|
||||
//
|
||||
implement{a}
|
||||
linset_remove
|
||||
(xs, x0) = let
|
||||
//
|
||||
fun rem
|
||||
{n:nat} .<n>. // tail-recursive
|
||||
(
|
||||
xs: &list_vt (a, n) >> list_vt (a, n1)
|
||||
) : #[n1:nat | n1 <= n; n <= n1+1] bool =
|
||||
(
|
||||
case+ xs of
|
||||
| @list_vt_cons
|
||||
(x, xs1) => let
|
||||
val sgn =
|
||||
compare_elt_elt<a> (x0, x)
|
||||
// end of [val]
|
||||
in
|
||||
if sgn > 0 then let
|
||||
prval () = fold@ (xs)
|
||||
in
|
||||
false
|
||||
end else if sgn < 0 then let
|
||||
val ans = rem (xs1)
|
||||
prval () = fold@ (xs)
|
||||
in
|
||||
ans
|
||||
end else let // x0 = x
|
||||
val xs1_ = xs1
|
||||
val ((*void*)) = free@{a}{0}(xs)
|
||||
val () = xs := xs1_
|
||||
in
|
||||
true // [x0] in [xs]
|
||||
end (* end of [if] *)
|
||||
end // end of [list_vt_cons]
|
||||
| list_vt_nil () => false
|
||||
) (* end of [rem] *)
|
||||
//
|
||||
in
|
||||
$effmask_all (rem (xs))
|
||||
end // end of [linset_remove]
|
||||
*)
|
||||
|
||||
(* ****** ****** *)
|
||||
(*
|
||||
** By Brandon Barker
|
||||
*)
|
||||
implement
|
||||
{a}(*tmp*)
|
||||
linset_choose
|
||||
(xs, x0) = let
|
||||
in
|
||||
//
|
||||
case+ xs of
|
||||
| list_vt_cons
|
||||
(x, xs1) => let
|
||||
val () = x0 := x
|
||||
prval () = opt_some{a}(x0)
|
||||
in
|
||||
true
|
||||
end // end of [list_vt_cons]
|
||||
| list_vt_nil () => let
|
||||
prval () = opt_none{a}(x0)
|
||||
in
|
||||
false
|
||||
end // end of [list_vt_nil]
|
||||
//
|
||||
end // end of [linset_choose]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
{a}{env}
|
||||
linset_foreach_env (xs, env) = let
|
||||
//
|
||||
implement
|
||||
list_vt_foreach$fwork<a><env>
|
||||
(x, env) = linset_foreach$fwork<a><env> (x, env)
|
||||
//
|
||||
in
|
||||
list_vt_foreach_env<a><env> (xs, env)
|
||||
end // end of [linset_foreach_env]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement{a}
|
||||
linset_listize (xs) = xs
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement{a}
|
||||
linset_listize1 (xs) = list_vt_copy (xs)
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// HX: functions for processing mynodes
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
implement{
|
||||
} mynode_null{a} () =
|
||||
$UN.castvwtp0{mynode(a,null)}(the_null_ptr)
|
||||
// end of [mynode_null]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
{a}(*tmp*)
|
||||
mynode_make_elt
|
||||
(x) = let
|
||||
//
|
||||
val nx = list_vt_cons{a}{0}(x, _ )
|
||||
//
|
||||
in
|
||||
$UN.castvwtp0{mynode1(a)}(nx)
|
||||
end // end of [mynode_make_elt]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement{
|
||||
} mynode_free
|
||||
{a}(nx) = () where {
|
||||
val nx =
|
||||
$UN.castvwtp0{List1_vt(a)}(nx)
|
||||
//
|
||||
val+~list_vt_cons (_, nx2) = nx
|
||||
//
|
||||
prval ((*void*)) = $UN.cast2void (nx2)
|
||||
//
|
||||
} (* end of [mynode_free] *)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
{a}(*tmp*)
|
||||
mynode_get_elt
|
||||
(nx) = (x) where {
|
||||
//
|
||||
val nx1 =
|
||||
$UN.castvwtp1{List1_vt(a)}(nx)
|
||||
//
|
||||
val+list_vt_cons (x, _) = nx1
|
||||
//
|
||||
prval ((*void*)) = $UN.cast2void (nx1)
|
||||
//
|
||||
} (* end of [mynode_get_elt] *)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
{a}(*tmp*)
|
||||
mynode_set_elt
|
||||
{l} (nx, x0) =
|
||||
{
|
||||
//
|
||||
val nx1 =
|
||||
$UN.castvwtp1{List1_vt(a)}(nx)
|
||||
//
|
||||
val+@list_vt_cons (x, _) = nx1
|
||||
//
|
||||
val () = x := x0
|
||||
//
|
||||
prval () = fold@ (nx1)
|
||||
prval () = $UN.cast2void (nx1)
|
||||
//
|
||||
prval () = __assert (nx) where
|
||||
{
|
||||
extern praxi __assert (nx: !mynode(a?, l) >> mynode (a, l)): void
|
||||
} (* end of [prval] *)
|
||||
//
|
||||
} (* end of [mynode_set_elt] *)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
{a}(*tmp*)
|
||||
mynode_getfree_elt
|
||||
(nx) = (x) where {
|
||||
//
|
||||
val nx =
|
||||
$UN.castvwtp0{List1_vt(a)}(nx)
|
||||
//
|
||||
val+~list_vt_cons (x, nx2) = nx
|
||||
//
|
||||
prval ((*void*)) = $UN.cast2void (nx2)
|
||||
//
|
||||
} (* end of [mynode_getfree_elt] *)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
(*
|
||||
fun{a:t0p}
|
||||
linset_takeout_ngc
|
||||
(set: &set(INV(a)) >> _, x0: a):<!wrt> mynode0 (a)
|
||||
// end of [linset_takeout_ngc]
|
||||
*)
|
||||
implement
|
||||
{a}(*tmp*)
|
||||
linset_takeout_ngc
|
||||
(set, x0) = let
|
||||
//
|
||||
fun takeout
|
||||
(
|
||||
xs: &List0_vt (a) >> _
|
||||
) : mynode0(a) = let
|
||||
in
|
||||
//
|
||||
case+ xs of
|
||||
| @list_vt_cons
|
||||
(x, xs1) => let
|
||||
prval pf_x = view@x
|
||||
prval pf_xs1 = view@xs1
|
||||
val sgn =
|
||||
compare_elt_elt<a> (x0, x)
|
||||
// end of [val]
|
||||
in
|
||||
if sgn > 0 then let
|
||||
prval () = fold@ (xs)
|
||||
in
|
||||
mynode_null{a}((*void*))
|
||||
end else if sgn < 0 then let
|
||||
val res = takeout (xs1)
|
||||
prval ((*void*)) = fold@ (xs)
|
||||
in
|
||||
res
|
||||
end else let // x0 = x
|
||||
val xs1_ = xs1
|
||||
val res = $UN.castvwtp0{mynode1(a)}((pf_x, pf_xs1 | xs))
|
||||
val () = xs := xs1_
|
||||
in
|
||||
res // [x0] in [xs]
|
||||
end (* end of [if] *)
|
||||
end // end of [list_vt_cons]
|
||||
| list_vt_nil () => mynode_null{a}((*void*))
|
||||
//
|
||||
end (* end of [takeout] *)
|
||||
//
|
||||
in
|
||||
$effmask_all (takeout (set))
|
||||
end // end of [linset_takeout_ngc]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
{a}(*tmp*)
|
||||
linset_takeoutmax_ngc
|
||||
(xs) = let
|
||||
in
|
||||
//
|
||||
case+ xs of
|
||||
| @list_vt_cons
|
||||
(x, xs1) => let
|
||||
prval pf_x = view@x
|
||||
prval pf_xs1 = view@xs1
|
||||
val xs_ = xs
|
||||
val () = xs := xs1
|
||||
in
|
||||
$UN.castvwtp0{mynode1(a)}((pf_x, pf_xs1 | xs_))
|
||||
end // end of [list_vt_cons]
|
||||
| @list_vt_nil () => let
|
||||
prval () = fold@ (xs)
|
||||
in
|
||||
mynode_null{a}((*void*))
|
||||
end // end of [list_vt_nil]
|
||||
//
|
||||
end // end of [linset_takeoutmax_ngc]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
implement
|
||||
{a}(*tmp*)
|
||||
linset_takeoutmin_ngc
|
||||
(xs) = let
|
||||
//
|
||||
fun unsnoc
|
||||
{n:pos} .<n>.
|
||||
(
|
||||
xs: &list_vt (a, n) >> list_vt (a, n-1)
|
||||
) :<!wrt> mynode1 (a) = let
|
||||
//
|
||||
val+@list_vt_cons (x, xs1) = xs
|
||||
//
|
||||
prval pf_x = view@x and pf_xs1 = view@xs1
|
||||
//
|
||||
in
|
||||
//
|
||||
case+ xs1 of
|
||||
| list_vt_cons _ =>
|
||||
let val res = unsnoc(xs1) in fold@xs; res end
|
||||
// end of [list_vt_cons]
|
||||
| list_vt_nil () => let
|
||||
val xs_ = xs
|
||||
val () = xs := list_vt_nil{a}()
|
||||
in
|
||||
$UN.castvwtp0{mynode1(a)}((pf_x, pf_xs1 | xs_))
|
||||
end // end of [list_vt_nil]
|
||||
//
|
||||
end // end of [unsnoc]
|
||||
//
|
||||
in
|
||||
//
|
||||
case+ xs of
|
||||
| list_vt_cons _ => unsnoc (xs)
|
||||
| list_vt_nil () => mynode_null{a}((*void*))
|
||||
//
|
||||
end // end of [linset_takeoutmin_ngc]
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
(* end of [linset_listord.dats] *)
|
||||
51
samples/ATS/linset_listord.sats
Normal file
51
samples/ATS/linset_listord.sats
Normal file
@@ -0,0 +1,51 @@
|
||||
(***********************************************************************)
|
||||
(* *)
|
||||
(* Applied Type System *)
|
||||
(* *)
|
||||
(***********************************************************************)
|
||||
|
||||
(*
|
||||
** ATS/Postiats - Unleashing the Potential of Types!
|
||||
** Copyright (C) 2011-2013 Hongwei Xi, ATS Trustful Software, Inc.
|
||||
** All rights reserved
|
||||
**
|
||||
** ATS is free software; you can redistribute it and/or modify it under
|
||||
** the terms of the GNU GENERAL PUBLIC LICENSE (GPL) as published by the
|
||||
** Free Software Foundation; either version 3, or (at your option) any
|
||||
** later version.
|
||||
**
|
||||
** ATS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
** WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
** for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with ATS; see the file COPYING. If not, please write to the
|
||||
** Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
** 02110-1301, USA.
|
||||
*)
|
||||
|
||||
(* ****** ****** *)
|
||||
//
|
||||
// Author: Hongwei Xi
|
||||
// Authoremail: hwxiATcsDOTbuDOTedu
|
||||
// Time: October, 2010
|
||||
//
|
||||
(* ****** ****** *)
|
||||
|
||||
#define ATS_PACKNAME "ATSLIB.libats.linset_listord"
|
||||
#define ATS_STALOADFLAG 0 // no static loading at run-time
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
#include "./SHARE/linset.hats"
|
||||
#include "./SHARE/linset_node.hats"
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
castfn
|
||||
linset2list {a:t0p} (xs: set (INV(a))):<> List0_vt (a)
|
||||
|
||||
(* ****** ****** *)
|
||||
|
||||
(* end of [linset_listord.sats] *)
|
||||
215
samples/ATS/main.atxt
Normal file
215
samples/ATS/main.atxt
Normal file
@@ -0,0 +1,215 @@
|
||||
%{
|
||||
#include "./../ATEXT/atextfun.hats"
|
||||
%}
|
||||
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
|
||||
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=UTF-8" />
|
||||
<title>EFFECTIVATS-DiningPhil2</title>
|
||||
#patscode_style()
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<h1>
|
||||
Effective ATS: Dining Philosophers
|
||||
</h1>
|
||||
|
||||
In this article, I present an implementation of a slight variant of the
|
||||
famous problem of 5-Dining-Philosophers by Dijkstra that makes simple but
|
||||
convincing use of linear types.
|
||||
|
||||
<h2>
|
||||
The Original Problem
|
||||
</h2>
|
||||
|
||||
There are five philosophers sitting around a table and there are also 5
|
||||
forks placed on the table such that each fork is located between the left
|
||||
hand of a philosopher and the right hand of another philosopher. Each
|
||||
philosopher does the following routine repeatedly: thinking and dining. In
|
||||
order to dine, a philosopher needs to first acquire two forks: one located
|
||||
on his left-hand side and the other on his right-hand side. After
|
||||
finishing dining, a philosopher puts the two acquired forks onto the table:
|
||||
one on his left-hand side and the other on his right-hand side.
|
||||
|
||||
<h2>
|
||||
A Variant of the Original Problem
|
||||
</h2>
|
||||
|
||||
The following twist is added to the original version:
|
||||
|
||||
<p>
|
||||
|
||||
After a fork is used, it becomes a "dirty" fork and needs to be put in a
|
||||
tray for dirty forks. There is a cleaner who cleans dirty forks and then
|
||||
puts them back on the table.
|
||||
|
||||
<h2>
|
||||
Channels for Communication
|
||||
</h2>
|
||||
|
||||
A channel is just a shared queue of fixed capacity. The following two
|
||||
functions are for inserting an element into and taking an element out of a
|
||||
given channel:
|
||||
|
||||
<pre
|
||||
class="patsyntax">
|
||||
#pats2xhtml_sats("\
|
||||
fun{a:vt0p} channel_insert (channel (a), a): void
|
||||
fun{a:vt0p} channel_takeout (chan: channel (a)): (a)
|
||||
")</pre>
|
||||
|
||||
If [channel_insert] is called on a channel that is full, then the caller is
|
||||
blocked until an element is taken out of the channel. If [channel_takeout]
|
||||
is called on a channel that is empty, then the caller is blocked until an
|
||||
element is inserted into the channel.
|
||||
|
||||
<h2>
|
||||
A Channel for Each Fork
|
||||
</h2>
|
||||
|
||||
Forks are resources given a linear type. Each fork is initially stored in a
|
||||
channel, which can be obtained by calling the following function:
|
||||
|
||||
<pre
|
||||
class="patsyntax">
|
||||
#pats2xhtml_sats("\
|
||||
fun fork_changet (n: nphil): channel(fork)
|
||||
")</pre>
|
||||
|
||||
where the type [nphil] is defined to be [natLt(5)] (for natural numbers
|
||||
less than 5). The channels for storing forks are chosen to be of capacity
|
||||
2. The reason that channels of capacity 2 are chosen to store at most one
|
||||
element (in each of them) is to guarantee that these channels can never be
|
||||
full (so that there is no attempt made to send signals to awake callers
|
||||
supposedly being blocked due to channels being full).
|
||||
|
||||
|
||||
<h2>
|
||||
A Channel for the Fork Tray
|
||||
</h2>
|
||||
|
||||
A tray for storing "dirty" forks is also a channel, which can be obtained
|
||||
by calling the following function:
|
||||
|
||||
<pre
|
||||
class="patsyntax">
|
||||
#pats2xhtml_sats("\
|
||||
fun forktray_changet ((*void*)): channel(fork)
|
||||
")</pre>
|
||||
|
||||
The capacity chosen for the channel is 6 (instead of 5) so that it can
|
||||
never become full (as there are only 5 forks in total).
|
||||
|
||||
<h2>
|
||||
Philosopher Loop
|
||||
</h2>
|
||||
|
||||
Each philosopher is implemented as a loop:
|
||||
|
||||
<pre
|
||||
class="patsyntax">
|
||||
#pats2xhtml_dats('\
|
||||
implement
|
||||
phil_loop (n) = let
|
||||
//
|
||||
val () = phil_think (n)
|
||||
//
|
||||
val nl = phil_left (n) // = n
|
||||
val nr = phil_right (n) // = (n+1) % 5
|
||||
//
|
||||
val ch_lfork = fork_changet (nl)
|
||||
val ch_rfork = fork_changet (nr)
|
||||
//
|
||||
val lf = channel_takeout (ch_lfork)
|
||||
val () = println! ("phil_loop(", n, ") picks left fork")
|
||||
//
|
||||
val () = randsleep (2) // sleep up to 2 seconds
|
||||
//
|
||||
val rf = channel_takeout (ch_rfork)
|
||||
val () = println! ("phil_loop(", n, ") picks right fork")
|
||||
//
|
||||
val () = phil_dine (n, lf, rf)
|
||||
//
|
||||
val ch_forktray = forktray_changet ()
|
||||
val () = channel_insert (ch_forktray, lf) // left fork to dirty tray
|
||||
val () = channel_insert (ch_forktray, rf) // right fork to dirty tray
|
||||
//
|
||||
in
|
||||
phil_loop (n)
|
||||
end // end of [phil_loop]
|
||||
')</pre>
|
||||
|
||||
It should be straighforward to follow the code for [phil_loop].
|
||||
|
||||
<h2>
|
||||
Fork Cleaner Loop
|
||||
</h2>
|
||||
|
||||
A cleaner is implemented as a loop:
|
||||
|
||||
<pre
|
||||
class="patsyntax">
|
||||
#pats2xhtml_dats('\
|
||||
implement
|
||||
cleaner_loop () = let
|
||||
//
|
||||
val ch = forktray_changet ()
|
||||
val f0 = channel_takeout (ch) // [f0] is dirty
|
||||
//
|
||||
val () = cleaner_wash (f0) // washes dirty [f0]
|
||||
val () = cleaner_return (f0) // puts back cleaned [f0]
|
||||
//
|
||||
in
|
||||
cleaner_loop ()
|
||||
end // end of [cleaner_loop]
|
||||
')</pre>
|
||||
|
||||
The function [cleaner_return] first finds out the number of a given fork
|
||||
and then uses the number to locate the channel for storing the fork. Its
|
||||
actual implementation is given as follows:
|
||||
|
||||
<pre
|
||||
class="patsyntax">
|
||||
#pats2xhtml_dats('\
|
||||
implement
|
||||
cleaner_return (f) =
|
||||
{
|
||||
val n = fork_get_num (f)
|
||||
val ch = fork_changet (n)
|
||||
val () = channel_insert (ch, f)
|
||||
}
|
||||
')</pre>
|
||||
|
||||
It should now be straighforward to follow the code for [cleaner_loop].
|
||||
|
||||
<h2>
|
||||
Testing
|
||||
</h2>
|
||||
|
||||
The entire code of this implementation is stored in the following files:
|
||||
|
||||
<pre>
|
||||
DiningPhil2.sats
|
||||
DiningPhil2.dats
|
||||
DiningPhil2_fork.dats
|
||||
DiningPhil2_thread.dats
|
||||
</pre>
|
||||
|
||||
There is also a Makefile available for compiling the ATS source code into
|
||||
an excutable for testing. One should be able to encounter a deadlock after
|
||||
running the simulation for a while.
|
||||
|
||||
<hr size="2">
|
||||
|
||||
This article is written by <a href="http://www.cs.bu.edu/~hwxi/">Hongwei Xi</a>.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
%{
|
||||
implement main () = fprint_filsub (stdout_ref, "main_atxt.txt")
|
||||
%}
|
||||
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());
|
||||
}
|
||||
}
|
||||
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
|
||||
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
|
||||
56
samples/C/dynarray.cats
Normal file
56
samples/C/dynarray.cats
Normal file
@@ -0,0 +1,56 @@
|
||||
/* ******************************************************************* */
|
||||
/* */
|
||||
/* Applied Type System */
|
||||
/* */
|
||||
/* ******************************************************************* */
|
||||
|
||||
/*
|
||||
** ATS/Postiats - Unleashing the Potential of Types!
|
||||
** Copyright (C) 2011-20?? Hongwei Xi, ATS Trustful Software, Inc.
|
||||
** All rights reserved
|
||||
**
|
||||
** ATS is free software; you can redistribute it and/or modify it under
|
||||
** the terms of the GNU GENERAL PUBLIC LICENSE (GPL) as published by the
|
||||
** Free Software Foundation; either version 3, or (at your option) any
|
||||
** later version.
|
||||
**
|
||||
** ATS is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
** WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
** for more details.
|
||||
**
|
||||
** You should have received a copy of the GNU General Public License
|
||||
** along with ATS; see the file COPYING. If not, please write to the
|
||||
** Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
** 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/* ****** ****** */
|
||||
|
||||
/*
|
||||
(* Author: Hongwei Xi *)
|
||||
(* Authoremail: hwxi AT cs DOT bu DOT edu *)
|
||||
(* Start time: March, 2013 *)
|
||||
*/
|
||||
|
||||
/* ****** ****** */
|
||||
|
||||
#ifndef ATSHOME_LIBATS_DYNARRAY_CATS
|
||||
#define ATSHOME_LIBATS_DYNARRAY_CATS
|
||||
|
||||
/* ****** ****** */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/* ****** ****** */
|
||||
|
||||
#define atslib_dynarray_memcpy memcpy
|
||||
#define atslib_dynarray_memmove memmove
|
||||
|
||||
/* ****** ****** */
|
||||
|
||||
#endif // ifndef ATSHOME_LIBATS_DYNARRAY_CATS
|
||||
|
||||
/* ****** ****** */
|
||||
|
||||
/* end of [dynarray.cats] */
|
||||
47
samples/C/readline.cats
Normal file
47
samples/C/readline.cats
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
** API in ATS for GNU-readline
|
||||
*/
|
||||
|
||||
/* ****** ****** */
|
||||
|
||||
/*
|
||||
** Permission to use, copy, modify, and distribute this software for any
|
||||
** purpose with or without fee is hereby granted, provided that the above
|
||||
** copyright notice and this permission notice appear in all copies.
|
||||
**
|
||||
** THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
** WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
** MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
** ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
** WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
** ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
** OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/* ****** ****** */
|
||||
|
||||
#ifndef READLINE_READLINE_CATS
|
||||
#define READLINE_READLINE_CATS
|
||||
|
||||
/* ****** ****** */
|
||||
|
||||
#include <readline/readline.h>
|
||||
|
||||
/* ****** ****** */
|
||||
//
|
||||
#define \
|
||||
atscntrb_readline_rl_library_version() ((char*)rl_library_version)
|
||||
//
|
||||
#define atscntrb_readline_rl_readline_version() (rl_readline_version)
|
||||
//
|
||||
/* ****** ****** */
|
||||
|
||||
#define atscntrb_readline_readline readline
|
||||
|
||||
/* ****** ****** */
|
||||
|
||||
#endif // ifndef READLINE_READLINE_CATS
|
||||
|
||||
/* ****** ****** */
|
||||
|
||||
/* end of [readline.cats] */
|
||||
12
samples/Cirru/array.cirru
Normal file
12
samples/Cirru/array.cirru
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
print $ array
|
||||
int 1
|
||||
string 2
|
||||
|
||||
print $ array
|
||||
int 1
|
||||
array
|
||||
int 2
|
||||
string 3
|
||||
array
|
||||
string 4
|
||||
7
samples/Cirru/block.cirru
Normal file
7
samples/Cirru/block.cirru
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
set f $ block (a b c)
|
||||
print a b c
|
||||
|
||||
call f (int 1) (int 2) (int 3)
|
||||
|
||||
f (int 1) (int 2) (int 3)
|
||||
7
samples/Cirru/bool.cirru
Normal file
7
samples/Cirru/bool.cirru
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
print $ bool true
|
||||
print $ bool false
|
||||
print $ bool yes
|
||||
print $ bool no
|
||||
print $ bool 1
|
||||
print $ bool 0
|
||||
14
samples/Cirru/map.cirru
Normal file
14
samples/Cirru/map.cirru
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
print $ map
|
||||
a $ int 5
|
||||
b $ array (int 1) (int 2)
|
||||
c $ map
|
||||
int 1
|
||||
array (int 4)
|
||||
|
||||
set m $ map
|
||||
a $ int 1
|
||||
|
||||
set m b $ int 2
|
||||
|
||||
print m
|
||||
3
samples/Cirru/number.cirru
Normal file
3
samples/Cirru/number.cirru
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
print $ int 1
|
||||
print $ float 1.2
|
||||
2
samples/Cirru/require.cirru
Normal file
2
samples/Cirru/require.cirru
Normal file
@@ -0,0 +1,2 @@
|
||||
|
||||
require ./stdio.cr
|
||||
23
samples/Cirru/scope.cirru
Normal file
23
samples/Cirru/scope.cirru
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
set a (int 2)
|
||||
|
||||
print (self)
|
||||
|
||||
set c (child)
|
||||
|
||||
under c
|
||||
under parent
|
||||
print a
|
||||
|
||||
print $ get c a
|
||||
|
||||
set c x (int 3)
|
||||
print $ get c x
|
||||
|
||||
set just-print $ code
|
||||
print a
|
||||
|
||||
print just-print
|
||||
|
||||
eval (self) just-print
|
||||
eval just-print
|
||||
55
samples/Cirru/stdio.cirru
Normal file
55
samples/Cirru/stdio.cirru
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
set a $ string 1
|
||||
print a
|
||||
|
||||
print (string 1)
|
||||
|
||||
print nothing
|
||||
|
||||
print
|
||||
map
|
||||
a (int 4)
|
||||
b $ map
|
||||
a $ int 5
|
||||
b $ int 6
|
||||
c $ map
|
||||
int 7
|
||||
|
||||
print
|
||||
array
|
||||
int 1
|
||||
int 2
|
||||
array
|
||||
int 3
|
||||
int 4
|
||||
|
||||
print
|
||||
array
|
||||
int 1
|
||||
map
|
||||
a $ int 2
|
||||
b $ array
|
||||
int 3
|
||||
|
||||
print
|
||||
int 1
|
||||
int 2
|
||||
|
||||
print $ code
|
||||
set a 1
|
||||
print (get a)
|
||||
print $ array
|
||||
int a
|
||||
array
|
||||
int a
|
||||
|
||||
set container (map)
|
||||
set container code $ code
|
||||
set a 1
|
||||
print (get a)
|
||||
print $ array
|
||||
int a
|
||||
array
|
||||
int a
|
||||
|
||||
print container
|
||||
3
samples/Cirru/string.cirru
Normal file
3
samples/Cirru/string.cirru
Normal file
@@ -0,0 +1,3 @@
|
||||
|
||||
print $ string a
|
||||
print $ string "a b"
|
||||
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
|
||||
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
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
|
||||
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
|
||||
|
||||
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;
|
||||
}
|
||||
);
|
||||
48
samples/GLSL/recurse1.frag
Normal file
48
samples/GLSL/recurse1.frag
Normal file
@@ -0,0 +1,48 @@
|
||||
#version 330 core
|
||||
|
||||
// cross-unit recursion
|
||||
|
||||
void main() {}
|
||||
|
||||
// two-level recursion
|
||||
|
||||
float cbar(int);
|
||||
|
||||
void cfoo(float)
|
||||
{
|
||||
cbar(2);
|
||||
}
|
||||
|
||||
// four-level, out of order
|
||||
|
||||
void CB();
|
||||
void CD();
|
||||
void CA() { CB(); }
|
||||
void CC() { CD(); }
|
||||
|
||||
// high degree
|
||||
|
||||
void CBT();
|
||||
void CDT();
|
||||
void CAT() { CBT(); CBT(); CBT(); }
|
||||
void CCT() { CDT(); CDT(); CBT(); }
|
||||
|
||||
// not recursive
|
||||
|
||||
void norA() {}
|
||||
void norB() { norA(); }
|
||||
void norC() { norA(); }
|
||||
void norD() { norA(); }
|
||||
void norE() { norB(); }
|
||||
void norF() { norB(); }
|
||||
void norG() { norE(); }
|
||||
void norH() { norE(); }
|
||||
void norI() { norE(); }
|
||||
|
||||
// not recursive, but with a call leading into a cycle if ignoring direction
|
||||
|
||||
void norcA() { }
|
||||
void norcB() { norcA(); }
|
||||
void norcC() { norcB(); }
|
||||
void norcD() { norcC(); norcB(); } // head of cycle
|
||||
void norcE() { norcD(); } // lead into cycle
|
||||
642
samples/Game Maker Language/ClientBeginStep.gml
Normal file
642
samples/Game Maker Language/ClientBeginStep.gml
Normal file
@@ -0,0 +1,642 @@
|
||||
/*
|
||||
Originally from /Source/gg2/Scripts/Client/ClientBeginStep.gml in Gang Garrison 2
|
||||
|
||||
Copyright (C) 2008-2013 Faucet Software
|
||||
http://www.ganggarrison.com
|
||||
|
||||
This program is free software;
|
||||
you can redistribute it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License along with this program; if not,
|
||||
see <http://www.gnu.org/licenses>.
|
||||
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,
|
||||
the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries,
|
||||
the licensors of this Program grant you additional permission to convey the resulting work.
|
||||
*/
|
||||
|
||||
// receive and interpret the server's message(s)
|
||||
var i, playerObject, playerID, player, otherPlayerID, otherPlayer, sameVersion, buffer, plugins, pluginsRequired, usePlugins;
|
||||
|
||||
if(tcp_eof(global.serverSocket)) {
|
||||
if(gotServerHello)
|
||||
show_message("You have been disconnected from the server.");
|
||||
else
|
||||
show_message("Unable to connect to the server.");
|
||||
instance_destroy();
|
||||
exit;
|
||||
}
|
||||
|
||||
if(room == DownloadRoom and keyboard_check(vk_escape))
|
||||
{
|
||||
instance_destroy();
|
||||
exit;
|
||||
}
|
||||
|
||||
if(downloadingMap)
|
||||
{
|
||||
while(tcp_receive(global.serverSocket, min(1024, downloadMapBytes-buffer_size(downloadMapBuffer))))
|
||||
{
|
||||
write_buffer(downloadMapBuffer, global.serverSocket);
|
||||
if(buffer_size(downloadMapBuffer) == downloadMapBytes)
|
||||
{
|
||||
write_buffer_to_file(downloadMapBuffer, "Maps/" + downloadMapName + ".png");
|
||||
downloadingMap = false;
|
||||
buffer_destroy(downloadMapBuffer);
|
||||
downloadMapBuffer = -1;
|
||||
exit;
|
||||
}
|
||||
}
|
||||
exit;
|
||||
}
|
||||
|
||||
roomchange = false;
|
||||
do {
|
||||
if(tcp_receive(global.serverSocket,1)) {
|
||||
switch(read_ubyte(global.serverSocket)) {
|
||||
case HELLO:
|
||||
gotServerHello = true;
|
||||
global.joinedServerName = receivestring(global.serverSocket, 1);
|
||||
downloadMapName = receivestring(global.serverSocket, 1);
|
||||
advertisedMapMd5 = receivestring(global.serverSocket, 1);
|
||||
receiveCompleteMessage(global.serverSocket, 1, global.tempBuffer);
|
||||
pluginsRequired = read_ubyte(global.tempBuffer);
|
||||
plugins = receivestring(global.serverSocket, 1);
|
||||
if(string_pos("/", downloadMapName) != 0 or string_pos("\", downloadMapName) != 0)
|
||||
{
|
||||
show_message("Server sent illegal map name: "+downloadMapName);
|
||||
instance_destroy();
|
||||
exit;
|
||||
}
|
||||
|
||||
if (!noReloadPlugins && string_length(plugins))
|
||||
{
|
||||
usePlugins = pluginsRequired || !global.serverPluginsPrompt;
|
||||
if (global.serverPluginsPrompt)
|
||||
{
|
||||
var prompt;
|
||||
if (pluginsRequired)
|
||||
{
|
||||
prompt = show_question(
|
||||
"This server requires the following plugins to play on it: "
|
||||
+ string_replace_all(plugins, ",", "#")
|
||||
+ '#They are downloaded from the source: "'
|
||||
+ PLUGIN_SOURCE
|
||||
+ '"#The source states: "'
|
||||
+ PLUGIN_SOURCE_NOTICE
|
||||
+ '"#Do you wish to download them and continue connecting?'
|
||||
);
|
||||
if (!prompt)
|
||||
{
|
||||
instance_destroy();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
prompt = show_question(
|
||||
"This server suggests the following optional plugins to play on it: "
|
||||
+ string_replace_all(plugins, ",", "#")
|
||||
+ '#They are downloaded from the source: "'
|
||||
+ PLUGIN_SOURCE
|
||||
+ '"#The source states: "'
|
||||
+ PLUGIN_SOURCE_NOTICE
|
||||
+ '"#Do you wish to download them and use them?'
|
||||
);
|
||||
if (prompt)
|
||||
{
|
||||
usePlugins = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (usePlugins)
|
||||
{
|
||||
if (!loadserverplugins(plugins))
|
||||
{
|
||||
show_message("Error ocurred loading server-sent plugins.");
|
||||
instance_destroy();
|
||||
exit;
|
||||
}
|
||||
global.serverPluginsInUse = true;
|
||||
}
|
||||
}
|
||||
noReloadPlugins = false;
|
||||
|
||||
if(advertisedMapMd5 != "")
|
||||
{
|
||||
var download;
|
||||
download = not file_exists("Maps/" + downloadMapName + ".png");
|
||||
if(!download and CustomMapGetMapMD5(downloadMapName) != advertisedMapMd5)
|
||||
{
|
||||
if(show_question("The server's copy of the map (" + downloadMapName + ") differs from ours.#Would you like to download this server's version of the map?"))
|
||||
download = true;
|
||||
else
|
||||
{
|
||||
instance_destroy();
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
if(download)
|
||||
{
|
||||
write_ubyte(global.serverSocket, DOWNLOAD_MAP);
|
||||
socket_send(global.serverSocket);
|
||||
receiveCompleteMessage(global.serverSocket,4,global.tempBuffer);
|
||||
downloadMapBytes = read_uint(global.tempBuffer);
|
||||
downloadMapBuffer = buffer_create();
|
||||
downloadingMap = true;
|
||||
roomchange=true;
|
||||
}
|
||||
}
|
||||
ClientPlayerJoin(global.serverSocket);
|
||||
if(global.rewardKey != "" and global.rewardId != "")
|
||||
{
|
||||
var rewardId;
|
||||
rewardId = string_copy(global.rewardId, 0, 255);
|
||||
write_ubyte(global.serverSocket, REWARD_REQUEST);
|
||||
write_ubyte(global.serverSocket, string_length(rewardId));
|
||||
write_string(global.serverSocket, rewardId);
|
||||
}
|
||||
if(global.queueJumping == true)
|
||||
{
|
||||
write_ubyte(global.serverSocket, CLIENT_SETTINGS);
|
||||
write_ubyte(global.serverSocket, global.queueJumping);
|
||||
}
|
||||
socket_send(global.serverSocket);
|
||||
break;
|
||||
|
||||
case JOIN_UPDATE:
|
||||
receiveCompleteMessage(global.serverSocket,2,global.tempBuffer);
|
||||
global.playerID = read_ubyte(global.tempBuffer);
|
||||
global.currentMapArea = read_ubyte(global.tempBuffer);
|
||||
break;
|
||||
|
||||
case FULL_UPDATE:
|
||||
deserializeState(FULL_UPDATE);
|
||||
break;
|
||||
|
||||
case QUICK_UPDATE:
|
||||
deserializeState(QUICK_UPDATE);
|
||||
break;
|
||||
|
||||
case CAPS_UPDATE:
|
||||
deserializeState(CAPS_UPDATE);
|
||||
break;
|
||||
|
||||
case INPUTSTATE:
|
||||
deserializeState(INPUTSTATE);
|
||||
break;
|
||||
|
||||
case PLAYER_JOIN:
|
||||
player = instance_create(0,0,Player);
|
||||
player.name = receivestring(global.serverSocket, 1);
|
||||
|
||||
ds_list_add(global.players, player);
|
||||
if(ds_list_size(global.players)-1 == global.playerID) {
|
||||
global.myself = player;
|
||||
instance_create(0,0,PlayerControl);
|
||||
}
|
||||
break;
|
||||
|
||||
case PLAYER_LEAVE:
|
||||
// Delete player from the game, adjust own ID accordingly
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
playerID = read_ubyte(global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, playerID);
|
||||
removePlayer(player);
|
||||
if(playerID < global.playerID) {
|
||||
global.playerID -= 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case PLAYER_DEATH:
|
||||
var causeOfDeath, assistantPlayerID, assistantPlayer;
|
||||
receiveCompleteMessage(global.serverSocket,4,global.tempBuffer);
|
||||
playerID = read_ubyte(global.tempBuffer);
|
||||
otherPlayerID = read_ubyte(global.tempBuffer);
|
||||
assistantPlayerID = read_ubyte(global.tempBuffer);
|
||||
causeOfDeath = read_ubyte(global.tempBuffer);
|
||||
|
||||
player = ds_list_find_value(global.players, playerID);
|
||||
|
||||
otherPlayer = noone;
|
||||
if(otherPlayerID != 255)
|
||||
otherPlayer = ds_list_find_value(global.players, otherPlayerID);
|
||||
|
||||
assistantPlayer = noone;
|
||||
if(assistantPlayerID != 255)
|
||||
assistantPlayer = ds_list_find_value(global.players, assistantPlayerID);
|
||||
|
||||
doEventPlayerDeath(player, otherPlayer, assistantPlayer, causeOfDeath);
|
||||
break;
|
||||
|
||||
case BALANCE:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
balanceplayer=read_ubyte(global.tempBuffer);
|
||||
if balanceplayer == 255 {
|
||||
if !instance_exists(Balancer) instance_create(x,y,Balancer);
|
||||
with(Balancer) notice=0;
|
||||
} else {
|
||||
player = ds_list_find_value(global.players, balanceplayer);
|
||||
if(player.object != -1) {
|
||||
with(player.object) {
|
||||
instance_destroy();
|
||||
}
|
||||
player.object = -1;
|
||||
}
|
||||
if(player.team==TEAM_RED) {
|
||||
player.team = TEAM_BLUE;
|
||||
} else {
|
||||
player.team = TEAM_RED;
|
||||
}
|
||||
if !instance_exists(Balancer) instance_create(x,y,Balancer);
|
||||
Balancer.name=player.name;
|
||||
with (Balancer) notice=1;
|
||||
}
|
||||
break;
|
||||
|
||||
case PLAYER_CHANGETEAM:
|
||||
receiveCompleteMessage(global.serverSocket,2,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
if(player.object != -1) {
|
||||
with(player.object) {
|
||||
instance_destroy();
|
||||
}
|
||||
player.object = -1;
|
||||
}
|
||||
player.team = read_ubyte(global.tempBuffer);
|
||||
break;
|
||||
|
||||
case PLAYER_CHANGECLASS:
|
||||
receiveCompleteMessage(global.serverSocket,2,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
if(player.object != -1) {
|
||||
with(player.object) {
|
||||
instance_destroy();
|
||||
}
|
||||
player.object = -1;
|
||||
}
|
||||
player.class = read_ubyte(global.tempBuffer);
|
||||
break;
|
||||
|
||||
case PLAYER_CHANGENAME:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
player.name = receivestring(global.serverSocket, 1);
|
||||
if player=global.myself {
|
||||
global.playerName=player.name
|
||||
}
|
||||
break;
|
||||
|
||||
case PLAYER_SPAWN:
|
||||
receiveCompleteMessage(global.serverSocket,3,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
doEventSpawn(player, read_ubyte(global.tempBuffer), read_ubyte(global.tempBuffer));
|
||||
break;
|
||||
|
||||
case CHAT_BUBBLE:
|
||||
var bubbleImage;
|
||||
receiveCompleteMessage(global.serverSocket,2,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
setChatBubble(player, read_ubyte(global.tempBuffer));
|
||||
break;
|
||||
|
||||
case BUILD_SENTRY:
|
||||
receiveCompleteMessage(global.serverSocket,6,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
buildSentry(player, read_ushort(global.tempBuffer)/5, read_ushort(global.tempBuffer)/5, read_byte(global.tempBuffer));
|
||||
break;
|
||||
|
||||
case DESTROY_SENTRY:
|
||||
receiveCompleteMessage(global.serverSocket,4,global.tempBuffer);
|
||||
playerID = read_ubyte(global.tempBuffer);
|
||||
otherPlayerID = read_ubyte(global.tempBuffer);
|
||||
assistantPlayerID = read_ubyte(global.tempBuffer);
|
||||
causeOfDeath = read_ubyte(global.tempBuffer);
|
||||
|
||||
player = ds_list_find_value(global.players, playerID);
|
||||
if(otherPlayerID == 255) {
|
||||
doEventDestruction(player, noone, noone, causeOfDeath);
|
||||
} else {
|
||||
otherPlayer = ds_list_find_value(global.players, otherPlayerID);
|
||||
if (assistantPlayerID == 255) {
|
||||
doEventDestruction(player, otherPlayer, noone, causeOfDeath);
|
||||
} else {
|
||||
assistantPlayer = ds_list_find_value(global.players, assistantPlayerID);
|
||||
doEventDestruction(player, otherPlayer, assistantPlayer, causeOfDeath);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GRAB_INTEL:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
doEventGrabIntel(player);
|
||||
break;
|
||||
|
||||
case SCORE_INTEL:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
doEventScoreIntel(player);
|
||||
break;
|
||||
|
||||
case DROP_INTEL:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
doEventDropIntel(player);
|
||||
break;
|
||||
|
||||
case RETURN_INTEL:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
doEventReturnIntel(read_ubyte(global.tempBuffer));
|
||||
break;
|
||||
|
||||
case GENERATOR_DESTROY:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
team = read_ubyte(global.tempBuffer);
|
||||
doEventGeneratorDestroy(team);
|
||||
break;
|
||||
|
||||
case UBER_CHARGED:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
doEventUberReady(player);
|
||||
break;
|
||||
|
||||
case UBER:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
doEventUber(player);
|
||||
break;
|
||||
|
||||
case OMNOMNOMNOM:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
if(player.object != -1) {
|
||||
with(player.object) {
|
||||
omnomnomnom=true;
|
||||
if(hp < 200)
|
||||
{
|
||||
canEat = false;
|
||||
alarm[6] = eatCooldown; //10 second cooldown
|
||||
}
|
||||
if(player.team == TEAM_RED) {
|
||||
omnomnomnomindex=0;
|
||||
omnomnomnomend=31;
|
||||
} else if(player.team==TEAM_BLUE) {
|
||||
omnomnomnomindex=32;
|
||||
omnomnomnomend=63;
|
||||
}
|
||||
xscale=image_xscale;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TOGGLE_ZOOM:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
if player.object != -1 {
|
||||
toggleZoom(player.object);
|
||||
}
|
||||
break;
|
||||
|
||||
case PASSWORD_REQUEST:
|
||||
if(!usePreviousPwd)
|
||||
global.clientPassword = get_string("Enter Password:", "");
|
||||
write_ubyte(global.serverSocket, string_length(global.clientPassword));
|
||||
write_string(global.serverSocket, global.clientPassword);
|
||||
socket_send(global.serverSocket);
|
||||
break;
|
||||
|
||||
case PASSWORD_WRONG:
|
||||
show_message("Incorrect Password.");
|
||||
instance_destroy();
|
||||
exit;
|
||||
|
||||
case INCOMPATIBLE_PROTOCOL:
|
||||
show_message("Incompatible server protocol version.");
|
||||
instance_destroy();
|
||||
exit;
|
||||
|
||||
case KICK:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
reason = read_ubyte(global.tempBuffer);
|
||||
if reason == KICK_NAME kickReason = "Name Exploit";
|
||||
else if reason == KICK_BAD_PLUGIN_PACKET kickReason = "Invalid plugin packet ID";
|
||||
else if reason == KICK_MULTI_CLIENT kickReason = "There are too many connections from your IP";
|
||||
else kickReason = "";
|
||||
show_message("You have been kicked from the server. "+kickReason+".");
|
||||
instance_destroy();
|
||||
exit;
|
||||
|
||||
case ARENA_STARTROUND:
|
||||
doEventArenaStartRound();
|
||||
break;
|
||||
|
||||
case ARENA_ENDROUND:
|
||||
with ArenaHUD clientArenaEndRound();
|
||||
break;
|
||||
|
||||
case ARENA_RESTART:
|
||||
doEventArenaRestart();
|
||||
break;
|
||||
|
||||
case UNLOCKCP:
|
||||
doEventUnlockCP();
|
||||
break;
|
||||
|
||||
case MAP_END:
|
||||
global.nextMap=receivestring(global.serverSocket, 1);
|
||||
receiveCompleteMessage(global.serverSocket,2,global.tempBuffer);
|
||||
global.winners=read_ubyte(global.tempBuffer);
|
||||
global.currentMapArea=read_ubyte(global.tempBuffer);
|
||||
global.mapchanging = true;
|
||||
if !instance_exists(ScoreTableController) instance_create(0,0,ScoreTableController);
|
||||
instance_create(0,0,WinBanner);
|
||||
break;
|
||||
|
||||
case CHANGE_MAP:
|
||||
roomchange=true;
|
||||
global.mapchanging = false;
|
||||
global.currentMap = receivestring(global.serverSocket, 1);
|
||||
global.currentMapMD5 = receivestring(global.serverSocket, 1);
|
||||
if(global.currentMapMD5 == "") { // if this is an internal map (signified by the lack of an md5)
|
||||
if(findInternalMapRoom(global.currentMap))
|
||||
room_goto_fix(findInternalMapRoom(global.currentMap));
|
||||
else
|
||||
{
|
||||
show_message("Error:#Server went to invalid internal map: " + global.currentMap + "#Exiting.");
|
||||
instance_destroy();
|
||||
exit;
|
||||
}
|
||||
} else { // it's an external map
|
||||
if(string_pos("/", global.currentMap) != 0 or string_pos("\", global.currentMap) != 0)
|
||||
{
|
||||
show_message("Server sent illegal map name: "+global.currentMap);
|
||||
instance_destroy();
|
||||
exit;
|
||||
}
|
||||
if(!file_exists("Maps/" + global.currentMap + ".png") or CustomMapGetMapMD5(global.currentMap) != global.currentMapMD5)
|
||||
{ // Reconnect to the server to download the map
|
||||
var oldReturnRoom;
|
||||
oldReturnRoom = returnRoom;
|
||||
returnRoom = DownloadRoom;
|
||||
if (global.serverPluginsInUse)
|
||||
noUnloadPlugins = true;
|
||||
event_perform(ev_destroy,0);
|
||||
ClientCreate();
|
||||
if (global.serverPluginsInUse)
|
||||
noReloadPlugins = true;
|
||||
returnRoom = oldReturnRoom;
|
||||
usePreviousPwd = true;
|
||||
exit;
|
||||
}
|
||||
room_goto_fix(CustomMapRoom);
|
||||
}
|
||||
|
||||
for(i=0; i<ds_list_size(global.players); i+=1) {
|
||||
player = ds_list_find_value(global.players, i);
|
||||
if global.currentMapArea == 1 {
|
||||
player.stats[KILLS] = 0;
|
||||
player.stats[DEATHS] = 0;
|
||||
player.stats[CAPS] = 0;
|
||||
player.stats[ASSISTS] = 0;
|
||||
player.stats[DESTRUCTION] = 0;
|
||||
player.stats[STABS] = 0;
|
||||
player.stats[HEALING] = 0;
|
||||
player.stats[DEFENSES] = 0;
|
||||
player.stats[INVULNS] = 0;
|
||||
player.stats[BONUS] = 0;
|
||||
player.stats[DOMINATIONS] = 0;
|
||||
player.stats[REVENGE] = 0;
|
||||
player.stats[POINTS] = 0;
|
||||
player.roundStats[KILLS] = 0;
|
||||
player.roundStats[DEATHS] = 0;
|
||||
player.roundStats[CAPS] = 0;
|
||||
player.roundStats[ASSISTS] = 0;
|
||||
player.roundStats[DESTRUCTION] = 0;
|
||||
player.roundStats[STABS] = 0;
|
||||
player.roundStats[HEALING] = 0;
|
||||
player.roundStats[DEFENSES] = 0;
|
||||
player.roundStats[INVULNS] = 0;
|
||||
player.roundStats[BONUS] = 0;
|
||||
player.roundStats[DOMINATIONS] = 0;
|
||||
player.roundStats[REVENGE] = 0;
|
||||
player.roundStats[POINTS] = 0;
|
||||
player.team = TEAM_SPECTATOR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SERVER_FULL:
|
||||
show_message("The server is full.");
|
||||
instance_destroy();
|
||||
exit;
|
||||
|
||||
case REWARD_CHALLENGE_CODE:
|
||||
var challengeData;
|
||||
receiveCompleteMessage(global.serverSocket,16,global.tempBuffer);
|
||||
challengeData = read_binstring(global.tempBuffer, buffer_size(global.tempBuffer));
|
||||
challengeData += socket_remote_ip(global.serverSocket);
|
||||
|
||||
write_ubyte(global.serverSocket, REWARD_CHALLENGE_RESPONSE);
|
||||
write_binstring(global.serverSocket, hmac_md5_bin(global.rewardKey, challengeData));
|
||||
socket_send(global.serverSocket);
|
||||
break;
|
||||
|
||||
case REWARD_UPDATE:
|
||||
receiveCompleteMessage(global.serverSocket,1,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
var rewardString;
|
||||
rewardString = receivestring(global.serverSocket, 2);
|
||||
doEventUpdateRewards(player, rewardString);
|
||||
break;
|
||||
|
||||
case MESSAGE_STRING:
|
||||
var message, notice;
|
||||
message = receivestring(global.serverSocket, 1);
|
||||
with NoticeO instance_destroy();
|
||||
notice = instance_create(0, 0, NoticeO);
|
||||
notice.notice = NOTICE_CUSTOM;
|
||||
notice.message = message;
|
||||
break;
|
||||
|
||||
case SENTRY_POSITION:
|
||||
receiveCompleteMessage(global.serverSocket,5,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
if(player.sentry)
|
||||
{
|
||||
player.sentry.x = read_ushort(global.tempBuffer) / 5;
|
||||
player.sentry.y = read_ushort(global.tempBuffer) / 5;
|
||||
player.sentry.xprevious = player.sentry.x;
|
||||
player.sentry.yprevious = player.sentry.y;
|
||||
player.sentry.vspeed = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case WEAPON_FIRE:
|
||||
receiveCompleteMessage(global.serverSocket,9,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
|
||||
if(player.object)
|
||||
{
|
||||
with(player.object)
|
||||
{
|
||||
x = read_ushort(global.tempBuffer)/5;
|
||||
y = read_ushort(global.tempBuffer)/5;
|
||||
hspeed = read_byte(global.tempBuffer)/8.5;
|
||||
vspeed = read_byte(global.tempBuffer)/8.5;
|
||||
xprevious = x;
|
||||
yprevious = y;
|
||||
}
|
||||
|
||||
doEventFireWeapon(player, read_ushort(global.tempBuffer));
|
||||
}
|
||||
break;
|
||||
|
||||
case PLUGIN_PACKET:
|
||||
var packetID, packetLen, buf, success;
|
||||
|
||||
// fetch full packet
|
||||
receiveCompleteMessage(global.serverSocket, 2, global.tempBuffer);
|
||||
packetLen = read_ushort(global.tempBuffer);
|
||||
receiveCompleteMessage(global.serverSocket, packetLen, global.tempBuffer);
|
||||
|
||||
packetID = read_ubyte(global.tempBuffer);
|
||||
|
||||
// get packet data
|
||||
buf = buffer_create();
|
||||
write_buffer_part(buf, global.tempBuffer, packetLen - 1);
|
||||
|
||||
// try to enqueue
|
||||
// give "noone" value for client since received from server
|
||||
success = _PluginPacketPush(packetID, buf, noone);
|
||||
|
||||
// if it returned false, packetID was invalid
|
||||
if (!success)
|
||||
{
|
||||
// clear up buffer
|
||||
buffer_destroy(buf);
|
||||
show_error("ERROR when reading plugin packet: no such plugin packet ID " + string(packetID), true);
|
||||
}
|
||||
break;
|
||||
|
||||
case CLIENT_SETTINGS:
|
||||
receiveCompleteMessage(global.serverSocket,2,global.tempBuffer);
|
||||
player = ds_list_find_value(global.players, read_ubyte(global.tempBuffer));
|
||||
player.queueJump = read_ubyte(global.tempBuffer);
|
||||
break;
|
||||
|
||||
default:
|
||||
promptRestartOrQuit("The Server sent unexpected data.");
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} until(roomchange);
|
||||
141
samples/Game Maker Language/Create.gml
Normal file
141
samples/Game Maker Language/Create.gml
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
Originally from /Source/gg2/Objects/Updater.events/Create.xml in Gang Garrison 2
|
||||
|
||||
Copyright (C) 2008-2013 Faucet Software
|
||||
http://www.ganggarrison.com
|
||||
|
||||
This program is free software;
|
||||
you can redistribute it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License along with this program; if not,
|
||||
see <http://www.gnu.org/licenses>.
|
||||
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,
|
||||
the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries,
|
||||
the licensors of this Program grant you additional permission to convey the resulting work.
|
||||
*/
|
||||
// Downloading code.
|
||||
|
||||
var downloadHandle, url, tmpfile, window_oldshowborder, window_oldfullscreen;
|
||||
timeLeft = 0;
|
||||
counter = 0;
|
||||
AudioControlPlaySong(-1, false);
|
||||
window_oldshowborder = window_get_showborder();
|
||||
window_oldfullscreen = window_get_fullscreen();
|
||||
window_set_fullscreen(false);
|
||||
window_set_showborder(false);
|
||||
|
||||
if(global.updaterBetaChannel)
|
||||
url = UPDATE_SOURCE_BETA;
|
||||
else
|
||||
url = UPDATE_SOURCE;
|
||||
|
||||
tmpfile = temp_directory + "\gg2update.zip";
|
||||
|
||||
downloadHandle = httpGet(url, -1);
|
||||
|
||||
while(!httpRequestStatus(downloadHandle))
|
||||
{ // while download isn't finished
|
||||
sleep(floor(1000/30)); // sleep for the equivalent of one frame
|
||||
io_handle(); // this prevents GameMaker from appearing locked-up
|
||||
httpRequestStep(downloadHandle);
|
||||
|
||||
// check if the user cancelled the download with the esc key
|
||||
if(keyboard_check(vk_escape))
|
||||
{
|
||||
httpRequestDestroy(downloadHandle);
|
||||
window_set_showborder(window_oldshowborder);
|
||||
window_set_fullscreen(window_oldfullscreen);
|
||||
room_goto_fix(Menu);
|
||||
exit;
|
||||
}
|
||||
|
||||
if(counter == 0 || counter mod 60 == 0)
|
||||
timer = random(359)+1;
|
||||
draw_sprite(UpdaterBackgroundS,0,0,0);
|
||||
draw_set_color(c_white);
|
||||
draw_set_halign(fa_left);
|
||||
draw_set_valign(fa_center);
|
||||
minutes=floor(timer/60);
|
||||
seconds=floor(timer-minutes*60);
|
||||
draw_text(x,y-20,string(minutes) + " minutes " + string(seconds) + " seconds Remaining...");
|
||||
counter+=1;
|
||||
var progress, size;
|
||||
progress = httpRequestResponseBodyProgress(downloadHandle);
|
||||
size = httpRequestResponseBodySize(downloadHandle);
|
||||
if (size != -1)
|
||||
{
|
||||
progressBar = floor((progress/size) * 20);
|
||||
offset = 3;
|
||||
for(i=0;i<progressBar;i+=1){
|
||||
draw_sprite(UpdaterProgressS,0,x+offset,y);
|
||||
offset+=12;
|
||||
}
|
||||
}
|
||||
screen_refresh();
|
||||
}
|
||||
// Errored
|
||||
if (httpRequestStatus(downloadHandle) == 2)
|
||||
{
|
||||
show_message("Downloading update failed!#" + httpRequestError(downloadHandle));
|
||||
httpRequestDestroy(downloadHandle);
|
||||
window_set_showborder(window_oldshowborder);
|
||||
window_set_fullscreen(window_oldfullscreen);
|
||||
room_goto_fix(Menu);
|
||||
exit;
|
||||
}
|
||||
// Request failed
|
||||
if (httpRequestStatusCode(downloadHandle) != 200)
|
||||
{
|
||||
show_message("Downloading update failed!#" + string(httpRequestStatusCode(downloadHandle)) + " " + httpRequestReasonPhrase(downloadHandle));
|
||||
httpRequestDestroy(downloadHandle);
|
||||
window_set_showborder(window_oldshowborder);
|
||||
window_set_fullscreen(window_oldfullscreen);
|
||||
room_goto_fix(Menu);
|
||||
exit;
|
||||
}
|
||||
|
||||
write_buffer_to_file(httpRequestResponseBody(downloadHandle), tmpfile);
|
||||
httpRequestDestroy(downloadHandle);
|
||||
|
||||
if(!file_exists(tmpfile))
|
||||
{
|
||||
window_set_showborder(window_oldshowborder);
|
||||
window_set_fullscreen(window_oldfullscreen);
|
||||
show_message("Error updating: Missing gg2update.zip in temp directory, download failed(?)");
|
||||
room_goto_fix(Menu);
|
||||
exit;
|
||||
}
|
||||
|
||||
// rename existing "Gang Garrison 2.exe" to avoid conflict when extracting
|
||||
if (file_exists("Gang Garrison 2.exe"))
|
||||
{
|
||||
var newName, n;
|
||||
n = 1;
|
||||
|
||||
// increment until unused name found
|
||||
do
|
||||
{
|
||||
newName = "gg2-old.delete.me." + string(n);
|
||||
n += 1;
|
||||
}
|
||||
until(!file_exists(newName));
|
||||
|
||||
file_rename("Gang Garrison 2.exe", newName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// let's extract the downloaded file now.
|
||||
extractzip(tmpfile, working_directory);
|
||||
|
||||
// run new version
|
||||
execute_program("Gang Garrison 2.exe", "", false);
|
||||
|
||||
// exit
|
||||
game_end();
|
||||
161
samples/Game Maker Language/Draw.gml
Normal file
161
samples/Game Maker Language/Draw.gml
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
Originally from /Source/gg2/Objects/InGameElements/Character.events/Draw.xml in Gang Garrison 2
|
||||
|
||||
Copyright (C) 2008-2013 Faucet Software
|
||||
http://www.ganggarrison.com
|
||||
|
||||
This program is free software;
|
||||
you can redistribute it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License along with this program; if not,
|
||||
see <http://www.gnu.org/licenses>.
|
||||
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,
|
||||
the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries,
|
||||
the licensors of this Program grant you additional permission to convey the resulting work.
|
||||
*/
|
||||
|
||||
xoffset = view_xview[0];
|
||||
yoffset = view_yview[0];
|
||||
xsize = view_wview[0];
|
||||
ysize = view_hview[0];
|
||||
|
||||
if (distance_to_point(xoffset+xsize/2,yoffset+ysize/2) > 800)
|
||||
exit;
|
||||
|
||||
var xr, yr;
|
||||
xr = round(x);
|
||||
yr = round(y);
|
||||
|
||||
image_alpha = cloakAlpha;
|
||||
|
||||
if (global.myself.team == team and canCloak)
|
||||
image_alpha = cloakAlpha/2 + 0.5;
|
||||
|
||||
if (invisible)
|
||||
exit;
|
||||
|
||||
if(stabbing)
|
||||
image_alpha -= power(currentWeapon.stab.alpha, 2);
|
||||
|
||||
if team == global.myself.team && (player != global.myself || global.showHealthBar == 1){
|
||||
draw_set_alpha(1);
|
||||
draw_healthbar(xr-10, yr-30, xr+10, yr-25,hp*100/maxHp,c_black,c_red,c_green,0,true,true);
|
||||
}
|
||||
if(distance_to_point(mouse_x, mouse_y)<25) {
|
||||
if cloak && team!=global.myself.team exit;
|
||||
draw_set_alpha(1);
|
||||
draw_set_halign(fa_center);
|
||||
draw_set_valign(fa_bottom);
|
||||
if(team==TEAM_RED) {
|
||||
draw_set_color(c_red);
|
||||
} else {
|
||||
draw_set_color(c_blue);
|
||||
}
|
||||
draw_text(xr, yr-35, player.name);
|
||||
|
||||
if(team == global.myself.team && global.showTeammateStats)
|
||||
{
|
||||
if(weapons[0] == Medigun)
|
||||
draw_text(xr,yr+50, "Superburst: " + string(currentWeapon.uberCharge/20) + "%");
|
||||
else if(weapons[0] == Shotgun)
|
||||
draw_text(xr,yr+50, "Nuts 'N' Bolts: " + string(nutsNBolts));
|
||||
else if(weapons[0] == Minegun)
|
||||
draw_text(xr,yr+50, "Lobbed Mines: " + string(currentWeapon.lobbed));
|
||||
}
|
||||
}
|
||||
|
||||
draw_set_alpha(1);
|
||||
if team == TEAM_RED ubercolour = c_red;
|
||||
if team == TEAM_BLUE ubercolour = c_blue;
|
||||
|
||||
var sprite, overlaySprite;
|
||||
if zoomed
|
||||
{
|
||||
if (team == TEAM_RED)
|
||||
sprite = SniperCrouchRedS;
|
||||
else
|
||||
sprite = SniperCrouchBlueS;
|
||||
overlaySprite = sniperCrouchOverlay;
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite = sprite_index;
|
||||
overlaySprite = overlay;
|
||||
}
|
||||
|
||||
if (omnomnomnom)
|
||||
{
|
||||
draw_sprite_ext_overlay(omnomnomnomSprite,omnomnomnomOverlay,omnomnomnomindex,xr,yr,image_xscale,image_yscale,image_angle,c_white,1);
|
||||
if (ubered)
|
||||
draw_sprite_ext_overlay(omnomnomnomSprite,omnomnomnomOverlay,omnomnomnomindex,xr,yr,image_xscale,image_yscale,image_angle,ubercolour,0.7);
|
||||
}
|
||||
else if (taunting)
|
||||
{
|
||||
draw_sprite_ext_overlay(tauntsprite,tauntOverlay,tauntindex,xr,yr,image_xscale,image_yscale,image_angle,c_white,1);
|
||||
if (ubered)
|
||||
draw_sprite_ext_overlay(tauntsprite,tauntOverlay,tauntindex,xr,yr,image_xscale,image_yscale,image_angle,ubercolour,0.7);
|
||||
}
|
||||
else if (player.humiliated)
|
||||
draw_sprite_ext(humiliationPoses,floor(animationImage)+humiliationOffset,xr,yr,image_xscale,image_yscale,image_angle,c_white,image_alpha);
|
||||
else if (!taunting)
|
||||
{
|
||||
if (cloak)
|
||||
{
|
||||
if (!ubered)
|
||||
draw_sprite_ext(sprite,floor(animationImage+animationOffset),xr,yr,image_xscale,image_yscale,image_angle,c_white,image_alpha);
|
||||
else if (ubered)
|
||||
{
|
||||
draw_sprite_ext(sprite,floor(animationImage+animationOffset),xr,yr,image_xscale,image_yscale,image_angle,c_white,1);
|
||||
draw_sprite_ext(sprite,floor(animationImage+animationOffset),xr,yr,image_xscale,image_yscale,image_angle,ubercolour,0.7);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ubered)
|
||||
draw_sprite_ext_overlay(sprite,overlaySprite,floor(animationImage+animationOffset),xr,yr,image_xscale,image_yscale,image_angle,c_white,image_alpha);
|
||||
else if (ubered)
|
||||
{
|
||||
draw_sprite_ext_overlay(sprite,overlaySprite,floor(animationImage+animationOffset),xr,yr,image_xscale,image_yscale,image_angle,c_white,1);
|
||||
draw_sprite_ext_overlay(sprite,overlaySprite,floor(animationImage+animationOffset),xr,yr,image_xscale,image_yscale,image_angle,ubercolour,0.7);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (burnDuration > 0 or burnIntensity > 0) {
|
||||
for(i = 0; i < numFlames * burnIntensity / maxIntensity; i += 1)
|
||||
{
|
||||
draw_sprite_ext(FlameS, alarm[5] + i + random(2), x + flameArray_x[i], y + flameArray_y[i], 1, 1, 0, c_white, burnDuration / maxDuration * 0.71 + 0.35);
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from Lorgan's itemserver "angels" with slight modifications
|
||||
// All credit be upon him
|
||||
if (demon != -1)
|
||||
{
|
||||
demonX = median(x-40,demonX,x+40);
|
||||
demonY = median(y-40,demonY,y);
|
||||
demonOffset += demonDir;
|
||||
if (abs(demonOffset) > 15)
|
||||
demonDir *= -1;
|
||||
|
||||
var dir;
|
||||
if (demonX > x)
|
||||
dir = -1;
|
||||
else
|
||||
dir = 1;
|
||||
|
||||
if (demonFrame > sprite_get_number(demon))
|
||||
demonFrame = 0;
|
||||
|
||||
if (stabbing || ubered)
|
||||
draw_sprite_ext(demon,demonFrame+floor(animationImage)+7*player.team,demonX,demonY+demonOffset,dir*1,1,0,c_white,1);
|
||||
else
|
||||
draw_sprite_ext(demon,demonFrame+floor(animationImage)+7*player.team,demonX,demonY+demonOffset,dir*1,1,0,c_white,image_alpha);
|
||||
|
||||
demonFrame += 1;
|
||||
}
|
||||
80
samples/Game Maker Language/characterDrawEvent.gml
Normal file
80
samples/Game Maker Language/characterDrawEvent.gml
Normal file
@@ -0,0 +1,80 @@
|
||||
// Originally from /spelunky/Scripts/Platform Engine/characterDrawEvent.gml in the Spelunky Community Update Project
|
||||
|
||||
/**********************************************************************************
|
||||
Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC
|
||||
|
||||
This file is part of Spelunky.
|
||||
|
||||
You can redistribute and/or modify Spelunky, including its source code, under
|
||||
the terms of the Spelunky User License.
|
||||
|
||||
Spelunky is distributed in the hope that it will be entertaining and useful,
|
||||
but WITHOUT WARRANTY. Please see the Spelunky User License for more details.
|
||||
|
||||
The Spelunky User License should be available in "Game Information", which
|
||||
can be found in the Resource Explorer, or as an external file called COPYING.
|
||||
If not, please obtain a new copy of Spelunky from <http://spelunkyworld.com/>
|
||||
|
||||
***********************************************************************************/
|
||||
|
||||
/*
|
||||
This event should be placed in the draw event of the platform character.
|
||||
*/
|
||||
//draws the sprite
|
||||
draw = true;
|
||||
if (facing == RIGHT) image_xscale = -1;
|
||||
else image_xscale = 1;
|
||||
|
||||
if (blinkToggle != 1)
|
||||
{
|
||||
if ((state == CLIMBING or (sprite_index == sPExit or sprite_index == sDamselExit or sprite_index == sTunnelExit)) and global.hasJetpack and not whipping)
|
||||
{
|
||||
draw_sprite_ext(sprite_index, -1, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha);
|
||||
//draw_sprite(sprite_index,-1,x,y);
|
||||
draw_sprite(sJetpackBack,-1,x,y);
|
||||
draw = false;
|
||||
}
|
||||
else if (global.hasJetpack and facing == RIGHT) draw_sprite(sJetpackRight,-1,x-4,y-1);
|
||||
else if (global.hasJetpack) draw_sprite(sJetpackLeft,-1,x+4,y-1);
|
||||
if (draw)
|
||||
{
|
||||
if (redColor > 0) draw_sprite_ext(sprite_index, -1, x, y, image_xscale, image_yscale, image_angle, make_color_rgb(200 + redColor,0,0), image_alpha);
|
||||
else draw_sprite_ext(sprite_index, -1, x, y, image_xscale, image_yscale, image_angle, image_blend, image_alpha);
|
||||
}
|
||||
if (facing == RIGHT)
|
||||
{
|
||||
if (holdArrow == ARROW_NORM)
|
||||
{
|
||||
draw_sprite(sArrowRight, -1, x+4, y+1);
|
||||
}
|
||||
else if (holdArrow == ARROW_BOMB)
|
||||
{
|
||||
if (holdArrowToggle) draw_sprite(sBombArrowRight, 0, x+4, y+2);
|
||||
else draw_sprite(sBombArrowRight, 1, x+4, y+2);
|
||||
}
|
||||
}
|
||||
else if (facing == LEFT)
|
||||
{
|
||||
if (holdArrow == ARROW_NORM)
|
||||
{
|
||||
draw_sprite(sArrowLeft, -1, x-4, y+1);
|
||||
}
|
||||
else if (holdArrow == ARROW_BOMB)
|
||||
{
|
||||
if (holdArrowToggle) draw_sprite(sBombArrowLeft, 0, x-4, y+2);
|
||||
else draw_sprite(sBombArrowLeft, 1, x-4, y+2);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
if canRun
|
||||
{
|
||||
xOffset=80
|
||||
if player=1
|
||||
yOffset=120
|
||||
else
|
||||
yOffset=143
|
||||
//draw the "flySpeed" bar, which shows how much speed the character has acquired while holding the "run" button
|
||||
//draw_healthbar(view_xview[0]+224+xOffset,view_yview[0]+432+yOffset,view_xview[0]+400+xOffset,view_yview[0]+450+yOffset,flySpeed,make_color_rgb(0,64,128),c_blue,c_aqua,0,1,1)
|
||||
}
|
||||
*/
|
||||
1050
samples/Game Maker Language/characterStepEvent.gml
Normal file
1050
samples/Game Maker Language/characterStepEvent.gml
Normal file
File diff suppressed because it is too large
Load Diff
251
samples/Game Maker Language/doEventPlayerDeath.gml
Normal file
251
samples/Game Maker Language/doEventPlayerDeath.gml
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
Originally from /Source/gg2/Scripts/Events/doEventPlayerDeath.gml in Gang Garrison 2
|
||||
|
||||
Copyright (C) 2008-2013 Faucet Software
|
||||
http://www.ganggarrison.com
|
||||
|
||||
This program is free software;
|
||||
you can redistribute it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License along with this program; if not,
|
||||
see <http://www.gnu.org/licenses>.
|
||||
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,
|
||||
the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries,
|
||||
the licensors of this Program grant you additional permission to convey the resulting work.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Perform the "player death" event, i.e. change the appropriate scores,
|
||||
* destroy the character object to much splattering and so on.
|
||||
*
|
||||
* argument0: The player whose character died
|
||||
* argument1: The player who inflicted the fatal damage (or noone for unknown)
|
||||
* argument2: The player who assisted the kill (or noone for no assist)
|
||||
* argument3: The source of the fatal damage
|
||||
*/
|
||||
var victim, killer, assistant, damageSource;
|
||||
victim = argument0;
|
||||
killer = argument1;
|
||||
assistant = argument2;
|
||||
damageSource = argument3;
|
||||
|
||||
if(!instance_exists(killer))
|
||||
killer = noone;
|
||||
|
||||
if(!instance_exists(assistant))
|
||||
assistant = noone;
|
||||
|
||||
//*************************************
|
||||
//* Scoring and Kill log
|
||||
//*************************************
|
||||
|
||||
|
||||
recordKillInLog(victim, killer, assistant, damageSource);
|
||||
|
||||
victim.stats[DEATHS] += 1;
|
||||
if(killer)
|
||||
{
|
||||
if(damageSource == WEAPON_KNIFE || damageSource == WEAPON_BACKSTAB)
|
||||
{
|
||||
killer.stats[STABS] += 1;
|
||||
killer.roundStats[STABS] += 1;
|
||||
killer.stats[POINTS] += 1;
|
||||
killer.roundStats[POINTS] +=1;
|
||||
}
|
||||
|
||||
if (victim.object.currentWeapon.object_index == Medigun)
|
||||
{
|
||||
if (victim.object.currentWeapon.uberReady)
|
||||
{
|
||||
killer.stats[BONUS] += 1;
|
||||
killer.roundStats[BONUS] += 1;
|
||||
killer.stats[POINTS] += 1;
|
||||
killer.roundStats[POINTS] += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (killer != victim)
|
||||
{
|
||||
killer.stats[KILLS] += 1;
|
||||
killer.roundStats[KILLS] += 1;
|
||||
killer.stats[POINTS] += 1;
|
||||
killer.roundStats[POINTS] += 1;
|
||||
if(victim.object.intel)
|
||||
{
|
||||
killer.stats[DEFENSES] += 1;
|
||||
killer.roundStats[DEFENSES] += 1;
|
||||
killer.stats[POINTS] += 1;
|
||||
killer.roundStats[POINTS] += 1;
|
||||
recordEventInLog(4, killer.team, killer.name, global.myself == killer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (assistant)
|
||||
{
|
||||
assistant.stats[ASSISTS] += 1;
|
||||
assistant.roundStats[ASSISTS] += 1;
|
||||
assistant.stats[POINTS] += .5;
|
||||
assistant.roundStats[POINTS] += .5;
|
||||
}
|
||||
|
||||
//SPEC
|
||||
if (victim == global.myself)
|
||||
instance_create(victim.object.x, victim.object.y, Spectator);
|
||||
|
||||
//*************************************
|
||||
//* Gibbing
|
||||
//*************************************
|
||||
var xoffset, yoffset, xsize, ysize;
|
||||
|
||||
xoffset = view_xview[0];
|
||||
yoffset = view_yview[0];
|
||||
xsize = view_wview[0];
|
||||
ysize = view_hview[0];
|
||||
|
||||
randomize();
|
||||
with(victim.object) {
|
||||
if((damageSource == WEAPON_ROCKETLAUNCHER
|
||||
or damageSource == WEAPON_MINEGUN or damageSource == FRAG_BOX
|
||||
or damageSource == WEAPON_REFLECTED_STICKY or damageSource == WEAPON_REFLECTED_ROCKET
|
||||
or damageSource == FINISHED_OFF_GIB or damageSource == GENERATOR_EXPLOSION)
|
||||
and (player.class != CLASS_QUOTE) and (global.gibLevel>1)
|
||||
and distance_to_point(xoffset+xsize/2,yoffset+ysize/2) < 900) {
|
||||
if (hasReward(victim, 'PumpkinGibs'))
|
||||
{
|
||||
repeat(global.gibLevel * 2) {
|
||||
createGib(x,y,PumpkinGib,hspeed,vspeed,random(145)-72, choose(0,1,1,2,2,3), false, true)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
repeat(global.gibLevel) {
|
||||
createGib(x,y,Gib,hspeed,vspeed,random(145)-72, 0, false)
|
||||
}
|
||||
switch(player.team)
|
||||
{
|
||||
case TEAM_BLUE :
|
||||
repeat(global.gibLevel - 1) {
|
||||
createGib(x,y,BlueClump,hspeed,vspeed,random(145)-72, 0, false)
|
||||
}
|
||||
break;
|
||||
case TEAM_RED :
|
||||
repeat(global.gibLevel - 1) {
|
||||
createGib(x,y,RedClump,hspeed,vspeed,random(145)-72, 0, false)
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
repeat(global.gibLevel * 14) {
|
||||
var blood;
|
||||
blood = instance_create(x+random(23)-11,y+random(23)-11,BloodDrop);
|
||||
blood.hspeed=(random(21)-10);
|
||||
blood.vspeed=(random(21)-13);
|
||||
if (hasReward(victim, 'PumpkinGibs'))
|
||||
{
|
||||
blood.sprite_index = PumpkinJuiceS;
|
||||
}
|
||||
}
|
||||
if (!hasReward(victim, 'PumpkinGibs'))
|
||||
{
|
||||
//All Classes gib head, hands, and feet
|
||||
if(global.gibLevel > 2 || choose(0,1) == 1)
|
||||
createGib(x,y,Headgib,0,0,random(105)-52, player.class, false);
|
||||
repeat(global.gibLevel -1){
|
||||
//Medic has specially colored hands
|
||||
if (player.class == CLASS_MEDIC){
|
||||
if (player.team == TEAM_RED)
|
||||
createGib(x,y,Hand, hspeed, vspeed, random(105)-52 , 9, false);
|
||||
else
|
||||
createGib(x,y,Hand, hspeed, vspeed, random(105)-52 , 10, false);
|
||||
}else{
|
||||
createGib(x,y,Hand, hspeed, vspeed, random(105)-52 , player.class, false);
|
||||
}
|
||||
createGib(x,y,Feet,random(5)-2,random(3),random(13)-6 , player.class, true);
|
||||
}
|
||||
}
|
||||
|
||||
//Class specific gibs
|
||||
switch(player.class) {
|
||||
case CLASS_PYRO :
|
||||
if(global.gibLevel > 2 || choose(0,1) == 1)
|
||||
createGib(x,y,Accesory,hspeed,vspeed,random(105)-52, 4, false)
|
||||
break;
|
||||
case CLASS_SOLDIER :
|
||||
if(global.gibLevel > 2 || choose(0,1) == 1){
|
||||
switch(player.team) {
|
||||
case TEAM_BLUE :
|
||||
createGib(x,y,Accesory,hspeed,vspeed,random(105)-52, 2, false);
|
||||
break;
|
||||
case TEAM_RED :
|
||||
createGib(x,y,Accesory,hspeed,vspeed,random(105)-52, 1, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CLASS_ENGINEER :
|
||||
if(global.gibLevel > 2 || choose(0,1) == 1)
|
||||
createGib(x,y,Accesory,hspeed,vspeed,random(105)-52, 3, false)
|
||||
break;
|
||||
case CLASS_SNIPER :
|
||||
if(global.gibLevel > 2 || choose(0,1) == 1)
|
||||
createGib(x,y,Accesory,hspeed,vspeed,random(105)-52, 0, false)
|
||||
break;
|
||||
}
|
||||
playsound(x,y,Gibbing);
|
||||
} else {
|
||||
var deadbody;
|
||||
if player.class != CLASS_QUOTE playsound(x,y,choose(DeathSnd1, DeathSnd2));
|
||||
deadbody = instance_create(x,y-30,DeadGuy);
|
||||
// 'GS' reward - *G*olden *S*tatue
|
||||
if(hasReward(player, 'GS'))
|
||||
{
|
||||
deadbody.sprite_index = haxxyStatue;
|
||||
deadbody.image_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
deadbody.sprite_index = sprite_index;
|
||||
deadbody.image_index = CHARACTER_ANIMATION_DEAD;
|
||||
}
|
||||
deadbody.hspeed=hspeed;
|
||||
deadbody.vspeed=vspeed;
|
||||
if(hspeed>0) {
|
||||
deadbody.image_xscale = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (global.gg_birthday){
|
||||
myHat = instance_create(victim.object.x,victim.object.y,PartyHat);
|
||||
myHat.image_index = victim.team;
|
||||
}
|
||||
if (global.xmas){
|
||||
myHat = instance_create(victim.object.x,victim.object.y,XmasHat);
|
||||
myHat.image_index = victim.team;
|
||||
}
|
||||
|
||||
|
||||
with(victim.object) {
|
||||
instance_destroy();
|
||||
}
|
||||
|
||||
//*************************************
|
||||
//* Deathcam
|
||||
//*************************************
|
||||
if( global.killCam and victim == global.myself and killer and killer != victim and !(damageSource == KILL_BOX || damageSource == FRAG_BOX || damageSource == FINISHED_OFF || damageSource == FINISHED_OFF_GIB || damageSource == GENERATOR_EXPLOSION)) {
|
||||
instance_create(0,0,DeathCam);
|
||||
DeathCam.killedby=killer;
|
||||
DeathCam.name=killer.name;
|
||||
DeathCam.oldxview=view_xview[0];
|
||||
DeathCam.oldyview=view_yview[0];
|
||||
DeathCam.lastDamageSource=damageSource;
|
||||
DeathCam.team = global.myself.team;
|
||||
}
|
||||
1469
samples/Game Maker Language/faucet-http.gml
Normal file
1469
samples/Game Maker Language/faucet-http.gml
Normal file
File diff suppressed because it is too large
Load Diff
484
samples/Game Maker Language/game_init.gml
Normal file
484
samples/Game Maker Language/game_init.gml
Normal file
@@ -0,0 +1,484 @@
|
||||
/*
|
||||
Originally from /Source/gg2/Scripts/game_init.gml in Gang Garrison 2
|
||||
|
||||
Copyright (C) 2008-2013 Faucet Software
|
||||
http://www.ganggarrison.com
|
||||
|
||||
This program is free software;
|
||||
you can redistribute it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License along with this program; if not,
|
||||
see <http://www.gnu.org/licenses>.
|
||||
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,
|
||||
the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries,
|
||||
the licensors of this Program grant you additional permission to convey the resulting work.
|
||||
*/
|
||||
|
||||
// Returns true if the game is successfully initialized, false if there was an error and we should quit.
|
||||
{
|
||||
instance_create(0,0,RoomChangeObserver);
|
||||
set_little_endian_global(true);
|
||||
if file_exists("game_errors.log") file_delete("game_errors.log");
|
||||
if file_exists("last_plugin.log") file_delete("last_plugin.log");
|
||||
|
||||
// Delete old left-over files created by the updater
|
||||
var backupFilename;
|
||||
backupFilename = file_find_first("gg2-old.delete.me.*", 0);
|
||||
while(backupFilename != "")
|
||||
{
|
||||
file_delete(backupFilename);
|
||||
backupFilename = file_find_next();
|
||||
}
|
||||
file_find_close();
|
||||
|
||||
var customMapRotationFile, restart;
|
||||
restart = false;
|
||||
|
||||
//import wav files for music
|
||||
global.MenuMusic=sound_add(choose("Music/menumusic1.wav","Music/menumusic2.wav","Music/menumusic3.wav","Music/menumusic4.wav","Music/menumusic5.wav","Music/menumusic6.wav"), 1, true);
|
||||
global.IngameMusic=sound_add("Music/ingamemusic.wav", 1, true);
|
||||
global.FaucetMusic=sound_add("Music/faucetmusic.wav", 1, true);
|
||||
if(global.MenuMusic != -1)
|
||||
sound_volume(global.MenuMusic, 0.8);
|
||||
if(global.IngameMusic != -1)
|
||||
sound_volume(global.IngameMusic, 0.8);
|
||||
if(global.FaucetMusic != -1)
|
||||
sound_volume(global.FaucetMusic, 0.8);
|
||||
|
||||
global.sendBuffer = buffer_create();
|
||||
global.tempBuffer = buffer_create();
|
||||
global.HudCheck = false;
|
||||
global.map_rotation = ds_list_create();
|
||||
|
||||
global.CustomMapCollisionSprite = -1;
|
||||
|
||||
window_set_region_scale(-1, false);
|
||||
|
||||
ini_open("gg2.ini");
|
||||
global.playerName = ini_read_string("Settings", "PlayerName", "Player");
|
||||
if string_count("#",global.playerName) > 0 global.playerName = "Player";
|
||||
global.playerName = string_copy(global.playerName, 0, min(string_length(global.playerName), MAX_PLAYERNAME_LENGTH));
|
||||
global.fullscreen = ini_read_real("Settings", "Fullscreen", 0);
|
||||
global.useLobbyServer = ini_read_real("Settings", "UseLobby", 1);
|
||||
global.hostingPort = ini_read_real("Settings", "HostingPort", 8190);
|
||||
global.music = ini_read_real("Settings", "Music", ini_read_real("Settings", "IngameMusic", MUSIC_BOTH));
|
||||
global.playerLimit = ini_read_real("Settings", "PlayerLimit", 10);
|
||||
//thy playerlimit shalt not exceed 48!
|
||||
if (global.playerLimit > 48)
|
||||
{
|
||||
if (global.dedicatedMode != 1)
|
||||
show_message("Warning: Player Limit cannot exceed 48. It has been set to 48");
|
||||
global.playerLimit = 48;
|
||||
ini_write_real("Settings", "PlayerLimit", 48);
|
||||
}
|
||||
global.multiClientLimit = ini_read_real("Settings", "MultiClientLimit", 3);
|
||||
global.particles = ini_read_real("Settings", "Particles", PARTICLES_NORMAL);
|
||||
global.gibLevel = ini_read_real("Settings", "Gib Level", 3);
|
||||
global.killCam = ini_read_real("Settings", "Kill Cam", 1);
|
||||
global.monitorSync = ini_read_real("Settings", "Monitor Sync", 0);
|
||||
if global.monitorSync == 1 set_synchronization(true);
|
||||
else set_synchronization(false);
|
||||
global.medicRadar = ini_read_real("Settings", "Healer Radar", 1);
|
||||
global.showHealer = ini_read_real("Settings", "Show Healer", 1);
|
||||
global.showHealing = ini_read_real("Settings", "Show Healing", 1);
|
||||
global.showHealthBar = ini_read_real("Settings", "Show Healthbar", 0);
|
||||
global.showTeammateStats = ini_read_real("Settings", "Show Extra Teammate Stats", 0);
|
||||
global.serverPluginsPrompt = ini_read_real("Settings", "ServerPluginsPrompt", 1);
|
||||
global.restartPrompt = ini_read_real("Settings", "RestartPrompt", 1);
|
||||
//user HUD settings
|
||||
global.timerPos=ini_read_real("Settings","Timer Position", 0)
|
||||
global.killLogPos=ini_read_real("Settings","Kill Log Position", 0)
|
||||
global.kothHudPos=ini_read_real("Settings","KoTH HUD Position", 0)
|
||||
global.clientPassword = "";
|
||||
// for admin menu
|
||||
customMapRotationFile = ini_read_string("Server", "MapRotation", "");
|
||||
global.shuffleRotation = ini_read_real("Server", "ShuffleRotation", 1);
|
||||
global.timeLimitMins = max(1, min(255, ini_read_real("Server", "Time Limit", 15)));
|
||||
global.serverPassword = ini_read_string("Server", "Password", "");
|
||||
global.mapRotationFile = customMapRotationFile;
|
||||
global.dedicatedMode = ini_read_real("Server", "Dedicated", 0);
|
||||
global.serverName = ini_read_string("Server", "ServerName", "My Server");
|
||||
global.welcomeMessage = ini_read_string("Server", "WelcomeMessage", "");
|
||||
global.caplimit = max(1, min(255, ini_read_real("Server", "CapLimit", 5)));
|
||||
global.caplimitBkup = global.caplimit;
|
||||
global.autobalance = ini_read_real("Server", "AutoBalance",1);
|
||||
global.Server_RespawntimeSec = ini_read_real("Server", "Respawn Time", 5);
|
||||
global.rewardKey = unhex(ini_read_string("Haxxy", "RewardKey", ""));
|
||||
global.rewardId = ini_read_string("Haxxy", "RewardId", "");
|
||||
global.mapdownloadLimitBps = ini_read_real("Server", "Total bandwidth limit for map downloads in bytes per second", 50000);
|
||||
global.updaterBetaChannel = ini_read_real("General", "UpdaterBetaChannel", isBetaVersion());
|
||||
global.attemptPortForward = ini_read_real("Server", "Attempt UPnP Forwarding", 0);
|
||||
global.serverPluginList = ini_read_string("Server", "ServerPluginList", "");
|
||||
global.serverPluginsRequired = ini_read_real("Server", "ServerPluginsRequired", 0);
|
||||
if (string_length(global.serverPluginList) > 254) {
|
||||
show_message("Error: Server plugin list cannot exceed 254 characters");
|
||||
return false;
|
||||
}
|
||||
var CrosshairFilename, CrosshairRemoveBG;
|
||||
CrosshairFilename = ini_read_string("Settings", "CrosshairFilename", "");
|
||||
CrosshairRemoveBG = ini_read_real("Settings", "CrosshairRemoveBG", 1);
|
||||
global.queueJumping = ini_read_real("Settings", "Queued Jumping", 0);
|
||||
|
||||
global.backgroundHash = ini_read_string("Background", "BackgroundHash", "default");
|
||||
global.backgroundTitle = ini_read_string("Background", "BackgroundTitle", "");
|
||||
global.backgroundURL = ini_read_string("Background", "BackgroundURL", "");
|
||||
global.backgroundShowVersion = ini_read_real("Background", "BackgroundShowVersion", true);
|
||||
|
||||
readClasslimitsFromIni();
|
||||
|
||||
global.currentMapArea=1;
|
||||
global.totalMapAreas=1;
|
||||
global.setupTimer=1800;
|
||||
global.joinedServerName="";
|
||||
global.serverPluginsInUse=false;
|
||||
// Create plugin packet maps
|
||||
global.pluginPacketBuffers = ds_map_create();
|
||||
global.pluginPacketPlayers = ds_map_create();
|
||||
|
||||
ini_write_string("Settings", "PlayerName", global.playerName);
|
||||
ini_write_real("Settings", "Fullscreen", global.fullscreen);
|
||||
ini_write_real("Settings", "UseLobby", global.useLobbyServer);
|
||||
ini_write_real("Settings", "HostingPort", global.hostingPort);
|
||||
ini_key_delete("Settings", "IngameMusic");
|
||||
ini_write_real("Settings", "Music", global.music);
|
||||
ini_write_real("Settings", "PlayerLimit", global.playerLimit);
|
||||
ini_write_real("Settings", "MultiClientLimit", global.multiClientLimit);
|
||||
ini_write_real("Settings", "Particles", global.particles);
|
||||
ini_write_real("Settings", "Gib Level", global.gibLevel);
|
||||
ini_write_real("Settings", "Kill Cam", global.killCam);
|
||||
ini_write_real("Settings", "Monitor Sync", global.monitorSync);
|
||||
ini_write_real("Settings", "Healer Radar", global.medicRadar);
|
||||
ini_write_real("Settings", "Show Healer", global.showHealer);
|
||||
ini_write_real("Settings", "Show Healing", global.showHealing);
|
||||
ini_write_real("Settings", "Show Healthbar", global.showHealthBar);
|
||||
ini_write_real("Settings", "Show Extra Teammate Stats", global.showTeammateStats);
|
||||
ini_write_real("Settings", "Timer Position", global.timerPos);
|
||||
ini_write_real("Settings", "Kill Log Position", global.killLogPos);
|
||||
ini_write_real("Settings", "KoTH HUD Position", global.kothHudPos);
|
||||
ini_write_real("Settings", "ServerPluginsPrompt", global.serverPluginsPrompt);
|
||||
ini_write_real("Settings", "RestartPrompt", global.restartPrompt);
|
||||
ini_write_string("Server", "MapRotation", customMapRotationFile);
|
||||
ini_write_real("Server", "ShuffleRotation", global.shuffleRotation);
|
||||
ini_write_real("Server", "Dedicated", global.dedicatedMode);
|
||||
ini_write_string("Server", "ServerName", global.serverName);
|
||||
ini_write_string("Server", "WelcomeMessage", global.welcomeMessage);
|
||||
ini_write_real("Server", "CapLimit", global.caplimit);
|
||||
ini_write_real("Server", "AutoBalance", global.autobalance);
|
||||
ini_write_real("Server", "Respawn Time", global.Server_RespawntimeSec);
|
||||
ini_write_real("Server", "Total bandwidth limit for map downloads in bytes per second", global.mapdownloadLimitBps);
|
||||
ini_write_real("Server", "Time Limit", global.timeLimitMins);
|
||||
ini_write_string("Server", "Password", global.serverPassword);
|
||||
ini_write_real("General", "UpdaterBetaChannel", global.updaterBetaChannel);
|
||||
ini_write_real("Server", "Attempt UPnP Forwarding", global.attemptPortForward);
|
||||
ini_write_string("Server", "ServerPluginList", global.serverPluginList);
|
||||
ini_write_real("Server", "ServerPluginsRequired", global.serverPluginsRequired);
|
||||
ini_write_string("Settings", "CrosshairFilename", CrosshairFilename);
|
||||
ini_write_real("Settings", "CrosshairRemoveBG", CrosshairRemoveBG);
|
||||
ini_write_real("Settings", "Queued Jumping", global.queueJumping);
|
||||
|
||||
ini_write_string("Background", "BackgroundHash", global.backgroundHash);
|
||||
ini_write_string("Background", "BackgroundTitle", global.backgroundTitle);
|
||||
ini_write_string("Background", "BackgroundURL", global.backgroundURL);
|
||||
ini_write_real("Background", "BackgroundShowVersion", global.backgroundShowVersion);
|
||||
|
||||
ini_write_real("Classlimits", "Scout", global.classlimits[CLASS_SCOUT])
|
||||
ini_write_real("Classlimits", "Pyro", global.classlimits[CLASS_PYRO])
|
||||
ini_write_real("Classlimits", "Soldier", global.classlimits[CLASS_SOLDIER])
|
||||
ini_write_real("Classlimits", "Heavy", global.classlimits[CLASS_HEAVY])
|
||||
ini_write_real("Classlimits", "Demoman", global.classlimits[CLASS_DEMOMAN])
|
||||
ini_write_real("Classlimits", "Medic", global.classlimits[CLASS_MEDIC])
|
||||
ini_write_real("Classlimits", "Engineer", global.classlimits[CLASS_ENGINEER])
|
||||
ini_write_real("Classlimits", "Spy", global.classlimits[CLASS_SPY])
|
||||
ini_write_real("Classlimits", "Sniper", global.classlimits[CLASS_SNIPER])
|
||||
ini_write_real("Classlimits", "Quote", global.classlimits[CLASS_QUOTE])
|
||||
|
||||
//screw the 0 index we will start with 1
|
||||
//map_truefort
|
||||
maps[1] = ini_read_real("Maps", "ctf_truefort", 1);
|
||||
//map_2dfort
|
||||
maps[2] = ini_read_real("Maps", "ctf_2dfort", 2);
|
||||
//map_conflict
|
||||
maps[3] = ini_read_real("Maps", "ctf_conflict", 3);
|
||||
//map_classicwell
|
||||
maps[4] = ini_read_real("Maps", "ctf_classicwell", 4);
|
||||
//map_waterway
|
||||
maps[5] = ini_read_real("Maps", "ctf_waterway", 5);
|
||||
//map_orange
|
||||
maps[6] = ini_read_real("Maps", "ctf_orange", 6);
|
||||
//map_dirtbowl
|
||||
maps[7] = ini_read_real("Maps", "cp_dirtbowl", 7);
|
||||
//map_egypt
|
||||
maps[8] = ini_read_real("Maps", "cp_egypt", 8);
|
||||
//arena_montane
|
||||
maps[9] = ini_read_real("Maps", "arena_montane", 9);
|
||||
//arena_lumberyard
|
||||
maps[10] = ini_read_real("Maps", "arena_lumberyard", 10);
|
||||
//gen_destroy
|
||||
maps[11] = ini_read_real("Maps", "gen_destroy", 11);
|
||||
//koth_valley
|
||||
maps[12] = ini_read_real("Maps", "koth_valley", 12);
|
||||
//koth_corinth
|
||||
maps[13] = ini_read_real("Maps", "koth_corinth", 13);
|
||||
//koth_harvest
|
||||
maps[14] = ini_read_real("Maps", "koth_harvest", 14);
|
||||
//dkoth_atalia
|
||||
maps[15] = ini_read_real("Maps", "dkoth_atalia", 15);
|
||||
//dkoth_sixties
|
||||
maps[16] = ini_read_real("Maps", "dkoth_sixties", 16);
|
||||
|
||||
//Server respawn time calculator. Converts each second to a frame. (read: multiply by 30 :hehe:)
|
||||
if (global.Server_RespawntimeSec == 0)
|
||||
{
|
||||
global.Server_Respawntime = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
global.Server_Respawntime = global.Server_RespawntimeSec * 30;
|
||||
}
|
||||
|
||||
// I have to include this, or the client'll complain about an unknown variable.
|
||||
global.mapchanging = false;
|
||||
|
||||
ini_write_real("Maps", "ctf_truefort", maps[1]);
|
||||
ini_write_real("Maps", "ctf_2dfort", maps[2]);
|
||||
ini_write_real("Maps", "ctf_conflict", maps[3]);
|
||||
ini_write_real("Maps", "ctf_classicwell", maps[4]);
|
||||
ini_write_real("Maps", "ctf_waterway", maps[5]);
|
||||
ini_write_real("Maps", "ctf_orange", maps[6]);
|
||||
ini_write_real("Maps", "cp_dirtbowl", maps[7]);
|
||||
ini_write_real("Maps", "cp_egypt", maps[8]);
|
||||
ini_write_real("Maps", "arena_montane", maps[9]);
|
||||
ini_write_real("Maps", "arena_lumberyard", maps[10]);
|
||||
ini_write_real("Maps", "gen_destroy", maps[11]);
|
||||
ini_write_real("Maps", "koth_valley", maps[12]);
|
||||
ini_write_real("Maps", "koth_corinth", maps[13]);
|
||||
ini_write_real("Maps", "koth_harvest", maps[14]);
|
||||
ini_write_real("Maps", "dkoth_atalia", maps[15]);
|
||||
ini_write_real("Maps", "dkoth_sixties", maps[16]);
|
||||
|
||||
ini_close();
|
||||
|
||||
// parse the protocol version UUID for later use
|
||||
global.protocolUuid = buffer_create();
|
||||
parseUuid(PROTOCOL_UUID, global.protocolUuid);
|
||||
|
||||
global.gg2lobbyId = buffer_create();
|
||||
parseUuid(GG2_LOBBY_UUID, global.gg2lobbyId);
|
||||
|
||||
// Create abbreviations array for rewards use
|
||||
initRewards()
|
||||
|
||||
var a, IPRaw, portRaw;
|
||||
doubleCheck=0;
|
||||
global.launchMap = "";
|
||||
|
||||
for(a = 1; a <= parameter_count(); a += 1)
|
||||
{
|
||||
if (parameter_string(a) == "-dedicated")
|
||||
{
|
||||
global.dedicatedMode = 1;
|
||||
}
|
||||
else if (parameter_string(a) == "-restart")
|
||||
{
|
||||
restart = true;
|
||||
}
|
||||
else if (parameter_string(a) == "-server")
|
||||
{
|
||||
IPRaw = parameter_string(a+1);
|
||||
if (doubleCheck == 1)
|
||||
{
|
||||
doubleCheck = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
doubleCheck = 1;
|
||||
}
|
||||
}
|
||||
else if (parameter_string(a) == "-port")
|
||||
{
|
||||
portRaw = parameter_string(a+1);
|
||||
if (doubleCheck == 1)
|
||||
{
|
||||
doubleCheck = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
doubleCheck = 1;
|
||||
}
|
||||
}
|
||||
else if (parameter_string(a) == "-map")
|
||||
{
|
||||
global.launchMap = parameter_string(a+1);
|
||||
global.dedicatedMode = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (doubleCheck == 2)
|
||||
{
|
||||
global.serverPort = real(portRaw);
|
||||
global.serverIP = IPRaw;
|
||||
global.isHost = false;
|
||||
instance_create(0,0,Client);
|
||||
}
|
||||
|
||||
global.customMapdesginated = 0;
|
||||
|
||||
// if the user defined a valid map rotation file, then load from there
|
||||
|
||||
if(customMapRotationFile != "" && file_exists(customMapRotationFile) && global.launchMap == "") {
|
||||
global.customMapdesginated = 1;
|
||||
var fileHandle, i, mapname;
|
||||
fileHandle = file_text_open_read(customMapRotationFile);
|
||||
for(i = 1; !file_text_eof(fileHandle); i += 1) {
|
||||
mapname = file_text_read_string(fileHandle);
|
||||
// remove leading whitespace from the string
|
||||
while(string_char_at(mapname, 0) == " " || string_char_at(mapname, 0) == chr(9)) { // while it starts with a space or tab
|
||||
mapname = string_delete(mapname, 0, 1); // delete that space or tab
|
||||
}
|
||||
if(mapname != "" && string_char_at(mapname, 0) != "#") { // if it's not blank and it's not a comment (starting with #)
|
||||
ds_list_add(global.map_rotation, mapname);
|
||||
}
|
||||
file_text_readln(fileHandle);
|
||||
}
|
||||
file_text_close(fileHandle);
|
||||
}
|
||||
|
||||
else if (global.launchMap != "") && (global.dedicatedMode == 1)
|
||||
{
|
||||
ds_list_add(global.map_rotation, global.launchMap);
|
||||
}
|
||||
|
||||
else { // else load from the ini file Maps section
|
||||
//Set up the map rotation stuff
|
||||
var i, sort_list;
|
||||
sort_list = ds_list_create();
|
||||
for(i=1; i <= 16; i += 1) {
|
||||
if(maps[i] != 0) ds_list_add(sort_list, ((100*maps[i])+i));
|
||||
}
|
||||
ds_list_sort(sort_list, 1);
|
||||
|
||||
// translate the numbers back into the names they represent
|
||||
for(i=0; i < ds_list_size(sort_list); i += 1) {
|
||||
switch(ds_list_find_value(sort_list, i) mod 100) {
|
||||
case 1:
|
||||
ds_list_add(global.map_rotation, "ctf_truefort");
|
||||
break;
|
||||
case 2:
|
||||
ds_list_add(global.map_rotation, "ctf_2dfort");
|
||||
break;
|
||||
case 3:
|
||||
ds_list_add(global.map_rotation, "ctf_conflict");
|
||||
break;
|
||||
case 4:
|
||||
ds_list_add(global.map_rotation, "ctf_classicwell");
|
||||
break;
|
||||
case 5:
|
||||
ds_list_add(global.map_rotation, "ctf_waterway");
|
||||
break;
|
||||
case 6:
|
||||
ds_list_add(global.map_rotation, "ctf_orange");
|
||||
break;
|
||||
case 7:
|
||||
ds_list_add(global.map_rotation, "cp_dirtbowl");
|
||||
break;
|
||||
case 8:
|
||||
ds_list_add(global.map_rotation, "cp_egypt");
|
||||
break;
|
||||
case 9:
|
||||
ds_list_add(global.map_rotation, "arena_montane");
|
||||
break;
|
||||
case 10:
|
||||
ds_list_add(global.map_rotation, "arena_lumberyard");
|
||||
break;
|
||||
case 11:
|
||||
ds_list_add(global.map_rotation, "gen_destroy");
|
||||
break;
|
||||
case 12:
|
||||
ds_list_add(global.map_rotation, "koth_valley");
|
||||
break;
|
||||
case 13:
|
||||
ds_list_add(global.map_rotation, "koth_corinth");
|
||||
break;
|
||||
case 14:
|
||||
ds_list_add(global.map_rotation, "koth_harvest");
|
||||
break;
|
||||
case 15:
|
||||
ds_list_add(global.map_rotation, "dkoth_atalia");
|
||||
break;
|
||||
case 16:
|
||||
ds_list_add(global.map_rotation, "dkoth_sixties");
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
ds_list_destroy(sort_list);
|
||||
}
|
||||
|
||||
window_set_fullscreen(global.fullscreen);
|
||||
|
||||
global.gg2Font = font_add_sprite(gg2FontS,ord("!"),false,0);
|
||||
global.countFont = font_add_sprite(countFontS, ord("0"),false,2);
|
||||
draw_set_font(global.gg2Font);
|
||||
cursor_sprite = CrosshairS;
|
||||
|
||||
if(!directory_exists(working_directory + "\Maps")) directory_create(working_directory + "\Maps");
|
||||
|
||||
instance_create(0, 0, AudioControl);
|
||||
instance_create(0, 0, SSControl);
|
||||
|
||||
// custom dialog box graphics
|
||||
message_background(popupBackgroundB);
|
||||
message_button(popupButtonS);
|
||||
message_text_font("Century",9,c_white,1);
|
||||
message_button_font("Century",9,c_white,1);
|
||||
message_input_font("Century",9,c_white,0);
|
||||
|
||||
//Key Mapping
|
||||
ini_open("controls.gg2");
|
||||
global.jump = ini_read_real("Controls", "jump", ord("W"));
|
||||
global.down = ini_read_real("Controls", "down", ord("S"));
|
||||
global.left = ini_read_real("Controls", "left", ord("A"));
|
||||
global.right = ini_read_real("Controls", "right", ord("D"));
|
||||
global.attack = ini_read_real("Controls", "attack", MOUSE_LEFT);
|
||||
global.special = ini_read_real("Controls", "special", MOUSE_RIGHT);
|
||||
global.taunt = ini_read_real("Controls", "taunt", ord("F"));
|
||||
global.chat1 = ini_read_real("Controls", "chat1", ord("Z"));
|
||||
global.chat2 = ini_read_real("Controls", "chat2", ord("X"));
|
||||
global.chat3 = ini_read_real("Controls", "chat3", ord("C"));
|
||||
global.medic = ini_read_real("Controls", "medic", ord("E"));
|
||||
global.drop = ini_read_real("Controls", "drop", ord("B"));
|
||||
global.changeTeam = ini_read_real("Controls", "changeTeam", ord("N"));
|
||||
global.changeClass = ini_read_real("Controls", "changeClass", ord("M"));
|
||||
global.showScores = ini_read_real("Controls", "showScores", vk_shift);
|
||||
ini_close();
|
||||
|
||||
calculateMonthAndDay();
|
||||
|
||||
if(!directory_exists(working_directory + "\Plugins")) directory_create(working_directory + "\Plugins");
|
||||
loadplugins();
|
||||
|
||||
/* Windows 8 is known to crash GM when more than three (?) sounds play at once
|
||||
* We'll store the kernel version (Win8 is 6.2, Win7 is 6.1) and check it there.
|
||||
***/
|
||||
registry_set_root(1); // HKLM
|
||||
global.NTKernelVersion = real(registry_read_string_ext("\SOFTWARE\Microsoft\Windows NT\CurrentVersion\", "CurrentVersion")); // SIC
|
||||
|
||||
if (file_exists(CrosshairFilename))
|
||||
{
|
||||
sprite_replace(CrosshairS,CrosshairFilename,1,CrosshairRemoveBG,false,0,0);
|
||||
sprite_set_offset(CrosshairS,sprite_get_width(CrosshairS)/2,sprite_get_height(CrosshairS)/2);
|
||||
}
|
||||
if(global.dedicatedMode == 1) {
|
||||
AudioControlToggleMute();
|
||||
room_goto_fix(Menu);
|
||||
} else if(restart) {
|
||||
room_goto_fix(Menu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
1861
samples/Game Maker Language/jsonion.gml
Normal file
1861
samples/Game Maker Language/jsonion.gml
Normal file
File diff suppressed because it is too large
Load Diff
1169
samples/Game Maker Language/jsonion_test.gml
Normal file
1169
samples/Game Maker Language/jsonion_test.gml
Normal file
File diff suppressed because it is too large
Load Diff
252
samples/Game Maker Language/loadserverplugins.gml
Normal file
252
samples/Game Maker Language/loadserverplugins.gml
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
Originally from /Source/gg2/Scripts/Plugins/loadserverplugins.gml in Gang Garrison 2
|
||||
|
||||
Copyright (C) 2008-2013 Faucet Software
|
||||
http://www.ganggarrison.com
|
||||
|
||||
This program is free software;
|
||||
you can redistribute it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License along with this program; if not,
|
||||
see <http://www.gnu.org/licenses>.
|
||||
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,
|
||||
the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries,
|
||||
the licensors of this Program grant you additional permission to convey the resulting work.
|
||||
*/
|
||||
|
||||
// loads plugins from ganggarrison.com asked for by server
|
||||
// argument0 - comma separated plugin list (pluginname@md5hash)
|
||||
// returns true on success, false on failure
|
||||
var list, hashList, text, i, pluginname, pluginhash, realhash, url, handle, filesize, progress, tempfile, tempdir, failed, lastContact, isCached;
|
||||
|
||||
failed = false;
|
||||
list = ds_list_create();
|
||||
lastContact = 0;
|
||||
isCached = false;
|
||||
isDebug = false;
|
||||
hashList = ds_list_create();
|
||||
|
||||
// split plugin list string
|
||||
list = split(argument0, ',');
|
||||
|
||||
// Split hashes from plugin names
|
||||
for (i = 0; i < ds_list_size(list); i += 1)
|
||||
{
|
||||
text = ds_list_find_value(list, i);
|
||||
pluginname = string_copy(text, 0, string_pos("@", text) - 1);
|
||||
pluginhash = string_copy(text, string_pos("@", text) + 1, string_length(text) - string_pos("@", text));
|
||||
ds_list_replace(list, i, pluginname);
|
||||
ds_list_add(hashList, pluginhash);
|
||||
}
|
||||
|
||||
// Check plugin names and check for duplicates
|
||||
for (i = 0; i < ds_list_size(list); i += 1)
|
||||
{
|
||||
pluginname = ds_list_find_value(list, i);
|
||||
|
||||
// invalid plugin name
|
||||
if (!checkpluginname(pluginname))
|
||||
{
|
||||
show_message('Error loading server-sent plugins - invalid plugin name:#"' + pluginname + '"');
|
||||
return false;
|
||||
}
|
||||
// is duplicate
|
||||
else if (ds_list_find_index(list, pluginname) != i)
|
||||
{
|
||||
show_message('Error loading server-sent plugins - duplicate plugin:#"' + pluginname + '"');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Download plugins
|
||||
for (i = 0; i < ds_list_size(list); i += 1)
|
||||
{
|
||||
pluginname = ds_list_find_value(list, i);
|
||||
pluginhash = ds_list_find_value(hashList, i);
|
||||
isDebug = file_exists(working_directory + "\ServerPluginsDebug\" + pluginname + ".zip");
|
||||
isCached = file_exists(working_directory + "\ServerPluginsCache\" + pluginname + "@" + pluginhash);
|
||||
tempfile = temp_directory + "\" + pluginname + ".zip.tmp";
|
||||
tempdir = temp_directory + "\" + pluginname + ".tmp";
|
||||
|
||||
// check to see if we have a local copy for debugging
|
||||
if (isDebug)
|
||||
{
|
||||
file_copy(working_directory + "\ServerPluginsDebug\" + pluginname + ".zip", tempfile);
|
||||
// show warning
|
||||
if (global.isHost)
|
||||
{
|
||||
show_message(
|
||||
"Warning: server-sent plugin '"
|
||||
+ pluginname
|
||||
+ "' is being loaded from ServerPluginsDebug. Make sure clients have the same version, else they may be unable to connect."
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
show_message(
|
||||
"Warning: server-sent plugin '"
|
||||
+ pluginname
|
||||
+ "' is being loaded from ServerPluginsDebug. Make sure the server has the same version, else you may be unable to connect."
|
||||
);
|
||||
}
|
||||
}
|
||||
// otherwise, check if we have it cached
|
||||
else if (isCached)
|
||||
{
|
||||
file_copy(working_directory + "\ServerPluginsCache\" + pluginname + "@" + pluginhash, tempfile);
|
||||
}
|
||||
// otherwise, download as usual
|
||||
else
|
||||
{
|
||||
// construct the URL
|
||||
// http://www.ganggarrison.com/plugins/$PLUGINNAME$@$PLUGINHASH$.zip)
|
||||
url = PLUGIN_SOURCE + pluginname + "@" + pluginhash + ".zip";
|
||||
|
||||
// let's make the download handle
|
||||
handle = httpGet(url, -1);
|
||||
|
||||
// download it
|
||||
while (!httpRequestStatus(handle)) {
|
||||
// prevent game locking up
|
||||
io_handle();
|
||||
|
||||
httpRequestStep(handle);
|
||||
|
||||
if (!global.isHost) {
|
||||
// send ping if we haven't contacted server in 20 seconds
|
||||
// we need to do this to keep the connection open
|
||||
if (current_time-lastContact > 20000) {
|
||||
write_byte(global.serverSocket, PING);
|
||||
socket_send(global.serverSocket);
|
||||
lastContact = current_time;
|
||||
}
|
||||
}
|
||||
|
||||
// draw progress bar since they may be waiting a while
|
||||
filesize = httpRequestResponseBodySize(handle);
|
||||
progress = httpRequestResponseBodyProgress(handle);
|
||||
draw_background_ext(background_index[0], 0, 0, background_xscale[0], background_yscale[0], 0, c_white, 1);
|
||||
draw_set_color(c_white);
|
||||
draw_set_alpha(1);
|
||||
draw_set_halign(fa_left);
|
||||
draw_rectangle(50, 550, 300, 560, 2);
|
||||
draw_text(50, 530, "Downloading server-sent plugin " + string(i + 1) + "/" + string(ds_list_size(list)) + ' - "' + pluginname + '"');
|
||||
if (filesize != -1)
|
||||
draw_rectangle(50, 550, 50 + progress / filesize * 250, 560, 0);
|
||||
screen_refresh();
|
||||
}
|
||||
|
||||
// errored
|
||||
if (httpRequestStatus(handle) == 2)
|
||||
{
|
||||
show_message('Error loading server-sent plugins - download failed for "' + pluginname + '":#' + httpRequestError(handle));
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// request failed
|
||||
if (httpRequestStatusCode(handle) != 200)
|
||||
{
|
||||
show_message('Error loading server-sent plugins - download failed for "' + pluginname + '":#' + string(httpRequestStatusCode(handle)) + ' ' + httpRequestReasonPhrase(handle));
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
write_buffer_to_file(httpRequestResponseBody(handle), tempfile);
|
||||
if (!file_exists(tempfile))
|
||||
{
|
||||
show_message('Error loading server-sent plugins - download failed for "' + pluginname + '":# No such file?');
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
httpRequestDestroy(handle);
|
||||
}
|
||||
|
||||
// check file integrity
|
||||
realhash = GG2DLL_compute_MD5(tempfile);
|
||||
if (realhash != pluginhash)
|
||||
{
|
||||
show_message('Error loading server-sent plugins - integrity check failed (MD5 hash mismatch) for:#"' + pluginname + '"');
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// don't try to cache debug plugins
|
||||
if (!isDebug)
|
||||
{
|
||||
// add to cache if we don't already have it
|
||||
if (!file_exists(working_directory + "\ServerPluginsCache\" + pluginname + "@" + pluginhash))
|
||||
{
|
||||
// make sure directory exists
|
||||
if (!directory_exists(working_directory + "\ServerPluginsCache"))
|
||||
{
|
||||
directory_create(working_directory + "\ServerPluginsCache");
|
||||
}
|
||||
// store in cache
|
||||
file_copy(tempfile, working_directory + "\ServerPluginsCache\" + pluginname + "@" + pluginhash);
|
||||
}
|
||||
}
|
||||
|
||||
// let's get 7-zip to extract the files
|
||||
extractzip(tempfile, tempdir);
|
||||
|
||||
// if the directory doesn't exist, extracting presumably failed
|
||||
if (!directory_exists(tempdir))
|
||||
{
|
||||
show_message('Error loading server-sent plugins - extracting zip failed for:#"' + pluginname + '"');
|
||||
failed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!failed)
|
||||
{
|
||||
// Execute plugins
|
||||
for (i = 0; i < ds_list_size(list); i += 1)
|
||||
{
|
||||
pluginname = ds_list_find_value(list, i);
|
||||
tempdir = temp_directory + "\" + pluginname + ".tmp";
|
||||
|
||||
// Debugging facility, so we know *which* plugin caused compile/execute error
|
||||
fp = file_text_open_write(working_directory + "\last_plugin.log");
|
||||
file_text_write_string(fp, pluginname);
|
||||
file_text_close(fp);
|
||||
|
||||
// packetID is (i), so make queues for it
|
||||
ds_map_add(global.pluginPacketBuffers, i, ds_queue_create());
|
||||
ds_map_add(global.pluginPacketPlayers, i, ds_queue_create());
|
||||
|
||||
// Execute plugin
|
||||
execute_file(
|
||||
// the plugin's main gml file must be in the root of the zip
|
||||
// it is called plugin.gml
|
||||
tempdir + "\plugin.gml",
|
||||
// the plugin needs to know where it is
|
||||
// so the temporary directory is passed as first argument
|
||||
tempdir,
|
||||
// the plugin needs to know its packetID
|
||||
// so it is passed as the second argument
|
||||
i
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete last plugin log
|
||||
file_delete(working_directory + "\last_plugin.log");
|
||||
|
||||
// Get rid of plugin list
|
||||
ds_list_destroy(list);
|
||||
|
||||
// Get rid of plugin hash list
|
||||
ds_list_destroy(hashList);
|
||||
|
||||
return !failed;
|
||||
384
samples/Game Maker Language/processClientCommands.gml
Normal file
384
samples/Game Maker Language/processClientCommands.gml
Normal file
@@ -0,0 +1,384 @@
|
||||
/*
|
||||
Originally from /Source/gg2/Scripts/GameServer/processClientCommands.gml in Gang Garrison 2
|
||||
|
||||
Copyright (C) 2008-2013 Faucet Software
|
||||
http://www.ganggarrison.com
|
||||
|
||||
This program is free software;
|
||||
you can redistribute it and/or modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 3 of the License, or (at your option)
|
||||
any later version.
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
||||
without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
See the GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License along with this program; if not,
|
||||
see <http://www.gnu.org/licenses>.
|
||||
|
||||
Additional permission under GNU GPL version 3 section 7
|
||||
If you modify this Program, or any covered work, by linking or combining it with the Game Maker runtime library,
|
||||
the 39dll library/extension, Hobbel's Download Manager DLL, or modified versions of these libraries,
|
||||
the licensors of this Program grant you additional permission to convey the resulting work.
|
||||
*/
|
||||
|
||||
var player, playerId, commandLimitRemaining;
|
||||
|
||||
player = argument0;
|
||||
playerId = argument1;
|
||||
|
||||
// To prevent players from flooding the server, limit the number of commands to process per step and player.
|
||||
commandLimitRemaining = 10;
|
||||
|
||||
with(player) {
|
||||
if(!variable_local_exists("commandReceiveState")) {
|
||||
// 0: waiting for command byte.
|
||||
// 1: waiting for command data length (1 byte)
|
||||
// 2: waiting for command data.
|
||||
commandReceiveState = 0;
|
||||
commandReceiveExpectedBytes = 1;
|
||||
commandReceiveCommand = 0;
|
||||
}
|
||||
}
|
||||
|
||||
while(commandLimitRemaining > 0) {
|
||||
var socket;
|
||||
socket = player.socket;
|
||||
if(!tcp_receive(socket, player.commandReceiveExpectedBytes)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch(player.commandReceiveState)
|
||||
{
|
||||
case 0:
|
||||
player.commandReceiveCommand = read_ubyte(socket);
|
||||
switch(commandBytes[player.commandReceiveCommand]) {
|
||||
case commandBytesInvalidCommand:
|
||||
// Invalid byte received. Wait for another command byte.
|
||||
break;
|
||||
|
||||
case commandBytesPrefixLength1:
|
||||
player.commandReceiveState = 1;
|
||||
player.commandReceiveExpectedBytes = 1;
|
||||
break;
|
||||
|
||||
case commandBytesPrefixLength2:
|
||||
player.commandReceiveState = 3;
|
||||
player.commandReceiveExpectedBytes = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
player.commandReceiveState = 2;
|
||||
player.commandReceiveExpectedBytes = commandBytes[player.commandReceiveCommand];
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
player.commandReceiveState = 2;
|
||||
player.commandReceiveExpectedBytes = read_ubyte(socket);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
player.commandReceiveState = 2;
|
||||
player.commandReceiveExpectedBytes = read_ushort(socket);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
player.commandReceiveState = 0;
|
||||
player.commandReceiveExpectedBytes = 1;
|
||||
commandLimitRemaining -= 1;
|
||||
|
||||
switch(player.commandReceiveCommand)
|
||||
{
|
||||
case PLAYER_LEAVE:
|
||||
socket_destroy(player.socket);
|
||||
player.socket = -1;
|
||||
break;
|
||||
|
||||
case PLAYER_CHANGECLASS:
|
||||
var class;
|
||||
class = read_ubyte(socket);
|
||||
if(getCharacterObject(player.team, class) != -1)
|
||||
{
|
||||
if(player.object != -1)
|
||||
{
|
||||
with(player.object)
|
||||
{
|
||||
if (collision_point(x,y,SpawnRoom,0,0) < 0)
|
||||
{
|
||||
if (!instance_exists(lastDamageDealer) || lastDamageDealer == player)
|
||||
{
|
||||
sendEventPlayerDeath(player, player, noone, BID_FAREWELL);
|
||||
doEventPlayerDeath(player, player, noone, BID_FAREWELL);
|
||||
}
|
||||
else
|
||||
{
|
||||
var assistant;
|
||||
assistant = secondToLastDamageDealer;
|
||||
if (lastDamageDealer.object)
|
||||
if (lastDamageDealer.object.healer)
|
||||
assistant = lastDamageDealer.object.healer;
|
||||
sendEventPlayerDeath(player, lastDamageDealer, assistant, FINISHED_OFF);
|
||||
doEventPlayerDeath(player, lastDamageDealer, assistant, FINISHED_OFF);
|
||||
}
|
||||
}
|
||||
else
|
||||
instance_destroy();
|
||||
|
||||
}
|
||||
}
|
||||
else if(player.alarm[5]<=0)
|
||||
player.alarm[5] = 1;
|
||||
class = checkClasslimits(player, player.team, class);
|
||||
player.class = class;
|
||||
ServerPlayerChangeclass(playerId, player.class, global.sendBuffer);
|
||||
}
|
||||
break;
|
||||
|
||||
case PLAYER_CHANGETEAM:
|
||||
var newTeam, balance, redSuperiority;
|
||||
newTeam = read_ubyte(socket);
|
||||
|
||||
redSuperiority = 0 //calculate which team is bigger
|
||||
with(Player)
|
||||
{
|
||||
if(team == TEAM_RED)
|
||||
redSuperiority += 1;
|
||||
else if(team == TEAM_BLUE)
|
||||
redSuperiority -= 1;
|
||||
}
|
||||
if(redSuperiority > 0)
|
||||
balance = TEAM_RED;
|
||||
else if(redSuperiority < 0)
|
||||
balance = TEAM_BLUE;
|
||||
else
|
||||
balance = -1;
|
||||
|
||||
if(balance != newTeam)
|
||||
{
|
||||
if(getCharacterObject(newTeam, player.class) != -1 or newTeam==TEAM_SPECTATOR)
|
||||
{
|
||||
if(player.object != -1)
|
||||
{
|
||||
with(player.object)
|
||||
{
|
||||
if (!instance_exists(lastDamageDealer) || lastDamageDealer == player)
|
||||
{
|
||||
sendEventPlayerDeath(player, player, noone, BID_FAREWELL);
|
||||
doEventPlayerDeath(player, player, noone, BID_FAREWELL);
|
||||
}
|
||||
else
|
||||
{
|
||||
var assistant;
|
||||
assistant = secondToLastDamageDealer;
|
||||
if (lastDamageDealer.object)
|
||||
if (lastDamageDealer.object.healer)
|
||||
assistant = lastDamageDealer.object.healer;
|
||||
sendEventPlayerDeath(player, lastDamageDealer, assistant, FINISHED_OFF);
|
||||
doEventPlayerDeath(player, lastDamageDealer, assistant, FINISHED_OFF);
|
||||
}
|
||||
}
|
||||
player.alarm[5] = global.Server_Respawntime;
|
||||
}
|
||||
else if(player.alarm[5]<=0)
|
||||
player.alarm[5] = 1;
|
||||
var newClass;
|
||||
newClass = checkClasslimits(player, newTeam, player.class);
|
||||
if newClass != player.class
|
||||
{
|
||||
player.class = newClass;
|
||||
ServerPlayerChangeclass(playerId, player.class, global.sendBuffer);
|
||||
}
|
||||
player.team = newTeam;
|
||||
ServerPlayerChangeteam(playerId, player.team, global.sendBuffer);
|
||||
ServerBalanceTeams();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CHAT_BUBBLE:
|
||||
var bubbleImage;
|
||||
bubbleImage = read_ubyte(socket);
|
||||
if(global.aFirst) {
|
||||
bubbleImage = 0;
|
||||
}
|
||||
write_ubyte(global.sendBuffer, CHAT_BUBBLE);
|
||||
write_ubyte(global.sendBuffer, playerId);
|
||||
write_ubyte(global.sendBuffer, bubbleImage);
|
||||
|
||||
setChatBubble(player, bubbleImage);
|
||||
break;
|
||||
|
||||
case BUILD_SENTRY:
|
||||
if(player.object != -1)
|
||||
{
|
||||
if(player.class == CLASS_ENGINEER
|
||||
and collision_circle(player.object.x, player.object.y, 50, Sentry, false, true) < 0
|
||||
and player.object.nutsNBolts == 100
|
||||
and (collision_point(player.object.x,player.object.y,SpawnRoom,0,0) < 0)
|
||||
and !player.sentry
|
||||
and !player.object.onCabinet)
|
||||
{
|
||||
write_ubyte(global.sendBuffer, BUILD_SENTRY);
|
||||
write_ubyte(global.sendBuffer, playerId);
|
||||
write_ushort(global.serializeBuffer, round(player.object.x*5));
|
||||
write_ushort(global.serializeBuffer, round(player.object.y*5));
|
||||
write_byte(global.serializeBuffer, player.object.image_xscale);
|
||||
buildSentry(player, player.object.x, player.object.y, player.object.image_xscale);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DESTROY_SENTRY:
|
||||
with(player.sentry)
|
||||
instance_destroy();
|
||||
break;
|
||||
|
||||
case DROP_INTEL:
|
||||
if (player.object != -1)
|
||||
{
|
||||
if (player.object.intel)
|
||||
{
|
||||
sendEventDropIntel(player);
|
||||
doEventDropIntel(player);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OMNOMNOMNOM:
|
||||
if(player.object != -1) {
|
||||
if(!player.humiliated
|
||||
and !player.object.taunting
|
||||
and !player.object.omnomnomnom
|
||||
and player.object.canEat
|
||||
and player.class==CLASS_HEAVY)
|
||||
{
|
||||
write_ubyte(global.sendBuffer, OMNOMNOMNOM);
|
||||
write_ubyte(global.sendBuffer, playerId);
|
||||
with(player.object)
|
||||
{
|
||||
omnomnomnom = true;
|
||||
if player.team == TEAM_RED {
|
||||
omnomnomnomindex=0;
|
||||
omnomnomnomend=31;
|
||||
} else if player.team==TEAM_BLUE {
|
||||
omnomnomnomindex=32;
|
||||
omnomnomnomend=63;
|
||||
}
|
||||
xscale=image_xscale;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TOGGLE_ZOOM:
|
||||
if player.object != -1 {
|
||||
if player.class == CLASS_SNIPER {
|
||||
write_ubyte(global.sendBuffer, TOGGLE_ZOOM);
|
||||
write_ubyte(global.sendBuffer, playerId);
|
||||
toggleZoom(player.object);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PLAYER_CHANGENAME:
|
||||
var nameLength;
|
||||
nameLength = socket_receivebuffer_size(socket);
|
||||
if(nameLength > MAX_PLAYERNAME_LENGTH)
|
||||
{
|
||||
write_ubyte(player.socket, KICK);
|
||||
write_ubyte(player.socket, KICK_NAME);
|
||||
socket_destroy(player.socket);
|
||||
player.socket = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
with(player)
|
||||
{
|
||||
if(variable_local_exists("lastNamechange"))
|
||||
if(current_time - lastNamechange < 1000)
|
||||
break;
|
||||
lastNamechange = current_time;
|
||||
name = read_string(socket, nameLength);
|
||||
if(string_count("#",name) > 0)
|
||||
{
|
||||
name = "I <3 Bacon";
|
||||
}
|
||||
write_ubyte(global.sendBuffer, PLAYER_CHANGENAME);
|
||||
write_ubyte(global.sendBuffer, playerId);
|
||||
write_ubyte(global.sendBuffer, string_length(name));
|
||||
write_string(global.sendBuffer, name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case INPUTSTATE:
|
||||
if(player.object != -1)
|
||||
{
|
||||
with(player.object)
|
||||
{
|
||||
keyState = read_ubyte(socket);
|
||||
netAimDirection = read_ushort(socket);
|
||||
aimDirection = netAimDirection*360/65536;
|
||||
event_user(1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case REWARD_REQUEST:
|
||||
player.rewardId = read_string(socket, socket_receivebuffer_size(socket));
|
||||
player.challenge = rewardCreateChallenge();
|
||||
|
||||
write_ubyte(socket, REWARD_CHALLENGE_CODE);
|
||||
write_binstring(socket, player.challenge);
|
||||
break;
|
||||
|
||||
case REWARD_CHALLENGE_RESPONSE:
|
||||
var answer, i, authbuffer;
|
||||
answer = read_binstring(socket, 16);
|
||||
|
||||
with(player)
|
||||
if(variable_local_exists("challenge") and variable_local_exists("rewardId"))
|
||||
rewardAuthStart(player, answer, challenge, true, rewardId);
|
||||
|
||||
break;
|
||||
|
||||
case PLUGIN_PACKET:
|
||||
var packetID, buf, success;
|
||||
|
||||
packetID = read_ubyte(socket);
|
||||
|
||||
// get packet data
|
||||
buf = buffer_create();
|
||||
write_buffer_part(buf, socket, socket_receivebuffer_size(socket));
|
||||
|
||||
// try to enqueue
|
||||
success = _PluginPacketPush(packetID, buf, player);
|
||||
|
||||
// if it returned false, packetID was invalid
|
||||
if (!success)
|
||||
{
|
||||
// clear up buffer
|
||||
buffer_destroy(buf);
|
||||
|
||||
// kick player
|
||||
write_ubyte(player.socket, KICK);
|
||||
write_ubyte(player.socket, KICK_BAD_PLUGIN_PACKET);
|
||||
socket_destroy(player.socket);
|
||||
player.socket = -1;
|
||||
}
|
||||
break;
|
||||
|
||||
case CLIENT_SETTINGS:
|
||||
var mirror;
|
||||
mirror = read_ubyte(player.socket);
|
||||
player.queueJump = mirror;
|
||||
|
||||
write_ubyte(global.sendBuffer, CLIENT_SETTINGS);
|
||||
write_ubyte(global.sendBuffer, playerId);
|
||||
write_ubyte(global.sendBuffer, mirror);
|
||||
break;
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
298
samples/Game Maker Language/scrInitLevel.gml
Normal file
298
samples/Game Maker Language/scrInitLevel.gml
Normal file
@@ -0,0 +1,298 @@
|
||||
// Originally from /spelunky/Scripts/Level Generation/scrInitLevel.gml in the Spelunky Community Update Project
|
||||
|
||||
//
|
||||
// scrInitLevel()
|
||||
//
|
||||
// Calls scrLevelGen(), scrRoomGen*(), and scrEntityGen() to build level.
|
||||
//
|
||||
|
||||
/**********************************************************************************
|
||||
Copyright (c) 2008, 2009 Derek Yu and Mossmouth, LLC
|
||||
|
||||
This file is part of Spelunky.
|
||||
|
||||
You can redistribute and/or modify Spelunky, including its source code, under
|
||||
the terms of the Spelunky User License.
|
||||
|
||||
Spelunky is distributed in the hope that it will be entertaining and useful,
|
||||
but WITHOUT WARRANTY. Please see the Spelunky User License for more details.
|
||||
|
||||
The Spelunky User License should be available in "Game Information", which
|
||||
can be found in the Resource Explorer, or as an external file called COPYING.
|
||||
If not, please obtain a new copy of Spelunky from <http://spelunkyworld.com/>
|
||||
|
||||
***********************************************************************************/
|
||||
|
||||
global.levelType = 0;
|
||||
//global.currLevel = 16;
|
||||
if (global.currLevel > 4 and global.currLevel < 9) global.levelType = 1;
|
||||
if (global.currLevel > 8 and global.currLevel < 13) global.levelType = 2;
|
||||
if (global.currLevel > 12 and global.currLevel < 16) global.levelType = 3;
|
||||
if (global.currLevel == 16) global.levelType = 4;
|
||||
|
||||
if (global.currLevel <= 1 or
|
||||
global.currLevel == 5 or
|
||||
global.currLevel == 9 or
|
||||
global.currLevel == 13)
|
||||
{
|
||||
global.hadDarkLevel = false;
|
||||
}
|
||||
|
||||
// global.levelType = 3; // debug
|
||||
|
||||
// DEBUG MODE //
|
||||
/*
|
||||
if (global.currLevel == 2) global.levelType = 4;
|
||||
if (global.currLevel == 3) global.levelType = 2;
|
||||
if (global.currLevel == 4) global.levelType = 3;
|
||||
if (global.currLevel == 5) global.levelType = 4;
|
||||
*/
|
||||
|
||||
// global.levelType = 0;
|
||||
|
||||
global.startRoomX = 0;
|
||||
global.startRoomY = 0;
|
||||
global.endRoomX = 0;
|
||||
global.endRoomY = 0;
|
||||
oGame.levelGen = false;
|
||||
|
||||
// this is used to determine the path to the exit (generally no bombs required)
|
||||
for (i = 0; i < 4; i += 1)
|
||||
{
|
||||
for (j = 0; j < 4; j += 1)
|
||||
{
|
||||
global.roomPath[i,j] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// side walls
|
||||
if (global.levelType == 4)
|
||||
k = 54;
|
||||
else if (global.levelType == 2)
|
||||
k = 38;
|
||||
else if (global.lake)
|
||||
k = 41;
|
||||
else
|
||||
k = 33;
|
||||
for (i = 0; i <= 42; i += 1)
|
||||
{
|
||||
for (j = 0; j <= k; j += 1)
|
||||
{
|
||||
if (not isLevel())
|
||||
{
|
||||
i = 999;
|
||||
j = 999;
|
||||
}
|
||||
else if (global.levelType == 2)
|
||||
{
|
||||
if (i*16 == 0 or
|
||||
i*16 == 656 or
|
||||
j*16 == 0)
|
||||
{
|
||||
obj = instance_create(i*16, j*16, oDark);
|
||||
obj.invincible = true;
|
||||
obj.sprite_index = sDark;
|
||||
}
|
||||
}
|
||||
else if (global.levelType == 4)
|
||||
{
|
||||
if (i*16 == 0 or
|
||||
i*16 == 656 or
|
||||
j*16 == 0)
|
||||
{
|
||||
obj = instance_create(i*16, j*16, oTemple);
|
||||
obj.invincible = true;
|
||||
if (not global.cityOfGold) obj.sprite_index = sTemple;
|
||||
}
|
||||
}
|
||||
else if (global.lake)
|
||||
{
|
||||
if (i*16 == 0 or
|
||||
i*16 == 656 or
|
||||
j*16 == 0 or
|
||||
j*16 >= 656)
|
||||
{
|
||||
obj = instance_create(i*16, j*16, oLush); obj.sprite_index = sLush;
|
||||
obj.invincible = true;
|
||||
}
|
||||
}
|
||||
else if (i*16 == 0 or
|
||||
i*16 == 656 or
|
||||
j*16 == 0 or
|
||||
j*16 >= 528)
|
||||
{
|
||||
if (global.levelType == 0) { obj = instance_create(i*16, j*16, oBrick); obj.sprite_index = sBrick; }
|
||||
else if (global.levelType == 1) { obj = instance_create(i*16, j*16, oLush); obj.sprite_index = sLush; }
|
||||
else { obj = instance_create(i*16, j*16, oTemple); if (not global.cityOfGold) obj.sprite_index = sTemple; }
|
||||
obj.invincible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (global.levelType == 2)
|
||||
{
|
||||
for (i = 0; i <= 42; i += 1)
|
||||
{
|
||||
instance_create(i*16, 40*16, oDark);
|
||||
//instance_create(i*16, 35*16, oSpikes);
|
||||
}
|
||||
}
|
||||
|
||||
if (global.levelType == 3)
|
||||
{
|
||||
background_index = bgTemple;
|
||||
}
|
||||
|
||||
global.temp1 = global.gameStart;
|
||||
scrLevelGen();
|
||||
|
||||
global.cemetary = false;
|
||||
if (global.levelType == 1 and rand(1,global.probCemetary) == 1) global.cemetary = true;
|
||||
|
||||
with oRoom
|
||||
{
|
||||
if (global.levelType == 0) scrRoomGen();
|
||||
else if (global.levelType == 1)
|
||||
{
|
||||
if (global.blackMarket) scrRoomGenMarket();
|
||||
else scrRoomGen2();
|
||||
}
|
||||
else if (global.levelType == 2)
|
||||
{
|
||||
if (global.yetiLair) scrRoomGenYeti();
|
||||
else scrRoomGen3();
|
||||
}
|
||||
else if (global.levelType == 3) scrRoomGen4();
|
||||
else scrRoomGen5();
|
||||
}
|
||||
|
||||
global.darkLevel = false;
|
||||
//if (not global.hadDarkLevel and global.currLevel != 0 and global.levelType != 2 and global.currLevel != 16 and rand(1,1) == 1)
|
||||
if (not global.hadDarkLevel and not global.noDarkLevel and global.currLevel != 0 and global.currLevel != 1 and global.levelType != 2 and global.currLevel != 16 and rand(1,global.probDarkLevel) == 1)
|
||||
{
|
||||
global.darkLevel = true;
|
||||
global.hadDarkLevel = true;
|
||||
//instance_create(oPlayer1.x, oPlayer1.y, oFlare);
|
||||
}
|
||||
|
||||
if (global.blackMarket) global.darkLevel = false;
|
||||
|
||||
global.genUdjatEye = false;
|
||||
if (not global.madeUdjatEye)
|
||||
{
|
||||
if (global.currLevel == 2 and rand(1,3) == 1) global.genUdjatEye = true;
|
||||
else if (global.currLevel == 3 and rand(1,2) == 1) global.genUdjatEye = true;
|
||||
else if (global.currLevel == 4) global.genUdjatEye = true;
|
||||
}
|
||||
|
||||
global.genMarketEntrance = false;
|
||||
if (not global.madeMarketEntrance)
|
||||
{
|
||||
if (global.currLevel == 5 and rand(1,3) == 1) global.genMarketEntrance = true;
|
||||
else if (global.currLevel == 6 and rand(1,2) == 1) global.genMarketEntrance = true;
|
||||
else if (global.currLevel == 7) global.genMarketEntrance = true;
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
// ENTITY / TREASURES
|
||||
////////////////////////////
|
||||
global.temp2 = global.gameStart;
|
||||
if (not isRoom("rTutorial") and not isRoom("rLoadLevel")) scrEntityGen();
|
||||
|
||||
if (instance_exists(oEntrance) and not global.customLevel)
|
||||
{
|
||||
oPlayer1.x = oEntrance.x+8;
|
||||
oPlayer1.y = oEntrance.y+8;
|
||||
}
|
||||
|
||||
if (global.darkLevel or
|
||||
global.blackMarket or
|
||||
global.snakePit or
|
||||
global.cemetary or
|
||||
global.lake or
|
||||
global.yetiLair or
|
||||
global.alienCraft or
|
||||
global.sacrificePit or
|
||||
global.cityOfGold)
|
||||
{
|
||||
if (not isRoom("rLoadLevel"))
|
||||
{
|
||||
with oPlayer1 { alarm[0] = 10; }
|
||||
}
|
||||
}
|
||||
|
||||
if (global.levelType == 4) scrSetupWalls(864);
|
||||
else if (global.lake) scrSetupWalls(656);
|
||||
else scrSetupWalls(528);
|
||||
|
||||
// add background details
|
||||
if (global.graphicsHigh)
|
||||
{
|
||||
repeat(20)
|
||||
{
|
||||
// bg = instance_create(16*rand(1,42), 16*rand(1,33), oCaveBG);
|
||||
if (global.levelType == 1 and rand(1,3) < 3)
|
||||
tile_add(bgExtrasLush, 32*rand(0,1), 0, 32, 32, 16*rand(1,42), 16*rand(1,33), 10002);
|
||||
else if (global.levelType == 2 and rand(1,3) < 3)
|
||||
tile_add(bgExtrasIce, 32*rand(0,1), 0, 32, 32, 16*rand(1,42), 16*rand(1,33), 10002);
|
||||
else if (global.levelType == 3 and rand(1,3) < 3)
|
||||
tile_add(bgExtrasTemple, 32*rand(0,1), 0, 32, 32, 16*rand(1,42), 16*rand(1,33), 10002);
|
||||
else
|
||||
tile_add(bgExtras, 32*rand(0,1), 0, 32, 32, 16*rand(1,42), 16*rand(1,33), 10002);
|
||||
}
|
||||
}
|
||||
|
||||
oGame.levelGen = true;
|
||||
|
||||
// generate angry shopkeeper at exit if murderer or thief
|
||||
if ((global.murderer or global.thiefLevel > 0) and isRealLevel())
|
||||
{
|
||||
with oExit
|
||||
{
|
||||
if (type == "Exit")
|
||||
{
|
||||
obj = instance_create(x, y, oShopkeeper);
|
||||
obj.status = 4;
|
||||
}
|
||||
}
|
||||
// global.thiefLevel -= 1;
|
||||
}
|
||||
|
||||
with oTreasure
|
||||
{
|
||||
if (collision_point(x, y, oSolid, 0, 0))
|
||||
{
|
||||
obj = instance_place(x, y, oSolid);
|
||||
if (obj.invincible) instance_destroy();
|
||||
}
|
||||
}
|
||||
|
||||
with oWater
|
||||
{
|
||||
if (sprite_index == sWaterTop or sprite_index == sLavaTop)
|
||||
{
|
||||
scrCheckWaterTop();
|
||||
}
|
||||
/*
|
||||
obj = instance_place(x-16, y, oWater);
|
||||
if (instance_exists(obj))
|
||||
{
|
||||
if (obj.sprite_index == sWaterTop or obj.sprite_index == sLavaTop)
|
||||
{
|
||||
if (type == "Lava") sprite_index = sLavaTop;
|
||||
else sprite_index = sWaterTop;
|
||||
}
|
||||
}
|
||||
obj = instance_place(x+16, y, oWater);
|
||||
if (instance_exists(obj))
|
||||
{
|
||||
if (obj.sprite_index == sWaterTop or obj.sprite_index == sLavaTop)
|
||||
{
|
||||
if (type == "Lava") sprite_index = sLavaTop;
|
||||
else sprite_index = sWaterTop;
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
global.temp3 = global.gameStart;
|
||||
22
samples/Gnuplot/dashcolor.1.gnu
Normal file
22
samples/Gnuplot/dashcolor.1.gnu
Normal file
@@ -0,0 +1,22 @@
|
||||
# set terminal pngcairo background "#ffffff" fontscale 1.0 dashed size 640, 480
|
||||
# set output 'dashcolor.1.png'
|
||||
set label 1 "set style line 1 lt 2 lc rgb \"red\" lw 3" at -0.4, -0.25, 0 left norotate back textcolor rgb "red" nopoint offset character 0, 0, 0
|
||||
set label 2 "set style line 2 lt 2 lc rgb \"orange\" lw 2" at -0.4, -0.35, 0 left norotate back textcolor rgb "orange" nopoint offset character 0, 0, 0
|
||||
set label 3 "set style line 3 lt 2 lc rgb \"yellow\" lw 3" at -0.4, -0.45, 0 left norotate back textcolor rgb "yellow" nopoint offset character 0, 0, 0
|
||||
set label 4 "set style line 4 lt 2 lc rgb \"green\" lw 2" at -0.4, -0.55, 0 left norotate back textcolor rgb "green" nopoint offset character 0, 0, 0
|
||||
set label 5 "plot ... lt 1 lc 3 " at -0.4, -0.65, 0 left norotate back textcolor lt 3 nopoint offset character 0, 0, 0
|
||||
set label 6 "plot ... lt 3 lc 3 " at -0.4, -0.75, 0 left norotate back textcolor lt 3 nopoint offset character 0, 0, 0
|
||||
set label 7 "plot ... lt 5 lc 3 " at -0.4, -0.85, 0 left norotate back textcolor lt 3 nopoint offset character 0, 0, 0
|
||||
set style line 1 linetype 2 linecolor rgb "red" linewidth 3.000 pointtype 2 pointsize default pointinterval 0
|
||||
set style line 2 linetype 2 linecolor rgb "orange" linewidth 2.000 pointtype 2 pointsize default pointinterval 0
|
||||
set style line 3 linetype 2 linecolor rgb "yellow" linewidth 3.000 pointtype 2 pointsize default pointinterval 0
|
||||
set style line 4 linetype 2 linecolor rgb "green" linewidth 2.000 pointtype 2 pointsize default pointinterval 0
|
||||
set noxtics
|
||||
set noytics
|
||||
set title "Independent colors and dot/dash styles"
|
||||
set xlabel "You will only see dashed lines if your current terminal setting permits it"
|
||||
set xrange [ -0.500000 : 3.50000 ] noreverse nowriteback
|
||||
set yrange [ -1.00000 : 1.40000 ] noreverse nowriteback
|
||||
set bmargin 7
|
||||
unset colorbox
|
||||
plot cos(x) ls 1 title 'ls 1', cos(x-.2) ls 2 title 'ls 2', cos(x-.4) ls 3 title 'ls 3', cos(x-.6) ls 4 title 'ls 4', cos(x-.8) lt 1 lc 3 title 'lt 1 lc 3', cos(x-1.) lt 3 lc 3 title 'lt 3 lc 3', cos(x-1.2) lt 5 lc 3 title 'lt 5 lc 3'
|
||||
15
samples/Gnuplot/histograms.2.gnu
Normal file
15
samples/Gnuplot/histograms.2.gnu
Normal file
@@ -0,0 +1,15 @@
|
||||
# set terminal pngcairo transparent enhanced font "arial,10" fontscale 1.0 size 500, 350
|
||||
# set output 'histograms.2.png'
|
||||
set boxwidth 0.9 absolute
|
||||
set style fill solid 1.00 border lt -1
|
||||
set key inside right top vertical Right noreverse noenhanced autotitles nobox
|
||||
set style histogram clustered gap 1 title offset character 0, 0, 0
|
||||
set datafile missing '-'
|
||||
set style data histograms
|
||||
set xtics border in scale 0,0 nomirror rotate by -45 offset character 0, 0, 0 autojustify
|
||||
set xtics norangelimit font ",8"
|
||||
set xtics ()
|
||||
set title "US immigration from Northern Europe\nPlot selected data columns as histogram of clustered boxes"
|
||||
set yrange [ 0.00000 : 300000. ] noreverse nowriteback
|
||||
i = 22
|
||||
plot 'immigration.dat' using 6:xtic(1) ti col, '' u 12 ti col, '' u 13 ti col, '' u 14 ti col
|
||||
14
samples/Gnuplot/rates.gp
Normal file
14
samples/Gnuplot/rates.gp
Normal file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env gnuplot
|
||||
|
||||
reset
|
||||
|
||||
set terminal png
|
||||
set output 'rates100.png'
|
||||
|
||||
set xlabel "A2A price"
|
||||
set ylabel "Response Rate"
|
||||
|
||||
#set xr [0:5]
|
||||
#set yr [0:6]
|
||||
|
||||
plot 'rates100.dat' pt 7 notitle
|
||||
40
samples/Gnuplot/surface1.16.gnu
Normal file
40
samples/Gnuplot/surface1.16.gnu
Normal file
@@ -0,0 +1,40 @@
|
||||
# set terminal pngcairo transparent enhanced font "arial,10" fontscale 1.0 size 500, 350
|
||||
# set output 'surface1.16.png'
|
||||
set dummy u,v
|
||||
set label 1 "increasing v" at 6, 0, -1 left norotate back nopoint offset character 0, 0, 0
|
||||
set label 2 "u=0" at 5, 6.5, -1 left norotate back nopoint offset character 0, 0, 0
|
||||
set label 3 "u=1" at 5, 6.5, 0.100248 left norotate back nopoint offset character 0, 0, 0
|
||||
set arrow 1 from 5, -5, -1.2 to 5, 5, -1.2 head back nofilled linetype -1 linewidth 1.000
|
||||
set arrow 2 from 5, 6, -1 to 5, 5, -1 head back nofilled linetype -1 linewidth 1.000
|
||||
set arrow 3 from 5, 6, 0.100248 to 5, 5, 0.100248 head back nofilled linetype -1 linewidth 1.000
|
||||
set parametric
|
||||
set view 70, 20, 1, 1
|
||||
set samples 51, 51
|
||||
set isosamples 2, 33
|
||||
set hidden3d back offset 1 trianglepattern 3 undefined 1 altdiagonal bentover
|
||||
set ztics -1.00000,0.25,1.00000 norangelimit
|
||||
set title "\"fence plot\" using separate parametric surfaces"
|
||||
set xlabel "X axis"
|
||||
set xlabel offset character -3, -2, 0 font "" textcolor lt -1 norotate
|
||||
set xrange [ -5.00000 : 5.00000 ] noreverse nowriteback
|
||||
set ylabel "Y axis"
|
||||
set ylabel offset character 3, -2, 0 font "" textcolor lt -1 rotate by -270
|
||||
set yrange [ -5.00000 : 5.00000 ] noreverse nowriteback
|
||||
set zlabel "Z axis"
|
||||
set zlabel offset character -5, 0, 0 font "" textcolor lt -1 norotate
|
||||
set zrange [ -1.00000 : 1.00000 ] noreverse nowriteback
|
||||
sinc(u,v) = sin(sqrt(u**2+v**2)) / sqrt(u**2+v**2)
|
||||
GPFUN_sinc = "sinc(u,v) = sin(sqrt(u**2+v**2)) / sqrt(u**2+v**2)"
|
||||
xx = 6.08888888888889
|
||||
dx = 1.10888888888889
|
||||
x0 = -5
|
||||
x1 = -3.89111111111111
|
||||
x2 = -2.78222222222222
|
||||
x3 = -1.67333333333333
|
||||
x4 = -0.564444444444444
|
||||
x5 = 0.544444444444445
|
||||
x6 = 1.65333333333333
|
||||
x7 = 2.76222222222222
|
||||
x8 = 3.87111111111111
|
||||
x9 = 4.98
|
||||
splot [u=0:1][v=-4.99:4.99] x0, v, (u<0.5) ? -1 : sinc(x0,v) notitle, x1, v, (u<0.5) ? -1 : sinc(x1,v) notitle, x2, v, (u<0.5) ? -1 : sinc(x2,v) notitle, x3, v, (u<0.5) ? -1 : sinc(x3,v) notitle, x4, v, (u<0.5) ? -1 : sinc(x4,v) notitle, x5, v, (u<0.5) ? -1 : sinc(x5,v) notitle, x6, v, (u<0.5) ? -1 : sinc(x6,v) notitle, x7, v, (u<0.5) ? -1 : sinc(x7,v) notitle, x8, v, (u<0.5) ? -1 : sinc(x8,v) notitle, x9, v, (u<0.5) ? -1 : sinc(x9,v) notitle
|
||||
46
samples/Gnuplot/surface1.17.gnu
Normal file
46
samples/Gnuplot/surface1.17.gnu
Normal file
@@ -0,0 +1,46 @@
|
||||
# set terminal pngcairo transparent enhanced font "arial,10" fontscale 1.0 size 500, 350
|
||||
# set output 'surface1.17.png'
|
||||
set dummy u,v
|
||||
set label 1 "increasing v" at 6, 0, -1 left norotate back nopoint offset character 0, 0, 0
|
||||
set label 2 "increasing u" at 0, -5, -1.5 left norotate back nopoint offset character 0, 0, 0
|
||||
set label 3 "floor(u)%3=0" at 5, 6.5, -1 left norotate back nopoint offset character 0, 0, 0
|
||||
set label 4 "floor(u)%3=1" at 5, 6.5, 0.100248 left norotate back nopoint offset character 0, 0, 0
|
||||
set arrow 1 from 5, -5, -1.2 to 5, 5, -1.2 head back nofilled linetype -1 linewidth 1.000
|
||||
set arrow 2 from -5, -5, -1.2 to 5, -5, -1.2 head back nofilled linetype -1 linewidth 1.000
|
||||
set arrow 3 from 5, 6, -1 to 5, 5, -1 head back nofilled linetype -1 linewidth 1.000
|
||||
set arrow 4 from 5, 6, 0.100248 to 5, 5, 0.100248 head back nofilled linetype -1 linewidth 1.000
|
||||
set parametric
|
||||
set view 70, 20, 1, 1
|
||||
set samples 51, 51
|
||||
set isosamples 30, 33
|
||||
set hidden3d back offset 1 trianglepattern 3 undefined 1 altdiagonal bentover
|
||||
set ztics -1.00000,0.25,1.00000 norangelimit
|
||||
set title "\"fence plot\" using single parametric surface with undefined points"
|
||||
set xlabel "X axis"
|
||||
set xlabel offset character -3, -2, 0 font "" textcolor lt -1 norotate
|
||||
set xrange [ -5.00000 : 5.00000 ] noreverse nowriteback
|
||||
set ylabel "Y axis"
|
||||
set ylabel offset character 3, -2, 0 font "" textcolor lt -1 rotate by -270
|
||||
set yrange [ -5.00000 : 5.00000 ] noreverse nowriteback
|
||||
set zlabel "Z axis"
|
||||
set zlabel offset character -5, 0, 0 font "" textcolor lt -1 norotate
|
||||
set zrange [ -1.00000 : 1.00000 ] noreverse nowriteback
|
||||
sinc(u,v) = sin(sqrt(u**2+v**2)) / sqrt(u**2+v**2)
|
||||
GPFUN_sinc = "sinc(u,v) = sin(sqrt(u**2+v**2)) / sqrt(u**2+v**2)"
|
||||
xx = 6.08888888888889
|
||||
dx = 1.11
|
||||
x0 = -5
|
||||
x1 = -3.89111111111111
|
||||
x2 = -2.78222222222222
|
||||
x3 = -1.67333333333333
|
||||
x4 = -0.564444444444444
|
||||
x5 = 0.544444444444445
|
||||
x6 = 1.65333333333333
|
||||
x7 = 2.76222222222222
|
||||
x8 = 3.87111111111111
|
||||
x9 = 4.98
|
||||
xmin = -4.99
|
||||
xmax = 5
|
||||
n = 10
|
||||
zbase = -1
|
||||
splot [u=.5:3*n-.5][v=-4.99:4.99] xmin+floor(u/3)*dx, v, ((floor(u)%3)==0) ? zbase : (((floor(u)%3)==1) ? sinc(xmin+u/3.*dx,v) : 1/0) notitle
|
||||
21
samples/Gnuplot/world2.1.gnu
Normal file
21
samples/Gnuplot/world2.1.gnu
Normal file
@@ -0,0 +1,21 @@
|
||||
# set terminal pngcairo transparent enhanced font "arial,10" fontscale 1.0 size 500, 350
|
||||
# set output 'world2.1.png'
|
||||
unset border
|
||||
set dummy u,v
|
||||
set angles degrees
|
||||
set parametric
|
||||
set view 60, 136, 1.22, 1.26
|
||||
set samples 64, 64
|
||||
set isosamples 13, 13
|
||||
set mapping spherical
|
||||
set noxtics
|
||||
set noytics
|
||||
set noztics
|
||||
set title "Labels colored by GeV plotted in spherical coordinate system"
|
||||
set urange [ -90.0000 : 90.0000 ] noreverse nowriteback
|
||||
set vrange [ 0.00000 : 360.000 ] noreverse nowriteback
|
||||
set cblabel "GeV"
|
||||
set cbrange [ 0.00000 : 8.00000 ] noreverse nowriteback
|
||||
set colorbox user
|
||||
set colorbox vertical origin screen 0.9, 0.2, 0 size screen 0.02, 0.75, 0 front bdefault
|
||||
splot cos(u)*cos(v),cos(u)*sin(v),sin(u) notitle with lines lt 5, 'world.dat' notitle with lines lt 2, 'srl.dat' using 3:2:(1):1:4 with labels notitle point pt 6 lw .1 left offset 1,0 font "Helvetica,7" tc pal
|
||||
15
samples/Grammatical Framework/Foods.gf
Normal file
15
samples/Grammatical Framework/Foods.gf
Normal file
@@ -0,0 +1,15 @@
|
||||
-- (c) 2009 Aarne Ranta under LGPL
|
||||
|
||||
abstract Foods = {
|
||||
flags startcat = Comment ;
|
||||
cat
|
||||
Comment ; Item ; Kind ; Quality ;
|
||||
fun
|
||||
Pred : Item -> Quality -> Comment ;
|
||||
This, That, These, Those : Kind -> Item ;
|
||||
Mod : Quality -> Kind -> Kind ;
|
||||
Wine, Cheese, Fish, Pizza : Kind ;
|
||||
Very : Quality -> Quality ;
|
||||
Fresh, Warm, Italian,
|
||||
Expensive, Delicious, Boring : Quality ;
|
||||
}
|
||||
79
samples/Grammatical Framework/FoodsAfr.gf
Normal file
79
samples/Grammatical Framework/FoodsAfr.gf
Normal file
@@ -0,0 +1,79 @@
|
||||
-- (c) 2009 Laurette Pretorius Sr & Jr and Ansu Berg under LGPL
|
||||
|
||||
concrete FoodsAfr of Foods = open Prelude, Predef in{
|
||||
|
||||
flags coding=utf8;
|
||||
|
||||
lincat
|
||||
Comment = {s: Str} ;
|
||||
Kind = {s: Number => Str} ;
|
||||
Item = {s: Str ; n: Number} ;
|
||||
Quality = {s: AdjAP => Str} ;
|
||||
|
||||
lin
|
||||
Pred item quality = {s = item.s ++ "is" ++ (quality.s ! Predic)};
|
||||
This kind = {s = "hierdie" ++ (kind.s ! Sg); n = Sg};
|
||||
That kind = {s = "daardie" ++ (kind.s ! Sg); n = Sg};
|
||||
These kind = {s = "hierdie" ++ (kind.s ! Pl); n = Pl};
|
||||
Those kind = {s = "daardie" ++ (kind.s ! Pl); n = Pl};
|
||||
Mod quality kind = {s = table{n => (quality.s ! Attr) ++ (kind.s!n)}};
|
||||
|
||||
Wine = declNoun_e "wyn";
|
||||
Cheese = declNoun_aa "kaas";
|
||||
Fish = declNoun_ss "vis";
|
||||
Pizza = declNoun_s "pizza";
|
||||
|
||||
Very quality = veryAdj quality;
|
||||
|
||||
Fresh = regAdj "vars";
|
||||
Warm = regAdj "warm";
|
||||
Italian = smartAdj_e "Italiaans";
|
||||
Expensive = regAdj "duur";
|
||||
Delicious = smartAdj_e "heerlik";
|
||||
Boring = smartAdj_e "vervelig";
|
||||
|
||||
param
|
||||
AdjAP = Attr | Predic ;
|
||||
Number = Sg | Pl ;
|
||||
|
||||
oper
|
||||
--Noun operations (wyn, kaas, vis, pizza)
|
||||
|
||||
declNoun_aa: Str -> {s: Number => Str} = \x ->
|
||||
let v = tk 2 x
|
||||
in
|
||||
{s = table{Sg => x ; Pl => v + (last x) +"e"}};
|
||||
|
||||
declNoun_e: Str -> {s: Number => Str} = \x -> {s = table{Sg => x ; Pl => x + "e"}} ;
|
||||
declNoun_s: Str -> {s: Number => Str} = \x -> {s = table{Sg => x ; Pl => x + "s"}} ;
|
||||
|
||||
declNoun_ss: Str -> {s: Number => Str} = \x -> {s = table{Sg => x ; Pl => x + (last x) + "e"}} ;
|
||||
|
||||
|
||||
--Adjective operations
|
||||
|
||||
mkAdj : Str -> Str -> {s: AdjAP => Str} = \x,y -> {s = table{Attr => x; Predic => y}};
|
||||
|
||||
declAdj_e : Str -> {s : AdjAP=> Str} = \x -> mkAdj (x + "e") x;
|
||||
declAdj_g : Str -> {s : AdjAP=> Str} = \w ->
|
||||
let v = init w
|
||||
in mkAdj (v + "ë") w ;
|
||||
|
||||
declAdj_oog : Str -> {s : AdjAP=> Str} = \w ->
|
||||
let v = init w
|
||||
in
|
||||
let i = init v
|
||||
in mkAdj (i + "ë") w ;
|
||||
|
||||
regAdj : Str -> {s : AdjAP=> Str} = \x -> mkAdj x x;
|
||||
|
||||
veryAdj : {s: AdjAP => Str} -> {s : AdjAP=> Str} = \x -> {s = table{a => "baie" ++ (x.s!a)}};
|
||||
|
||||
|
||||
smartAdj_e : Str -> {s : AdjAP=> Str} = \a -> case a of
|
||||
{
|
||||
_ + "oog" => declAdj_oog a ;
|
||||
_ + ("e" | "ie" | "o" | "oe") + "g" => declAdj_g a ;
|
||||
_ => declAdj_e a
|
||||
};
|
||||
}
|
||||
21
samples/Grammatical Framework/FoodsAmh.gf
Normal file
21
samples/Grammatical Framework/FoodsAmh.gf
Normal file
@@ -0,0 +1,21 @@
|
||||
concrete FoodsAmh of Foods ={
|
||||
flags coding = utf8;
|
||||
lincat
|
||||
Comment,Item,Kind,Quality = Str;
|
||||
lin
|
||||
Pred item quality = item ++ quality++ "ነው::" ;
|
||||
This kind = "ይህ" ++ kind;
|
||||
That kind = "ያ" ++ kind;
|
||||
Mod quality kind = quality ++ kind;
|
||||
Wine = "ወይን";
|
||||
Cheese = "አይብ";
|
||||
Fish = "ዓሳ";
|
||||
Very quality = "በጣም" ++ quality;
|
||||
Fresh = "አዲስ";
|
||||
Warm = "ትኩስ";
|
||||
Italian = "የጥልያን";
|
||||
Expensive = "ውድ";
|
||||
Delicious = "ጣፋጭ";
|
||||
Boring = "አስቀያሚ";
|
||||
|
||||
}
|
||||
43
samples/Grammatical Framework/FoodsBul.gf
Normal file
43
samples/Grammatical Framework/FoodsBul.gf
Normal file
@@ -0,0 +1,43 @@
|
||||
-- (c) 2009 Krasimir Angelov under LGPL
|
||||
|
||||
concrete FoodsBul of Foods = {
|
||||
|
||||
flags
|
||||
coding = utf8;
|
||||
|
||||
param
|
||||
Gender = Masc | Fem | Neutr;
|
||||
Number = Sg | Pl;
|
||||
Agr = ASg Gender | APl ;
|
||||
|
||||
lincat
|
||||
Comment = Str ;
|
||||
Quality = {s : Agr => Str} ;
|
||||
Item = {s : Str; a : Agr} ;
|
||||
Kind = {s : Number => Str; g : Gender} ;
|
||||
|
||||
lin
|
||||
Pred item qual = item.s ++ case item.a of {ASg _ => "е"; APl => "са"} ++ qual.s ! item.a ;
|
||||
|
||||
This kind = {s=case kind.g of {Masc=>"този"; Fem=>"тази"; Neutr=>"това" } ++ kind.s ! Sg; a=ASg kind.g} ;
|
||||
That kind = {s=case kind.g of {Masc=>"онзи"; Fem=>"онази"; Neutr=>"онова"} ++ kind.s ! Sg; a=ASg kind.g} ;
|
||||
These kind = {s="тези" ++ kind.s ! Pl; a=APl} ;
|
||||
Those kind = {s="онези" ++ kind.s ! Pl; a=APl} ;
|
||||
|
||||
Mod qual kind = {s=\\n => qual.s ! (case n of {Sg => ASg kind.g; Pl => APl}) ++ kind.s ! n; g=kind.g} ;
|
||||
|
||||
Wine = {s = table {Sg => "вино"; Pl => "вина"}; g = Neutr};
|
||||
Cheese = {s = table {Sg => "сирене"; Pl => "сирена"}; g = Neutr};
|
||||
Fish = {s = table {Sg => "риба"; Pl => "риби"}; g = Fem};
|
||||
Pizza = {s = table {Sg => "пица"; Pl => "пици"}; g = Fem};
|
||||
|
||||
Very qual = {s = \\g => "много" ++ qual.s ! g};
|
||||
|
||||
Fresh = {s = table {ASg Masc => "свеж"; ASg Fem => "свежа"; ASg Neutr => "свежо"; APl => "свежи"}};
|
||||
Warm = {s = table {ASg Masc => "горещ"; ASg Fem => "гореща"; ASg Neutr => "горещо"; APl => "горещи"}};
|
||||
Italian = {s = table {ASg Masc => "италиански"; ASg Fem => "италианска"; ASg Neutr => "италианско"; APl => "италиански"}};
|
||||
Expensive = {s = table {ASg Masc => "скъп"; ASg Fem => "скъпа"; ASg Neutr => "скъпо"; APl => "скъпи"}};
|
||||
Delicious = {s = table {ASg Masc => "превъзходен"; ASg Fem => "превъзходна"; ASg Neutr => "превъзходно"; APl => "превъзходни"}};
|
||||
Boring = {s = table {ASg Masc => "еднообразен"; ASg Fem => "еднообразна"; ASg Neutr => "еднообразно"; APl => "еднообразни"}};
|
||||
|
||||
}
|
||||
7
samples/Grammatical Framework/FoodsCat.gf
Normal file
7
samples/Grammatical Framework/FoodsCat.gf
Normal file
@@ -0,0 +1,7 @@
|
||||
--# -path=.:present
|
||||
|
||||
-- (c) 2009 Jordi Saludes under LGPL
|
||||
|
||||
concrete FoodsCat of Foods = FoodsI with
|
||||
(Syntax = SyntaxCat),
|
||||
(LexFoods = LexFoodsCat) ;
|
||||
35
samples/Grammatical Framework/FoodsChi.gf
Normal file
35
samples/Grammatical Framework/FoodsChi.gf
Normal file
@@ -0,0 +1,35 @@
|
||||
concrete FoodsChi of Foods = {
|
||||
flags coding = utf8 ;
|
||||
lincat
|
||||
Comment, Item = Str ;
|
||||
Kind = {s,c : Str} ;
|
||||
Quality = {s,p : Str} ;
|
||||
lin
|
||||
Pred item quality = item ++ "是" ++ quality.s ++ quality.p ;
|
||||
This kind = "这" ++ kind.c ++ kind.s ;
|
||||
That kind = "那" ++ kind.c ++ kind.s ;
|
||||
These kind = "这" ++ "些" ++ kind.s ;
|
||||
Those kind = "那" ++ "些" ++ kind.s ;
|
||||
Mod quality kind = {
|
||||
s = quality.s ++ quality.p ++ kind.s ;
|
||||
c = kind.c
|
||||
} ;
|
||||
Wine = geKind "酒" ;
|
||||
Pizza = geKind "比 萨 饼" ;
|
||||
Cheese = geKind "奶 酪" ;
|
||||
Fish = geKind "鱼" ;
|
||||
Very quality = longQuality ("非 常" ++ quality.s) ;
|
||||
Fresh = longQuality "新 鲜" ;
|
||||
Warm = longQuality "温 热" ;
|
||||
Italian = longQuality "意 大 利 式" ;
|
||||
Expensive = longQuality "昂 贵" ;
|
||||
Delicious = longQuality "美 味" ;
|
||||
Boring = longQuality "难 吃" ;
|
||||
oper
|
||||
mkKind : Str -> Str -> {s,c : Str} = \s,c ->
|
||||
{s = s ; c = c} ;
|
||||
geKind : Str -> {s,c : Str} = \s ->
|
||||
mkKind s "个" ;
|
||||
longQuality : Str -> {s,p : Str} = \s ->
|
||||
{s = s ; p = "的"} ;
|
||||
}
|
||||
35
samples/Grammatical Framework/FoodsCze.gf
Normal file
35
samples/Grammatical Framework/FoodsCze.gf
Normal file
@@ -0,0 +1,35 @@
|
||||
-- (c) 2011 Katerina Bohmova under LGPL
|
||||
|
||||
concrete FoodsCze of Foods = open ResCze in {
|
||||
flags
|
||||
coding = utf8 ;
|
||||
lincat
|
||||
Comment = {s : Str} ;
|
||||
Quality = Adjective ;
|
||||
Kind = Noun ;
|
||||
Item = NounPhrase ;
|
||||
lin
|
||||
Pred item quality =
|
||||
{s = item.s ++ copula ! item.n ++
|
||||
quality.s ! item.g ! item.n} ;
|
||||
This = det Sg "tento" "tato" "toto" ;
|
||||
That = det Sg "tamten" "tamta" "tamto" ;
|
||||
These = det Pl "tyto" "tyto" "tato" ;
|
||||
Those = det Pl "tamty" "tamty" "tamta" ;
|
||||
Mod quality kind = {
|
||||
s = \\n => quality.s ! kind.g ! n ++ kind.s ! n ;
|
||||
g = kind.g
|
||||
} ;
|
||||
Wine = noun "víno" "vína" Neutr ;
|
||||
Cheese = noun "sýr" "sýry" Masc ;
|
||||
Fish = noun "ryba" "ryby" Fem ;
|
||||
Pizza = noun "pizza" "pizzy" Fem ;
|
||||
Very qual = {s = \\g,n => "velmi" ++ qual.s ! g ! n} ;
|
||||
Fresh = regAdj "čerstv" ;
|
||||
Warm = regAdj "tepl" ;
|
||||
Italian = regAdj "italsk" ;
|
||||
Expensive = regAdj "drah" ;
|
||||
Delicious = regnfAdj "vynikající" ;
|
||||
Boring = regAdj "nudn" ;
|
||||
}
|
||||
|
||||
58
samples/Grammatical Framework/FoodsDut.gf
Normal file
58
samples/Grammatical Framework/FoodsDut.gf
Normal file
@@ -0,0 +1,58 @@
|
||||
-- (c) 2009 Femke Johansson under LGPL
|
||||
|
||||
concrete FoodsDut of Foods = {
|
||||
|
||||
lincat
|
||||
Comment = {s : Str};
|
||||
Quality = {s : AForm => Str};
|
||||
Kind = { s : Number => Str};
|
||||
Item = {s : Str ; n : Number};
|
||||
|
||||
lin
|
||||
Pred item quality =
|
||||
{s = item.s ++ copula ! item.n ++ quality.s ! APred};
|
||||
This = det Sg "deze";
|
||||
These = det Pl "deze";
|
||||
That = det Sg "die";
|
||||
Those = det Pl "die";
|
||||
|
||||
Mod quality kind =
|
||||
{s = \\n => quality.s ! AAttr ++ kind.s ! n};
|
||||
Wine = regNoun "wijn";
|
||||
Cheese = noun "kaas" "kazen";
|
||||
Fish = noun "vis" "vissen";
|
||||
Pizza = noun "pizza" "pizza's";
|
||||
|
||||
Very a = {s = \\f => "erg" ++ a.s ! f};
|
||||
|
||||
Fresh = regadj "vers";
|
||||
Warm = regadj "warm";
|
||||
Italian = regadj "Italiaans";
|
||||
Expensive = adj "duur" "dure";
|
||||
Delicious = regadj "lekker";
|
||||
Boring = regadj "saai";
|
||||
|
||||
param
|
||||
Number = Sg | Pl;
|
||||
AForm = APred | AAttr;
|
||||
|
||||
oper
|
||||
det : Number -> Str ->
|
||||
{s : Number => Str} -> {s : Str ; n: Number} =
|
||||
\n,det,noun -> {s = det ++ noun.s ! n ; n=n};
|
||||
|
||||
noun : Str -> Str -> {s : Number => Str} =
|
||||
\man,men -> {s = table {Sg => man; Pl => men}};
|
||||
|
||||
regNoun : Str -> {s : Number => Str} =
|
||||
\wijn -> noun wijn (wijn + "en");
|
||||
|
||||
regadj : Str -> {s : AForm => Str} =
|
||||
\koud -> adj koud (koud+"e");
|
||||
|
||||
adj : Str -> Str -> {s : AForm => Str} =
|
||||
\duur, dure -> {s = table {APred => duur; AAttr => dure}};
|
||||
|
||||
copula : Number => Str =
|
||||
table {Sg => "is" ; Pl => "zijn"};
|
||||
}
|
||||
43
samples/Grammatical Framework/FoodsEng.gf
Normal file
43
samples/Grammatical Framework/FoodsEng.gf
Normal file
@@ -0,0 +1,43 @@
|
||||
-- (c) 2009 Aarne Ranta under LGPL
|
||||
|
||||
concrete FoodsEng of Foods = {
|
||||
flags language = en_US;
|
||||
lincat
|
||||
Comment, Quality = {s : Str} ;
|
||||
Kind = {s : Number => Str} ;
|
||||
Item = {s : Str ; n : Number} ;
|
||||
lin
|
||||
Pred item quality =
|
||||
{s = item.s ++ copula ! item.n ++ quality.s} ;
|
||||
This = det Sg "this" ;
|
||||
That = det Sg "that" ;
|
||||
These = det Pl "these" ;
|
||||
Those = det Pl "those" ;
|
||||
Mod quality kind =
|
||||
{s = \\n => quality.s ++ kind.s ! n} ;
|
||||
Wine = regNoun "wine" ;
|
||||
Cheese = regNoun "cheese" ;
|
||||
Fish = noun "fish" "fish" ;
|
||||
Pizza = regNoun "pizza" ;
|
||||
Very a = {s = "very" ++ a.s} ;
|
||||
Fresh = adj "fresh" ;
|
||||
Warm = adj "warm" ;
|
||||
Italian = adj "Italian" ;
|
||||
Expensive = adj "expensive" ;
|
||||
Delicious = adj "delicious" ;
|
||||
Boring = adj "boring" ;
|
||||
param
|
||||
Number = Sg | Pl ;
|
||||
oper
|
||||
det : Number -> Str ->
|
||||
{s : Number => Str} -> {s : Str ; n : Number} =
|
||||
\n,det,noun -> {s = det ++ noun.s ! n ; n = n} ;
|
||||
noun : Str -> Str -> {s : Number => Str} =
|
||||
\man,men -> {s = table {Sg => man ; Pl => men}} ;
|
||||
regNoun : Str -> {s : Number => Str} =
|
||||
\car -> noun car (car + "s") ;
|
||||
adj : Str -> {s : Str} =
|
||||
\cold -> {s = cold} ;
|
||||
copula : Number => Str =
|
||||
table {Sg => "is" ; Pl => "are"} ;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user