mirror of
https://github.com/KevinMidboe/linguist.git
synced 2025-10-29 17:50:22 +00:00
@@ -25,6 +25,9 @@ module Linguist
|
||||
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
|
||||
@@ -94,6 +97,16 @@ 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))
|
||||
|
||||
@@ -1021,6 +1021,14 @@ HTTP:
|
||||
extensions:
|
||||
- .http
|
||||
|
||||
Hack:
|
||||
type: programming
|
||||
lexer: PHP
|
||||
ace_mode: php
|
||||
extensions:
|
||||
- .hh
|
||||
- .php
|
||||
|
||||
Haml:
|
||||
group: HTML
|
||||
type: markup
|
||||
|
||||
10
samples/C++/bar.hh
Normal file
10
samples/C++/bar.hh
Normal file
@@ -0,0 +1,10 @@
|
||||
class Bar
|
||||
{
|
||||
protected:
|
||||
|
||||
char *name;
|
||||
|
||||
public:
|
||||
|
||||
void hello();
|
||||
}
|
||||
55
samples/Hack/Assert.hh
Normal file
55
samples/Hack/Assert.hh
Normal 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');
|
||||
}
|
||||
}
|
||||
52
samples/Hack/AssertRecipe.hh
Normal file
52
samples/Hack/AssertRecipe.hh
Normal 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;
|
||||
}
|
||||
}
|
||||
39
samples/Hack/Controller.hh
Normal file
39
samples/Hack/Controller.hh
Normal 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>;
|
||||
}
|
||||
}
|
||||
52
samples/Hack/DBResultRecipe.hh
Normal file
52
samples/Hack/DBResultRecipe.hh
Normal 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;
|
||||
}
|
||||
}
|
||||
22
samples/Hack/Documentation.hh
Normal file
22
samples/Hack/Documentation.hh
Normal 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 →</a>;
|
||||
}
|
||||
}
|
||||
65
samples/Hack/FakeDB.hh
Normal file
65
samples/Hack/FakeDB.hh
Normal 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;
|
||||
}
|
||||
}
|
||||
72
samples/Hack/GetAndPostRecipe.hh
Normal file
72
samples/Hack/GetAndPostRecipe.hh
Normal 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>;
|
||||
}
|
||||
}
|
||||
30
samples/Hack/GetController.hh
Normal file
30
samples/Hack/GetController.hh
Normal 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;
|
||||
}
|
||||
}
|
||||
38
samples/Hack/HomeController.hh
Normal file
38
samples/Hack/HomeController.hh
Normal 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>;
|
||||
}
|
||||
}
|
||||
13
samples/Hack/MySecureRequest.hh
Normal file
13
samples/Hack/MySecureRequest.hh
Normal 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
104
samples/Hack/Nav.hh
Normal 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>;
|
||||
}
|
||||
}
|
||||
27
samples/Hack/NonStrictFile.hh
Normal file
27
samples/Hack/NonStrictFile.hh
Normal 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
93
samples/Hack/Recipe.hh
Normal 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;
|
||||
}
|
||||
}
|
||||
16
samples/Hack/RecipeWithDemo.hh
Normal file
16
samples/Hack/RecipeWithDemo.hh
Normal 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
15
samples/Hack/Request.hh
Normal 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) {}
|
||||
}
|
||||
|
||||
81
samples/Hack/StandardPage.hh
Normal file
81
samples/Hack/StandardPage.hh
Normal 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>;
|
||||
}
|
||||
}
|
||||
46
samples/Hack/StrictFile.hh
Normal file
46
samples/Hack/StrictFile.hh
Normal 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();
|
||||
}
|
||||
}
|
||||
16
samples/Hack/UnescapedString.hh
Normal file
16
samples/Hack/UnescapedString.hh
Normal 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);
|
||||
}
|
||||
59
samples/Hack/UnescapedStringRecipe.hh
Normal file
59
samples/Hack/UnescapedStringRecipe.hh
Normal 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
33
samples/Hack/UserID.hh
Normal 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;
|
||||
}
|
||||
54
samples/Hack/UserIDRecipe.hh
Normal file
54
samples/Hack/UserIDRecipe.hh
Normal 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;
|
||||
}
|
||||
}
|
||||
22
samples/Hack/UsingUserID.hh
Normal file
22
samples/Hack/UsingUserID.hh
Normal 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
43
samples/Hack/error.hh
Normal 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
32
samples/Hack/funs.hh
Normal 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
32
samples/Hack/funs.php
Normal 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
14
samples/Hack/index.hh
Normal 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
31
samples/Hack/phpfile.hh
Normal 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
14
samples/Hack/startup.hh
Normal 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();
|
||||
}
|
||||
@@ -40,25 +40,25 @@ class TestHeuristcs < Test::Unit::TestCase
|
||||
match = Language.detect(blob)
|
||||
assert_equal Language["Objective-C"], match
|
||||
end
|
||||
|
||||
|
||||
def test_pl_prolog_by_heuristics
|
||||
languages = ["Perl", "Prolog"]
|
||||
results = Heuristics.disambiguate_pl(fixture("Prolog/turing.pl"), languages)
|
||||
assert_equal Language["Prolog"], results.first
|
||||
end
|
||||
|
||||
|
||||
def test_pl_perl_by_heuristics
|
||||
languages = ["Perl", "Prolog"]
|
||||
results = Heuristics.disambiguate_pl(fixture("Perl/perl-test.t"), languages)
|
||||
assert_equal Language["Perl"], results.first
|
||||
end
|
||||
|
||||
|
||||
def test_ecl_prolog_by_heuristics
|
||||
languages = ["ECL", "Prolog"]
|
||||
results = Heuristics.disambiguate_ecl(fixture("Prolog/or-constraint.ecl"), languages)
|
||||
assert_equal Language["Prolog"], results.first
|
||||
end
|
||||
|
||||
|
||||
def test_ecl_ecl_by_heuristics
|
||||
languages = ["ECL", "Prolog"]
|
||||
results = Heuristics.disambiguate_ecl(fixture("ECL/sample.ecl"), languages)
|
||||
@@ -105,6 +105,12 @@ class TestHeuristcs < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
def test_hack_by_heuristics
|
||||
languages = ["Hack", "PHP"]
|
||||
results = Heuristics.disambiguate_hack(fixture("Hack/funs.php"), languages)
|
||||
assert_equal Language["Hack"], results.first
|
||||
end
|
||||
|
||||
def test_sc_supercollider_by_heuristics
|
||||
languages = ["Scala", "SuperCollider"]
|
||||
results = Heuristics.disambiguate_sc(fixture("SuperCollider/WarpPreset.sc"), languages)
|
||||
|
||||
Reference in New Issue
Block a user