Compare commits

...

317 Commits

Author SHA1 Message Date
Adam Roben
32b07a4e10 Merge pull request #1694 from github/cut-release-v3.5.0
Bumping to 3.5.0
2014-11-10 14:52:55 -05:00
Adam Roben
8890c57681 Bumping to 3.5.0 2014-11-10 14:38:55 -05:00
Adam Roben
de188126fb Merge pull request #1683 from github/find-by-ext
Extract Language.find_by_extension
2014-11-10 14:37:45 -05:00
Adam Roben
97a1adcef1 Allow extensions without a leading dot
This makes the API a little easier to use.
2014-11-10 14:30:37 -05:00
Adam Roben
ffbe95d6e5 Fix docs 2014-11-10 14:15:21 -05:00
Adam Roben
d54f86ae58 Add some tests for Language.find_by_extension 2014-11-10 14:12:29 -05:00
Brandon Keepers
92ace440b9 Merge pull request #1540 from rlespinasse/golo-support
Add support for Golo language
2014-11-08 14:00:36 -05:00
Adam Roben
d5ee477d3b Merge pull request #1687 from github/shell-session-scope
Add a TextMate scope for .sh-session files
2014-11-07 15:47:35 -05:00
Adam Roben
6e8152c423 Add a TextMate scope for .sh-session files
Coming soon to Atom. See https://github.com/atom/language-shellscript/pull/3
2014-11-07 15:02:37 -05:00
Adam Roben
8149356668 Merge pull request #1678 from tenbits/master
Use MaskLexer for *.mask
2014-11-07 13:39:24 -05:00
Alex Kit
806e30d70f Use MaskLexer for *.mask 2014-11-07 19:26:37 +01:00
Adam Roben
299ec8f8ea Merge pull request #1686 from github/pytb-tm_scope
Add a TextMate scope for .pytb files
2014-11-07 12:57:36 -05:00
Adam Roben
f6fbd18bd5 Add a TextMate scope for .pytb files
This is the scope that Atom uses for these files.
See https://github.com/atom/language-python/blob/master/grammars/python-traceback.cson
2014-11-07 12:55:59 -05:00
Adam Roben
ecd30d3ccf Merge pull request #1675 from github/more-aliases
Pull in aliases and file extensions from Pygments
2014-11-07 10:31:00 -05:00
Brandon Keepers
228d89649a Add Language.find_by_extension 2014-11-07 10:27:07 -05:00
Adam Roben
751360ecf1 Make Language.[] and Language.find_by(alias|name) ignore case
This makes it easier to find a Linguist::Language for a fenced code
block in Markdown, where language names are often specified in
lowercase.
2014-11-07 10:09:55 -05:00
Adam Roben
d9ed216092 Add language aliases from Pygments
I went through all the aliases Pygments supports and removed the ones
that could already be used to find a Linguist::Language. Then I found
the Pygments::Lexer associated with each alias and found an associated
Linguist::Language for it (looking for a language with the same name as
the lexer, or by looking for the first langauge that uses that lexer).
Then I added the alias to the language's alias list.
2014-11-06 16:48:52 -05:00
Adam Roben
18a3ef9e5e Pull in file extensions from Pygments
I read all the file extensions that Pygments knows about, mapped them
back to the appropriate Linguist::Language, and added them to the
languages.yaml file.
2014-11-06 16:43:08 -05:00
Arfon Smith
e7b670c5de Merge pull request #1669 from github/support-hack
Support hack
2014-11-05 13:56:37 -06:00
Arfon Smith
114fabd29a Test for Hack heuristic 2014-11-04 16:12:46 -06:00
Arfon Smith
0946791434 Merge branch 'master' into support-hack
Conflicts:
	lib/linguist/heuristics.rb
2014-11-04 16:09:00 -06:00
Brandon Keepers
06bcdba9c4 Merge pull request #1654 from danijar/master
Exclude minified JavaScript and CSS
2014-11-03 14:20:59 -05:00
Danijar Hafner
1dbbcb73e7 Add tests for minified JavaScript and CSS
Also, exclude -min.css pattern, like already done for JavaScript files
2014-11-03 19:41:31 +01:00
Arfon Smith
f2cd75332c Merge pull request #1660 from github/1623-local
1623 local
2014-11-02 20:17:38 -06:00
Arfon Smith
2cd7579e21 Merge branch '1623-local' of github.com:github/linguist into 1623-local
Conflicts:
	lib/linguist/heuristics.rb
2014-11-02 20:14:46 -06:00
Arfon Smith
d9daae176e Merge branch 'master' into 1623-local
Conflicts:
	lib/linguist/heuristics.rb
2014-11-02 20:13:58 -06:00
Arfon Smith
20814ec533 Merge branch 'master' into 1623-local
Conflicts:
	lib/linguist/heuristics.rb
2014-11-02 20:12:59 -06:00
Arfon Smith
9d8ab16a38 Merge branch 'master' into 1623-local
Conflicts:
	lib/linguist/heuristics.rb
2014-11-02 20:11:49 -06:00
Arfon Smith
49c2793bf5 Syntax preference 2014-11-02 19:56:20 -06:00
Danijar Hafner
20aee11cea Exclude minified JavaScript and CSS
Those files are either external libraries or builds of the repository itself. In any case they are generated automatically and shouldn't count in the language statistics. This also simplifies some of the rules that had to exclude both minified and normal dependencies.
2014-11-01 19:13:19 +01:00
Arfon Smith
e8cf750e18 Merge pull request #1639 from pchaigno/asc
Heuristic rule to detect AsciiDoc files
2014-11-01 09:26:49 -05:00
Brandon Keepers
21f56744d4 Merge pull request #1608 from github/just-yajl
Use yajl since it is already a dependency
2014-10-31 18:03:28 -04:00
Brandon Keepers
02aeb4f895 Merge remote-tracking branch 'origin/master' into just-yajl
* origin/master: (42 commits)
  its always greener
  that new green shell
  Removing stale extension
  Update README.md
  Add moon interpreter for MoonScript
  Bumping version for 3.4.1 release
  Use text.html.erb scope for HTML+ERB files
  Add sample .dyalog file for file type APL
  Added extra Papyrus sample files.
  Add sample Papyrus script
  Add Papyrus support
  Add LOLCODE support
  Add ProGuard config files to vendored files
  Recognise *.dyalog as APL sources
  Assign a bunch more TextMate scopes
  CI step for samples
  Add .command as a Shell file extension
  CI config
  Vendored gems
  Update cibuild
  ...

Conflicts:
	Rakefile
2014-10-31 18:03:03 -04:00
Arfon Smith
f9de16fbd2 Merge pull request #1620 from unfunco/ant-build-dist-support
Add build.xml.dist to XML filenames
2014-10-31 16:46:49 -05:00
Brandon Keepers
abe002f30c Merge remote-tracking branch 'origin/master' into tricknotes-ruby-22
* origin/master: (51 commits)
  its always greener
  that new green shell
  Removing stale extension
  Update README.md
  Add moon interpreter for MoonScript
  Bumping version for 3.4.1 release
  Use text.html.erb scope for HTML+ERB files
  Add sample .dyalog file for file type APL
  Added extra Papyrus sample files.
  Add sample Papyrus script
  Add Papyrus support
  Add LOLCODE support
  Add ProGuard config files to vendored files
  Recognise *.dyalog as APL sources
  Assign a bunch more TextMate scopes
  CI step for samples
  Add .command as a Shell file extension
  CI config
  Vendored gems
  Update cibuild
  ...

Conflicts:
	Gemfile
2014-10-31 17:36:06 -04:00
Jessica Lord
e5ae6fb00d Merge pull request #1650 from github/greenshell
That new green shell, fixes #1640
2014-10-31 21:16:34 +00:00
Jessica Lord
a0a8dd8897 its always greener 2014-10-31 21:15:59 +00:00
Jessica Lord
e00f073726 that new green shell 2014-10-31 20:08:25 +00:00
Arfon Smith
1a9ee8e187 Merge pull request #1636 from Verteiron/master
Add support for Papyrus scripts
2014-10-30 06:24:56 -05:00
Arfon Smith
213fce00e0 Merge pull request #1646 from github/gradle-extension
Removing stale extension
2014-10-29 19:57:32 -05:00
Arfon Smith
380739b209 Removing stale extension 2014-10-29 19:56:59 -05:00
Arfon Smith
36322f8ac0 Update README.md 2014-10-29 19:38:19 -05:00
Arfon Smith
57d1ec7733 Merge pull request #1645 from pchaigno/moon-shebang
Add moon interpreter for MoonScript
2014-10-29 17:10:14 -05:00
Paul Chaignon
648c6d4547 Add moon interpreter for MoonScript 2014-10-29 15:00:21 -04:00
Arfon Smith
6ab5870b59 Merge pull request #1643 from github/linguist-3.4.1
Bumping version for 3.4.1 release
2014-10-29 13:34:41 -05:00
Arfon Smith
7dbe2bb774 Bumping version for 3.4.1 release 2014-10-29 13:13:26 -05:00
Adam Roben
163a039e0d Merge pull request #1641 from github/aroben-patch-1
Use text.html.erb scope for HTML+ERB files
2014-10-29 10:02:49 -04:00
Adam Roben
9595e2ba7e Use text.html.erb scope for HTML+ERB files
This grammar does a better job highlighting than the text.html.ruby grammar does. It requires injection grammar support, but there's no getting around that.
2014-10-29 10:00:09 -04:00
Arfon Smith
a696e3a7a2 Merge pull request #1632 from ngn/master
Recognise *.dyalog as APL sources
2014-10-27 17:38:34 +00:00
Paul Chaignon
ebabcfc84f Heuristic rule to detect AsciiDoc files 2014-10-27 10:50:18 -04:00
ngn
8336dc33e4 Add sample .dyalog file for file type APL
Taken from
https://github.com/Gianfrancoalongi/APLUnit/blob/master/UT.dyalog
2014-10-27 10:35:23 +00:00
Verteiron
5f22bf225c Added extra Papyrus sample files. 2014-10-26 15:30:40 -05:00
Verteiron
8eee8ad9cf Add sample Papyrus script
This is the metaquest script from one of my own mods.
2014-10-26 14:58:17 -05:00
Verteiron
24743985e4 Add Papyrus support
Papyrus is a scripting language used by mods/plugins for The Elder Scrolls V: Skyrim.
2014-10-26 14:53:20 -05:00
Arfon Smith
94fba197d1 Merge pull request #1634 from wil93/master
Add LOLCODE support
2014-10-26 09:06:38 +00:00
William Di Luigi
3504a36c3e Add LOLCODE support 2014-10-26 00:23:08 +02:00
Arfon Smith
c8038d1c80 Merge pull request #1633 from pchaigno/proguard
ProGuard config files as vendored
2014-10-24 22:48:11 +01:00
Paul Chaignon
8ba8b48caf Add ProGuard config files to vendored files 2014-10-24 17:18:22 -04:00
ngn
92d0c1f3b7 Recognise *.dyalog as APL sources 2014-10-24 15:55:27 +01:00
Adam Roben
d4186bd34a Merge pull request #1630 from github/even-more-tmscopes
Assign a bunch more TextMate scopes
2014-10-23 11:42:57 -07:00
Adam Roben
008ba9e23f Assign a bunch more TextMate scopes 2014-10-23 11:22:19 -07:00
Paul Chaignon
fd707ddf7e Heuristic rules to distinguish .sc files between SuperCollider and Scala 2014-10-23 14:22:12 -04:00
Arfon Smith
f258e4940d Merge branch 'master' of github.com:github/linguist 2014-10-23 12:16:26 +01:00
Arfon Smith
a7b8e38bf3 CI step for samples 2014-10-23 12:16:02 +01:00
Arfon Smith
b65129a8e1 Merge pull request #1622 from pchaigno/shell-extensions
Add .command as a Shell file extension
2014-10-23 10:54:05 +01:00
Paul Chaignon
b6a9993c97 Add .sc as a SuperCollider file extension 2014-10-22 10:16:30 -04:00
Josh Watzman
9c044c5bd0 Add detection for Hack files with ".php" file extension
Based on top of PR#1447. Adds a simple heuristic check for Hack files vs PHP files (`<?hh` vs other `<?`).

Tested by verifying that the Hack example site was detected as 100% Hack and that Laravel was detected as 100% PHP. (Without the heuristic, Laravel gets detected as about 50% Hack, just by randomness in the classifier since PHP and Hack are very hard to distinguish unless you actually parse the file and look for specific language features.)
2014-10-21 16:17:58 -07:00
Paul Chaignon
6b0783936f Add .command as a Shell file extension 2014-10-21 19:07:03 -04:00
Arfon Smith
2a66b754c2 CI config 2014-10-21 18:41:25 -04:00
Arfon Smith
460443b3c8 Merge branch 'master' of github.com:github/linguist 2014-10-21 18:40:53 -04:00
Arfon Smith
cd99ab2d6e Vendored gems 2014-10-21 18:40:43 -04:00
Josh Watzman
b2cb74cabf Add detection for Hack files with ".hh" file extension
Hack is Facebook's dialect of PHP: http://hacklang.org/. This adds support for detecting it via the ".hh" file extension; although that extension techincally conflicts with C++ headers, the files look different enough that the existing classifier based on sample code has no trouble distinguising them.

This diff deliberately does not deal with detecting ".php" as another valid extension for Hack code. That's much trickier since the code looks basically identical to PHP to the classifier, and needs a different approach.
2014-10-21 15:35:57 -07:00
Arfon Smith
6d07302963 Update cibuild 2014-10-21 16:49:13 -05:00
Arfon Smith
d831205f6a Update cibuild 2014-10-21 16:41:55 -05:00
Arfon Smith
a9b9e6216b Update cibuild 2014-10-21 16:10:05 -05:00
Arfon Smith
3ba090de7e Update cibuild 2014-10-21 16:07:49 -05:00
Arfon Smith
c105208481 Update cibuild 2014-10-21 14:06:43 -05:00
Arfon Smith
0c9e14eeff Update cibuild 2014-10-21 14:06:13 -05:00
Arfon Smith
2a8a5cdca9 +x 2014-10-21 14:04:52 -05:00
Arfon Smith
1f91acbd9d Janky CI 2014-10-21 14:03:30 -05:00
Daniel Morris
6f8278aa79 Add build.xml.dist to XML filenames 2014-10-21 10:21:39 +01:00
Arfon Smith
3e48a84cf1 Merge pull request #1612 from briandela/patch-1
Add hbs alias for Handlebars
2014-10-20 10:29:04 -05:00
Arfon Smith
31728a3a78 Merge pull request #1613 from hearsilent/patch-1
Add .a51 to Assembly
2014-10-20 10:21:24 -05:00
Arfon Smith
e56a2ed6ad Merge pull request #1614 from creasty/viml_underscore_vimrc
Add a filename rule for _vimrc
2014-10-19 16:45:42 -05:00
HearSilent
35aa57657b Add .a51 sample 2014-10-20 05:16:51 +08:00
Yuki Iwanaga
423c8865bd Add a filename rule for _vimrc 2014-10-20 00:39:26 +09:00
HearSilent
55ecc5f7eb Add .a51 to Assembly
.a51 doc is 8051-asm (coding in MIDE-51)
2014-10-19 17:32:41 +08:00
Brian Delahunty
6aae7882df Update indenentation 2014-10-18 18:03:27 -07:00
Brian Delahunty
240fcec3ce Add hbs alias for Handlebars
Adds a `hbs` alias for `Handlebars`. It's very commonly used and would make adding hbs code blocks easier in github comments.
2014-10-18 11:13:12 -07:00
Arfon Smith
170c1d4ee8 Merge pull request #1584 from laomaiweng/linguist-detect-tcl-shebang
Shebang detection for Tcl/Tk scripts
2014-10-17 14:32:13 -05:00
Arfon Smith
38f0a71ea3 Merge pull request #1596 from pchaigno/fcgi
Add .fcgi as an extension for script languages
2014-10-17 14:30:40 -05:00
Arfon Smith
62936dc6b5 Merge pull request #1609 from github/bundler-rakefile
Require "bundler/setup" in rakefile
2014-10-17 14:27:39 -05:00
Arfon Smith
fb9c784f4f Merge pull request #1611 from github/rugged-gemspec
twiddle-wakka
2014-10-17 14:27:24 -05:00
Arfon Smith
89477ed2fa twiddle-wakka 2014-10-17 14:20:32 -05:00
Arfon Smith
844679dcbe Merge pull request #1610 from github/rugged-gemspec
Moving Rugged dependency back to gemspec
2014-10-17 14:07:47 -05:00
Brandon Keepers
cd743332f4 Use yajl since it is already a dependency
Both JSON and Yajl were listed as dependencies. Pygments.rb already requires yajl, so let's just use that instead of using both.
2014-10-17 14:45:28 -04:00
Arfon Smith
47843e7e78 Moving Rugged dependency back to gemspec 2014-10-17 13:36:13 -05:00
Brandon Keepers
85957ecf56 Require "bundler/setup" in rakefile
This ensures that the Rake task will use bundler to manage dependencies and print a warning to run `bundle install` if dependencies are missing.
2014-10-17 14:14:27 -04:00
Arfon Smith
4232b04571 Merge pull request #1602 from github/gitattribute-docs
Docs update
2014-10-17 08:20:03 -05:00
Arfon Smith
34f717526a Merge pull request #1605 from github/bkeepers/gitattribute-docs
Suggested cuts for .gitattribute docs
2014-10-17 08:19:04 -05:00
Brandon Keepers
b0b94182a2 ✂️ 2014-10-17 09:15:00 -04:00
Arfon Smith
843e196f00 Formatting 2014-10-16 20:56:21 -05:00
Arfon Smith
63661dfc6e Docs update 2014-10-16 16:33:49 -05:00
Arfon Smith
f100dc91c2 Merge pull request #1588 from github/cache-bustin
Bust that cache
2014-10-16 14:21:33 -05:00
Arfon Smith
fd9d63d605 Removing beta label 2014-10-16 14:05:36 -05:00
Arfon Smith
5c21c35875 Merge branch 'master' into cache-bustin 2014-10-16 12:59:41 -05:00
Arfon Smith
370d55fd74 Merge pull request #1595 from github/text-html-ruby
Use TextMate 1 scope for HTML+ERB files
2014-10-15 17:05:08 -05:00
Paul Chaignon
0fcc26f778 Add .fcgi as an extension for script languages 2014-10-15 10:37:58 -04:00
Arfon Smith
8dd2ddcbf7 CI 2014-10-14 20:18:32 -05:00
Arfon Smith
037857623d Merge branch 'master' into cache-bustin
Conflicts:
	lib/linguist/version.rb
2014-10-14 19:45:09 -05:00
Arfon Smith
d7b19d577b Bumping version 2014-10-14 19:44:35 -05:00
Adam Roben
c70048a3e2 Use TextMate 1 scope for HTML+ERB files
The TextMate 2 scope requires support for injection grammars, which some parsers don't support.
2014-10-14 14:19:05 -04:00
Ryunosuke SATO
a1884ca261 Run test against Ruby 2.2 on Travis CI 2014-10-15 00:54:00 +09:00
Ryunosuke SATO
e452291314 Run test against latest Ruby 2.1 on Travis CI
see: https://twitter.com/travisci/status/513233940442644480
2014-10-15 00:53:57 +09:00
Arfon Smith
6d51117a91 Merge pull request #1593 from github/more-tmscopes
Add more TextMate scopes
2014-10-14 10:06:47 -05:00
Arfon Smith
848a1cc1e5 Minor bump 2014-10-14 10:06:38 -05:00
Adam Roben
9092dfdc7f Add a TextMate scope for Literate CoffeeScript 2014-10-14 10:50:39 -04:00
Adam Roben
d7fe0cc5c7 Add TextMate scopes for HTML variants 2014-10-14 10:41:19 -04:00
Adam Roben
15ec37d4bc Add a TextMate scope for Objective-C++ 2014-10-14 10:41:19 -04:00
Adam Roben
43cc701ac3 Add a TextMate scope for JSON 2014-10-14 10:41:19 -04:00
Adam Roben
7cb8357f73 Add a TextMate scope for YAML 2014-10-14 10:41:19 -04:00
Adam Roben
4b46bcf649 Add TextMate scopes for Sass/SCSS files 2014-10-14 10:41:19 -04:00
Arfon Smith
a954a6465e Update README.md 2014-10-14 09:29:45 -05:00
Arfon Smith
afb6041104 Merge pull request #1592 from github/vmg/tmscopes
Vmg/tmscopes
2014-10-14 09:07:02 -05:00
Arfon Smith
4b28fdbc4d Removing beta label 2014-10-14 08:45:49 -05:00
Arfon Smith
b8a5e8505a Merge branch 'vmg/tmscopes' into cache-bustin
Conflicts:
	lib/linguist/version.rb
