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) }
 | 
					        if languages.all? { |l| ["Common Lisp", "OpenCL"].include?(l) }
 | 
				
			||||||
          result = disambiguate_cl(data, languages)
 | 
					          result = disambiguate_cl(data, languages)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
 | 
					        if languages.all? { |l| ["Hack", "PHP"].include?(l) }
 | 
				
			||||||
 | 
					          result = disambiguate_hack(data, languages)
 | 
				
			||||||
 | 
					        end
 | 
				
			||||||
        if languages.all? { |l| ["Scala", "SuperCollider"].include?(l) }
 | 
					        if languages.all? { |l| ["Scala", "SuperCollider"].include?(l) }
 | 
				
			||||||
          result = disambiguate_sc(data, languages)
 | 
					          result = disambiguate_sc(data, languages)
 | 
				
			||||||
        end
 | 
					        end
 | 
				
			||||||
@@ -94,6 +97,16 @@ module Linguist
 | 
				
			|||||||
      matches
 | 
					      matches
 | 
				
			||||||
    end
 | 
					    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)
 | 
					    def self.disambiguate_sc(data, languages)
 | 
				
			||||||
      matches = []
 | 
					      matches = []
 | 
				
			||||||
      if (/\^(this|super)\./.match(data) || /^\s*(\+|\*)\s*\w+\s*{/.match(data) || /^\s*~\w+\s*=\./.match(data))
 | 
					      if (/\^(this|super)\./.match(data) || /^\s*(\+|\*)\s*\w+\s*{/.match(data) || /^\s*~\w+\s*=\./.match(data))
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1021,6 +1021,14 @@ HTTP:
 | 
				
			|||||||
  extensions:
 | 
					  extensions:
 | 
				
			||||||
  - .http
 | 
					  - .http
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Hack:
 | 
				
			||||||
 | 
					  type: programming
 | 
				
			||||||
 | 
					  lexer: PHP
 | 
				
			||||||
 | 
					  ace_mode: php
 | 
				
			||||||
 | 
					  extensions:
 | 
				
			||||||
 | 
					  - .hh
 | 
				
			||||||
 | 
					  - .php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Haml:
 | 
					Haml:
 | 
				
			||||||
  group: HTML
 | 
					  group: HTML
 | 
				
			||||||
  type: markup
 | 
					  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();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -105,6 +105,12 @@ class TestHeuristcs < Test::Unit::TestCase
 | 
				
			|||||||
    end
 | 
					    end
 | 
				
			||||||
  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
 | 
					  def test_sc_supercollider_by_heuristics
 | 
				
			||||||
    languages = ["Scala", "SuperCollider"]
 | 
					    languages = ["Scala", "SuperCollider"]
 | 
				
			||||||
    results = Heuristics.disambiguate_sc(fixture("SuperCollider/WarpPreset.sc"), languages)
 | 
					    results = Heuristics.disambiguate_sc(fixture("SuperCollider/WarpPreset.sc"), languages)
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user