2014-10-13 20:21:31 -05:00
Arfon Smith
3087d640a3 3.2.2b1 2014-10-13 19:33:03 -05:00
Arfon Smith
e87b89ab5b Removing todo 2014-10-13 18:52:27 -05:00
Arfon Smith
7aabc6a5ad A different approach 2014-10-13 17:01:53 -05:00
Arfon Smith
5cc053694a Remove pry 2014-10-13 16:38:51 -05:00
Arfon Smith
653314448c Bust that cache 2014-10-13 16:37:46 -05:00
Arfon Smith
4f14db10ea Merge pull request #933 from pchaigno/pro
Support of the .pro file extension for Prolog.
2014-10-13 14:57:19 -05:00
Arfon Smith
98e348ba5f Minor docs update fixes #1581 2014-10-13 14:48:50 -05:00
Arfon Smith
a69b20c1a4 Minor docs update #fixes 1581 2014-10-13 14:48:04 -05:00
Vicent Marti
9275e5240f Bump version 2014-10-13 17:50:57 +02:00
Vicent Marti
7dcc3b3edf Add tm_scope to the BlobHelper 2014-10-13 17:19:38 +02:00
Vicent Marti
6e872c11b6 Pass tm_scope overrides 2014-10-13 17:19:38 +02:00
Vicent Marti
e5b6001759 Add support for TextMate scopes 2014-10-13 17:19:38 +02:00
Arfon Smith
769f1b8658 Merge pull request #1587 from github/linguist-3.2.1
Linguist v3.2.1
2014-10-13 09:47:52 -05:00
Arfon Smith
5814b61356 Linguist v3.2.1 2014-10-13 09:47:02 -05:00
Arfon Smith
8a6d7f67ed Merge pull request #1517 from github/1515-local
3.2.0b3 gem / cc @vmg
2014-10-13 09:40:14 -05:00
Arfon Smith
bcb016a938 Removing beta label 2014-10-13 09:30:09 -05:00
Arfon Smith
065c6c02a8 Merge branch '1515-local' of github.com:github/linguist into 1515-local 2014-10-13 09:10:21 -05:00
Arfon Smith
f7386fcd72 Rugged bump 2014-10-13 09:10:08 -05:00
Arfon Smith
df703ef997 Rugged bump 2014-10-13 09:09:33 -05:00
Arfon Smith
9f6c421d91 Merge pull request #1586 from github/revert-1515-vmg/attributes
Revert "Load Git Attributes for Linguist-specific overrides"
2014-10-13 09:03:36 -05:00
Arfon Smith
91370ae955 Revert "Load Git Attributes for Linguist-specific overrides" 2014-10-13 08:58:53 -05:00
Arfon Smith
ffc0be191e Removing beta label 2014-10-13 08:42:46 -05:00
Vicent Marti
6e9f6da2a2 Merge pull request #1515 from github/vmg/attributes
Load Git Attributes for Linguist-specific overrides
2014-10-13 15:13:22 +02:00
quentin
48f2949d69 Move the extension-less sample scripts in a filenames/ subdir 2014-10-13 10:09:07 +02:00
quentin
baa3cba0fc Add sample Tcl/Tk scripts to test Tcl/Tk shebang detection
Scripts taken from:
* starfield: http://wiki.tcl.tk/14140
* owh: http://wiki.tcl.tk/906
2014-10-13 03:05:56 +02:00
quentin
eb54a92328 Add Tcl/Tk interpreters to languages.yml for shebang detection 2014-10-13 02:38:07 +02:00
Romain Lespinasse
ce1e2441f4 Choose a color from the Golo logo 2014-10-11 10:27:06 +02:00
Arfon Smith
c8cb7b7cab Git attr 2014-10-10 15:34:03 -05:00
Arfon Smith
7baa130d8d Merge branch 'master' into 1515-local 2014-10-10 15:32:28 -05:00
Arfon Smith
332d97b57f Removing generated override for now. 2014-10-10 15:32:08 -05:00
Ted Nyman
9c0dbdd48e Merge pull request #1575 from Jaxan/clean-samples
Adds samples for the clean programming language
2014-10-10 12:52:30 -07:00
Joshua Moerman
bec0052065 Adds samples for the clean programming language 2014-10-05 12:55:00 +02:00
Arfon Smith
5010f32421 Merge pull request #1570 from lucaswerkmeister/patch-1
Update Ceylon sample file
2014-10-02 17:06:30 -07:00
Lucas Werkmeister
ded4672ccc Update Ceylon sample file
See ceylon/ceylon-spec#585 for the new annotation syntax and ceylon/ceylon-spec#574 for the new string interpolation syntax.
2014-10-02 12:10:11 +02:00
Arfon Smith
03bb48cf28 Version bump 2014-09-30 08:42:08 -05:00
Arfon Smith
e71eefe8fc Merge branch 'master' into 1515-local 2014-09-30 08:38:26 -05:00
Arfon Smith
c203781e1b Merge pull request #1557 from larsbrinkhoff/frt
Only Forth uses .frt
2014-09-30 08:22:34 -05:00
Lars Brinkhoff
7a2be16d77 Add .frt samples for Forth. 2014-09-30 07:03:58 +02:00
Arfon Smith
77126e9e17 Removing fixture file 2014-09-29 16:28:23 -05:00
Arfon Smith
d1d5c61df5 Updating ref for gitattribute testing 2014-09-29 16:27:20 -05:00
Arfon Smith
09323c8bbc Version bump 2014-09-29 15:28:00 -05:00
Arfon Smith
ac9f82544a Merge pull request #1555 from github/vendored-ignored-gitattributes
Vendored ignored gitattributes
2014-09-29 15:24:30 -05:00
Arfon Smith
2e4e602787 Housekeeping 2014-09-29 15:20:11 -05:00
Arfon Smith
9d0ba5801b Reverting b0db064d09 now we have a better way to test these attributes 2014-09-29 15:11:44 -05:00
Arfon Smith
0cd7d85ec4 Using .gitattributes from test branch 2014-09-29 15:10:01 -05:00
Arfon Smith
b0f674e511 Merge pull request #1563 from github/bkeepers/vendored-ignored-gitattributes
A few tweaks to ignored methods
2014-09-29 14:26:27 -05:00
Brandon Keepers
2b411aad90 Extract #read_index for tests 2014-09-29 15:04:48 -04:00
Brandon Keepers
1c6483a499 Simplify boolean attribute handling 2014-09-29 14:13:44 -04:00
Brandon Keepers
6edf4498ce Move overridden_language to just #language 2014-09-29 14:12:36 -04:00
Brandon Keepers
b160a39678 Remove linguist_* prefix from vendored? and generated? 2014-09-29 13:48:40 -04:00
Lars Brinkhoff
86b4de89bd Only Forth uses .frt. 2014-09-27 06:10:19 +02:00
Brandon Keepers
a35d9a8d29 Merge pull request #1561 from pchaigno/graph-ml
Support for Graph Modeling Language
2014-09-26 14:34:39 -07:00
Paul Chaignon
8012876d5e Support for Graph Modeling Language 2014-09-26 10:43:35 -04:00
Arfon Smith
2e3e8c5b89 Removing pry 2014-09-25 13:55:14 -05:00
Arfon Smith
5284608942 Stubbing git attributes (for now) 2014-09-25 13:48:03 -05:00
Arfon Smith
ea2c7d8b27 Testing 2014-09-25 13:11:43 -05:00
Arfon Smith
b0db064d09 Updating .gitattributes for real usage 2014-09-25 12:57:21 -05:00
Arfon Smith
3ff1e38f6c Adding support for overriding configurations in vendor.yml and generated? 2014-09-25 12:50:42 -05:00
Arfon Smith
b533b682d5 Test files for .gitattributes 2014-09-25 12:13:55 -05:00
Paul Chaignon
f59cf24a82 Merge branch 'master' into pro 2014-09-25 10:23:21 -04:00
Arfon Smith
f87436d499 Adding linguist_vendored? and linguist_generated? to include overrides from .gitattributes 2014-09-24 19:57:30 -05:00
Arfon Smith
178d4756ef Changing up .gitattributes keys for testing 2014-09-24 19:25:05 -05:00
Arfon Smith
5152bd7124 Merge pull request #1547 from bwestlin/master
Added files generated by Typesafe Activator to vendor.yml
2014-09-24 17:04:16 -05:00
Arfon Smith
b5015b6cc7 Merge pull request #1554 from github/1267-local
1267 local
2014-09-24 16:50:55 -05:00
Arfon Smith
097900a327 Merge pull request #1553 from github/1372-local
1372 local
2014-09-24 16:45:39 -05:00
Arfon Smith
1d2a6c38c7 Merge branch 'master' into 1267-local
Conflicts:
	lib/linguist/samples.json
2014-09-24 16:43:42 -05:00
Arfon Smith
cc87ceb0d5 Merge branch 'master' into 1372-local
Conflicts:
	lib/linguist/samples.json
2014-09-24 16:38:07 -05:00
Arfon Smith
a38f77683b Merge pull request #1552 from github/benchmarking
Benchmarking
2014-09-24 16:13:53 -05:00
Arfon Smith
d8da05cde2 Merge pull request #1522 from github/cl-heuristics
Heuristics on for .cl
2014-09-24 10:58:40 -05:00
Arfon Smith
554b5bfe7f Merge pull request #1549 from kr/godep
Treat Go dependency tree as generated and vendored code
2014-09-24 10:56:41 -05:00
Keith Rarick
86aa4c3f3d Add Go dependencies to generated.rb and test_blob.rb 2014-09-22 01:12:46 -07:00
Keith Rarick
19b8721225 Add Go dependencies to vendor.yml and test_blob.rb 2014-09-22 00:58:56 -07:00
Arfon Smith
0cb1ebc41e Merge pull request #1546 from vivekgalatage/master
Adding JavaScript syntax support for JavaScriptBuild (.jsb) files
2014-09-21 21:44:03 -05:00
Björn Westlin
c7c4883f49 Added files generated by Typesafe Activator to vendor.yml 2014-09-21 22:08:12 +02:00
Vivek Galatage
d8b4d4639c Sample JSBuild file showing the usage javascript as scripting language. 2014-09-22 00:15:35 +05:30
Vivek Galatage
ebe45e6f37 Adding JavaScript syntax support for JavaScriptBuild (.jsb) files
jsb is a meta build system [1] which can generate actual build files for GNU make, ninja, visual studio etc.

These files are pure javascript files. Just to differentiate them from rest of the javascript files, these are marked as .jsb file.

[1] https://github.com/vivekgalatage/jsb
2014-09-21 10:27:54 +05:30
Arfon Smith
cb016f8439 Merge pull request #1545 from larsbrinkhoff/groff
Add Groff sample.
2014-09-20 13:58:18 -05:00
Lars Brinkhoff
92212d2652 Add Groff sample. 2014-09-19 13:51:19 +02:00
Arfon Smith
950882be78 Merge pull request #1537 from github/drop-samples.json
Ignore samples.json
2014-09-18 14:30:15 -05:00
Arfon Smith
036855072e Merge branch 'master' into drop-samples.json
Conflicts:
	.travis.yml
2014-09-18 14:29:54 -05:00
Arfon Smith
29bbf50900 Merge pull request #1542 from github/travis-updates
Cleaning up travis.yml
2014-09-18 14:26:23 -05:00
Arfon Smith
ca59303dba Preferred syntax 2014-09-18 14:25:36 -05:00
Arfon Smith
e21f35039b Is this still needed? 2014-09-18 14:11:08 -05:00
Arfon Smith
f2b377fae8 Removing unnecessary Travis build step 2014-09-18 14:07:14 -05:00
Arfon Smith
24a36bf4bb Removing docs about generating samples 2014-09-18 14:06:11 -05:00
Arfon Smith
3284450dc4 Make sure samples.json is present before running tests 2014-09-18 13:56:41 -05:00
Arfon Smith
ea9d326819 Merge branch 'master' into drop-samples.json 2014-09-18 13:50:53 -05:00
Arfon Smith
4cc679c1e5 Merge branch 'master' into 1515-local 2014-09-17 09:54:45 -05:00
Arfon Smith
c49ce55714 Bumping Rugged 2014-09-17 09:54:41 -05:00
The rugged tests are fragile
9d4b5416a5 Bump Rugged 2014-09-17 15:48:14 +02:00
Romain Lespinasse
5a59ecbc2a Add support for Golo language 2014-09-17 13:59:02 +02:00
Arfon Smith
82285df54b Merge pull request #1536 from pchaigno/apex-lexer
Use Java lexer for Apex
2014-09-16 16:46:50 -05:00
Brandon Keepers
e67c1789b8 Generate samples.json before building gem 2014-09-16 10:26:35 -04:00
Brandon Keepers
015af19eaf Move Samples::DATA constant to Samples.cache method 2014-09-16 10:25:30 -04:00
Brandon Keepers
156985ed52 Remove samples.json from version control 2014-09-16 10:24:05 -04:00
Paul Chaignon
71d1bd75c0 Use Java lexer for Apex 2014-09-15 16:10:36 -04:00
Arfon Smith
8e7c9c4bc4 Merge pull request #1524 from ankitr/patch-1
Changes C# to proposed color in #1332
2014-09-15 14:07:46 -05:00
Arfon Smith
7b7236fe30 Merge pull request #1534 from github/1530-local
1530 local
2014-09-15 14:00:49 -05:00
Arfon Smith
55d997f43a Merge branch 'master' into 1530-local
Conflicts:
	lib/linguist/samples.json
2014-09-15 13:48:22 -05:00
Arfon Smith
1829b38339 Merge pull request #1529 from fingolfin/godot
Add support for the GDScript language
2014-09-15 13:44:23 -05:00
Arfon Smith
e4c28e12cf Merge pull request #1533 from github/travis-samples
Generate samples before build
2014-09-15 13:22:43 -05:00
Arfon Smith
066cf45f4a Merge pull request #1525 from fingolfin/typos
Fix typos
2014-09-15 13:21:26 -05:00
Arfon Smith
ac32b09a6b Generate samples before build 2014-09-15 13:17:38 -05:00
Arfon Smith
92296f4b4b Merge pull request #1520 from pmoura/master
Use the Logtalk lexer for syntax coloring of Prolog files
2014-09-15 09:10:46 -05:00
Max Horn
3b4d2499eb Update samples.json 2014-09-15 15:02:25 +02:00
Max Horn
f38e15790e Update samples.json 2014-09-15 15:01:46 +02:00
Max Horn
b67c2bc2b2 Add support for G-code language
This is a special language controlling 3D printers (by RepRap, Makerbot,
Ultimaker etc.). It is not a general purpose programming language, but
still contains commands for e.g. looping. On the other hand, most of the
time it will be generated by another program, not hand-written. Hence I
classified it as "data".

Specification:
* http://reprap.org/wiki/G-code

Some repositories with examples:
* https://github.com/reprappro/Mendel
* https://github.com/BLLIP/bllip-parser
* https://github.com/MakerGear/M2
2014-09-15 14:59:40 +02:00
Max Horn
393c9b759e Add support for the GDScript language
References:
* https://github.com/okamstudio/godot/wiki/gdscript
* http://www.godotengine.org/

Some projects using it:
* https://github.com/okamstudio/godot
* https://github.com/Qwertie-/Godot-games

My motivation for adding it: To disambiguate these .gd
files from GAP .gd files.
2014-09-15 14:31:58 +02:00
Max Horn
54a7cf6785 Fix typos 2014-09-15 13:24:39 +02:00
Ankit Ranjan
1cf7a6389c Changes C# to proposed color in #1332 2014-09-13 12:00:30 -07:00
Arfon Smith
c204d7c297 Merge pull request #1403 from github/benchmarking
Benchmarking
2014-09-13 13:41:09 -05:00
Arfon Smith
5932f5f273 Allow for result to be generated when there are un-committed changes. 2014-09-13 11:06:15 -05:00
Arfon Smith
98977c87db Heuristics on for .cl 2014-09-12 16:34:51 -05:00
Paulo Moura
ff457af2d4 Use the Logtalk lexer for syntax coloring of Prolog files 2014-09-12 20:49:54 +01:00
Arfon Smith
0e86ab9044 Version beta bump and some notes 2014-09-11 15:05:36 -05:00
Vicent Marti
3d39e842ec Load Git Attributes for Linguist-specific overrides 2014-09-11 13:51:07 +02:00
The rugged tests are fragile
16c1aa2845 Fetch the attributes test branch in Travis 2014-09-11 13:51:07 +02:00
The rugged tests are fragile
d0cf883558 Use rugged 0.21.1b0 2014-09-11 13:51:06 +02:00
Arfon Smith
64e4830aad Merge branch 'benchmarking' of github.com:github/linguist into benchmarking 2014-09-10 17:07:01 -05:00
Arfon Smith
0c47f2af75 Merge branch 'master' into benchmarking
Conflicts:
	lib/linguist/heuristics.rb
	lib/linguist/languages.yml
2014-09-10 17:06:48 -05:00
Arfon Smith
14c5d8c95a Merge pull request #1516 from github/benchmarking-2
Tweaks to benchmarking stuff
2014-09-10 17:00:55 -05:00
Brandon Keepers
6850499056 Remove git dependency 2014-09-10 15:49:59 -05:00
Brandon Keepers
9288f784a1 remove hash extension 2014-09-10 15:49:54 -05:00
Brandon Keepers
dab75f6f97 Rework benchmarking script to avoid git operations
$ git checkout master
    $ bundle exec rake benchmark:generate CORPUS=~/Downloads/samples-9
    wrote benchmark/results/samples-9-8cdb8ed4.json

    $ git checkout branch-name
    $ bx rake benchmark:generate CORPUS=~/Downloads/samples-9

    wrote benchmark/results/samples-9-8d8020dd.json

    $ bx rake benchmark:compare
REFERENCE=benchmark/results/samples-9-8cdb8ed4.json
CANDIDATE=benchmark/results/samples-9-8d8020dd.json
    LanguageA changed from 95.9% to 0.0%
    LanguageB changed from 4.0% to 99.9%
2014-09-10 15:47:44 -05:00
Arfon Smith
4a017d9033 Merge pull request #1509 from github/cut-release-v3.1.5
3.1.5
2014-09-05 13:58:58 -05:00
Arfon Smith
6f896d988f 3.1.5 2014-09-05 13:24:39 -05:00
Arfon Smith
35a9d241fc Samples 2014-09-05 13:23:10 -05:00
Arfon Smith
9ba0a7db64 Merge pull request #1506 from pchaigno/cgi-scripts
Add .cgi as an extension for Python and Bash
2014-09-05 13:21:33 -05:00
Arfon Smith
9968503872 Merge pull request #1508 from github/prolog-script
Scripty Prolog
2014-09-05 13:17:48 -05:00
Arfon Smith
34218c5f58 Scripty Prolog 2014-09-05 13:00:19 -05:00
Arfon Smith
ebd41f1f20 Merge pull request #1507 from github/cut-release-v3.1.4
3.1.4
2014-09-05 11:25:36 -05:00
Paul Chaignon
2dfb864e4e Add .cgi as an extension for Python and Bash 2014-09-04 20:32:45 -04:00
Arfon Smith
8cdb8ed48d Heuristics on and a bad commit for C++ 2014-08-06 19:31:52 +01:00
Arfon Smith
417bf7e1c9 Reworking Rake tasks 2014-08-06 19:21:20 +01:00
Arfon Smith
149f8967ad Fixing up bin/linguist 2014-07-23 11:41:50 -05:00
Arfon Smith
e376fe921b Skipping Text and Binary dirs 2014-07-23 11:30:25 -05:00
Arfon Smith
8d8020ddb5 Merge branch 'master' into benchmarking
Conflicts:
	lib/linguist/version.rb
2014-07-23 11:01:16 -05:00
Arfon Smith
7d13b9eb99 Formatting 2014-07-23 10:59:10 -05:00
Arfon Smith
6ed0a05b44 Reporting errors in classifications 2014-07-23 10:49:29 -05:00
Arfon Smith
c4c479578a Heuristics off 2014-07-23 10:37:50 -05:00
Arfon Smith
441caa91dd Samples 2014-07-23 10:34:03 -05:00
Arfon Smith
20154eb049 Rework diff slightly 2014-07-23 10:30:54 -05:00
Arfon Smith
84ea710d42 Moving linguist detection into rake task and ignoring diff for now. 2014-07-23 10:30:53 -05:00
Arfon Smith
8d524d618e Toy example 2014-07-23 10:30:53 -05:00
Arfon Smith
9fa34ab1fe Fixing BlobHelper loading issue 2014-07-23 10:30:53 -05:00
Arfon Smith
47db1cf1ac Explictly load FileBlob 2014-07-23 10:30:53 -05:00
Arfon Smith
f2f9b70659 Fixing broken test 2014-07-23 10:30:53 -05:00
Josh Abernathy
61c93ab08c pbproj's are cool too. 2014-07-23 10:30:53 -05:00
Josh Abernathy
d72f3fae33 Actually let's keep those. 2014-07-23 10:30:53 -05:00
Josh Abernathy
3f14d15722 Most Xcode files have a human-readable diff now! 2014-07-23 10:30:53 -05:00
Arfon Smith
963c0b46a0 Modifying Mirah search terms 2014-07-23 10:30:53 -05:00
Arfon Smith
66b4977a67 Linguist v3.0.4 2014-07-23 10:30:53 -05:00
Arfon Smith
126c2147e9 Checking all files for binary? 2014-07-23 10:30:43 -05:00
Paul Chaignon
f7c42a4e6a Rename file for the test on non-existing extension 2014-07-23 10:30:43 -05:00
Paul Chaignon
b1ea1fd96f Remove stylistic yet useless parentheses 2014-07-23 10:30:38 -05:00
Paul Chaignon
a5475bf839 Sample files to test the new FileBlob.extension method 2014-07-23 10:30:01 -05:00
Paul Chaignon
be9e187cc6 Remove .rb test 2014-07-23 10:29:31 -05:00
Paul Chaignon
d5098c6f66 Custom File.extname method which returns the filename if it is an extension 2014-07-23 10:29:22 -05:00
Arfon Smith
41fc785330 Kicking the tyres 2014-07-23 10:26:23 -05:00
Arfon Smith
4d83bf34f3 Ditching IO 2014-07-23 10:26:23 -05:00
Arfon Smith
3a797e2583 Formatting 2014-07-23 10:26:23 -05:00
Arfon Smith
7802030a53 Counting changes 2014-07-23 10:26:22 -05:00
Arfon Smith
e8e1e0ca23 Abort unless files exist 2014-07-23 10:26:22 -05:00
Arfon Smith
973431be40 Breaking comparsion step out into separate task 2014-07-23 10:26:22 -05:00
Arfon Smith
24fb5a8e29 3.0.3 release 2014-07-23 10:26:22 -05:00
Arfon Smith
37d161c290 Removing second binary? check 2014-07-23 10:26:22 -05:00
Arfon Smith
ddefa5f9e6 Ask Charlock earlier 2014-07-23 10:26:22 -05:00
Arfon Smith
955dd3d4d5 Adding test for Normalize.css 2014-07-23 10:26:22 -05:00
Arthur Verschaeve
d125205564 Update vendor.yml: normalize.css
Added popular CSS reset Normalize.css (http://necolas.github.io/normalize.css/)
2014-07-23 10:26:22 -05:00
Arfon Smith
7fa1b52497 Benchmark dir 2014-07-23 10:26:22 -05:00
Arfon Smith
a90d21899a Shellwords 2014-07-23 10:26:22 -05:00
Arfon Smith
569058f481 test on all 2014-07-23 10:26:22 -05:00
Arfon Smith
4ecda08f1f Prettier print 2014-07-23 10:26:21 -05:00
Arfon Smith
3b23059c09 Prettier print 2014-07-23 10:26:21 -05:00
Arfon Smith
a474ffc101 Deep diffing 2014-07-23 10:26:21 -05:00
Arfon Smith
f7672b837a Building language indexes 2014-07-23 10:26:21 -05:00
Arfon Smith
5235871fd8 Pry for development. 2014-07-23 10:26:21 -05:00
Arfon Smith
cac9873e20 Ignoring benchmark files 2014-07-23 10:26:21 -05:00
Arfon Smith
9094923de9 Debug statements 2014-07-23 10:26:21 -05:00
Arfon Smith
6454c96e6a Abort 2014-07-23 10:26:21 -05:00
Arfon Smith
7fbb9edc0f Gem deps 2014-07-23 10:26:21 -05:00
Arfon Smith
0a717f5c81 Gem 2014-07-23 10:26:21 -05:00
Arfon Smith
dab9777621 Branches 2014-07-23 10:26:20 -05:00
Arfon Smith
c8d1e9def1 Testing Pods 2014-07-23 10:26:20 -05:00
Josh Oldenburg
272dd45a43 Ignore everything in the Pods directory. 2014-07-23 10:26:20 -05:00
Josh Oldenburg
5abec96df7 Only ignore Pods/ for CocoaPods. 2014-07-23 10:26:20 -05:00
Josh Oldenburg
e860f961a9 Ignore files related to Cocoapods.
These include Podfile, Podfile.lock, and Pods/.
2014-07-23 10:26:20 -05:00
Paul Chaignon
c4b876472f Rename Groovy sample file with a .gradle extension 2014-07-09 23:23:21 +02:00
Paul Chaignon
5580f39df2 Support of the .pp extension for Pascal 2014-06-10 15:40:26 +02:00
Paul Chaignon
d94bffb198 Merge branch 'master' of https://github.com/github/linguist into pro 2014-02-21 16:49:46 +01:00
Paul Chaignon
2beb450df6 Support of the .pro file extension for Prolog. 2014-02-10 18:10:20 +01:00
149 changed files with 63087 additions and 73588 deletions

0
.gitattributes vendored Normal file
View File

3
.gitignore vendored
View File

@@ -1,3 +1,4 @@
Gemfile.lock
.bundle/
vendor/
benchmark/
lib/linguist/samples.json

View File

@@ -1,11 +1,12 @@
before_install:
before_install:
- git fetch origin master:master
- git fetch origin v2.0.0:v2.0.0
- git fetch origin test/attributes:test/attributes
- sudo apt-get install libicu-dev -y
- gem update --system 2.1.11
rvm:
- 1.9.3
- 2.0.0
- 2.1.1
- 2.1
- 2.2
notifications:
disabled: true

View File

@@ -1,2 +1,3 @@
source 'https://rubygems.org'
gemspec
gem 'test-unit', require: false if RUBY_VERSION >= '2.2'

View File

@@ -32,33 +32,57 @@ The Language stats bar that you see on every repository is built by aggregating
The repository stats API, accessed through `#languages`, can be used on a directory:
***API UPDATE***
Since [Version 3.0.0](https://github.com/github/linguist/releases/tag/v3.0.0) Linguist expects a git repository (in the form of a [Rugged::Repository](https://github.com/libgit2/rugged#repositories)) to be passed when initializing `Linguist::Repository`.
```ruby
project = Linguist::Repository.from_directory(".")
project.language.name #=> "Ruby"
project.languages #=> { "Ruby" => 0.98, "Shell" => 0.02 }
require 'rugged'
require 'linguist'
repo = Rugged::Repository.new('.')
project = Linguist::Repository.new(repo, repo.head.target_id)
project.language #=> "Ruby"
project.languages #=> { "Ruby" => 119387 }
```
These stats are also printed out by the `linguist` binary. You can use the
`--breakdown` flag, and the binary will also output the breakdown of files by language.
You can try running `linguist` on the `lib/` directory in this repository itself:
You can try running `linguist` on the root directory in this repository itself:
$ bundle exec linguist lib/ --breakdown
$ bundle exec linguist --breakdown
100.00% Ruby
Ruby:
linguist/blob_helper.rb
linguist/classifier.rb
linguist/file_blob.rb
linguist/generated.rb
linguist/heuristics.rb
linguist/language.rb
linguist/md5.rb
linguist/repository.rb
linguist/samples.rb
linguist/tokenizer.rb
linguist.rb
Gemfile
Rakefile
bin/linguist
github-linguist.gemspec
lib/linguist.rb
lib/linguist/blob_helper.rb
lib/linguist/classifier.rb
lib/linguist/file_blob.rb
lib/linguist/generated.rb
lib/linguist/heuristics.rb
lib/linguist/language.rb
lib/linguist/lazy_blob.rb
lib/linguist/md5.rb
lib/linguist/repository.rb
lib/linguist/samples.rb
lib/linguist/tokenizer.rb
lib/linguist/version.rb
test/test_blob.rb
test/test_classifier.rb
test/test_heuristics.rb
test/test_language.rb
test/test_md5.rb
test/test_pedantic.rb
test/test_repository.rb
test/test_samples.rb
test/test_tokenizer.rb
#### Ignore vendored files
@@ -80,9 +104,34 @@ Linguist::FileBlob.new("underscore.min.js").generated? # => true
See [Linguist::Generated#generated?](https://github.com/github/linguist/blob/master/lib/linguist/generated.rb).
## Overrides
Linguist supports custom overrides for language definitions and vendored paths. Add a `.gitattributes` file to your project using the keys `linguist-language` and `linguist-vendored` with the standard git-style path matchers for the files you want to override.
Please note that the overrides currently only affect the language statistics for a repository and not the syntax-highlighting of files.
```
$ cat .gitattributes
*.rb linguist-language=Java
$ linguist --breakdown
100.00% Java
Java:
ruby_file.rb
```
By default, Linguist treats all of the paths defined in [lib/linguist/vendor.yml](https://github.com/github/linguist/blob/master/lib/linguist/vendor.yml) as vendored and therefore doesn't include them in the language statistics for a repository. Use the `linguist-vendored` attribute to vendor or un-vendor paths.
```
$ cat .gitattributes
special-vendored-path/* linguist-vendored
jquery.js linguist-vendored=false
```
## Installation
github.com is usually running the latest version of the `github-linguist` gem that is released on [RubyGems.org](http://rubygems.org/gems/github-linguist).
Github.com is usually running the latest version of the `github-linguist` gem that is released on [RubyGems.org](http://rubygems.org/gems/github-linguist).
But for development you are going to want to checkout out the source. To get it, clone the repo and run [Bundler](http://gembundler.com/) to install its dependencies.
@@ -102,10 +151,6 @@ We try to only add languages once they have some usage on GitHub, so please note
Almost all bug fixes or new language additions should come with some additional code samples. Just drop them under [`samples/`](https://github.com/github/linguist/tree/master/samples) in the correct subdirectory and our test suite will automatically test them. In most cases you shouldn't need to add any new assertions.
To update the `samples.json` after adding new files to [`samples/`](https://github.com/github/linguist/tree/master/samples):
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`:
@@ -145,7 +190,7 @@ If you are the current maintainer of this gem:
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. Build a local gem: `bundle exec rake build_gem`
0. Testing:
0. Bump the Gemfile and Gemfile.lock versions for an app which relies on this gem
0. Install the new gem locally

101
Rakefile
View File

@@ -1,27 +1,97 @@
require 'json'
require 'bundler/setup'
require 'rake/clean'
require 'rake/testtask'
require 'yaml'
require 'yajl'
task :default => :test
Rake::TestTask.new
task :samples do
require 'linguist/samples'
require 'yajl'
data = Linguist::Samples.data
json = Yajl::Encoder.encode(data, :pretty => true)
File.open('lib/linguist/samples.json', 'w') { |io| io.write json }
# Extend test task to check for samples
task :test => :check_samples
desc "Check that we have samples.json generated"
task :check_samples do
unless File.exist?('lib/linguist/samples.json')
Rake::Task[:samples].invoke
end
end
task :build_gem do
task :samples do
require 'linguist/samples'
json = Yajl.dump(Linguist::Samples.data, :pretty => true)
File.write 'lib/linguist/samples.json', json
end
task :build_gem => :samples do
languages = YAML.load_file("lib/linguist/languages.yml")
File.write("lib/linguist/languages.json", JSON.dump(languages))
File.write("lib/linguist/languages.json", Yajl.dump(languages))
`gem build github-linguist.gemspec`
File.delete("lib/linguist/languages.json")
end
namespace :benchmark do
benchmark_path = "benchmark/results"
# $ bundle exec rake benchmark:generate CORPUS=path/to/samples
desc "Generate results for"
task :generate do
ref = `git rev-parse HEAD`.strip[0,8]
corpus = File.expand_path(ENV["CORPUS"] || "samples")
require 'linguist/language'
results = Hash.new
Dir.glob("#{corpus}/**/*").each do |file|
next unless File.file?(file)
filename = file.gsub("#{corpus}/", "")
results[filename] = Linguist::FileBlob.new(file).language
end
# Ensure results directory exists
FileUtils.mkdir_p("benchmark/results")
# Write results
if `git status`.include?('working directory clean')
result_filename = "benchmark/results/#{File.basename(corpus)}-#{ref}.json"
else
result_filename = "benchmark/results/#{File.basename(corpus)}-#{ref}-unstaged.json"
end
File.write(result_filename, results.to_json)
puts "wrote #{result_filename}"
end
# $ bundle exec rake benchmark:compare REFERENCE=path/to/reference.json CANDIDATE=path/to/candidate.json
desc "Compare results"
task :compare do
reference_file = ENV["REFERENCE"]
candidate_file = ENV["CANDIDATE"]
reference = Yajl.load(File.read(reference_file))
reference_counts = Hash.new(0)
reference.each { |filename, language| reference_counts[language] += 1 }
candidate = Yajl.load(File.read(candidate_file))
candidate_counts = Hash.new(0)
candidate.each { |filename, language| candidate_counts[language] += 1 }
changes = diff(reference_counts, candidate_counts)
if changes.any?
changes.each do |language, (before, after)|
before_percent = 100 * before / reference.size.to_f
after_percent = 100 * after / candidate.size.to_f
puts "%s changed from %.1f%% to %.1f%%" % [language || 'unknown', before_percent, after_percent]
end
else
puts "No changes"
end
end
end
namespace :classifier do
LIMIT = 1_000
@@ -37,7 +107,7 @@ namespace :classifier do
next if file_language.nil? || file_language == 'Text'
begin
data = open(file_url).read
guessed_language, score = Linguist::Classifier.classify(Linguist::Samples::DATA, data).first
guessed_language, score = Linguist::Classifier.classify(Linguist::Samples.cache, data).first
total += 1
guessed_language == file_language ? correct += 1 : incorrect += 1
@@ -54,14 +124,12 @@ namespace :classifier do
def each_public_gist
require 'open-uri'
require 'json'
url = "https://api.github.com/gists/public"
loop do
resp = open(url)
url = resp.meta['link'][/<([^>]+)>; rel="next"/, 1]
gists = JSON.parse(resp.read)
gists = Yajl.load(resp.read)
for gist in gists
for filename, attrs in gist['files']
@@ -71,3 +139,10 @@ namespace :classifier do
end
end
end
def diff(a, b)
(a.keys | b.keys).each_with_object({}) do |key, diff|
diff[key] = [a[key], b[key]] unless a[key] == b[key]
end
end

View File

@@ -17,10 +17,10 @@ Gem::Specification.new do |s|
s.add_dependency 'escape_utils', '~> 1.0.1'
s.add_dependency 'mime-types', '~> 1.19'
s.add_dependency 'pygments.rb', '~> 0.6.0'
s.add_dependency 'rugged', '~> 0.21.0'
s.add_dependency 'rugged', '~> 0.21.1b2'
s.add_development_dependency 'json'
s.add_development_dependency 'mocha'
s.add_development_dependency 'pry'
s.add_development_dependency 'rake'
s.add_development_dependency 'yajl-ruby'
end

View File

@@ -321,6 +321,11 @@ module Linguist
language ? language.lexer : Pygments::Lexer.find_by_name('Text only')
end
# Internal: Get the TextMate compatible scope for the blob
def tm_scope
language && language.tm_scope
end
# Public: Highlight syntax of blob
#
# options - A Hash of options (defaults to {})

View File

@@ -63,6 +63,7 @@ module Linguist
generated_jni_header? ||
composer_lock? ||
node_modules? ||
godeps? ||
vcr_cassette? ||
generated_by_zephir?
end
@@ -231,6 +232,14 @@ module Linguist
!!name.match(/node_modules\//)
end
# Internal: Is the blob part of Godeps/,
# which are not meant for humans in pull requests.
#
# Returns true or false.
def godeps?
!!name.match(/Godeps\//)
end
# Internal: Is the blob a generated php composer lock file?
#
# Returns true or false.

View File

@@ -19,11 +19,26 @@ module Linguist
if languages.all? { |l| ["ECL", "Prolog"].include?(l) }
result = disambiguate_ecl(data, languages)
end
if languages.all? { |l| ["IDL", "Prolog"].include?(l) }
result = disambiguate_pro(data, languages)
end
if languages.all? { |l| ["Common Lisp", "OpenCL"].include?(l) }
result = disambiguate_cl(data, languages)
end
if languages.all? { |l| ["Hack", "PHP"].include?(l) }
result = disambiguate_hack(data, languages)
end
if languages.all? { |l| ["Scala", "SuperCollider"].include?(l) }
result = disambiguate_sc(data, languages)
end
if languages.all? { |l| ["AsciiDoc", "AGS Script"].include?(l) }
result = disambiguate_asc(data, languages)
end
return result
end
end
# .h extensions are ambigious between C, C++, and Objective-C.
# .h extensions are ambiguous between C, C++, and Objective-C.
# We want to shortcut look for Objective-C _and_ now C++ too!
#
# Returns an array of Languages or []
@@ -48,6 +63,16 @@ module Linguist
matches
end
def self.disambiguate_pro(data, languages)
matches = []
if (data.include?(":-"))
matches << Language["Prolog"]
else
matches << Language["IDL"]
end
matches
end
def self.disambiguate_ts(data, languages)
matches = []
if (data.include?("</translation>"))
@@ -72,6 +97,33 @@ module Linguist
matches
end
def self.disambiguate_hack(data, languages)
matches = []
if data.include?("<?hh")
matches << Language["Hack"]
elsif /<?[^h]/.match(data)
matches << Language["PHP"]
end
matches
end
def self.disambiguate_sc(data, languages)
matches = []
if (/\^(this|super)\./.match(data) || /^\s*(\+|\*)\s*\w+\s*{/.match(data) || /^\s*~\w+\s*=\./.match(data))
matches << Language["SuperCollider"]
end
if (/^\s*import (scala|java)\./.match(data) || /^\s*val\s+\w+\s*=/.match(data) || /^\s*class\b/.match(data))
matches << Language["Scala"]
end
matches
end
def self.disambiguate_asc(data, languages)
matches = []
matches << Language["AsciiDoc"] if /^=+(\s|\n)/.match(data)
matches
end
def self.active?
!!ACTIVE
end

View File

@@ -2,7 +2,7 @@ require 'escape_utils'
require 'pygments'
require 'yaml'
begin
require 'json'
require 'yajl'
rescue LoadError
end
@@ -62,7 +62,7 @@ module Linguist
end
# Language name index
@index[language.name] = @name_index[language.name] = language
@index[language.name.downcase] = @name_index[language.name.downcase] = language
language.aliases.each do |name|
# All Language aliases should be unique. Raise if there is a duplicate.
@@ -70,7 +70,7 @@ module Linguist
raise ArgumentError, "Duplicate alias: #{name}"
end
@index[name] = @alias_index[name] = language
@index[name.downcase] = @alias_index[name.downcase] = language
end
language.extensions.each do |extension|
@@ -135,8 +135,8 @@ module Linguist
# No shebang. Still more work to do. Try to find it with our heuristics.
elsif (determined = Heuristics.find_by_heuristics(data, possible_language_names)) && !determined.empty?
determined.first
# Lastly, fall back to the probablistic classifier.
elsif classified = Classifier.classify(Samples::DATA, data, possible_language_names).first
# Lastly, fall back to the probabilistic classifier.
elsif classified = Classifier.classify(Samples.cache, data, possible_language_names).first
# Return the actual Language object based of the string language name (i.e., first element of `#classify`)
Language[classified[0]]
end
@@ -164,7 +164,7 @@ module Linguist
#
# Returns the Language or nil if none was found.
def self.find_by_name(name)
@name_index[name]
@name_index[name.downcase]
end
# Public: Look up Language by one of its aliases.
@@ -178,7 +178,7 @@ module Linguist
#
# Returns the Lexer or nil if none was found.
def self.find_by_alias(name)
@alias_index[name]
@alias_index[name.downcase]
end
# Public: Look up Languages by filename.
@@ -194,9 +194,25 @@ module Linguist
def self.find_by_filename(filename)
basename = File.basename(filename)
extname = FileBlob.new(filename).extension
langs = @filename_index[basename] +
@extension_index[extname]
langs.compact.uniq
(@filename_index[basename] + find_by_extension(extname)).compact.uniq
end
# Public: Look up Languages by file extension.
#
# extname - The extension String.
#
# Examples
#
# Language.find_by_extension('.rb')
# # => [#<Language name="Ruby">]
#
# Language.find_by_extension('rb')
# # => [#<Language name="Ruby">]
#
# Returns all matching Languages or [] if none were found.
def self.find_by_extension(extname)
extname = ".#{extname}" unless extname.start_with?(".")
@extension_index[extname]
end
# Public: Look up Languages by shebang line.
@@ -227,7 +243,7 @@ module Linguist
#
# Returns the Language or nil if none was found.
def self.[](name)
@index[name]
@index[name.downcase]
end
# Public: A List of popular languages
@@ -290,6 +306,16 @@ module Linguist
@lexer = Pygments::Lexer.find_by_name(attributes[:lexer] || name) ||
raise(ArgumentError, "#{@name} is missing lexer")
@tm_scope = attributes[:tm_scope] || begin
context = case @type
when :data, :markup, :prose
'text'
when :programming, nil
'source'
end
"#{context}.#{@name.downcase}"
end
@ace_mode = attributes[:ace_mode]
@wrap = attributes[:wrap] || false
@@ -363,6 +389,11 @@ module Linguist
# Returns the Lexer
attr_reader :lexer
# Public: Get the name of a TextMate-compatible scope
#
# Returns the scope
attr_reader :tm_scope
# Public: Get Ace mode
#
# Examples
@@ -510,16 +541,16 @@ module Linguist
end
end
extensions = Samples::DATA['extnames']
interpreters = Samples::DATA['interpreters']
filenames = Samples::DATA['filenames']
extensions = Samples.cache['extnames']
interpreters = Samples.cache['interpreters']
filenames = Samples.cache['filenames']
popular = YAML.load_file(File.expand_path("../popular.yml", __FILE__))
languages_yml = File.expand_path("../languages.yml", __FILE__)
languages_json = File.expand_path("../languages.json", __FILE__)
if File.exist?(languages_json) && defined?(JSON)
languages = JSON.load(File.read(languages_json))
if File.exist?(languages_json) && defined?(Yajl)
languages = Yajl.load(File.read(languages_json))
else
languages = YAML.load_file(languages_yml)
end
@@ -564,6 +595,7 @@ module Linguist
:type => options['type'],
:aliases => options['aliases'],
:lexer => options['lexer'],
:tm_scope => options['tm_scope'],
:ace_mode => options['ace_mode'],
:wrap => options['wrap'],
:group_name => options['group'],

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,13 @@
require 'linguist/blob_helper'
require 'linguist/language'
require 'rugged'
module Linguist
class LazyBlob
GIT_ATTR = ['linguist-language', 'linguist-vendored']
GIT_ATTR_OPTS = { :priority => [:index], :skip_system => true }
GIT_ATTR_FLAGS = Rugged::Repository::Attributes.parse_opts(GIT_ATTR_OPTS)
include BlobHelper
MAX_SIZE = 128 * 1024
@@ -19,6 +24,29 @@ module Linguist
@mode = mode
end
def git_attributes
@git_attributes ||= repository.fetch_attributes(
name, GIT_ATTR, GIT_ATTR_FLAGS)
end
def vendored?
if attr = git_attributes['linguist-vendored']
return boolean_attribute(attr)
else
return super
end
end
def language
return @language if defined?(@language)
@language = if lang = git_attributes['linguist-language']
Language.find_by_name(lang)
else
super
end
end
def data
load_blob!
@data
@@ -30,6 +58,12 @@ module Linguist
end
protected
# Returns true if the attribute is present and not the string "false".
def boolean_attribute(attr)
attr != "false"
end
def load_blob!
@data, @size = Rugged::Blob.to_buffer(repository, oid, MAX_SIZE) if @data.nil?
end

View File

@@ -110,18 +110,37 @@ module Linguist
if @old_commit_oid == @commit_oid
@old_stats
else
compute_stats(@old_commit_oid, @commit_oid, @old_stats)
compute_stats(@old_commit_oid, @old_stats)
end
end
end
protected
def compute_stats(old_commit_oid, commit_oid, cache = nil)
file_map = cache ? cache.dup : {}
old_tree = old_commit_oid && Rugged::Commit.lookup(repository, old_commit_oid).tree
new_tree = Rugged::Commit.lookup(repository, commit_oid).tree
def read_index
attr_index = Rugged::Index.new
attr_index.read_tree(current_tree)
repository.index = attr_index
end
diff = Rugged::Tree.diff(repository, old_tree, new_tree)
def current_tree
@tree ||= Rugged::Commit.lookup(repository, @commit_oid).tree
end
protected
def compute_stats(old_commit_oid, cache = nil)
old_tree = old_commit_oid && Rugged::Commit.lookup(repository, old_commit_oid).tree
read_index
diff = Rugged::Tree.diff(repository, old_tree, current_tree)
# Clear file map and fetch full diff if any .gitattributes files are changed
if cache && diff.each_delta.any? { |delta| File.basename(delta.new_file[:path]) == ".gitattributes" }
diff = Rugged::Tree.diff(repository, old_tree = nil, current_tree)
file_map = {}
else
file_map = cache ? cache.dup : {}
end
diff.each_delta do |delta|
old = delta.old_file[:path]

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,5 @@
begin
require 'json'
require 'yajl'
rescue LoadError
require 'yaml'
end
@@ -17,9 +17,11 @@ module Linguist
PATH = File.expand_path('../samples.json', __FILE__)
# Hash of serialized samples object
if File.exist?(PATH)
serializer = defined?(JSON) ? JSON : YAML
DATA = serializer.load(File.read(PATH))
def self.cache
@cache ||= begin
serializer = defined?(Yajl) ? Yajl : YAML
serializer.load(File.read(PATH))
end
end
# Public: Iterate over each sample.

View File

@@ -33,15 +33,19 @@
# Erlang bundles
- ^rebar$
# Bootstrap minified css and js
- (^|/)bootstrap([^.]*)(\.min)?\.(js|css)$
# Go dependencies
- Godeps/_workspace/
# Minified JavaScript and CSS
- (\.|-)min\.(js|css)$
# Bootstrap css and js
- (^|/)bootstrap([^.]*)\.(js|css)$
# Font Awesome
- font-awesome.min.css
- font-awesome.css
# Foundation css
- foundation.min.css
- foundation.css
# Normalize.css
@@ -53,7 +57,6 @@
# Animate.css
- animate.css
- animate.min.css
# Vendored dependencies
- third[-_]?party/
@@ -70,12 +73,12 @@
## Commonly Bundled JavaScript frameworks ##
# jQuery
- (^|/)jquery([^.]*)(\.min)?\.js$
- (^|/)jquery\-\d\.\d+(\.\d+)?(\.min)?\.js$
- (^|/)jquery([^.]*)\.js$
- (^|/)jquery\-\d\.\d+(\.\d+)?\.js$
# jQuery UI
- (^|/)jquery\-ui(\-\d\.\d+(\.\d+)?)?(\.\w+)?(\.min)?\.(js|css)$
- (^|/)jquery\.(ui|effects)\.([^.]*)(\.min)?\.(js|css)$
- (^|/)jquery\-ui(\-\d\.\d+(\.\d+)?)?(\.\w+)?\.(js|css)$
- (^|/)jquery\.(ui|effects)\.([^.]*)\.(js|css)$
# Prototype
- (^|/)prototype(.*)\.js$
@@ -113,21 +116,20 @@
- (^|/)shLegacy\.js$
# AngularJS
- (^|/)angular([^.]*)(\.min)?\.js$
- (^|/)angular([^.]*)\.js$
# D3.js
- (^|\/)d3(\.v\d+)?([^.]*)(\.min)?\.js$
- (^|\/)d3(\.v\d+)?([^.]*)\.js$
# React
- (^|/)react(-[^.]*)?(\.min)?\.js$
- (^|/)react(-[^.]*)?\.js$
# Modernizr
- (^|/)modernizr\-\d\.\d+(\.\d+)?(\.min)?\.js$
- (^|/)modernizr\-\d\.\d+(\.\d+)?\.js$
- (^|/)modernizr\.custom\.\d+\.js$
# Knockout
- (^|/)knockout-(\d+\.){3}(debug\.)?js$
- knockout-min.js
## Python ##
@@ -165,8 +167,8 @@
- \.intellisense\.js$
# jQuery validation plugin (MS bundles this with asp.net mvc)
- (^|/)jquery([^.]*)\.validate(\.unobtrusive)?(\.min)?\.js$
- (^|/)jquery([^.]*)\.unobtrusive\-ajax(\.min)?\.js$
- (^|/)jquery([^.]*)\.validate(\.unobtrusive)?\.js$
- (^|/)jquery([^.]*)\.unobtrusive\-ajax\.js$
# Microsoft Ajax
- (^|/)[Mm]icrosoft([Mm]vc)?([Aa]jax|[Vv]alidation)(\.debug)?\.js$
@@ -193,7 +195,7 @@
- (^|/)extjs/welcome/
# Html5shiv
- (^|/)html5shiv(\.min)?\.js$
- (^|/)html5shiv\.js$
# Samples folders
- ^[Ss]amples/
@@ -212,8 +214,8 @@
- ^[Tt]est/fixtures/
# PhoneGap/Cordova
- (^|/)cordova([^.]*)(\.min)?\.js$
- (^|/)cordova\-\d\.\d(\.\d)?(\.min)?\.js$
- (^|/)cordova([^.]*)\.js$
- (^|/)cordova\-\d\.\d(\.\d)?\.js$
# Foundation js
- foundation(\..*)?\.js$
@@ -233,5 +235,12 @@
# Octicons
- octicons.css
- octicons.min.css
- sprockets-octicons.scss
# Typesafe Activator
- (^|/)activator$
- (^|/)activator\.bat$
# ProGuard
- proguard.pro
- proguard-rules.pro

View File

@@ -1,3 +1,3 @@
module Linguist
VERSION = "3.1.4"
VERSION = "3.5.0"
end

367
samples/APL/UT.dyalog Normal file
View File

@@ -0,0 +1,367 @@
:NameSpace UT
sac ← 0
expect_orig ← expect ← ⎕NS⍬
exception ← ⍬
nexpect_orig ← nexpect ← ⎕NS⍬
∇ {Z}←{Conf}run Argument;PRE_test;POST_test;TEST_step;COVER_step;FromSpace
load_display_if_not_already_loaded
load_salt_scripts_into_current_namespace_if_configured
FromSpace←1⊃⎕RSI
PRE_test←{}
POST_test←{}
COVER_step←{}
:If 0≠⎕NC'Conf'
:If Conf has'cover_target'
PRE_test←{{}⎕PROFILE'start'}
POST_test←{{}⎕PROFILE'stop'}
:EndIf
:EndIf
:If is_function Argument
TEST_step←single_function_test_function
COVER_file←Argument,'_coverage.html'
:ElseIf is_list_of_functions Argument
TEST_step←list_of_functions_test_function
COVER_file←'list_coverage.html'
:ElseIf is_file Argument
TEST_step←file_test_function
COVER_file←(get_file_name Argument),'_coverage.html'
:ElseIf is_dir Argument
test_files←test_files_in_dir Argument
TEST_step←test_dir_function
Argument←test_files
:EndIf
:If 0≠⎕NC'Conf'
:If Conf has'cover_target'
COVER_step←{Conf,←⊂('cover_file'COVER_file)
generate_coverage_page Conf}
:EndIf
:EndIf
PRE_test ⍬
Z←FromSpace TEST_step Argument
POST_test ⍬
COVER_step ⍬
∇ load_display_if_not_already_loaded
:If 0=⎕NC'#.DISPLAY'
'DISPLAY'#.⎕CY'display'
:EndIf
∇ load_salt_scripts_into_current_namespace_if_configured
:If 0≠⎕NC'#.UT.appdir'
:If ⍬≢#.UT.appdir
⎕SE.SALT.Load #.UT.appdir,'src/*.dyalog -target=#'
⎕SE.SALT.Load #.UT.appdir,'test/*.dyalog -target=#'
:EndIf
:EndIf
∇ Z←FromSpace single_function_test_function TestName
Z←run_ut FromSpace TestName
∇ Z←FromSpace list_of_functions_test_function ListOfNames;t
t←⎕TS
Z←run_ut¨{FromSpace ⍵}¨ListOfNames
t←⎕TS-t
('Test execution report')print_passed_crashed_failed Z t
∇ Z←FromSpace file_test_function FilePath;FileNS;Functions;TestFunctions;t
FileNS←⎕SE.SALT.Load FilePath,' -target=#'
Functions←↓FileNS.⎕NL 3
TestFunctions←(is_test¨Functions)/Functions
:If (0/⍬,⊂0/'')≡TestFunctions
⎕←'No test functions found'
Z←⍬
:Else
t←⎕TS
Z←run_ut¨{FileNS ⍵}¨TestFunctions
t←⎕TS-t
(FilePath,' tests')print_passed_crashed_failed Z t
:EndIf
∇ Z←FromSpace test_dir_function Test_files
:If Test_files≡⍬/⍬,⊂''
⎕←'No test files found'
Z←⍬
:Else
Z←#.UT.run¨Test_files
:EndIf
∇ Z←get_file_name Argument;separator
separator←⊃⌽(Argument∊'/\')/Argument
Z←¯7↓separator↓Argument
∇ generate_coverage_page Conf;ProfileData;CoverResults;HTML
ProfileData←⎕PROFILE'data'
ToCover←retrieve_coverables¨(⊃'cover_target'in Conf)
:If (ToCover)≡(⊂1)
ToCover←⊃ToCover
:EndIf
Representations←get_representation¨ToCover
CoverResults←ProfileData∘generate_cover_result¨↓ToCover,[1.5]Representations
HTML←generate_html CoverResults
Conf write_html_to_page HTML
⎕PROFILE'clear'
∇ Z←retrieve_coverables Something;nc;functions
nc←⎕NC Something
:If nc=3
Z←Something
:ElseIf nc=9
functions←strip¨↓⍎Something,'.⎕NL 3'
Z←{(Something,'.',⍵)}¨functions
:EndIf
∇ Z←strip input
Z←(input≠' ')/input
∇ Z←get_representation Function;nc;rep
nc←⎕NC⊂Function
:If nc=3.1
rep←↓⎕CR Function
rep[1]←⊂'∇',⊃rep[1]
rep,←⊂'∇'
rep←↑rep
:Else
rep←⎕CR Function
:EndIf
Z←rep
∇ Z←ProfileData generate_cover_result(name representation);Indices;lines;functionlines;covered_lines
Indices←({name≡⍵}¨ProfileData[;1])/ProfileData[;1]
lines←ProfileData[Indices;2]
nc←⎕NC⊂name
:If 3.1=nc
functionlines←¯2+↓representation
:Else
functionlines←⊃↓representation
:EndIf
covered_lines←(⍬∘≢¨lines)/lines
Z←(nc lines functionlines covered_lines representation)
∇ Z←generate_html CoverResults;Covered;Total;Percentage;CoverageText;ColorizedCode;Timestamp;Page
Covered←⊃⊃+/{4⊃⍵}¨CoverResults
Total←⊃⊃+/{3⊃⍵}¨CoverResults
Percentage←100×Covered÷Total
CoverageText←'Coverage: ',Percentage,'% (',Covered,'/',Total,')'
ColorizedCode←⊃,/{colorize_code_by_coverage ⍵}¨CoverResults
Timestamp←generate_timestamp_text
Page←⍬
Page,←⊂⍬,'<html>'
Page,←⊂⍬,'<meta http-equiv="Content-Type" content="text/html;charset=utf-8"/>'
Page,←⊂⍬,'<style>pre cov {line-height:80%;}'
Page,←⊂⍬,'pre cov {color: green;}'
Page,←⊂⍬,'pre uncov {line-height:80%;}'
Page,←⊂⍬,'pre uncov {color:red;}</style>'
Page,←⊂⍬,CoverageText
Page,←⊂⍬,'<pre>'
Page,←ColorizedCode
Page,←⊂⍬,'</pre>'
Page,←Timestamp
Page,←⊂⍬,'</html>'
Z←Page
∇ Z←colorize_code_by_coverage CoverResult;Colors;Ends;Code
:If 3.1=⊃CoverResult
Colors←(2+3⊃CoverResult)⍴⊂'<uncov>'
Colors[1]←⊂''
Colors[Colors]←⊂''
Ends←(2+3⊃CoverResult)⍴⊂'</uncov>'
Ends[1]←⊂''
Ends[Ends]←⊂''
:Else
Colors←(3⊃CoverResult)⍴⊂'<uncov>'
Ends←(3⊃CoverResult)⍴⊂'</uncov>'
:EndIf
Colors[1+4⊃CoverResult]←⊂'<cov>'
Ends[1+4⊃CoverResult]←⊂'</cov>'
Code←↓5⊃CoverResult
Z←Colors,[1.5]Code
Z←{,(⎕UCS 13),⍵}/Z,Ends
∇ Z←generate_timestamp_text;TS;YYMMDD;HHMMSS
TS←⎕TS
YYMMDD←⊃{,'-',⍵}/3↑TS
HHMMSS←⊃{,':',⍵}/3↑3↓TS
Z←'Page generated: ',YYMMDD,'|',HHMMSS
∇ Conf write_html_to_page Page;tie;filename
filename←(⊃'cover_out'in Conf),(⊃'cover_file'in Conf)
:Trap 22
tie←filename ⎕NTIE 0
filename ⎕NERASE tie
filename ⎕NCREATE tie
:Else
tie←filename ⎕NCREATE 0
:EndTrap
Simple_array←⍕⊃,/Page
(⎕UCS'UTF-8'⎕UCS Simple_array)⎕NAPPEND tie
∇ Z←is_function Argument
Z←'_TEST'≡¯5↑Argument
∇ Z←is_list_of_functions Argument
Z←2=≡Argument
∇ Z←is_file Argument
Z←'.dyalog'≡¯7↑Argument
∇ Z←is_dir Argument;attr
:If 'Linux'≡5↑⊃'.'⎕WG'APLVersion'
Z←'yes'≡⊃⎕CMD'test -d ',Argument,' && echo yes || echo no'
:Else
'gfa'⎕NA'I kernel32|GetFileAttributes* <0t'
:If Z←¯1≠attr←gfa⊂Argument ⍝ If file exists
Z←⊃2 16attr ⍝ Return bit 4
:EndIf
:EndIf
∇ Z←test_files_in_dir Argument
:If 'Linux'≡5↑⊃'.'⎕WG'APLVersion'
Z←⎕SH'find ',Argument,' -name \*_tests.dyalog'
:Else
#.⎕CY'files'
Z←#.Files.Dir Argument,'\*_tests.dyalog'
Z←(Argument,'\')∘,¨Z
:EndIf
∇ Z←run_ut ut_data;returned;crashed;pass;crash;fail;message
(returned crashed time)←execute_function ut_data
(pass crash fail)←determine_pass_crash_or_fail returned crashed
message←determine_message pass fail crashed(2⊃ut_data)returned time
print_message_to_screen message
Z←(pass crash fail)
∇ Z←execute_function ut_data;function;t
reset_UT_globals
function←(⍕(⊃ut_data[1])),'.',⊃ut_data[2]
:Trap sac
:If 3.2≡⎕NC⊂function
t←⎕TS
Z←(⍎function,' ⍬')0
t←⎕TS-t
:Else
t←⎕TS
Z←(⍎function)0
t←⎕TS-t
:EndIf
:Else
Z←(↑⎕DM)1
:If exception≢⍬
expect←exception
Z[2]←0
t←⎕TS-t
:EndIf
:EndTrap
Z,←⊂t
∇ reset_UT_globals
expect_orig ← expect← ⎕NS⍬
exception←⍬
nexpect_orig ← nexpect← ⎕NS⍬
∇ Z←is_test FunctionName;wsIndex
wsIndex←FunctionName' '
FunctionName←(wsIndex-1)↑FunctionName
Z←'_TEST'≡¯5↑FunctionName
∇ Heading print_passed_crashed_failed(ArrayRes time)
⎕←'-----------------------------------------'
⎕←Heading
⎕←' ⍋ Passed: ',+/{1⊃⍵}¨ArrayRes
⎕←' ⍟ Crashed: ',+/{2⊃⍵}¨ArrayRes
⎕←' ⍒ Failed: ',+/{3⊃⍵}¨ArrayRes
⎕←' ○ Runtime: ',time[5],'m',time[6],'s',time[7],'ms'
determine_pass_crash_or_fail←{
r c←⍵ ⋄ 0≠c:0 1 0 ⋄ z←(0 0 1)(1 0 0)
expect_orig≢expect:(⎕IO+expect≡r)⊃z ⋄ (⎕IO+nexpect≢r)⊃z
}
∇ Z←determine_message(pass fail crashed name returned time)
:If crashed
Z←'CRASHED: 'failure_message name returned
:ElseIf pass
Z←'Passed ',time[5],'m',time[6],'s',time[7],'ms'
:Else
Z←'FAILED: 'failure_message name returned
:EndIf
∇ print_message_to_screen message
⎕←message
∇ Z←term_to_text Term;Text;Rows
Text←#.DISPLAY Term
Rows←1⊃Text
Z←(Rows 4''),Text
∇ Z←Cause failure_message(name returned);hdr;exp;expterm;got;gotterm
hdr←Cause,name
exp←'Expected'
expterm←term_to_text #.UT.expect
got←'Got'
gotterm←term_to_text returned
Z←align_and_join_message_parts hdr exp expterm got gotterm
∇ Z←align_and_join_message_parts Parts;hdr;exp;expterm;got;gotterm;R1;C1;R2;C2;W
(hdr exp expterm got gotterm)←Parts
(R1 C1)←expterm
(R2 C2)←gotterm
W←⊃⊃⌈/C1 C2(hdr)(exp)(got)
Z←(W↑hdr),[0.5](W↑exp)
Z←Z⍪(R1 W↑expterm)
Z←Z⍪(W↑got)
Z←Z⍪(R2 W↑gotterm)
∇ Z←confparam in config
Z←1↓⊃({confparam≡⊃⍵}¨config)/config
∇ Z←config has confparam
Z←/{confparam≡⊃⍵}¨config
:EndNameSpace

View File

@@ -0,0 +1,66 @@
ORG 0000h
SJMP START
ORG 0003h
LCALL INT0_ISR
RETI
ORG 000Bh
LCALL T0_ISR
RETI
ORG 0013h
LCALL INT1_ISR
RETI
ORG 001Bh
LCALL T1_ISR
RETI
ORG 0023h
LCALL UART_ISR
RETI
ORG 0030h
START:
MOV A,#11111110b
SETB IT0 ; Set External Interrupt 0 to be falling edge triggered
SETB EX0 ; Enable External Interrut 0
SETB EA ; Enable Interrupt
LEFT:
CJNE A,#01111111b,LOOP1
JMP RIGHT
LOOP1:
MOV P1,A
RL A
LCALL DELAY
SJMP LEFT
RIGHT:
CJNE A,#11111110b,LOOP2
JMP LEFT
LOOP2:
MOV P1,A
RR A
LCALL DELAY
SJMP RIGHT
INT0_ISR:
MOV R1,#3
FLASH:
MOV P1,#00h
LCALL DELAY
MOV P1,#0FFh
LCALL DELAY
DJNZ R1,FLASH
RET
T0_ISR:
RET
INT1_ISR:
RET
T1_ISR:
RET
UART_ISR:
RET
DELAY: MOV R5,#20 ;R5*20 mS
D1: MOV R6,#40
D2: MOV R7,#249
DJNZ R7,$
DJNZ R6,D2
DJNZ R5,D1
RET
END

10
samples/C++/bar.hh Normal file
View File

@@ -0,0 +1,10 @@
class Bar
{
protected:
char *name;
public:
void hello();
}

View File

@@ -1,13 +1,13 @@
doc "Test function for Ceylon"
by "Enrique"
"Test function for Ceylon"
by ("Enrique")
shared void test() {
print("test");
print("test");
}
doc "Test class for Ceylon"
"Test class for Ceylon"
shared class Test(name) satisfies Comparable<Test> {
shared String name;
shared actual String string = "Test " name ".";
shared actual String string = "Test ``name``.";
shared actual Comparison compare(Test other) {
return name<=>other.name;

11
samples/Clean/GenHylo.dcl Normal file
View File

@@ -0,0 +1,11 @@
definition module GenHylo
import StdGeneric, GenMap
:: Fix f = In (f .(Fix f))
Out :: !u:(Fix v:a) -> v:(a w:(Fix v:a)), [u <= w]
hylo :: ((.f .b) -> .b) (.a -> (.f .a)) -> (.a -> .b) | gMap{|*->*|} f
cata :: (u:(f .a) -> .a) -> (Fix u:f) -> .a | gMap{|*->*|} f
ana :: (.a -> u:(f .a)) -> .a -> (Fix u:f) | gMap{|*->*|} f

9
samples/Clean/GenMap.dcl Normal file
View File

@@ -0,0 +1,9 @@
definition module GenMap
import StdGeneric
generic gMap a b :: .a -> .b
derive gMap c, UNIT, PAIR, EITHER, CONS, FIELD, OBJECT, {}, {!}
derive gMap [], (,), (,,), (,,,), (,,,,), (,,,,,), (,,,,,,), (,,,,,,,)

19
samples/Clean/GenMap.icl Normal file
View File

@@ -0,0 +1,19 @@
implementation module GenMap
import StdClass, StdArray, StdInt, StdFunc
import StdGeneric, _Array
generic gMap a b :: .a -> .b
gMap{|c|} x = x
gMap{|UNIT|} x = x
gMap{|PAIR|} fx fy (PAIR x y) = PAIR (fx x) (fy y)
gMap{|EITHER|} fl fr (LEFT x) = LEFT (fl x)
gMap{|EITHER|} fl fr (RIGHT x) = RIGHT (fr x)
gMap{|CONS|} f (CONS x) = CONS (f x)
gMap{|FIELD|} f (FIELD x) = FIELD (f x)
gMap{|OBJECT|} f (OBJECT x) = OBJECT (f x)
gMap{|{}|} f xs = mapArray f xs
gMap{|{!}|} f xs = mapArray f xs
derive gMap [], (,), (,,), (,,,), (,,,,), (,,,,,), (,,,,,,), (,,,,,,,)

54
samples/Clean/fsieve.icl Normal file
View File

@@ -0,0 +1,54 @@
module fsieve
/*
The Fast Sieve of Eratosthenes.
A sequential and optimized version of the sieve of Eratosthenes.
The program calculates a list of the first NrOfPrime primes.
The result of the program is the NrOfPrimes'th prime.
Strictness annotations have been added because the strictness analyser
is not able to deduce all strictness information. Removal of these !'s
will make the program about 20% slower.
On a machine without a math coprocessor the execution of this
program might take a (very) long time. Set NrOfPrimes to a smaller value.
*/
import StdClass; // RWS
import StdInt, StdReal
NrOfPrimes :== 3000
// The sieve algorithm: generate an infinite list of all primes.
Primes::[Int]
Primes = pr where pr = [5 : Sieve 7 4 pr]
Sieve::Int !Int [Int] -> [Int]
Sieve g i prs
| IsPrime prs g (toInt (sqrt (toReal g))) = [g : Sieve` g i prs]
= Sieve (g + i) (6 - i) prs
Sieve`::Int Int [Int] -> [Int]
Sieve` g i prs = Sieve (g + i) (6 - i) prs
IsPrime::[Int] !Int Int -> Bool
IsPrime [f:r] pr bd | f>bd = True
| pr rem f==0 = False
= IsPrime r pr bd
// Select is used to get the NrOfPrimes'th prime from the infinite list.
Select::[x] Int -> x
Select [f:r] 1 = f
Select [f:r] n = Select r (n - 1)
/* The Start rule: Select the NrOfPrimes'th prime from the list of primes
generated by Primes.
*/
Start::Int
Start = Select [2, 3 : Primes] NrOfPrimes

99
samples/Clean/sem.icl Normal file
View File

@@ -0,0 +1,99 @@
module monadicSemantics
import StdEnv, StdGeneric, GenMap, GenHylo
/* For fun I implemented the recursive datastructre Exp and Stm as fixpoints
This helps us define recursive functions on them (only a little bit though)
However deriving gMap for Fix did not works out of the box
I had to remove some uniqueness typing in GenMap and GenHylo */
:: Op = Plus | Minus | Times | Rem | Equal | LessThan
:: Var :== String
:: ExpP a = Int Int | Var Var | Op Op a a
:: Exp :== Fix ExpP
:: StmP a = Assign Var Exp | If Exp a a | While Exp a | Seq a a | Cont
:: Stm :== Fix StmP
derive gMap ExpP, StmP, Fix
// Environment. Semantics is basically Env -> Env
:: Env :== Var -> Int
:: Sem :== Env -> (Int, Env)
empty = \v . 0
// return
rtn :: Int -> Sem
rtn i = \e. (i, e)
// the usual bind
(>>=) infixl 1 :: Sem (Int->Sem) -> Sem
(>>=) x y = \e. (\(i,e2).y i e2) (x e)
(>>|) infixl 1 :: Sem Sem -> Sem
(>>|) x y = x >>= \_. y
// read variable from environment
read :: Var -> Sem
read v = \e. (e v, e)
// assign value to give variable in environment
write :: Var Int -> Sem
write v i = \e. (i, \w. if (w==v) i (e w))
// semantics
class sem a :: a -> Sem
operator :: Op -> Int -> Int -> Int
operator Plus = (+)
operator Minus = (-)
operator Times = (*)
operator Rem = rem
operator Equal = \x y . if (x==y) 1 0
operator LessThan = \x y . if (x< y) 1 0
// semantics of expressions
instance sem Exp where
sem x = cata phi x where
phi (Int n) = rtn n
phi (Var v) = read v
phi (Op op x y) = x >>= \v1. y >>= return o (operator op v1)
// semantics of statments
// NOTE: while will always return 0, as it might not even be executed
instance sem Stm where
sem x = cata phi x where
phi (Assign v e) = sem e >>= write v
phi (If e s1 s2) = sem e >>= \b . if (b<>0) s1 s2
phi stm=:(While e s) = sem e >>= \b . if (b<>0) (s >>| phi stm) (phi Cont)
phi (Seq s1 s2) = s1 >>| s2 // Here the cata *finally* pays off :D
phi Cont = rtn 0
// convenience functions
int = In o Int
var = In o Var
op o = In o2 (Op o)
assign = In o2 Assign
ifte e = In o2 (If e)
while = In o2 While
seq = In o2 Seq
cont = In Cont
// test case, also testing the new operator <
pEuclides =
while (op LessThan (int 0) (var "b"))(
seq (assign "r" (op Rem (var "a") (var "b")))
(seq (assign "a" (var "b"))
( (assign "b" (var "r")))
)
)
Start = fst (program start) where
program = sem pEuclides >>| read "a"
start "a" = 9
start "b" = 12
start _ = 0
// Helper
(o2) infixr 9
(o2) f g x :== f o (g x)

14
samples/Clean/stack.dcl Normal file
View File

@@ -0,0 +1,14 @@
definition module stack
:: Stack a
newStack :: (Stack a)
push :: a (Stack a) -> Stack a
pushes :: [a] (Stack a) -> Stack a
pop :: (Stack a) -> Stack a
popn :: Int (Stack a) -> Stack a
top :: (Stack a) -> a
topn :: Int (Stack a) -> [a]
elements :: (Stack a) -> [a]
count :: (Stack a) -> Int

33
samples/Clean/stack.icl Normal file
View File

@@ -0,0 +1,33 @@
implementation module stack
import StdEnv
:: Stack a :== [a]
newStack :: (Stack a)
newStack = []
push :: a (Stack a) -> Stack a
push x s = [x:s]
pushes :: [a] (Stack a) -> Stack a
pushes x s = x ++ s
pop :: (Stack a) -> Stack a
pop [] = abort "Cannot use pop on an empty stack"
pop [e:s] = s
popn :: Int (Stack a) -> Stack a
popn n s = drop n s
top :: (Stack a) -> a
top [] = abort "Cannot use top on an empty stack"
top [e:s] = e
topn :: Int (Stack a) -> [a]
topn n s = take n s
elements :: (Stack a) -> [a]
elements s = s
count :: (Stack a) -> Int
count s = length s

16
samples/Clean/streams.dcl Normal file
View File

@@ -0,0 +1,16 @@
definition module streams
import StdEnv
instance zero [Real]
instance one [Real]
instance + [Real]
instance - [Real]
instance * [Real]
instance / [Real]
X :: [Real]
invert :: [Real] -> [Real]
pow :: [Real] Int -> [Real]
(shuffle) infixl 7 :: [Real] [Real] -> [Real]

49
samples/Clean/streams.icl Normal file
View File

@@ -0,0 +1,49 @@
implementation module streams
import StdEnv
instance zero [Real]
where
zero = [] //Infinite row of zeroes represented as empty list to ease computation
instance one [Real]
where
one = [1.0:zero]
instance + [Real]
where
(+) [s:s`] [t:t`] = [s+t:s`+t`]
(+) [s:s`] [] = [s:s`]
(+) [] [t:t`] = [t:t`]
(+) [] [] = []
instance - [Real]
where
(-) [s:s`] [t:t`] = [s-t:s`-t`]
(-) [s:s`] [] = [s:s`]
(-) [] [t:t`] = [-1.0] * [t:t`]
(-) [] [] = []
instance * [Real]
where
(*) [s:s`] [t:t`] = [s*t:s`*[t:t`]+[s]*t`]
(*) _ _ = []
instance / [Real]
where
(/) s t = s * (invert t)
X :: [Real]
X = [0.0:one]
invert :: [Real] -> [Real]
invert [s:s`] = [1.0/s:(invert [s:s`]) * s` * [-1.0/s]]
pow :: [Real] Int -> [Real]
pow s 0 = one
pow s n = s * pow s (n-1)
(shuffle) infixl 7 :: [Real] [Real] -> [Real]
(shuffle) [s:s`] [t:t`] = [s*t:s` shuffle [t:t`] + [s:s`] shuffle t`]
(shuffle) _ _ = []

8
samples/Forth/bitmap.frt Normal file
View File

@@ -0,0 +1,8 @@
\ Bit arrays.
: bits ( u1 -- u2 ) 7 + 3 rshift ;
: bitmap ( u "name" -- ) create bits here over erase allot
does> ( u -- a x ) over 3 rshift + 1 rot 7 and lshift ;
: bit@ ( a x -- f ) swap c@ and ;
: 1bit ( a x -- ) over c@ or swap c! ;
: 0bit ( a x -- ) invert over c@ and swap c! ;
: bit! ( f a x -- ) rot if 1bit else 0bit then ;

7
samples/Forth/enum.frt Normal file
View File

@@ -0,0 +1,7 @@
\ Implements ENUM.
\ Double DOES>!
: enum create 0 , does> create dup @ 1 rot +! , does> @ ;
\ But this is simpler.
: enum create 0 , does> dup @ constant 1 swap +! ;

8
samples/Forth/macros.frt Normal file
View File

@@ -0,0 +1,8 @@
\ Simplifies compiling words.
: [[ ; immediate
: '<> >in @ ' swap >in ! <> ;
: (]]) begin dup '<> while postpone postpone repeat drop ;
: ]] ['] [[ (]]) ; immediate
( Usage: : foo ]] dup * [[ ; immediate : bar 42 foo . ; )

57
samples/G-code/duettest.g Normal file
View File

@@ -0,0 +1,57 @@
; RepRapPro Ormerod
; Board test GCodes
M111 S1; Debug on
G21 ; mm
G90 ; Absolute positioning
M83 ; Extrusion relative
M906 X800 Y800 Z800 E800 ; Motor currents (mA)
T0 ; Extruder 0
G1 X50 F500
G1 X0
G4 P500
G1 Y50 F500
G1 Y0
G4 P500
G1 Z20 F200
G1 Z0
G4 P500
G1 E20 F200
G1 E-20
G4 P500
M106 S255
G4 P500
M106 S0
G4 P500
M105
G10 P0 S100
T0
M140 S100
G4 P5000
M105
G4 P5000
M105
G4 P5000
M105
G4 P5000
M105
G4 P5000
M105
G4 P5000
M105
G4 P5000
M105
G4 P5000
M105
G4 P5000
M105
G4 P5000
M105
G4 P5000
M105
G4 P5000
M105
M0

25912
samples/G-code/lm.g Normal file

File diff suppressed because it is too large Load Diff

29735
samples/G-code/rm.g Normal file

File diff suppressed because it is too large Load Diff

13
samples/G-code/square.g Normal file
View File

@@ -0,0 +1,13 @@
G28 X0 Y0
G1 X55 Y5 F2000
G1 Y180
G1 X180
G1 Y5
G1 X55
G1 Y180
G1 X180
G1 Y5
G1 X55
M0

View File

@@ -0,0 +1,57 @@
# Taken from https://github.com/okamstudio/godot/wiki/gdscript
# a file is a class!
# inheritance
extends BaseClass
# member variables
var a = 5
var s = "Hello"
var arr = [1, 2, 3]
var dict = {"key":"value", 2:3}
# constants
const answer = 42
const thename = "Charly"
# built-in vector types
var v2 = Vector2(1, 2)
var v3 = Vector3(1, 2, 3)
# function
func some_function(param1, param2):
var local_var = 5
if param1 < local_var:
print(param1)
elif param2 > 5:
print(param2)
else:
print("fail!")
for i in range(20):
print(i)
while(param2 != 0):
param2 -= 1
var local_var2 = param1+3
return local_var2
# subclass
class Something:
var a = 10
# constructor
func _init():
print("constructed!")
var lv = Something.new()
print(lv.a)

216
samples/GDScript/grid.gd Normal file
View File

@@ -0,0 +1,216 @@
extends Control
# Simple Tetris-like demo, (c) 2012 Juan Linietsky
# Implemented by using a regular Control and drawing on it during the _draw() callback.
# The drawing surface is updated only when changes happen (by calling update())
var score = 0
var score_label=null
const MAX_SHAPES = 7
var block = preload("block.png")
var block_colors=[
Color(1,0.5,0.5),
Color(0.5,1,0.5),
Color(0.5,0.5,1),
Color(0.8,0.4,0.8),
Color(0.8,0.8,0.4),
Color(0.4,0.8,0.8),
Color(0.7,0.7,0.7)]
var block_shapes=[
[ Vector2(0,-1),Vector2(0,0),Vector2(0,1),Vector2(0,2) ], # I
[ Vector2(0,0),Vector2(1,0),Vector2(1,1),Vector2(0,1) ], # O
[ Vector2(-1,1),Vector2(0,1),Vector2(0,0),Vector2(1,0) ], # S
[ Vector2(1,1),Vector2(0,1),Vector2(0,0),Vector2(-1,0) ], # Z
[ Vector2(-1,1),Vector2(-1,0),Vector2(0,0),Vector2(1,0) ], # L
[ Vector2(1,1),Vector2(1,0),Vector2(0,0),Vector2(-1,0) ], # J
[ Vector2(0,1),Vector2(1,0),Vector2(0,0),Vector2(-1,0) ]] # T
var block_rotations=[
Matrix32( Vector2(1,0),Vector2(0,1), Vector2() ),
Matrix32( Vector2(0,1),Vector2(-1,0), Vector2() ),
Matrix32( Vector2(-1,0),Vector2(0,-1), Vector2() ),
Matrix32( Vector2(0,-1),Vector2(1,0), Vector2() )
]
var width=0
var height=0
var cells={}
var piece_active=false
var piece_shape=0
var piece_pos=Vector2()
var piece_rot=0
func piece_cell_xform(p,er=0):
var r = (4+er+piece_rot)%4
return piece_pos+block_rotations[r].xform(p)
func _draw():
var sb = get_stylebox("bg","Tree") # use line edit bg
draw_style_box(sb,Rect2(Vector2(),get_size()).grow(3))
var bs = block.get_size()
for y in range(height):
for x in range(width):
if (Vector2(x,y) in cells):
draw_texture_rect(block,Rect2(Vector2(x,y)*bs,bs),false,block_colors[cells[Vector2(x,y)]])
if (piece_active):
for c in block_shapes[piece_shape]:
draw_texture_rect(block,Rect2(piece_cell_xform(c)*bs,bs),false,block_colors[piece_shape])
func piece_check_fit(ofs,er=0):
for c in block_shapes[piece_shape]:
var pos = piece_cell_xform(c,er)+ofs
if (pos.x < 0):
return false
if (pos.y < 0):
return false
if (pos.x >= width):
return false
if (pos.y >= height):
return false
if (pos in cells):
return false
return true
func new_piece():
piece_shape = randi() % MAX_SHAPES
piece_pos = Vector2(width/2,0)
piece_active=true
piece_rot=0
if (piece_shape==0):
piece_pos.y+=1
if (not piece_check_fit(Vector2())):
#game over
#print("GAME OVER!")
game_over()
update()
func test_collapse_rows():
var accum_down=0
for i in range(height):
var y = height - i - 1
var collapse = true
for x in range(width):
if (Vector2(x,y) in cells):
if (accum_down):
cells[ Vector2(x,y+accum_down) ] = cells[Vector2(x,y)]
else:
collapse=false
if (accum_down):
cells.erase( Vector2(x,y+accum_down) )
if (collapse):
accum_down+=1
score+=accum_down*100
score_label.set_text(str(score))
func game_over():
piece_active=false
get_node("gameover").set_text("Game Over")
update()
func restart_pressed():
score=0
score_label.set_text("0")
cells.clear()
get_node("gameover").set_text("")
piece_active=true
update()
func piece_move_down():
if (!piece_active):
return
if (piece_check_fit(Vector2(0,1))):
piece_pos.y+=1
update()
else:
for c in block_shapes[piece_shape]:
var pos = piece_cell_xform(c)
cells[pos]=piece_shape
test_collapse_rows()
new_piece()
func piece_rotate():
var adv = 1
if (not piece_check_fit(Vector2(),1)):
return
piece_rot = (piece_rot + adv) % 4
update()
func _input(ie):
if (not piece_active):
return
if (!ie.is_pressed()):
return
if (ie.is_action("move_left")):
if (piece_check_fit(Vector2(-1,0))):
piece_pos.x-=1
update()
elif (ie.is_action("move_right")):
if (piece_check_fit(Vector2(1,0))):
piece_pos.x+=1
update()
elif (ie.is_action("move_down")):
piece_move_down()
elif (ie.is_action("rotate")):
piece_rotate()
func setup(w,h):
width=w
height=h
set_size( Vector2(w,h)*block.get_size() )
new_piece()
get_node("timer").start()
func _ready():
# Initalization here
setup(10,20)
score_label = get_node("../score")
set_process_input(true)

243
samples/GDScript/player.gd Normal file
View File

@@ -0,0 +1,243 @@
extends RigidBody
# member variables here, example:
# var a=2
# var b="textvar"
#var dir=Vector3()
const ANIM_FLOOR = 0
const ANIM_AIR_UP = 1
const ANIM_AIR_DOWN = 2
const SHOOT_TIME = 1.5
const SHOOT_SCALE = 2
const CHAR_SCALE = Vector3(0.3,0.3,0.3)
var facing_dir = Vector3(1, 0, 0)
var movement_dir = Vector3()
var jumping=false
var turn_speed=40
var keep_jump_inertia = true
var air_idle_deaccel = false
var accel=19.0
var deaccel=14.0
var sharp_turn_threshhold = 140
var max_speed=3.1
var on_floor = false
var prev_shoot = false
var last_floor_velocity = Vector3()
var shoot_blend = 0
func adjust_facing(p_facing, p_target,p_step, p_adjust_rate,current_gn):
var n = p_target # normal
var t = n.cross(current_gn).normalized()
var x = n.dot(p_facing)
var y = t.dot(p_facing)
var ang = atan2(y,x)
if (abs(ang)<0.001): # too small
return p_facing
var s = sign(ang)
ang = ang * s
var turn = ang * p_adjust_rate * p_step
var a
if (ang<turn):
a=ang
else:
a=turn
ang = (ang - a) * s
return ((n * cos(ang)) + (t * sin(ang))) * p_facing.length()
func _integrate_forces( state ):
var lv = state.get_linear_velocity() # linear velocity
var g = state.get_total_gravity()
var delta = state.get_step()
var d = 1.0 - delta*state.get_total_density()
if (d<0):
d=0
lv += g * delta #apply gravity
var anim = ANIM_FLOOR
var up = -g.normalized() # (up is against gravity)
var vv = up.dot(lv) # vertical velocity
var hv = lv - (up*vv) # horizontal velocity
var hdir = hv.normalized() # horizontal direction
var hspeed = hv.length() #horizontal speed
var floor_velocity
var onfloor = false
if (state.get_contact_count() == 0):
floor_velocity = last_floor_velocity
else:
for i in range(state.get_contact_count()):
if (state.get_contact_local_shape(i) != 1):
continue
onfloor = true
floor_velocity = state.get_contact_collider_velocity_at_pos(i)
break
var dir = Vector3() #where does the player intend to walk to
var cam_xform = get_node("target/camera").get_global_transform()
if (Input.is_action_pressed("move_forward")):
dir+=-cam_xform.basis[2]
if (Input.is_action_pressed("move_backwards")):
dir+=cam_xform.basis[2]
if (Input.is_action_pressed("move_left")):
dir+=-cam_xform.basis[0]
if (Input.is_action_pressed("move_right")):
dir+=cam_xform.basis[0]
var jump_attempt = Input.is_action_pressed("jump")
var shoot_attempt = Input.is_action_pressed("shoot")
var target_dir = (dir - up*dir.dot(up)).normalized()
if (onfloor):
var sharp_turn = hspeed > 0.1 and rad2deg(acos(target_dir.dot(hdir))) > sharp_turn_threshhold
if (dir.length()>0.1 and !sharp_turn) :
if (hspeed > 0.001) :
#linear_dir = linear_h_velocity/linear_vel
#if (linear_vel > brake_velocity_limit and linear_dir.dot(ctarget_dir)<-cos(Math::deg2rad(brake_angular_limit)))
# brake=true
#else
hdir = adjust_facing(hdir,target_dir,delta,1.0/hspeed*turn_speed,up)
facing_dir = hdir
else:
hdir = target_dir
if (hspeed<max_speed):
hspeed+=accel*delta
else:
hspeed-=deaccel*delta
if (hspeed<0):
hspeed=0
hv = hdir*hspeed
var mesh_xform = get_node("Armature").get_transform()
var facing_mesh=-mesh_xform.basis[0].normalized()
facing_mesh = (facing_mesh - up*facing_mesh.dot(up)).normalized()
facing_mesh = adjust_facing(facing_mesh,target_dir,delta,1.0/hspeed*turn_speed,up)
var m3 = Matrix3(-facing_mesh,up,-facing_mesh.cross(up).normalized()).scaled( CHAR_SCALE )
get_node("Armature").set_transform(Transform(m3,mesh_xform.origin))
if (not jumping and jump_attempt):
vv = 7.0
jumping = true
get_node("sfx").play("jump")
else:
if (vv>0):
anim=ANIM_AIR_UP
else:
anim=ANIM_AIR_DOWN
var hs
if (dir.length()>0.1):
hv += target_dir * (accel * 0.2) * delta
if (hv.length() > max_speed):
hv = hv.normalized() * max_speed
else:
if (air_idle_deaccel):
hspeed = hspeed - (deaccel * 0.2) * delta
if (hspeed<0):
hspeed=0
hv = hdir*hspeed
if (jumping and vv < 0):
jumping=false
lv = hv+up*vv
if (onfloor):
movement_dir = lv
#lv += floor_velocity
last_floor_velocity = floor_velocity
else:
if (on_floor) :
#if (keep_jump_inertia):
# lv += last_floor_velocity
pass
last_floor_velocity = Vector3()
movement_dir = lv
on_floor = onfloor
state.set_linear_velocity(lv)
if (shoot_blend>0):
shoot_blend -= delta * SHOOT_SCALE
if (shoot_blend<0):
shoot_blend=0
if (shoot_attempt and not prev_shoot):
shoot_blend = SHOOT_TIME
var bullet = preload("res://bullet.scn").instance()
bullet.set_transform( get_node("Armature/bullet").get_global_transform().orthonormalized() )
get_parent().add_child( bullet )
bullet.set_linear_velocity( get_node("Armature/bullet").get_global_transform().basis[2].normalized() * 20 )
PS.body_add_collision_exception( bullet.get_rid(), get_rid() ) #add it to bullet
get_node("sfx").play("shoot")
prev_shoot = shoot_attempt
if (onfloor):
get_node("AnimationTreePlayer").blend2_node_set_amount("walk",hspeed / max_speed)
get_node("AnimationTreePlayer").transition_node_set_current("state",anim)
get_node("AnimationTreePlayer").blend2_node_set_amount("gun",min(shoot_blend,1.0))
# state.set_angular_velocity(Vector3())
func _ready():
# Initalization here
get_node("AnimationTreePlayer").set_active(true)
pass

73
samples/GDScript/pong.gd Normal file
View File

@@ -0,0 +1,73 @@
extends Node2D
# member variables here, example:
# var a=2
# var b="textvar"
const INITIAL_BALL_SPEED = 80
var ball_speed = INITIAL_BALL_SPEED
var screen_size = Vector2(640,400)
#default ball direction
var direction = Vector2(-1,0)
var pad_size = Vector2(8,32)
const PAD_SPEED = 150
func _process(delta):
# get ball positio and pad rectangles
var ball_pos = get_node("ball").get_pos()
var left_rect = Rect2( get_node("left").get_pos() - pad_size*0.5, pad_size )
var right_rect = Rect2( get_node("right").get_pos() - pad_size*0.5, pad_size )
#integrate new ball postion
ball_pos+=direction*ball_speed*delta
#flip when touching roof or floor
if ( (ball_pos.y<0 and direction.y <0) or (ball_pos.y>screen_size.y and direction.y>0)):
direction.y = -direction.y
#flip, change direction and increase speed when touching pads
if ( (left_rect.has_point(ball_pos) and direction.x < 0) or (right_rect.has_point(ball_pos) and direction.x > 0)):
direction.x=-direction.x
ball_speed*=1.1
direction.y=randf()*2.0-1
direction = direction.normalized()
#check gameover
if (ball_pos.x<0 or ball_pos.x>screen_size.x):
ball_pos=screen_size*0.5
ball_speed=INITIAL_BALL_SPEED
direction=Vector2(-1,0)
get_node("ball").set_pos(ball_pos)
#move left pad
var left_pos = get_node("left").get_pos()
if (left_pos.y > 0 and Input.is_action_pressed("left_move_up")):
left_pos.y+=-PAD_SPEED*delta
if (left_pos.y < screen_size.y and Input.is_action_pressed("left_move_down")):
left_pos.y+=PAD_SPEED*delta
get_node("left").set_pos(left_pos)
#move right pad
var right_pos = get_node("right").get_pos()
if (right_pos.y > 0 and Input.is_action_pressed("right_move_up")):
right_pos.y+=-PAD_SPEED*delta
if (right_pos.y < screen_size.y and Input.is_action_pressed("right_move_down")):
right_pos.y+=PAD_SPEED*delta
get_node("right").set_pos(right_pos)
func _ready():
screen_size = get_viewport_rect().size # get actual size
pad_size = get_node("left").get_texture().get_size()
set_process(true)

67
samples/Golo/adapters.golo Executable file
View File

@@ -0,0 +1,67 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.Adapters
local function list_sample = |fabric| {
println(">>> list_sample()")
let carbonCopy = list[]
let conf = map[
["extends", "java.util.ArrayList"],
["overrides", map[
["*", |super, name, args| {
if name == "add" {
if args: length() == 2 {
carbonCopy: add(args: get(1))
} else {
carbonCopy: add(args: get(1), args: get(2))
}
}
return super: invokeWithArguments(args)
}
]]
]]
let list = fabric: maker(conf): newInstance()
list: add("bar")
list: add(0, "foo")
list: add("baz")
println(" list: " + list + " " + list: getClass())
println("carbonCopy: " + carbonCopy + " " + carbonCopy: getClass())
}
local function runnable_sample = |fabric| {
println(">>> runnable_sample")
let result = array[1, 2, 3]
let conf = map[
["interfaces", ["java.io.Serializable", "java.lang.Runnable"]],
["implements", map[
["run", |this| {
for (var i = 0, i < result: length(), i = i + 1) {
result: set(i, result: get(i) + 10)
}
}]
]]
]
let runner = fabric: maker(conf): newInstance()
runner: run()
println(" result: " + result: toString())
println("serializable? " + (runner oftype java.io.Serializable.class))
println(" runnable? " + (runner oftype java.lang.Runnable.class))
}
function main = |args| {
let fabric = AdapterFabric()
list_sample(fabric)
runnable_sample(fabric)
}

84
samples/Golo/async.golo Executable file
View File

@@ -0,0 +1,84 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.AsyncHelpers
import gololang.Async
import java.util.concurrent.TimeUnit
import java.util.concurrent.Executors
local function fib = |n| {
if n <= 1 {
return n
} else {
return fib(n - 1) + fib(n - 2)
}
}
function main = |args| {
let executor = newCachedThreadPool()
println("Let's do some useless asynchronous operations...")
var f = executor: enqueue({
Thread.sleep(1000_L)
return 666
})
f:
onSet(|v| -> println(">>> #slow -> " + v)):
onFail(|e| -> println(">>> #fail -> " + e))
f:
cancel(true)
f = executor: enqueue({
Thread.sleep(1000_L)
return 666
})
f:
onSet(|v| -> println(">>> #ok -> " + v)):
onFail(|e| -> println(">>> #wtf? -> " + e))
let fib_10 = promise()
let fib_20 = promise()
let fib_30 = promise()
let fib_40 = promise()
let futures = [
fib_10: future(), fib_20: future(),
fib_30: future(), fib_40: future()
]
executor: submit(-> fib_10: set(fib(10)))
executor: submit(-> fib_20: set(fib(20)))
executor: submit(-> fib_30: set(fib(30)))
executor: submit(-> fib_40: set(fib(40)))
all(futures): onSet(|results| -> println(">>> Fibs: " + results))
let truth = promise()
truth:
future():
map(|v| -> "truth=" + v):
onSet(|v| -> executor: submit(-> println(">>> (another thread) " + v))):
onSet(|v| -> println(">>> (same thread) " + v))
executor: submit({
Thread.sleep(500_L)
truth: set(42)
})
Thread.sleep(1000_L)
executor: shutdown()
executor: awaitTermination(2_L, SECONDS())
println("Bye!")
}

37
samples/Golo/augmentations.golo Executable file
View File

@@ -0,0 +1,37 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.Augmentations
import java.util.LinkedList
augment java.util.List {
function with = |this, value| {
this: add(value)
return this
}
}
augment java.util.Collection {
function doToEach = |this, func| {
foreach (element in this) {
func(element)
}
}
}
function main = |args| {
let list = LinkedList(): with("foo"): with("bar"): with("baz")
list: doToEach(|value| -> println(">>> " + value))
}

43
samples/Golo/closures.golo Executable file
View File

@@ -0,0 +1,43 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module Closures
local function sayHello = |who| -> "Hello " + who + "!"
function main = |args| {
let adder = |a, b| -> a + b
println(adder: invokeWithArguments(1, 2))
println(adder(1, 2))
let addToTen = adder: bindTo(10)
println(addToTen: invokeWithArguments(2))
println(addToTen(2))
let adding = |x| -> |y| -> adder(x, y)
let addingTen = adding(10)
println(addingTen(4))
println(adding(2)(4))
println(sayHello("Julien"))
let list = java.util.LinkedList()
let pump_it = {
list: add("I heard you say")
list: add("Hey!")
list: add("Hey!")
}
pump_it()
println(list)
}

34
samples/Golo/coin-change.golo Executable file
View File

@@ -0,0 +1,34 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module CoinChange
import java.util.LinkedList
function change = |money, coins| -> match {
when money == 0 then 1
when (money < 0) or (coins: isEmpty()) then 0
otherwise change(money - coins: head(), coins) + change(money, coins: tail())
}
function main = |args| {
let coins = LinkedList(): append(1, 2, 5, 10, 20)
println("Coins: " + coins)
println("0: " + change(0, coins))
println("1: " + change(1, coins))
println("2: " + change(2, coins))
println("10: " + change(10, coins))
println("12: " + change(12, coins))
println("6: " + change(6, coins))
}

View File

@@ -0,0 +1,55 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.CollectionLiterals
local function play_with_tuples = {
let hello = ["Hello", "world", "!"]
foreach str in hello {
print(str + " ")
}
println("")
println(hello: get(0) + "-" + hello: get(1) + "-" + hello: get(2))
println(hello: join("/"))
}
local function play_with_literals = {
let data = [
[1, 2, 3],
tuple[1, 2, 3],
array[1, 2, 3],
set[1, 2, 3, 3, 1],
map[
["a", 10],
["b", 20]
],
vector[1, 2, 3],
list[1, 2, 3]
]
data: each(|element| {
println(element: toString())
println(" type: " + element: getClass())
})
}
function main = |args| {
println(">>> Literals")
play_with_literals()
println("\n>>> Tuples")
play_with_tuples()
}

View File

@@ -0,0 +1,53 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.ContextDecorator
import gololang.Decorators
let myContext = defaultContext():
count(0):
define("entry", |this, args| {
this: count(this: count() + 1)
println("hello:" + this: count())
return args
}):
define("exit", |this, result| {
require(result >= 3, "wrong value")
println("goobye")
return result
}):
define("catcher", |this, e| {
println("Caught " + e)
throw e
}):
define("finallizer", |this| {println("do some cleanup")})
@withContext(myContext)
function foo = |a, b| {
println("Hard computation")
return a + b
}
function main = |args| {
println(foo(1,2))
println("====")
println(withContext(myContext)(|a| -> 2*a)(3))
println("====")
try {
println(foo(1, 1))
} catch (e) { }
}

83
samples/Golo/decorators.golo Executable file
View File

@@ -0,0 +1,83 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.Decorators
import java.util.LinkedList
function simple_decorator = |func| {
return |a,b| -> func(a+1,b+1)
}
@simple_decorator
function simple_adder = |x,y| -> x + y
function decorator_with_params = |param1, param2|{
return |func| {
return |a,b| -> func(a+param1,b+param2)
}
}
@decorator_with_params(10,2)
function parametrized_adder = |x,y| -> x + y
function generic_decorator = |func| {
return |args...| {
println("number of params : "+args: length())
return func: invokeWithArguments(args)
}
}
@generic_decorator
function generic_adder0 = -> 42
@generic_decorator
function generic_adder1 = |x| -> x
@generic_decorator
function generic_adder2 = |x,y| -> x + y
@generic_decorator
function generic_adder3 = |x,y,z| -> x + y + z
function list_sum_decorator = |func| {
return |this| -> func(this) - 8
}
augment java.util.List {
@list_sum_decorator
function sum = |this| {
var acc = 0
foreach elem in this {
acc = acc + elem
}
return acc
}
}
function main = |args| {
println(simple_adder(10,30))
println(parametrized_adder(10,20))
println(generic_adder0())
println(generic_adder1(42))
println(generic_adder2(20,22))
println(generic_adder3(10,12,20))
let list = LinkedList()
list: add(5)
list: add(10)
list: add(15)
list: add(20)
println(list: sum())
}

View File

@@ -0,0 +1,88 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.DynamicEvaluation
import gololang.EvaluationEnvironment
local function test_asModule = |env| {
let code =
"""
module foo
function a = -> "a!"
function b = -> "b!"
"""
let mod = env: asModule(code)
let a = fun("a", mod)
let b = fun("b", mod)
println(">>> asModule()")
println(a())
println(b())
}
local function test_anonymousModule = |env| {
let code =
"""
function a = -> "a."
function b = -> "b."
"""
let mod = env: anonymousModule(code)
let a = fun("a", mod)
let b = fun("b", mod)
println(">>> anonymousModule()")
println(a())
println(b())
}
local function test_asFunction = |env| {
let code = "return (a + b) * 2"
let f = env: asFunction(code, "a", "b")
println(">>> asFunction")
println(f(10, 20))
}
local function test_def = |env| {
let code = "|a, b| -> (a + b) * 2"
let f = env: def(code)
println(">>> def")
println(f(10, 20))
}
local function test_run = |env| {
let code = """println(">>> run")
foreach (i in range(0, 3)) {
println("w00t")
}"""
env: run(code)
}
local function test_run_map = |env| {
let code = """println(">>> run_map")
println(a)
println(b)
"""
let values = java.util.TreeMap(): add("a", 1): add("b", 2)
env: run(code, values)
}
function main = |args| {
let env = EvaluationEnvironment()
test_asModule(env)
test_anonymousModule(env)
test_asFunction(env)
test_def(env)
test_run(env)
test_run_map(env)
}

View File

@@ -0,0 +1,29 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.DynamicObjectPerson
local function mrbean = -> DynamicObject():
name("Mr Bean"):
email("mrbean@gmail.com"):
define("toString", |this| -> this: name() + " <" + this: email() + ">")
function main = |args| {
let bean = mrbean()
println(bean: toString())
bean: email("mrbean@outlook.com")
println(bean: toString())
}

34
samples/Golo/echo-args.golo Executable file
View File

@@ -0,0 +1,34 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module EchoArgs
function main = |args| {
println("With a for loop and an index:")
for (var i = 0, i < args: length(), i = i + 1) {
println(" #" + i + " -> " + args: get(i))
}
println("With a foreach loop:")
foreach arg in args {
println(" " + arg)
}
println("With a foreach over a range:")
foreach i in range(0, args: length()) {
println(" #" + i + " -> " + args: get(i))
}
}

View File

@@ -0,0 +1,31 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module sample.EnumsThreadState
import java.lang.Thread$State
function main = |args| {
# Call the enum entry like a function
let new = Thread$State.NEW()
println("name=" + new: name() + ", ordinal=" + new: ordinal())
println("-----------")
# Walk through all enum entries
foreach element in Thread$State.values() {
println("name=" + element: name() + ", ordinal=" + element: ordinal())
}
}

39
samples/Golo/fibonacci.golo Executable file
View File

@@ -0,0 +1,39 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.Fibonacci
import java.lang.System
function fib = |n| {
if n <= 1 {
return n
} else {
return fib(n - 1) + fib(n - 2)
}
}
local function run = {
let start = System.currentTimeMillis()
let result = fib(40)
let duration = System.currentTimeMillis() - start
println(">>> " + result + " (took " + duration + "ms)")
}
function main = |args| {
while true {
run()
}
}

20
samples/Golo/helloworld.golo Executable file
View File

@@ -0,0 +1,20 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module hello.World
function main = |args| {
println("Hello world!")
}

53
samples/Golo/http-server.golo Executable file
View File

@@ -0,0 +1,53 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.WebServer
import java.lang
import java.net.InetSocketAddress
import com.sun.net.httpserver
import com.sun.net.httpserver.HttpServer
function main = |args| {
let server = HttpServer.create(InetSocketAddress("localhost", 8081), 0)
server: createContext("/", |exchange| {
let headers = exchange: getResponseHeaders()
let response = StringBuilder():
append("Requested URI: "):
append(exchange: getRequestURI()):
append("\n"):
append("Current time: "):
append(java.util.Date()):
append("\n"):
toString()
headers: set("Content-Type", "text/plain")
exchange: sendResponseHeaders(200, response: length())
exchange: getResponseBody(): write(response: getBytes())
exchange: close()
})
server: createContext("/shutdown", |exchange| {
let response = "Ok, thanks, bye!"
exchange: getResponseHeaders(): set("Content-Type", "text/plain")
exchange: sendResponseHeaders(200, response: length())
exchange: getResponseBody(): write(response: getBytes())
exchange: close()
server: stop(5)
})
server: start()
println(">>> http://localhost:8081/")
}

65
samples/Golo/logdeco.golo Executable file
View File

@@ -0,0 +1,65 @@
module samples.LogDeco
function log1 = |msg| {
return |fun| {
return |args...| {
println(msg)
return fun: invokeWithArguments(args)
}
}
}
@log1("calling foo")
function foo = |a| {
println("foo got a " + a)
}
@log1("I'am a bar")
function bar = |a| -> 2*a
let sayHello = log1("Hello")
@sayHello
function baz = -> "Goodbye"
function log2 = |msgBefore| -> |msgAfter| -> |func| -> |args...| {
println(msgBefore)
let res = func: invokeWithArguments(args)
println(msgAfter)
return res
}
@log2("enter foo")("exit foo")
function spam = |a| {
println("foo: " + a)
}
function logEnterExit = |name| -> log2("# enter " + name)("# exit " + name)
@logEnterExit("bar")
function egg = { println("doing something...") }
function main = |args| {
foo("bar")
println("---")
println(bar(21))
println("---")
println(baz())
println("---")
spam("bar")
println("---")
egg()
println("---")
let strange_use = log2("hello")("goodbye")({println(":p")})
strange_use()
println("---")
log2("another")("use")(|a|{println(a)})("strange")
}

View File

@@ -0,0 +1,40 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module Matching
import java.util.LinkedList
local function data = {
let list = LinkedList()
list: add("foo@bar.com")
list: add("+33.6.11.22.33")
list: add("http://golo-lang.org/")
list: add("def foo = bar(_._) with :> T")
return list
}
local function what_it_could_be = |item| -> match {
when item: contains("@") then "an email?"
when item: startsWith("+33") then "a French phone number?"
when item: startsWith("http://") then "a website URL?"
otherwise "I have no clue, mate!"
}
function main = |args| {
foreach item in data() {
println(item + " => " + what_it_could_be(item))
}
}

24
samples/Golo/max-int.golo Executable file
View File

@@ -0,0 +1,24 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.MaxInt
local function max_int = {
return java.lang.Integer.MAX_VALUE()
}
function main = |args| {
println(max_int())
}

55
samples/Golo/memoize.golo Executable file
View File

@@ -0,0 +1,55 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.MemoizeDecorator
import gololang.Decorators
import java.lang.System
let memo = memoizer()
@memo
function fib = |n| {
if n <= 1 {
return n
} else {
return fib(n - 1) + fib(n - 2)
}
}
@memo
function foo = |n| -> n
local function run = {
let start = System.currentTimeMillis()
let result = fib(40)
let duration = System.currentTimeMillis() - start
println(">>> fib(40) = " + result + " (took " + duration + "ms)")
}
local function run2 = {
let start = System.currentTimeMillis()
let result = foo(40)
let duration = System.currentTimeMillis() - start
println(">>> foo(40) = " + result + " (took " + duration + "ms)")
}
function main = |args| {
foreach i in range(0, 5) {
println("run " + i)
run()
run2()
}
}

43
samples/Golo/null-safety.golo Executable file
View File

@@ -0,0 +1,43 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module DealingWithNull
import java.util
function main = |args| {
# Data model
let contacts = map[
["mrbean", map[
["email", "bean@gmail.com"],
["url", "http://mrbean.com"]
]],
["larry", map[
["email", "larry@iamricherthanyou.com"]
]]
]
# MrBean and Larry
let mrbean = contacts: get("mrbean")
let larry = contacts: get("larry")
# Illustrates orIfNull
println(mrbean: get("url") orIfNull "n/a")
println(larry: get("url") orIfNull "n/a")
# Querying a non-existent data model because there is no 'address' entry
println(mrbean: get("address")?: street()?: number() orIfNull "n/a")
}

View File

@@ -0,0 +1,65 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.PrepostDecorator
import gololang.Decorators
let isInteger = isOfType(Integer.class)
@checkResult(isString(): andThen(lengthIs(2)))
@checkArguments(isInteger: andThen(isPositive()), isString())
function foo = |a, b| {
return b + a
}
let myCheck = checkArguments(isInteger: andThen(isPositive()))
@myCheck
function inv = |v| -> 1.0 / v
let isPositiveInt = isInteger: andThen(isPositive())
@checkArguments(isPositiveInt)
function mul = |v| -> 10 * v
@checkArguments(isNumber())
function num = |v| -> "ok"
@checkArguments(isNotNull())
function notnull = |v| -> "ok"
function main = |args| {
try { println(foo(1, "b")) } catch (e) { println(e) }
try { println(foo(-1, "b")) } catch (e) { println(e) }
try { println(foo("a", 2)) } catch (e) { println(e) }
try { println(foo(1, 2)) } catch (e) { println(e) }
try { println(foo(10, "ab")) } catch (e) { println(e) }
try { println(inv(10)) } catch (e) { println(e) }
try { println(inv(0)) } catch (e) { println(e) }
try { println(mul(5)) } catch (e) { println(e) }
try { println(mul(0)) } catch (e) { println(e) }
try { println(num(1)) } catch (e) { println(e) }
try { println(num(1_L)) } catch (e) { println(e) }
try { println(num(1.5)) } catch (e) { println(e) }
try { println(num(1.5_F)) } catch (e) { println(e) }
try { println(num("a")) } catch (e) { println(e) }
try { println(num('a')) } catch (e) { println(e) }
try { println(notnull('1')) } catch (e) { println(e) }
try { println(notnull(null)) } catch (e) { println(e) }
}

69
samples/Golo/structs.golo Executable file
View File

@@ -0,0 +1,69 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module StructDemo
struct Point = { x, y }
augment StructDemo.types.Point {
function move = |this, offsetX, offsetY| {
this: x(this: x() + offsetX)
this: y(this: y() + offsetY)
return this
}
function relative = |this, offsetX, offsetY| -> Point(this: x() + offsetX, this: y() + offsetY)
}
function main = |args| {
let p1 = Point(1, 2)
let p2 = Point(): x(1): y(2)
let p3 = p1: frozenCopy()
let p4 = p1: frozenCopy()
println(p1)
println("x = " + p1: x())
println("y = " + p1: y())
println("p1 == p2 " + (p1 == p2))
println("p1 == p3 " + (p1 == p3))
println("p3 == p4 " + (p3 == p4))
println("#p1 " + p1: hashCode())
println("#p2 " + p2: hashCode())
println("#p3 " + p3: hashCode())
println("#p4 " + p4: hashCode())
println("p1: members() " + p1: members())
println("p1: values() " + p1: values())
foreach item in p1 {
println(item: get(0) + " -> " + item: get(1))
}
println("p1: set(\"x\", 10) " + p1: set("x", 10))
println("p1: move(10, 5) " + p1: move(10, 5))
println("p1: relative(11, 6) " + p1: relative(11, 6))
let p5 = ImmutablePoint(10, 20)
println("p5: " + p5)
try {
p5: x(100)
} catch (expected) {
println("p5 is immutable, so... " + expected: getMessage())
}
}

View File

@@ -0,0 +1,43 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.SwingActionListener
import java.awt.event
import javax.swing
import javax.swing.WindowConstants
local function listener = |handler| -> asInterfaceInstance(ActionListener.class, handler)
function main = |args| {
let frame = JFrame("Action listeners")
frame: setDefaultCloseOperation(EXIT_ON_CLOSE())
let button = JButton("Click me!")
button: setFont(button: getFont(): deriveFont(96.0_F))
# Using a helper function
button: addActionListener(listener(|event| -> println("Clicked!")))
# Using a standard augmentation: MethodHandle::to(Class)
button: addActionListener((|event| -> println("[click]")): to(ActionListener.class))
# Straight closure passing
button: addActionListener(|event| -> println("( )"))
frame: getContentPane(): add(button)
frame: pack()
frame: setVisible(true)
}

View File

@@ -0,0 +1,31 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.SwingHelloWorld
import javax.swing
import javax.swing.WindowConstants
function main = |args| {
let frame = JFrame("Hello world")
frame: setDefaultCloseOperation(EXIT_ON_CLOSE())
let label = JLabel("Hello world")
label: setFont(label: getFont(): deriveFont(128.0_F))
frame: getContentPane(): add(label)
frame: pack()
frame: setVisible(true)
}

View File

@@ -0,0 +1,90 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module samples.TemplatesChatWebapp
import java.lang
import java.io
import java.net.InetSocketAddress
import com.sun.net.httpserver
import com.sun.net.httpserver.HttpServer
local function redirect = |exchange, to| {
exchange: getResponseHeaders(): set("Location", to)
exchange: sendResponseHeaders(303, 0)
exchange: close()
}
local function respond = |exchange, body| {
exchange: getResponseHeaders(): set("Content-Type", "text/html")
exchange: sendResponseHeaders(200, body: length())
exchange: getResponseBody(): write(body: getBytes())
exchange: close()
}
# This is leaky and works with just 1 POST parameter...
local function extract_post = |exchange, posts| {
let reader = BufferedReader(InputStreamReader(exchange: getRequestBody()))
var line = reader: readLine()
while line isnt null {
if line: startsWith("msg=") {
posts: add(java.net.URLDecoder.decode(line: substring(4), "UTF-8"))
}
line = reader: readLine()
}
reader: close()
}
local function index = |posts, template, exchange| {
if exchange: getRequestMethod() == "POST" {
extract_post(exchange, posts)
redirect(exchange, "/")
} else {
respond(exchange, template(posts))
}
}
local function index_template = -> """
<%@params posts %>
<!DOCTYPE html>
<html>
<head>
<title>Golo Chat</title>
</head>
<body>
<form action="/" method="post">
<input type="text" name="msg">
<input type="submit" value="Send">
</form>
<div>
<h3>Last posts</h3>
<% foreach post in posts { %>
<div>
<%= post %>
</div>
<% } %>
</div>
</body>
</html>
"""
function main = |args| {
let index_tpl = gololang.TemplateEngine(): compile(index_template())
let posts = java.util.concurrent.ConcurrentLinkedDeque()
let server = HttpServer.create(InetSocketAddress("localhost", 8081), 0)
server: createContext("/", ^index: bindTo(posts): bindTo(index_tpl))
server: start()
println(">>> http://localhost:8081/")
}

View File

@@ -0,0 +1,51 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module MoreCoolContainers
function main = |args| {
println(">>> DynamicVariable")
let dyn = DynamicVariable("Foo")
println(dyn: value())
let t1 = Thread({
dyn: withValue(666, {
println(dyn: value())
})
})
let t2 = Thread({
dyn: withValue(69, {
println(dyn: value())
})
})
t1: start()
t2: start()
t1: join()
t2: join()
println(dyn: value())
println(">>> Observable")
let foo = Observable("Foo")
foo: onChange(|v| -> println("foo = " + v))
let mapped = foo: map(|v| -> v + "!")
mapped: onChange(|v| -> println("mapped = " + v))
foo: set("69")
}

48
samples/Golo/workers.golo Executable file
View File

@@ -0,0 +1,48 @@
# Copyright 2012-2014 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
module Workers
import java.lang.Thread
import java.util.concurrent
import gololang.concurrent.workers.WorkerEnvironment
local function pusher = |queue, message| -> queue: offer(message)
local function generator = |port, message| {
foreach i in range(0, 100) {
port: send(message)
}
}
function main = |args| {
let env = WorkerEnvironment.builder(): withFixedThreadPool()
let queue = ConcurrentLinkedQueue()
let pusherPort = env: spawn(^pusher: bindTo(queue))
let generatorPort = env: spawn(^generator: bindTo(pusherPort))
let finishPort = env: spawn(|any| -> env: shutdown())
foreach i in range(0, 10) {
generatorPort: send("[" + i + "]")
}
Thread.sleep(2000_L)
finishPort: send("Die!")
env: awaitTermination(2000)
println(queue: reduce("", |acc, next| -> acc + " " + next))
}

View File

@@ -0,0 +1,21 @@
graph
[
directed 0
node
[
id 0
label "Node 1"
value 100
]
node
[
id 1
label "Node 2"
value 200
]
edge
[
source 1
target 0
]
]

13
samples/Groff/sample.4 Normal file
View File

@@ -0,0 +1,13 @@
.TH FOO 1
.SH NAME
foo \- bar
.SH SYNOPSIS
.B foo
.I bar
.SH DESCRIPTION
Foo bar
.BR baz
quux.
.PP
.B Foo
bar baz.

55
samples/Hack/Assert.hh Normal file
View File

@@ -0,0 +1,55 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
final class AssertException extends Exception {}
final class Assert {
public static function isNum(mixed $x): num {
if (is_float($x)) {
return $x;
} else if (is_int($x)) {
return $x;
}
throw new AssertException('Expected an int or float value');
}
public static function isInt(mixed $x): int {
if (is_int($x)) {
return $x;
}
throw new AssertException('Expected an int');
}
public static function isFloat(mixed $x): float {
if (is_float($x)) {
return $x;
}
throw new AssertException('Expected a float');
}
public static function isString(mixed $x): string {
if (is_string($x)) {
return $x;
}
throw new AssertException('Expected a string');
}
// For arrays you need to check every element
public static function isArrayOf<T>(
(function(mixed): T) $fn,
mixed $x,
): array<T> {
if (is_array($x)) {
return array_map($fn, $x);
}
throw new AssertException('Expected an array');
}
}

View File

@@ -0,0 +1,52 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/recipe/init.php';
require_once "demo.php";
class AssertRecipe extends Recipe implements RecipeWithDemo {
protected function getName(): string {
return 'Assert';
}
<<Override>>
protected function getDescription(): ?string {
return 'When you have values with unknown types, it is useful to make '.
'some runtime assertions and have the type checker understand. This '.
'recipe demonstrates one approach.';
}
protected function getFilenames(): Vector<string> {
return Vector {
'Assert.php',
};
}
protected function getDocs(): Vector<(string, string)> {
return Vector{
tuple ('Mixed Types', 'hack.annotations.mixedtypes'),
tuple ('Type Inference', 'hack.otherrulesandfeatures.typeinference'),
};
}
public function getDemoFilename(): string {
return 'demo.php';
}
public function getDemoResult(): string {
return assert_main();
}
public function getDemoXHP(): ?:xhp {
return null;
}
}

View File

@@ -0,0 +1,39 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/startup/init.php';
abstract class Controller {
protected function __construct() {
startup();
}
abstract protected function getCSS(): Set<string>;
abstract protected function getJS(): Set<string>;
abstract protected function getTitle(): string;
abstract protected function render(): :xhp;
final protected function getHead(): :xhp {
$css = $this->getCSS()->toVector()->map(
($css) ==> <link rel="stylesheet" type="text/css" href={$css} />
);
$js = $this->getJS()->toVector()->map(
($js) ==> <script src={$js} />
);
return
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<title>{$this->getTitle()}</title>
{$css->toArray()}
{$js->toArray()}
</head>;
}
}

View File

@@ -0,0 +1,52 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/recipe/init.php';
require_once "demo.php";
class DBResultRecipe extends Recipe implements RecipeWithDemo {
protected function getName(): string {
return 'DB Result';
}
<<Override>>
protected function getDescription(): ?string {
return 'Fetching data from a DB introduces a few typing challenges. '.
'First, the data comes back untyped. Second, a row in a DB generally '.
'contains columns of different types.';
}
protected function getFilenames(): Vector<string> {
return Vector {
'FakeDB.php',
};
}
protected function getDocs(): Vector<(string, string)> {
return Vector{
tuple ('Hack Shapes', 'hack.shapes'),
tuple ('Mixed Types', 'hack.annotations.mixedtypes'),
};
}
public function getDemoFilename(): string {
return 'demo.php';
}
public function getDemoResult(): string {
return db_result_main();
}
public function getDemoXHP(): ?:xhp {
return null;
}
}

View File

@@ -0,0 +1,22 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/vendor/hhvm/xhp/src/init.php';
final class :documentation extends :x:element {
attribute string name;
protected function render(): :xhp {
$name = implode('.', explode(' ', $this->getAttribute('name'))).".php";
$href = "http://hhvm.com/manual/en/$name";
return <a class="docs button" href={$href} target="_blank">docs &rarr;</a>;
}
}

65
samples/Hack/FakeDB.hh Normal file
View File

@@ -0,0 +1,65 @@
<?hh // strict
type DBResultExtra = shape('age' => int);
type DBResult = shape(
'id' => int,
'name' => string,
'extra' => DBResultExtra,
);
final class FakeDB {
public function getRawRows(): array<array<string, mixed>> {
$good_extra = json_encode(array('age' => 40));
$bad_extra = 'corrupt data';
// Real code would query a DB, but for now let's hardcode it
return array(
array(
'id' => 123,
'name' => 'Alice',
'extra' => $good_extra,
),
array(
'id' => 456,
'name' => 'Bob',
'extra' => $bad_extra,
),
);
}
/**
* When processing untyped data you need to check each piece of data and
* figure out whether to give up or recover when the data is bad
*/
public function processRow(array<string, mixed> $row): ?DBResult {
$row = Map::fromArray($row);
$id = $row->contains('id') ? $row['id'] : null;
$name = $row->contains('name') ? $row['name'] : null;
$extra = $row->contains('extra') ? json_decode($row['extra'], true) : null;
// Ignore rows with invalid IDs or names
if (!is_int($id) || !is_string($name)) {
return null;
}
// Try to recover from a bad extra column
if (!is_array($extra)) {
$extra = shape('age' => 0);
} else {
$extra = Map::fromArray($extra);
$extra = shape('age' => $extra->contains('age') ? $extra['age'] : 0);
}
return shape('id' => $id, 'name' => $name, 'extra' => $extra);
}
public function getDBResults(): Vector<DBResult> {
$ret = Vector {};
foreach ($this->getRawRows() as $raw_row) {
$row = $this->processRow($raw_row);
if ($row !== null) {
$ret->add($row);
}
}
return $ret;
}
}

View File

@@ -0,0 +1,72 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/recipe/init.php';
require_once "demo.php";
class GetAndPostRecipe extends Recipe implements RecipeWithDemo {
protected function getName(): string {
return '$_GET and $_POST';
}
<<Override>>
protected function getDescription(): ?string {
return 'A small example of how to interact with superglobals and the '.
'untyped data they can contain.';
}
protected function getFilenames(): Vector<string> {
return Vector {
'NonStrictFile.php',
'StrictFile.php',
};
}
protected function getDocs(): Vector<(string, string)> {
return Vector {
tuple('invariant()', 'hack.otherrulesandfeatures.invariant'),
};
}
public function getDemoFilename(): string {
return 'demo.php';
}
public function getDemoResult(): string {
return get_and_post_main();
}
public function getDemoXHP(): :xhp {
$url = '/recipes/get-and-post/';
return
<x:frag>
<div>
<a href={"$url?myIntParam=8675309#demo"} class="button">GET myIntParam=8675309</a>
</div>
<div>
<a href={"$url?myIntParam=boom#demo"} class="button">GET myIntParam=boom</a>
</div>
<div>
<form action={"$url#demo"} method="post">
<input type="hidden" name="myIntParam" value="5551234"/>
<input type="submit" class="button" value="POST myIntParam=5551234"/>
</form>
</div>
<div>
<form action={"$url#demo"} method="post">
<input type="hidden" name="myIntParam" value="boom"/>
<input type="submit" class="button" value="POST myIntParam=boom"/>
</form>
</div>
</x:frag>;
}
}

View File

@@ -0,0 +1,30 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
abstract class GetController extends Controller {
final protected function __construct(private Request $request) {
parent::__construct();
}
final protected function getRequest(): Request {
return $this->request;
}
final public function go(array<mixed, mixed> $get): void {
$request = new Request(Map::fromArray($get));
$controller = new static($request);
echo "<!DOCTYPE html>";
$head = $controller->getHead();
$body = $controller->render();
echo (string)$head;
echo (string)$body;
}
}

View File

@@ -0,0 +1,38 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/init.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/standard-page/init.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/vendor/hhvm/xhp/src/init.php';
class HomeController extends GetController {
use StandardPage;
protected function getTitle(): string {
return 'Hack Cookbook';
}
protected function renderMainColumn(): :xhp {
return <div>
<h1>Cookbook</h1>
<p>
The Hack Cookbook helps you write Hack code by giving you examples of
Hack code. It is written in Hack and is open source. If you
<a href="http://github.com/facebook/hack-example-site">
head over to GitHub,
</a>
you can read the code, check out the repository, and run it
yourself. The recipes in this cookbook are small examples that
illustrate how to use Hack to solve common and interesting problems.
</p>
</div>;
}
}

View File

@@ -0,0 +1,13 @@
<?hh // strict
require_once $_SERVER['DOCUMENT_ROOT'].'/core/funs/init.php';
final class MySecureRequest {
public function __construct(private Map<string, mixed> $GETParams) {}
public function stringParam(string $name): UNESCAPED_STRING {
invariant($this->GETParams->contains($name), 'Unknown GET param: '.$name);
$raw_string = $this->GETParams[$name];
invariant(is_string($raw_string), $name.' is not a string');
return unescaped_string($raw_string);
}
}

104
samples/Hack/Nav.hh Normal file
View File

@@ -0,0 +1,104 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/vendor/hhvm/xhp/src/init.php';
type NavItem = shape(
'name' => string,
'location' => string,
);
type NavSection = shape(
'name' => string,
'location' => ?string,
'items' => Vector<NavItem>,
);
final class :hack:nav extends :x:element {
private function getNavSections(): Vector<NavSection> {
return Vector{
shape(
'name' => 'Home',
'location' => '/',
'items' => Vector {},
),
shape(
'name' => 'GitHub',
'location' => 'http://github.com/facebook/hack-example-site',
'items' => Vector {},
),
shape(
'name' => 'Recipes',
'location' => null,
'items' => Vector {
shape(
'name' => '$_GET and $_POST',
'location' => '/recipes/get-and-post/',
),
shape(
'name' => 'Assert',
'location' => '/recipes/assert/',
),
shape(
'name' => 'DB Result',
'location' => '/recipes/db-result/',
),
shape(
'name' => 'Unescaped String',
'location' => '/recipes/unescaped-string/',
),
shape(
'name' => 'User ID',
'location' => '/recipes/user-id/',
),
},
),
};
}
private function renderNavItems(Vector<NavItem> $items): :xhp {
$render_item = $item ==>
<li>
<a class="navItem" href={$item['location']}>
{$item['name']}
</a>
</li>;
return
<x:frag>
{$items->map($render_item)->toArray()}
</x:frag>;
}
private function renderNavSection(NavSection $section): :xhp {
$section_item = <h3 class="navItem">{$section['name']}</h3>;
if ($section['location'] !== null) {
$section_item = <a href={$section['location']}>{$section_item}</a>;
}
return
<li class="navSectionItem">
{$section_item}
<ul class="navItems">
{$this->renderNavItems($section['items'])}
</ul>
</li>;
}
public function render(): :xhp {
$sections = $this->getNavSections()
->map($section ==> $this->renderNavSection($section));
return
<div class="nav">
<ul class="navSections">
{$sections->toArray()}
</ul>
</div>;
}
}

View File

@@ -0,0 +1,27 @@
<?hh
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
function getGETParams(): Map<string, mixed> {
// $_GET is not defined in code so Hack doesn't know about it and you can't
// use it in strict mode. You can interact with it outside of strict mode,
// though.
return Map::fromArray($_GET);
}
function getPOSTParams(): Map<string, mixed> {
// Same deal with $_POST and other magically defined globals
return Map::fromArray($_POST);
}
// Same deal with $_SERVER
function isGET(): bool {
return $_SERVER['REQUEST_METHOD'] === 'GET';
}

93
samples/Hack/Recipe.hh Normal file
View File

@@ -0,0 +1,93 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/init.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/standard-page/init.php';
require_once $_SERVER['DOCUMENT_ROOT'].'/core/myxhp/init.php';
abstract class Recipe extends GetController {
use StandardPage;
abstract protected function getName(): string;
abstract protected function getFilenames(): Vector<string>;
abstract protected function getDocs(): Vector<(string, string)>;
protected function getDescription(): ?string {
return null;
}
final protected function getTitle(): string {
return $this->getName().' - Hack Cookbook';
}
final protected function renderMainColumn(): :xhp {
$main_column =
<x:frag>
<h1>{$this->getName()}</h1>
</x:frag>;
$description = $this->getDescription();
if ($description !== null) {
$main_column->appendChild(<p>{$description}</p>);
}
foreach ($this->getFilenames() as $filename) {
$file =
<div class="file">
<div class="filename">{$filename}</div>
<phpfile filename={$filename}/>
</div>;
$main_column->appendChild($file);
}
$recipe = $this;
if ($recipe instanceof RecipeWithDemo) {
try {
$result = $recipe->getDemoResult();
} catch (Exception $e) {
$result = sprintf(
"Demo threw an %s:\n%s",
get_class($e),
$e->getMessage(),
);
}
$result = explode("\n", trim($result));
$result = array_map($x ==> <x:frag>{$x}<br/></x:frag>, $result);
$demo =
<x:frag>
<div class="demo" id="demo">
<h3>Demo</h3>
{$recipe->getDemoXHP()}
<div class="filename">{$recipe->getDemoFilename()}</div>
<phpfile filename={$recipe->getDemoFilename()}/>
<div class="filename">Output</div>
<div class="demoResult">
{$result}
</div>
</div>
</x:frag>;
$main_column->appendChild($demo);
}
if (!$this->getDocs()->isEmpty()) {
$render_doc_link = function($doc) {
list($name, $link) = $doc;
$link = "http://hhvm.com/manual/en/$link.php";
return <li><a href={$link}>{$name}</a></li>;
};
$main_column->appendChild(
<div class="docs">
<h3>Relevant Official Documentation</h3>
<ul>
{$this->getDocs()->map($render_doc_link)->toArray()}
</ul>
</div>
);
}
return $main_column;
}
}

View File

@@ -0,0 +1,16 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
interface RecipeWithDemo {
public function getDemoFilename(): string;
public function getDemoResult(): string;
public function getDemoXHP(): ?:xhp;
}

15
samples/Hack/Request.hh Normal file
View File

@@ -0,0 +1,15 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
final class Request {
public function __construct(private Map<string, mixed> $params) {}
}

View File

@@ -0,0 +1,81 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
trait StandardPage {
require extends Controller;
abstract protected function renderMainColumn(): :xhp;
protected function getExtraCSS(): Set<string> {
return Set {};
}
protected function getExtraJS(): Set<string> {
return Set {};
}
final protected function getCSS(): Set<string> {
return (Set {
'/css/base.css',
})->addAll($this->getExtraCSS());
}
final protected function getJS(): Set<string> {
return (Set {
})->addAll($this->getExtraJS());
}
final private function renderHeader(): :xhp {
return
<div class="hackHeader">
<div class="width">
<a href="http://hacklang.org/">
<div class="logo">Hack</div>
</a>
<div class="headerNav">
<ul>
<li>
<a href="http://hacklang.org/install/">Install</a>
</li>
<li>
<a href="http://hacklang.org/tutorial/">Tutorial</a>
</li>
<li>
<a href="/">Cookbook</a>
</li>
<li>
<a href="http://hhvm.com/manual">Docs</a>
</li>
<li>
<a href="http://github.com/facebook/hhvm">GitHub</a>
</li>
<li>
<a href="http://hhvm.com/">HHVM</a>
</li>
</ul>
</div>
</div>
</div>;
}
final protected function render(): :xhp {
return
<div>
{$this->renderHeader()}
<div class="width">
<div class="mainContainer">
<div class="mainColumn">{$this->renderMainColumn()}</div>
<hack:nav/>
</div>
</div>
</div>;
}
}

View File

@@ -0,0 +1,46 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/funs/init.php';
abstract class MyRequest {
abstract public function getParams(): Map<string, mixed>;
// Throws when things go wrong
public function intParamX(string $name): int {
$params = $this->getParams();
invariant($params->contains($name), sprintf('Unknown param: %s', $name));
$param = $params[$name];
invariant(is_numeric($param), sprintf('Param %s is not an int', $name));
return (int)$param;
}
// A lenient version
public function intParam(string $name): ?int {
$params = $this->getParams();
if (!$params->contains($name)) { return null; }
$param = $params[$name];
if (!is_numeric($param)) { return null; }
return (int)$param;
}
}
final class MyGETRequest extends MyRequest {
public function getParams(): Map<string, mixed> {
return getGETParams();
}
}
final class MyPOSTRequest extends MyRequest {
public function getParams(): Map<string, mixed> {
return getPOSTParams();
}
}

View File

@@ -0,0 +1,16 @@
<?hh // strict
// Outside of this file, no one knows that UNESCAPED_STRING is a string
newtype UNESCAPED_STRING = string;
// This is how we initially taint a string.
function unescaped_string(string $s): UNESCAPED_STRING {
return $s;
}
// This is the only thing you can do with an UNESCAPED_STRING (other than pass
// it around)
function escape_unescaped_string(UNESCAPED_STRING $s): string {
// Your use case will decide how you want to escape your strings
return sprintf('Escaped ---> "%s" <--- Escaped', $s);
}

View File

@@ -0,0 +1,59 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/recipe/init.php';
require_once "demo.php";
class UnescapedStringRecipe extends Recipe implements RecipeWithDemo {
protected function getName(): string {
return 'Unescaped string';
}
<<Override>>
protected function getDescription(): ?string {
return 'Forgetting to properly escape the strings you get from your users '.
'can lead to serious security holes. Hack can help by forcing you to '.
'escape these strings before using them as strings.';
}
protected function getFilenames(): Vector<string> {
return Vector {
'UnescapedString.php',
'MySecureRequest.php',
};
}
protected function getDocs(): Vector<(string, string)> {
return Vector{
tuple('Opaque Type Aliasing', 'hack.typealiasing.opaquetypealiasing'),
};
}
public function getDemoFilename(): string {
return 'demo.php';
}
public function getDemoResult(): string {
return unescaped_string_main();
}
public function getDemoXHP(): ?:xhp {
$url = '/recipes/unescaped-string/';
return
<x:frag>
Try setting the myStrParam GET param to something nice and innocent with this button...
<div>
<a href={"$url?myStrParam='); DROP TABLE important_stuff; --#demo"} class="button">GET myStrParam=Hello world</a>
</div>
</x:frag>;
}
}

33
samples/Hack/UserID.hh Normal file
View File

@@ -0,0 +1,33 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/funs/init.php';
// Outside of this file, no one knows that these types are ints. They do know
// that USER_ID is an ID and COW_ID is an ID
newtype ID = int;
newtype USER_ID as ID = ID;
newtype COW_ID as ID = ID;
function assert_user_id(int $x): USER_ID {
// Everyone knows all user ids are odd
invariant($x % 2, sprintf('Invalid user ID: %d', $x));
return $x;
}
function assert_cow_id(int $x): COW_ID {
// Everyone knows all cow ids are even
invariant($x % 2 === 0, sprintf('Invalid cow ID: %d', $x));
return $x;
}
function id_to_int(ID $id): int {
return $id;
}

View File

@@ -0,0 +1,54 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/core/controller/recipe/init.php';
require_once "demo.php";
class UserIDRecipe extends Recipe implements RecipeWithDemo {
protected function getName(): string {
return 'User ID';
}
<<Override>>
protected function getDescription(): ?string {
return 'Protect your user IDs from being confused with normal ints';
}
protected function getFilenames(): Vector<string> {
return Vector {
'UserID.php',
'UsingUserID.php',
};
}
protected function getDocs(): Vector<(string, string)> {
return Vector {
tuple('Opaque Type Aliasing', 'hack.typealiasing.opaquetypealiasing'),
tuple(
'Opaque Type Aliasing with Constraints',
'hack.typealiasing.opaquewithconstraints',
),
};
}
public function getDemoFilename(): string {
return 'demo.php';
}
public function getDemoResult(): string {
return user_id_main();
}
public function getDemoXHP(): ?:xhp {
return null;
}
}

View File

@@ -0,0 +1,22 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
function get_something_string(ID $id, string $something): string {
return sprintf("Awesome %s #%d\n", $something, id_to_int($id));
}
function get_user_string(USER_ID $id): string {
return get_something_string($id, 'user');
}
function get_cow_string(COW_ID $id): string {
return get_something_string($id, 'cow');
}

43
samples/Hack/error.hh Normal file
View File

@@ -0,0 +1,43 @@
<?hh
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
final class TypehintViolationException extends Exception {
}
function setup_errors(): void {
set_error_handler('handle_error', E_ALL);
}
/**
* I want to turn failed typehints into exceptions so that I can handle them in
* my example code
*/
function handle_error(
$errno,
$errstr,
$errfile,
$errline,
$errcontext = array(),
$errtrace = array(),
): bool {
if (E_RECOVERABLE_ERROR == $errno) {
// Transform typehint failures into an exception.
if (strpos($errstr, 'must be an instance of ') !== false) {
throw new TypehintViolationException($errstr);
}
// Transform nullable type violations to exceptions.
if ((strpos($errstr, 'must be of type ?') !== false) &&
(strpos($errstr, 'Value returned from') === false)) {
throw new TypehintViolationException($errstr);
}
}
return false;
}

32
samples/Hack/funs.hh Normal file
View File

@@ -0,0 +1,32 @@
<?hh
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
/**
* This file contains a bunch of php stubs for functions that have been added
* to hhvm (though aren't in a release yet). These are important because the
* Hack typechecker can understand them
*/
class InvariantViolationException extends Exception {}
function invariant(mixed $test, string $message): void {
if (!$test) {
invariant_violation($message);
}
}
function invariant_violation(string $message): void {
throw new InvariantViolationException($message);
}
function class_meth(string $class, string $method) {
return array($class, $method);
}

32
samples/Hack/funs.php Normal file
View File

@@ -0,0 +1,32 @@
<?hh
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
/**
* This file contains a bunch of php stubs for functions that have been added
* to hhvm (though aren't in a release yet). These are important because the
* Hack typechecker can understand them
*/
class InvariantViolationException extends Exception {}
function invariant(mixed $test, string $message): void {
if (!$test) {
invariant_violation($message);
}
}
function invariant_violation(string $message): void {
throw new InvariantViolationException($message);
}
function class_meth(string $class, string $method) {
return array($class, $method);
}

14
samples/Hack/index.hh Normal file
View File

@@ -0,0 +1,14 @@
<?hh
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once 'HomeController.php';
HomeController::go($_GET);

31
samples/Hack/phpfile.hh Normal file
View File

@@ -0,0 +1,31 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
require_once $_SERVER['DOCUMENT_ROOT'].'/vendor/hhvm/xhp/src/init.php';
final class :phpfile extends :x:primitive {
category %flow;
attribute string filename;
/**
* Ok, I'll admit this is kind of gross. I don't really want to implement
* syntax highlighting, so I'm relying on the built-in PHP support. XHP
* makes html strings sort of difficult to use (which is good cause they're
* dangerous). Anyway, this is one way around it :)
*/
protected function stringify(): string {
return
'<div class="code">'.
(string)highlight_file($this->getAttribute('filename'), /*ret*/ true).
'</div>';
}
}

14
samples/Hack/startup.hh Normal file
View File

@@ -0,0 +1,14 @@
<?hh // strict
/**
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
function startup(): void {
setup_errors();
}

Some files were not shown because too many files have changed in this diff Show More