├── .gitignore ├── LICENSE.md ├── Makefile ├── README.md ├── composer.json ├── docs ├── 01-about.md ├── 02-language_design.md ├── _config.yml └── index.md ├── examples ├── 00-basic-usage │ ├── Prerano::Examples::BasicUsage.cfg │ ├── Prerano::Examples::BasicUsage.php │ ├── Prerano::Examples::BasicUsage.png │ ├── code.pr │ ├── code.pr.ast │ └── code.pr.processed.ast ├── 01-public-functions │ ├── Prerano::Examples::PublicFunctions.cfg │ ├── Prerano::Examples::PublicFunctions.php │ ├── Prerano::Examples::PublicFunctions.png │ ├── code.pr │ ├── code.pr.ast │ └── code.pr.processed.ast ├── 02-calling-php-functions │ ├── Prerano::Examples::CallingPHPFunctions.cfg │ ├── Prerano::Examples::CallingPHPFunctions.php │ ├── Prerano::Examples::CallingPHPFunctions.png │ ├── code.pr │ ├── code.pr.ast │ └── code.pr.processed.ast ├── 03-defining-types │ ├── Prerano::Examples::DefiningTypes.cfg │ ├── Prerano::Examples::DefiningTypes.php │ ├── Prerano::Examples::DefiningTypes.png │ ├── code.pr │ ├── code.pr.ast │ └── code.pr.processed.ast ├── 04-guards │ ├── Prerano::Examples::PublicFunctions.cfg │ ├── Prerano::Examples::PublicFunctions.php │ ├── Prerano::Examples::PublicFunctions.png │ ├── code.pr │ ├── code.pr.ast │ └── code.pr.processed.ast ├── 05-type-checks │ ├── Prerano::Examples::TypeChecks.cfg │ ├── Prerano::Examples::TypeChecks.php │ ├── Prerano::Examples::TypeChecks.png │ ├── code.pr │ ├── code.pr.ast │ └── code.pr.processed.ast ├── 06-matching │ ├── Prerano::Examples::Matching.cfg │ ├── Prerano::Examples::Matching.php │ ├── Prerano::Examples::Matching.png │ ├── code.pr │ ├── code.pr.ast │ └── code.pr.processed.ast ├── 07-expression-functions │ ├── Prerano::Examples::ExpressionFunctions.cfg │ ├── Prerano::Examples::ExpressionFunctions.php │ ├── Prerano::Examples::ExpressionFunctions.png │ ├── __main__.pr │ ├── __main__.pr.ast │ ├── __main__.pr.processed.ast │ ├── types.pr │ ├── types.pr.ast │ └── types.pr.processed.ast ├── 08-arrays │ ├── Prerano::Examples::Arrays.cfg │ ├── Prerano::Examples::Arrays.php │ ├── Prerano::Examples::Arrays.png │ ├── array.pr │ ├── array.pr.ast │ └── array.pr.processed.ast ├── 09-pipe-operator │ ├── Prerano::Examples::PipeOperator.cfg │ ├── Prerano::Examples::PipeOperator.php │ ├── Prerano::Examples::PipeOperator.png │ ├── pipe.pr │ ├── pipe.pr.ast │ └── pipe.pr.processed.ast ├── README.md └── rebuild.php ├── grammar ├── .gitignore ├── language.y ├── parser.template.php ├── rebuildParser.php └── tokens.template.php ├── lib ├── AST │ ├── Node.php │ ├── Node │ │ ├── Arg.php │ │ ├── Expr.php │ │ ├── Expr │ │ │ ├── Array_.php │ │ │ ├── Assign.php │ │ │ ├── BinaryOp.php │ │ │ ├── BinaryOp │ │ │ │ ├── BooleanOr.php │ │ │ │ ├── Div.php │ │ │ │ ├── Equals.php │ │ │ │ ├── Minus.php │ │ │ │ ├── Mod.php │ │ │ │ ├── Mul.php │ │ │ │ └── Plus.php │ │ │ ├── FuncCall.php │ │ │ ├── IdentifierReference.php │ │ │ ├── Is.php │ │ │ ├── Match.php │ │ │ ├── MatchEntry.php │ │ │ ├── MethodCall.php │ │ │ ├── Pipe.php │ │ │ ├── PointerDereference.php │ │ │ ├── Type.php │ │ │ ├── Type │ │ │ │ ├── Function_.php │ │ │ │ ├── Intersection.php │ │ │ │ ├── Named.php │ │ │ │ ├── Pointer.php │ │ │ │ ├── Specification.php │ │ │ │ ├── Union.php │ │ │ │ └── Value.php │ │ │ └── Variable.php │ │ ├── Name.php │ │ ├── Name │ │ │ └── Qualified.php │ │ ├── Scalar.php │ │ ├── Scalar │ │ │ └── LNumber.php │ │ ├── Stmt.php │ │ └── Stmt │ │ │ ├── Alias.php │ │ │ ├── Class_.php │ │ │ ├── Enum.php │ │ │ ├── ExprFunction.php │ │ │ ├── Function_.php │ │ │ ├── Import.php │ │ │ ├── Match │ │ │ └── Entry.php │ │ │ ├── Package.php │ │ │ ├── Parameter.php │ │ │ └── Type.php │ ├── NodeAbstract.php │ ├── Traverser.php │ ├── Visitor.php │ ├── Visitor │ │ ├── AliasResolver.php │ │ └── TypeQualifier.php │ └── VisitorAbstract.php ├── CFG │ ├── Generator.php │ ├── Node.php │ ├── Node │ │ ├── Expr.php │ │ └── Expr │ │ │ ├── Assign.php │ │ │ ├── BinaryOp.php │ │ │ ├── BinaryOp │ │ │ ├── Div.php │ │ │ ├── Equals.php │ │ │ ├── Minus.php │ │ │ ├── Mod.php │ │ │ ├── Mul.php │ │ │ └── Plus.php │ │ │ ├── ExpressionCall.php │ │ │ ├── FuncCall.php │ │ │ ├── If_.php │ │ │ ├── Is.php │ │ │ ├── MethodCall.php │ │ │ └── PointerDereference.php │ ├── NodeAbstract.php │ └── Package.php ├── Compiler.php ├── Compiler │ ├── Compiler.php │ ├── PHP.php │ ├── PHP │ │ ├── Code.php │ │ ├── Metadata.php │ │ ├── PHP.php │ │ ├── PublicFunctions.php │ │ ├── PublicValueConstants.php │ │ ├── Scope.php │ │ └── TypeCheck.php │ └── Utility │ │ └── PhiResolver.php ├── Debug │ ├── ASTDumper.php │ ├── CFGDumper.php │ └── CFGGrapher.php ├── Inference │ ├── Engine.php │ ├── Rule.php │ ├── Rule │ │ ├── ExpressionFunctionResolver.php │ │ ├── FunctionCallResolver.php │ │ ├── TypeReconstruction.php │ │ └── TypeResolver.php │ └── RuleAbstract.php ├── Language │ ├── Block.php │ ├── Block │ │ └── Simple.php │ ├── BlockAbstract.php │ ├── Function_.php │ ├── Package.php │ ├── Type.php │ ├── TypeTest.php │ ├── Variable.php │ ├── Variable │ │ ├── Array_.php │ │ ├── IdentifierReference.php │ │ ├── Literal.php │ │ ├── Named.php │ │ ├── Parameter.php │ │ ├── Phi.php │ │ ├── Phi │ │ │ └── Entry.php │ │ └── Temp.php │ └── VariableAbstract.php ├── Parser │ ├── Error.php │ ├── Lexer.php │ ├── Parser.php │ ├── ParserAbstract.php │ └── Tokens.php ├── Scope.php └── php │ ├── arrays.pr │ ├── numbers.pr │ └── strings.pr └── phpunit.xml.dist /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | vendor 3 | .php_cs.cache -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | rebuild: 2 | cd grammar && php rebuildParser.php 3 | 4 | rebuild-debug: 5 | cd grammar && php rebuildParser.php --debug --keep-tmp-grammar 6 | 7 | build: rebuild build-examples 8 | php-cs-fixer fix ./lib 9 | 10 | test: 11 | vendor/bin/phpunit --coverage-text 12 | 13 | build-examples: rebuild 14 | php examples/rebuild.php 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Prerano 2 | 3 | This project is experimental at this stage. 4 | 5 | Prerano is a new programming language built on and designed to interact with PHP natively. 6 | 7 | ## About 8 | 9 | Prerano aims to be a strongly typed language that's far less verbose than PHP, yet maintains a lot of its "charm" and all of its portability. 10 | 11 | Right now, it's just a toy and proving ground. Over time, if it's deemed useful, it could be expanded into a production-ready system. 12 | 13 | ## More Info 14 | 15 | Check the [documentation](https://ircmaxell.github.io/prerano/), and specifically the [language design document](https://ircmaxell.github.io/prerano/02-language_design). 16 | 17 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ircmaxell/prerano", 3 | "description": "A new language built on PHP", 4 | "license": "Apache2", 5 | "authors": [ 6 | { 7 | "name": "Anthony Ferrara", 8 | "email": "ircmaxell@gmail.com" 9 | } 10 | ], 11 | "autoload": { 12 | "psr-4": { 13 | "Prerano\\": "lib/" 14 | } 15 | }, 16 | "require": { 17 | "php": ">=7.0", 18 | "doctrine/lexer": ">=1.0", 19 | "nikic/php-parser": ">=3.0", 20 | "cilex/cilex": ">=1.0" 21 | }, 22 | "require-dev": { 23 | "phpdocumentor/graphviz": "1.0.*", 24 | "phpunit/phpunit": ">=6.3" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /docs/01-about.md: -------------------------------------------------------------------------------- 1 | # About Prerano 2 | 3 | Prerano is an attempt at building a simplified programming language that's completely interoperable with PHP. 4 | 5 | ## The Concept 6 | 7 | Prerano is "compiled" to native PHP and run by a normal PHP runtime. For these reasons it retains the basic advantages of PHP in that it's easy to deploy, portable and simple to use. 8 | 9 | Within the language however come several important differences from normal PHP. Prerano uses a compile step to ensure type safety. This means that Prerano code can use PHP code just like normal (with a few important limitations). And since Prerano generates PHP code, normal PHP code can use Prerano code just fine. 10 | 11 | ## Compilation Strategies 12 | 13 | There are three main modes of compiling: 14 | 15 | * Debug 16 | * Test 17 | * Production 18 | 19 | Debug compiles on-demand inside of a request, just like normal PHP. It uses `eval()` to turn the compiled code into PHP code. 20 | 21 | Test and Production generate files in the filesystem along side of the Prerano packages. This allows "building" inside of a folder and simply 'committing' the result. This allows library authors to write Prerano, but ship both Prerano and compiled PHP which has no dependencies on Prerano. 22 | 23 | The prime difference between Test and Production is the amount of "checks" generated in the compiled code. Test will include a multitude of assertions, as well as *potentially* generated unit tests. 24 | 25 | ## Interaction with PHP 26 | 27 | A custom autoloader will be built for Prerano code. Instead of trying to load the class itself, it will look at folders. If the folder exists, and has a `__PRERANO__.php` file, it will load the file and return. Otherwise, it will attempt to compile the folder and generate the appropriate code. 28 | 29 | TODO: A lot... -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-slate -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | # Prerano 2 | 3 | This document is a collection of ideas and concepts that we are collecting around an idea of a new language. It is not complete, it is not consistent and it is not a promise. 4 | 5 | Pull Requests and ideas are most definitly accepted! 6 | 7 | These documents are rapidly changing. 8 | 9 | ## Table Of Contents 10 | 11 | * [About](01-about) 12 | * [Language Design](02-language_design) 13 | 14 | More to come! -------------------------------------------------------------------------------- /examples/00-basic-usage/Prerano::Examples::BasicUsage.cfg: -------------------------------------------------------------------------------- 1 | Package: Prerano::Examples::BasicUsage 2 | Public: 3 | Types: 4 | Functions: 5 | Protected: 6 | Types: 7 | Functions: 8 | Private: 9 | Types: 10 | __main__ => fn()none 11 | Functions: 12 | __main__: 13 | result: none $1 14 | blocks: 15 | Block #1() 16 | 17 | -------------------------------------------------------------------------------- /examples/00-basic-usage/Prerano::Examples::BasicUsage.php: -------------------------------------------------------------------------------- 1 | headers) { 18 | $this->headers = unserialize(base64_decode(self::HEADERS)); 19 | } 20 | return $this->headers; 21 | } 22 | } 23 | final class __PRERANO_CODE__ 24 | { 25 | private static $Prerano܃܃Examples܃܃BasicUsage܃܃instance; 26 | public static function Prerano܃܃Examples܃܃BasicUsage܃܃∫() 27 | { 28 | if (!self::$Prerano܃܃Examples܃܃BasicUsage܃܃instance) { 29 | self::$Prerano܃܃Examples܃܃BasicUsage܃܃instance = new self(); 30 | } 31 | return self::$Prerano܃܃Examples܃܃BasicUsage܃܃instance; 32 | } 33 | /** fn()none */ 34 | public function __construct() 35 | { 36 | return $_1; 37 | } 38 | } 39 | __PRERANO_CODE__::Prerano܃܃Examples܃܃BasicUsage܃܃∫(); -------------------------------------------------------------------------------- /examples/00-basic-usage/Prerano::Examples::BasicUsage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ircmaxell/prerano/08acefad9ac7fab8db5c87b0a76b437fbaa0f897/examples/00-basic-usage/Prerano::Examples::BasicUsage.png -------------------------------------------------------------------------------- /examples/00-basic-usage/code.pr: -------------------------------------------------------------------------------- 1 | package Prerano::Examples::BasicUsage; 2 | 3 | fn __main__() none { 4 | } 5 | -------------------------------------------------------------------------------- /examples/00-basic-usage/code.pr.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::BasicUsage 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | __main__ 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | none 14 | ] 15 | parameters [ 16 | ] 17 | body [ 18 | ] 19 | -------------------------------------------------------------------------------- /examples/00-basic-usage/code.pr.processed.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::BasicUsage 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | __main__ 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | none 14 | ] 15 | parameters [ 16 | ] 17 | body [ 18 | ] 19 | -------------------------------------------------------------------------------- /examples/01-public-functions/Prerano::Examples::PublicFunctions.cfg: -------------------------------------------------------------------------------- 1 | Package: Prerano::Examples::PublicFunctions 2 | Public: 3 | Types: 4 | getOne => fn()int 5 | Functions: 6 | getOne: 7 | result: int $209 = 1 8 | blocks: 9 | Block #48() 10 | 11 | Protected: 12 | Types: 13 | Functions: 14 | Private: 15 | Types: 16 | inc => fn(int)int 17 | __main__ => fn()none 18 | Functions: 19 | inc: 20 | result: unknown $207 21 | blocks: 22 | Block #47() 23 | Expr_BinaryOp_Plus: 24 | left: int $205 25 | right: int $206 = 1 26 | result: unknown $207 27 | 28 | __main__: 29 | result: int $214 30 | blocks: 31 | Block #49() 32 | Expr_FuncCall: 33 | name: getOne $211 34 | result: int $212 35 | Expr_FuncCall: 36 | name: inc $213 37 | args: [int $212] 38 | result: int $214 39 | 40 | -------------------------------------------------------------------------------- /examples/01-public-functions/Prerano::Examples::PublicFunctions.php: -------------------------------------------------------------------------------- 1 | headers) { 18 | $this->headers = unserialize(base64_decode(self::HEADERS)); 19 | } 20 | return $this->headers; 21 | } 22 | } 23 | final class __PRERANO_CODE__ 24 | { 25 | private static $Prerano܃܃Examples܃܃PublicFunctions܃܃instance; 26 | public static function Prerano܃܃Examples܃܃PublicFunctions܃܃∫() 27 | { 28 | if (!self::$Prerano܃܃Examples܃܃PublicFunctions܃܃instance) { 29 | self::$Prerano܃܃Examples܃܃PublicFunctions܃܃instance = new self(); 30 | } 31 | return self::$Prerano܃܃Examples܃܃PublicFunctions܃܃instance; 32 | } 33 | /** fn()int */ 34 | public function Prerano܃܃Examples܃܃PublicFunctions܃܃getOne() 35 | { 36 | return 1; 37 | } 38 | /** fn(int)int */ 39 | public function Prerano܃܃Examples܃܃PublicFunctions܃܃inc($a) 40 | { 41 | $_207 = $a + 1; 42 | return $_207; 43 | } 44 | /** fn()none */ 45 | public function __construct() 46 | { 47 | $_212 = $this->Prerano܃܃Examples܃܃PublicFunctions܃܃getOne(); 48 | $_214 = $this->Prerano܃܃Examples܃܃PublicFunctions܃܃inc($_212); 49 | return $_214; 50 | } 51 | } 52 | __PRERANO_CODE__::Prerano܃܃Examples܃܃PublicFunctions܃܃∫(); 53 | function getOne() : int 54 | { 55 | $__result__ = \Prerano\Examples\PublicFunctions\__PRERANO_CODE__::Prerano܃܃Examples܃܃PublicFunctions܃܃∫()->Prerano܃܃Examples܃܃PublicFunctions܃܃getOne(); 56 | return $__result__; 57 | } -------------------------------------------------------------------------------- /examples/01-public-functions/Prerano::Examples::PublicFunctions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ircmaxell/prerano/08acefad9ac7fab8db5c87b0a76b437fbaa0f897/examples/01-public-functions/Prerano::Examples::PublicFunctions.png -------------------------------------------------------------------------------- /examples/01-public-functions/code.pr: -------------------------------------------------------------------------------- 1 | package Prerano::Examples::PublicFunctions; 2 | 3 | fn inc(int $a) int { 4 | $a + 1; 5 | } 6 | 7 | public fn getOne() int = 1; 8 | 9 | fn __main__() none { 10 | inc(getOne()); 11 | } -------------------------------------------------------------------------------- /examples/01-public-functions/code.pr.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::PublicFunctions 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | inc 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | int 14 | ] 15 | parameters [ 16 | Stmt_Parameter 17 | name(a) 18 | type: 19 | Expr_Type_Named 20 | name: 21 | Name 22 | parts [ 23 | int 24 | ] 25 | default() 26 | ] 27 | body [ 28 | Expr_BinaryOp_Plus 29 | left: 30 | Expr_Variable 31 | name: 32 | Name 33 | parts [ 34 | a 35 | ] 36 | right: 37 | Scalar_LNumber 38 | value(1) 39 | ] 40 | Stmt_Function 41 | name: 42 | Name 43 | parts [ 44 | getOne 45 | ] 46 | returnType: 47 | Expr_Type_Named 48 | name: 49 | Name 50 | parts [ 51 | int 52 | ] 53 | parameters [ 54 | ] 55 | body [ 56 | Scalar_LNumber 57 | value(1) 58 | ] 59 | Stmt_Function 60 | name: 61 | Name 62 | parts [ 63 | __main__ 64 | ] 65 | returnType: 66 | Expr_Type_Named 67 | name: 68 | Name 69 | parts [ 70 | none 71 | ] 72 | parameters [ 73 | ] 74 | body [ 75 | Expr_FuncCall 76 | name: 77 | Expr_IdentifierReference 78 | name: 79 | Name 80 | parts [ 81 | inc 82 | ] 83 | args [ 84 | Arg 85 | value: 86 | Expr_FuncCall 87 | name: 88 | Expr_IdentifierReference 89 | name: 90 | Name 91 | parts [ 92 | getOne 93 | ] 94 | args [ 95 | ] 96 | name() 97 | ] 98 | ] 99 | -------------------------------------------------------------------------------- /examples/01-public-functions/code.pr.processed.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::PublicFunctions 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | inc 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | int 14 | ] 15 | parameters [ 16 | Stmt_Parameter 17 | name(a) 18 | type: 19 | Expr_Type_Named 20 | name: 21 | Name 22 | parts [ 23 | int 24 | ] 25 | default() 26 | ] 27 | body [ 28 | Expr_BinaryOp_Plus 29 | left: 30 | Expr_Variable 31 | name: 32 | Name 33 | parts [ 34 | a 35 | ] 36 | right: 37 | Scalar_LNumber 38 | value(1) 39 | ] 40 | Stmt_Function 41 | name: 42 | Name 43 | parts [ 44 | getOne 45 | ] 46 | returnType: 47 | Expr_Type_Named 48 | name: 49 | Name 50 | parts [ 51 | int 52 | ] 53 | parameters [ 54 | ] 55 | body [ 56 | Scalar_LNumber 57 | value(1) 58 | ] 59 | Stmt_Function 60 | name: 61 | Name 62 | parts [ 63 | __main__ 64 | ] 65 | returnType: 66 | Expr_Type_Named 67 | name: 68 | Name 69 | parts [ 70 | none 71 | ] 72 | parameters [ 73 | ] 74 | body [ 75 | Expr_FuncCall 76 | name: 77 | Expr_IdentifierReference 78 | name: 79 | Name 80 | parts [ 81 | inc 82 | ] 83 | args [ 84 | Arg 85 | value: 86 | Expr_FuncCall 87 | name: 88 | Expr_IdentifierReference 89 | name: 90 | Name 91 | parts [ 92 | getOne 93 | ] 94 | args [ 95 | ] 96 | name() 97 | ] 98 | ] 99 | -------------------------------------------------------------------------------- /examples/02-calling-php-functions/Prerano::Examples::CallingPHPFunctions.cfg: -------------------------------------------------------------------------------- 1 | Package: Prerano::Examples::CallingPHPFunctions 2 | Public: 3 | Types: 4 | Functions: 5 | Protected: 6 | Types: 7 | Functions: 8 | Private: 9 | Types: 10 | intdiv => fn(int,int)int 11 | __main__ => fn()none 12 | Functions: 13 | intdiv: 14 | result: int $30 15 | blocks: 16 | Block #4() 17 | Expr_FuncCall: 18 | name: php::intdiv $29 19 | args: [int $27, int $28] 20 | args: [int $27, int $28] 21 | result: int $30 22 | 23 | __main__: 24 | result: int $35 25 | blocks: 26 | Block #5() 27 | Expr_FuncCall: 28 | name: intdiv $34 29 | args: [int $32 = 3, int $33 = 2] 30 | args: [int $32 = 3, int $33 = 2] 31 | result: int $35 32 | 33 | -------------------------------------------------------------------------------- /examples/02-calling-php-functions/Prerano::Examples::CallingPHPFunctions.php: -------------------------------------------------------------------------------- 1 | headers) { 18 | $this->headers = unserialize(base64_decode(self::HEADERS)); 19 | } 20 | return $this->headers; 21 | } 22 | } 23 | final class __PRERANO_CODE__ 24 | { 25 | private static $Prerano܃܃Examples܃܃CallingPHPFunctions܃܃instance; 26 | public static function Prerano܃܃Examples܃܃CallingPHPFunctions܃܃∫() 27 | { 28 | if (!self::$Prerano܃܃Examples܃܃CallingPHPFunctions܃܃instance) { 29 | self::$Prerano܃܃Examples܃܃CallingPHPFunctions܃܃instance = new self(); 30 | } 31 | return self::$Prerano܃܃Examples܃܃CallingPHPFunctions܃܃instance; 32 | } 33 | /** fn(int,int)int */ 34 | public function Prerano܃܃Examples܃܃CallingPHPFunctions܃܃intdiv($dividend, $divisor) 35 | { 36 | $_30 = intdiv($dividend, $divisor); 37 | return $_30; 38 | } 39 | /** fn()none */ 40 | public function __construct() 41 | { 42 | $_35 = $this->Prerano܃܃Examples܃܃CallingPHPFunctions܃܃intdiv(3, 2); 43 | return $_35; 44 | } 45 | } 46 | __PRERANO_CODE__::Prerano܃܃Examples܃܃CallingPHPFunctions܃܃∫(); -------------------------------------------------------------------------------- /examples/02-calling-php-functions/Prerano::Examples::CallingPHPFunctions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ircmaxell/prerano/08acefad9ac7fab8db5c87b0a76b437fbaa0f897/examples/02-calling-php-functions/Prerano::Examples::CallingPHPFunctions.png -------------------------------------------------------------------------------- /examples/02-calling-php-functions/code.pr: -------------------------------------------------------------------------------- 1 | package Prerano::Examples::CallingPHPFunctions; 2 | 3 | fn intdiv(int $dividend, int $divisor) int { 4 | php::intdiv($dividend, $divisor); 5 | } 6 | 7 | fn __main__() none { 8 | intdiv(3, 2); 9 | } -------------------------------------------------------------------------------- /examples/02-calling-php-functions/code.pr.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::CallingPHPFunctions 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | intdiv 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | int 14 | ] 15 | parameters [ 16 | Stmt_Parameter 17 | name(dividend) 18 | type: 19 | Expr_Type_Named 20 | name: 21 | Name 22 | parts [ 23 | int 24 | ] 25 | default() 26 | Stmt_Parameter 27 | name(divisor) 28 | type: 29 | Expr_Type_Named 30 | name: 31 | Name 32 | parts [ 33 | int 34 | ] 35 | default() 36 | ] 37 | body [ 38 | Expr_FuncCall 39 | name: 40 | Expr_IdentifierReference 41 | name: 42 | Name_Qualified 43 | parts [ 44 | php 45 | intdiv 46 | ] 47 | args [ 48 | Arg 49 | value: 50 | Expr_Variable 51 | name: 52 | Name 53 | parts [ 54 | dividend 55 | ] 56 | name() 57 | Arg 58 | value: 59 | Expr_Variable 60 | name: 61 | Name 62 | parts [ 63 | divisor 64 | ] 65 | name() 66 | ] 67 | ] 68 | Stmt_Function 69 | name: 70 | Name 71 | parts [ 72 | __main__ 73 | ] 74 | returnType: 75 | Expr_Type_Named 76 | name: 77 | Name 78 | parts [ 79 | none 80 | ] 81 | parameters [ 82 | ] 83 | body [ 84 | Expr_FuncCall 85 | name: 86 | Expr_IdentifierReference 87 | name: 88 | Name 89 | parts [ 90 | intdiv 91 | ] 92 | args [ 93 | Arg 94 | value: 95 | Scalar_LNumber 96 | value(3) 97 | name() 98 | Arg 99 | value: 100 | Scalar_LNumber 101 | value(2) 102 | name() 103 | ] 104 | ] 105 | -------------------------------------------------------------------------------- /examples/02-calling-php-functions/code.pr.processed.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::CallingPHPFunctions 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | intdiv 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | int 14 | ] 15 | parameters [ 16 | Stmt_Parameter 17 | name(dividend) 18 | type: 19 | Expr_Type_Named 20 | name: 21 | Name 22 | parts [ 23 | int 24 | ] 25 | default() 26 | Stmt_Parameter 27 | name(divisor) 28 | type: 29 | Expr_Type_Named 30 | name: 31 | Name 32 | parts [ 33 | int 34 | ] 35 | default() 36 | ] 37 | body [ 38 | Expr_FuncCall 39 | name: 40 | Expr_IdentifierReference 41 | name: 42 | Name_Qualified 43 | parts [ 44 | php 45 | intdiv 46 | ] 47 | args [ 48 | Arg 49 | value: 50 | Expr_Variable 51 | name: 52 | Name 53 | parts [ 54 | dividend 55 | ] 56 | name() 57 | Arg 58 | value: 59 | Expr_Variable 60 | name: 61 | Name 62 | parts [ 63 | divisor 64 | ] 65 | name() 66 | ] 67 | ] 68 | Stmt_Function 69 | name: 70 | Name 71 | parts [ 72 | __main__ 73 | ] 74 | returnType: 75 | Expr_Type_Named 76 | name: 77 | Name 78 | parts [ 79 | none 80 | ] 81 | parameters [ 82 | ] 83 | body [ 84 | Expr_FuncCall 85 | name: 86 | Expr_IdentifierReference 87 | name: 88 | Name 89 | parts [ 90 | intdiv 91 | ] 92 | args [ 93 | Arg 94 | value: 95 | Scalar_LNumber 96 | value(3) 97 | name() 98 | Arg 99 | value: 100 | Scalar_LNumber 101 | value(2) 102 | name() 103 | ] 104 | ] 105 | -------------------------------------------------------------------------------- /examples/03-defining-types/Prerano::Examples::DefiningTypes.cfg: -------------------------------------------------------------------------------- 1 | Package: Prerano::Examples::DefiningTypes 2 | Public: 3 | Types: 4 | age => int 5 | GOOD => 0 6 | BAD => 1 7 | STATUS => (GOOD|BAD) 8 | Functions: 9 | Protected: 10 | Types: 11 | Functions: 12 | Private: 13 | Types: 14 | numeric => (string|int) 15 | Functions: 16 | -------------------------------------------------------------------------------- /examples/03-defining-types/Prerano::Examples::DefiningTypes.php: -------------------------------------------------------------------------------- 1 | headers) { 18 | $this->headers = unserialize(base64_decode(self::HEADERS)); 19 | } 20 | return $this->headers; 21 | } 22 | } 23 | final class __PRERANO_CODE__ 24 | { 25 | private static $Prerano܃܃Examples܃܃DefiningTypes܃܃instance; 26 | public static function Prerano܃܃Examples܃܃DefiningTypes܃܃∫() 27 | { 28 | if (!self::$Prerano܃܃Examples܃܃DefiningTypes܃܃instance) { 29 | self::$Prerano܃܃Examples܃܃DefiningTypes܃܃instance = new self(); 30 | } 31 | return self::$Prerano܃܃Examples܃܃DefiningTypes܃܃instance; 32 | } 33 | } 34 | __PRERANO_CODE__::Prerano܃܃Examples܃܃DefiningTypes܃܃∫(); 35 | const GOOD = 0; 36 | const BAD = 1; -------------------------------------------------------------------------------- /examples/03-defining-types/Prerano::Examples::DefiningTypes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ircmaxell/prerano/08acefad9ac7fab8db5c87b0a76b437fbaa0f897/examples/03-defining-types/Prerano::Examples::DefiningTypes.png -------------------------------------------------------------------------------- /examples/03-defining-types/code.pr: -------------------------------------------------------------------------------- 1 | package Prerano::Examples::DefiningTypes; 2 | 3 | type numeric = string|int 4 | 5 | public type age = int 6 | 7 | public enum STATUS { 8 | GOOD, 9 | BAD 10 | } 11 | -------------------------------------------------------------------------------- /examples/03-defining-types/code.pr.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::DefiningTypes 2 | Stmt_Type 3 | name: 4 | Name 5 | parts [ 6 | numeric 7 | ] 8 | type: 9 | Expr_Type_Union 10 | left: 11 | Expr_Type_Named 12 | name: 13 | Name 14 | parts [ 15 | string 16 | ] 17 | right: 18 | Expr_Type_Named 19 | name: 20 | Name 21 | parts [ 22 | int 23 | ] 24 | Stmt_Type 25 | name: 26 | Name 27 | parts [ 28 | age 29 | ] 30 | type: 31 | Expr_Type_Named 32 | name: 33 | Name 34 | parts [ 35 | int 36 | ] 37 | Stmt_Enum 38 | name: 39 | Name 40 | parts [ 41 | STATUS 42 | ] 43 | subTypes [ 44 | Stmt_Type 45 | name: 46 | Name 47 | parts [ 48 | GOOD 49 | ] 50 | type: 51 | Expr_Type_Value 52 | value() 53 | Stmt_Type 54 | name: 55 | Name 56 | parts [ 57 | BAD 58 | ] 59 | type: 60 | Expr_Type_Value 61 | value() 62 | ] 63 | -------------------------------------------------------------------------------- /examples/03-defining-types/code.pr.processed.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::DefiningTypes 2 | Stmt_Type 3 | name: 4 | Name 5 | parts [ 6 | numeric 7 | ] 8 | type: 9 | Expr_Type_Union 10 | left: 11 | Expr_Type_Named 12 | name: 13 | Name 14 | parts [ 15 | string 16 | ] 17 | right: 18 | Expr_Type_Named 19 | name: 20 | Name 21 | parts [ 22 | int 23 | ] 24 | Stmt_Type 25 | name: 26 | Name 27 | parts [ 28 | age 29 | ] 30 | type: 31 | Expr_Type_Named 32 | name: 33 | Name 34 | parts [ 35 | int 36 | ] 37 | Stmt_Enum 38 | name: 39 | Name 40 | parts [ 41 | STATUS 42 | ] 43 | subTypes [ 44 | Stmt_Type 45 | name: 46 | Name 47 | parts [ 48 | GOOD 49 | ] 50 | type: 51 | Expr_Type_Value 52 | value() 53 | Stmt_Type 54 | name: 55 | Name 56 | parts [ 57 | BAD 58 | ] 59 | type: 60 | Expr_Type_Value 61 | value() 62 | ] 63 | -------------------------------------------------------------------------------- /examples/04-guards/Prerano::Examples::PublicFunctions.cfg: -------------------------------------------------------------------------------- 1 | Package: Prerano::Examples::PublicFunctions 2 | Public: 3 | Types: 4 | id => fn(int,float)int 5 | GOOD => 0 6 | BAD => 1 7 | STATUS => (GOOD|BAD) 8 | decode => fn((0|1))int 9 | decode2 => fn(Prerano::Examples::PublicFunctions::STATUS)int 10 | decode3 => fn(Prerano::Examples::PublicFunctions::numeric)int 11 | Functions: 12 | id: 13 | result: int $138 14 | blocks: 15 | Block #30() 16 | 17 | decode: 18 | result: (0|1) $141 19 | blocks: 20 | Block #31() 21 | 22 | decode2: 23 | result: Prerano::Examples::PublicFunctions::STATUS $144 24 | blocks: 25 | Block #32() 26 | 27 | decode3: 28 | result: Prerano::Examples::PublicFunctions::numeric $147 29 | blocks: 30 | Block #33() 31 | 32 | Protected: 33 | Types: 34 | Functions: 35 | Private: 36 | Types: 37 | numeric => (int|string|float) 38 | Functions: 39 | -------------------------------------------------------------------------------- /examples/04-guards/Prerano::Examples::PublicFunctions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ircmaxell/prerano/08acefad9ac7fab8db5c87b0a76b437fbaa0f897/examples/04-guards/Prerano::Examples::PublicFunctions.png -------------------------------------------------------------------------------- /examples/04-guards/code.pr: -------------------------------------------------------------------------------- 1 | package Prerano::Examples::PublicFunctions; 2 | 3 | public fn id(int $a, float $b) int = $a; 4 | 5 | public enum STATUS { 6 | GOOD, 7 | BAD 8 | } 9 | 10 | type numeric = int|string|float 11 | 12 | public fn decode(0|1 $status) int = $status; 13 | 14 | public fn decode2(STATUS $status) int = $status; 15 | 16 | public fn decode3(numeric $value) int = $value; -------------------------------------------------------------------------------- /examples/04-guards/code.pr.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::PublicFunctions 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | id 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | int 14 | ] 15 | parameters [ 16 | Stmt_Parameter 17 | name(a) 18 | type: 19 | Expr_Type_Named 20 | name: 21 | Name 22 | parts [ 23 | int 24 | ] 25 | default() 26 | Stmt_Parameter 27 | name(b) 28 | type: 29 | Expr_Type_Named 30 | name: 31 | Name 32 | parts [ 33 | float 34 | ] 35 | default() 36 | ] 37 | body [ 38 | Expr_Variable 39 | name: 40 | Name 41 | parts [ 42 | a 43 | ] 44 | ] 45 | Stmt_Enum 46 | name: 47 | Name 48 | parts [ 49 | STATUS 50 | ] 51 | subTypes [ 52 | Stmt_Type 53 | name: 54 | Name 55 | parts [ 56 | GOOD 57 | ] 58 | type: 59 | Expr_Type_Value 60 | value() 61 | Stmt_Type 62 | name: 63 | Name 64 | parts [ 65 | BAD 66 | ] 67 | type: 68 | Expr_Type_Value 69 | value() 70 | ] 71 | Stmt_Type 72 | name: 73 | Name 74 | parts [ 75 | numeric 76 | ] 77 | type: 78 | Expr_Type_Union 79 | left: 80 | Expr_Type_Union 81 | left: 82 | Expr_Type_Named 83 | name: 84 | Name 85 | parts [ 86 | int 87 | ] 88 | right: 89 | Expr_Type_Named 90 | name: 91 | Name 92 | parts [ 93 | string 94 | ] 95 | right: 96 | Expr_Type_Named 97 | name: 98 | Name 99 | parts [ 100 | float 101 | ] 102 | Stmt_Function 103 | name: 104 | Name 105 | parts [ 106 | decode 107 | ] 108 | returnType: 109 | Expr_Type_Named 110 | name: 111 | Name 112 | parts [ 113 | int 114 | ] 115 | parameters [ 116 | Stmt_Parameter 117 | name(status) 118 | type: 119 | Expr_Type_Union 120 | left: 121 | Expr_Type_Value 122 | value: 123 | Scalar_LNumber 124 | value(0) 125 | right: 126 | Expr_Type_Value 127 | value: 128 | Scalar_LNumber 129 | value(1) 130 | default() 131 | ] 132 | body [ 133 | Expr_Variable 134 | name: 135 | Name 136 | parts [ 137 | status 138 | ] 139 | ] 140 | Stmt_Function 141 | name: 142 | Name 143 | parts [ 144 | decode2 145 | ] 146 | returnType: 147 | Expr_Type_Named 148 | name: 149 | Name 150 | parts [ 151 | int 152 | ] 153 | parameters [ 154 | Stmt_Parameter 155 | name(status) 156 | type: 157 | Expr_Type_Named 158 | name: 159 | Name 160 | parts [ 161 | STATUS 162 | ] 163 | default() 164 | ] 165 | body [ 166 | Expr_Variable 167 | name: 168 | Name 169 | parts [ 170 | status 171 | ] 172 | ] 173 | Stmt_Function 174 | name: 175 | Name 176 | parts [ 177 | decode3 178 | ] 179 | returnType: 180 | Expr_Type_Named 181 | name: 182 | Name 183 | parts [ 184 | int 185 | ] 186 | parameters [ 187 | Stmt_Parameter 188 | name(value) 189 | type: 190 | Expr_Type_Named 191 | name: 192 | Name 193 | parts [ 194 | numeric 195 | ] 196 | default() 197 | ] 198 | body [ 199 | Expr_Variable 200 | name: 201 | Name 202 | parts [ 203 | value 204 | ] 205 | ] 206 | -------------------------------------------------------------------------------- /examples/04-guards/code.pr.processed.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::PublicFunctions 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | id 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | int 14 | ] 15 | parameters [ 16 | Stmt_Parameter 17 | name(a) 18 | type: 19 | Expr_Type_Named 20 | name: 21 | Name 22 | parts [ 23 | int 24 | ] 25 | default() 26 | Stmt_Parameter 27 | name(b) 28 | type: 29 | Expr_Type_Named 30 | name: 31 | Name 32 | parts [ 33 | float 34 | ] 35 | default() 36 | ] 37 | body [ 38 | Expr_Variable 39 | name: 40 | Name 41 | parts [ 42 | a 43 | ] 44 | ] 45 | Stmt_Enum 46 | name: 47 | Name 48 | parts [ 49 | STATUS 50 | ] 51 | subTypes [ 52 | Stmt_Type 53 | name: 54 | Name 55 | parts [ 56 | GOOD 57 | ] 58 | type: 59 | Expr_Type_Value 60 | value() 61 | Stmt_Type 62 | name: 63 | Name 64 | parts [ 65 | BAD 66 | ] 67 | type: 68 | Expr_Type_Value 69 | value() 70 | ] 71 | Stmt_Type 72 | name: 73 | Name 74 | parts [ 75 | numeric 76 | ] 77 | type: 78 | Expr_Type_Union 79 | left: 80 | Expr_Type_Union 81 | left: 82 | Expr_Type_Named 83 | name: 84 | Name 85 | parts [ 86 | int 87 | ] 88 | right: 89 | Expr_Type_Named 90 | name: 91 | Name 92 | parts [ 93 | string 94 | ] 95 | right: 96 | Expr_Type_Named 97 | name: 98 | Name 99 | parts [ 100 | float 101 | ] 102 | Stmt_Function 103 | name: 104 | Name 105 | parts [ 106 | decode 107 | ] 108 | returnType: 109 | Expr_Type_Named 110 | name: 111 | Name 112 | parts [ 113 | int 114 | ] 115 | parameters [ 116 | Stmt_Parameter 117 | name(status) 118 | type: 119 | Expr_Type_Union 120 | left: 121 | Expr_Type_Value 122 | value: 123 | Scalar_LNumber 124 | value(0) 125 | right: 126 | Expr_Type_Value 127 | value: 128 | Scalar_LNumber 129 | value(1) 130 | default() 131 | ] 132 | body [ 133 | Expr_Variable 134 | name: 135 | Name 136 | parts [ 137 | status 138 | ] 139 | ] 140 | Stmt_Function 141 | name: 142 | Name 143 | parts [ 144 | decode2 145 | ] 146 | returnType: 147 | Expr_Type_Named 148 | name: 149 | Name 150 | parts [ 151 | int 152 | ] 153 | parameters [ 154 | Stmt_Parameter 155 | name(status) 156 | type: 157 | Expr_Type_Named 158 | name: 159 | Name_Qualified 160 | parts [ 161 | Prerano 162 | Examples 163 | PublicFunctions 164 | STATUS 165 | ] 166 | default() 167 | ] 168 | body [ 169 | Expr_Variable 170 | name: 171 | Name 172 | parts [ 173 | status 174 | ] 175 | ] 176 | Stmt_Function 177 | name: 178 | Name 179 | parts [ 180 | decode3 181 | ] 182 | returnType: 183 | Expr_Type_Named 184 | name: 185 | Name 186 | parts [ 187 | int 188 | ] 189 | parameters [ 190 | Stmt_Parameter 191 | name(value) 192 | type: 193 | Expr_Type_Named 194 | name: 195 | Name_Qualified 196 | parts [ 197 | Prerano 198 | Examples 199 | PublicFunctions 200 | numeric 201 | ] 202 | default() 203 | ] 204 | body [ 205 | Expr_Variable 206 | name: 207 | Name 208 | parts [ 209 | value 210 | ] 211 | ] 212 | -------------------------------------------------------------------------------- /examples/05-type-checks/Prerano::Examples::TypeChecks.cfg: -------------------------------------------------------------------------------- 1 | Package: Prerano::Examples::TypeChecks 2 | Public: 3 | Types: 4 | Functions: 5 | Protected: 6 | Types: 7 | Functions: 8 | Private: 9 | Types: 10 | isString => fn(any)(true|false) 11 | isInt => fn(any)(true|false) 12 | isNumeric => fn(any)(true|false) 13 | is0or1 => fn(any)(true|false) 14 | Functions: 15 | isString: 16 | result: (true|false) $190 17 | blocks: 18 | Block #43() 19 | Expr_Is: 20 | cond: any $189 21 | type: string 22 | result: (true|false) $190 23 | 24 | isInt: 25 | result: (true|false) $194 26 | blocks: 27 | Block #44() 28 | Expr_Is: 29 | cond: any $193 30 | type: int 31 | result: (true|false) $194 32 | 33 | isNumeric: 34 | result: (true|false) $198 35 | blocks: 36 | Block #45() 37 | Expr_Is: 38 | cond: any $197 39 | type: (int|float) 40 | result: (true|false) $198 41 | 42 | is0or1: 43 | result: (true|false) $202 44 | blocks: 45 | Block #46() 46 | Expr_Is: 47 | cond: any $201 48 | type: (0|1) 49 | result: (true|false) $202 50 | 51 | -------------------------------------------------------------------------------- /examples/05-type-checks/Prerano::Examples::TypeChecks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ircmaxell/prerano/08acefad9ac7fab8db5c87b0a76b437fbaa0f897/examples/05-type-checks/Prerano::Examples::TypeChecks.png -------------------------------------------------------------------------------- /examples/05-type-checks/code.pr: -------------------------------------------------------------------------------- 1 | package Prerano::Examples::TypeChecks; 2 | 3 | fn isString(any $arg) bool = $arg is string; 4 | 5 | fn isInt(any $arg) bool = $arg is int; 6 | 7 | fn isNumeric(any $arg) bool = $arg is int|float; 8 | 9 | fn is0or1(any $arg) bool = $arg is 0|1; -------------------------------------------------------------------------------- /examples/05-type-checks/code.pr.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::TypeChecks 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | isString 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | bool 14 | ] 15 | parameters [ 16 | Stmt_Parameter 17 | name(arg) 18 | type: 19 | Expr_Type_Named 20 | name: 21 | Name 22 | parts [ 23 | any 24 | ] 25 | default() 26 | ] 27 | body [ 28 | Expr_Is 29 | cond: 30 | Expr_Variable 31 | name: 32 | Name 33 | parts [ 34 | arg 35 | ] 36 | type: 37 | Expr_Type_Named 38 | name: 39 | Name 40 | parts [ 41 | string 42 | ] 43 | ] 44 | Stmt_Function 45 | name: 46 | Name 47 | parts [ 48 | isInt 49 | ] 50 | returnType: 51 | Expr_Type_Named 52 | name: 53 | Name 54 | parts [ 55 | bool 56 | ] 57 | parameters [ 58 | Stmt_Parameter 59 | name(arg) 60 | type: 61 | Expr_Type_Named 62 | name: 63 | Name 64 | parts [ 65 | any 66 | ] 67 | default() 68 | ] 69 | body [ 70 | Expr_Is 71 | cond: 72 | Expr_Variable 73 | name: 74 | Name 75 | parts [ 76 | arg 77 | ] 78 | type: 79 | Expr_Type_Named 80 | name: 81 | Name 82 | parts [ 83 | int 84 | ] 85 | ] 86 | Stmt_Function 87 | name: 88 | Name 89 | parts [ 90 | isNumeric 91 | ] 92 | returnType: 93 | Expr_Type_Named 94 | name: 95 | Name 96 | parts [ 97 | bool 98 | ] 99 | parameters [ 100 | Stmt_Parameter 101 | name(arg) 102 | type: 103 | Expr_Type_Named 104 | name: 105 | Name 106 | parts [ 107 | any 108 | ] 109 | default() 110 | ] 111 | body [ 112 | Expr_Is 113 | cond: 114 | Expr_Variable 115 | name: 116 | Name 117 | parts [ 118 | arg 119 | ] 120 | type: 121 | Expr_Type_Union 122 | left: 123 | Expr_Type_Named 124 | name: 125 | Name 126 | parts [ 127 | int 128 | ] 129 | right: 130 | Expr_Type_Named 131 | name: 132 | Name 133 | parts [ 134 | float 135 | ] 136 | ] 137 | Stmt_Function 138 | name: 139 | Name 140 | parts [ 141 | is0or1 142 | ] 143 | returnType: 144 | Expr_Type_Named 145 | name: 146 | Name 147 | parts [ 148 | bool 149 | ] 150 | parameters [ 151 | Stmt_Parameter 152 | name(arg) 153 | type: 154 | Expr_Type_Named 155 | name: 156 | Name 157 | parts [ 158 | any 159 | ] 160 | default() 161 | ] 162 | body [ 163 | Expr_Is 164 | cond: 165 | Expr_Variable 166 | name: 167 | Name 168 | parts [ 169 | arg 170 | ] 171 | type: 172 | Expr_Type_Union 173 | left: 174 | Expr_Type_Value 175 | value: 176 | Scalar_LNumber 177 | value(0) 178 | right: 179 | Expr_Type_Value 180 | value: 181 | Scalar_LNumber 182 | value(1) 183 | ] 184 | -------------------------------------------------------------------------------- /examples/05-type-checks/code.pr.processed.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::TypeChecks 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | isString 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | bool 14 | ] 15 | parameters [ 16 | Stmt_Parameter 17 | name(arg) 18 | type: 19 | Expr_Type_Named 20 | name: 21 | Name 22 | parts [ 23 | any 24 | ] 25 | default() 26 | ] 27 | body [ 28 | Expr_Is 29 | cond: 30 | Expr_Variable 31 | name: 32 | Name 33 | parts [ 34 | arg 35 | ] 36 | type: 37 | Expr_Type_Named 38 | name: 39 | Name 40 | parts [ 41 | string 42 | ] 43 | ] 44 | Stmt_Function 45 | name: 46 | Name 47 | parts [ 48 | isInt 49 | ] 50 | returnType: 51 | Expr_Type_Named 52 | name: 53 | Name 54 | parts [ 55 | bool 56 | ] 57 | parameters [ 58 | Stmt_Parameter 59 | name(arg) 60 | type: 61 | Expr_Type_Named 62 | name: 63 | Name 64 | parts [ 65 | any 66 | ] 67 | default() 68 | ] 69 | body [ 70 | Expr_Is 71 | cond: 72 | Expr_Variable 73 | name: 74 | Name 75 | parts [ 76 | arg 77 | ] 78 | type: 79 | Expr_Type_Named 80 | name: 81 | Name 82 | parts [ 83 | int 84 | ] 85 | ] 86 | Stmt_Function 87 | name: 88 | Name 89 | parts [ 90 | isNumeric 91 | ] 92 | returnType: 93 | Expr_Type_Named 94 | name: 95 | Name 96 | parts [ 97 | bool 98 | ] 99 | parameters [ 100 | Stmt_Parameter 101 | name(arg) 102 | type: 103 | Expr_Type_Named 104 | name: 105 | Name 106 | parts [ 107 | any 108 | ] 109 | default() 110 | ] 111 | body [ 112 | Expr_Is 113 | cond: 114 | Expr_Variable 115 | name: 116 | Name 117 | parts [ 118 | arg 119 | ] 120 | type: 121 | Expr_Type_Union 122 | left: 123 | Expr_Type_Named 124 | name: 125 | Name 126 | parts [ 127 | int 128 | ] 129 | right: 130 | Expr_Type_Named 131 | name: 132 | Name 133 | parts [ 134 | float 135 | ] 136 | ] 137 | Stmt_Function 138 | name: 139 | Name 140 | parts [ 141 | is0or1 142 | ] 143 | returnType: 144 | Expr_Type_Named 145 | name: 146 | Name 147 | parts [ 148 | bool 149 | ] 150 | parameters [ 151 | Stmt_Parameter 152 | name(arg) 153 | type: 154 | Expr_Type_Named 155 | name: 156 | Name 157 | parts [ 158 | any 159 | ] 160 | default() 161 | ] 162 | body [ 163 | Expr_Is 164 | cond: 165 | Expr_Variable 166 | name: 167 | Name 168 | parts [ 169 | arg 170 | ] 171 | type: 172 | Expr_Type_Union 173 | left: 174 | Expr_Type_Value 175 | value: 176 | Scalar_LNumber 177 | value(0) 178 | right: 179 | Expr_Type_Value 180 | value: 181 | Scalar_LNumber 182 | value(1) 183 | ] 184 | -------------------------------------------------------------------------------- /examples/06-matching/Prerano::Examples::Matching.cfg: -------------------------------------------------------------------------------- 1 | Package: Prerano::Examples::Matching 2 | Public: 3 | Types: 4 | length => fn(any)int 5 | foo => fn(int)int 6 | mod2 => fn(int)int 7 | Functions: 8 | length: 9 | result: unknown $60{from #8: int $44, from #10: int $51, from #12: unknown $55, from #13: int $59 = 0} 10 | blocks: 11 | Block #6() 12 | Expr_Is: 13 | cond: any $38 14 | type: string 15 | result: (true|false) $39 16 | Expr_If: 17 | cond: (true|false) $39 18 | result: unknown $45 19 | if->Block #8 20 | else->Block #9 21 | 22 | Block #8($42) 23 | Expr_FuncCall: 24 | name: php::strlen $43 25 | args: [unknown $41] 26 | result: int $44 27 | *->Block #7 28 | 29 | Block #7() 30 | 31 | Block #9() 32 | Expr_Is: 33 | cond: any $38 34 | type: array 35 | result: (true|false) $46 36 | Expr_If: 37 | cond: (true|false) $46 38 | result: unknown $52 39 | if->Block #10 40 | else->Block #11 41 | 42 | Block #10($49) 43 | Expr_FuncCall: 44 | name: php::count $50 45 | args: [unknown $48] 46 | result: int $51 47 | *->Block #7 48 | 49 | Block #11() 50 | Expr_Is: 51 | cond: any $38 52 | type: int 53 | result: (true|false) $53 54 | Expr_If: 55 | cond: (true|false) $53 56 | result: unknown $57 57 | if->Block #12 58 | else->Block #13 59 | 60 | Block #12($56) 61 | *->Block #7 62 | 63 | Block #13() 64 | *->Block #7 65 | 66 | foo: 67 | result: unknown $76{from #16: int $67 = 1, from #18: int $72 = 2, from #19: int $75 = 3} 68 | blocks: 69 | Block #14() 70 | Expr_BinaryOp_Equals: 71 | left: int $63 72 | right: int $64 = 0 73 | result: (true|false) $65 74 | Expr_If: 75 | cond: (true|false) $65 76 | result: unknown $68 77 | if->Block #16 78 | else->Block #17 79 | 80 | Block #16() 81 | *->Block #15 82 | 83 | Block #15() 84 | 85 | Block #17() 86 | Expr_BinaryOp_Equals: 87 | left: int $63 88 | right: int $69 = 1 89 | result: (true|false) $70 90 | Expr_If: 91 | cond: (true|false) $70 92 | result: unknown $73 93 | if->Block #18 94 | else->Block #19 95 | 96 | Block #18() 97 | *->Block #15 98 | 99 | Block #19() 100 | *->Block #15 101 | 102 | mod2: 103 | result: unknown $102{from #23: int $91 = 0, from #25: int $98 = 0, from #26: int $101 = 1} 104 | blocks: 105 | Block #21() 106 | Expr_FuncCall: 107 | name: isEven $88 108 | args: [int $87] 109 | result: (true|false) $89 110 | Expr_If: 111 | cond: (true|false) $89 112 | result: unknown $92 113 | if->Block #23 114 | else->Block #24 115 | 116 | Block #23() 117 | *->Block #22 118 | 119 | Block #22() 120 | 121 | Block #24($94) 122 | Expr_BinaryOp_Equals: 123 | left: unknown $93 124 | right: int $95 = 1 125 | result: (true|false) $96 126 | Expr_If: 127 | cond: (true|false) $96 128 | result: unknown $99 129 | if->Block #25 130 | else->Block #26 131 | 132 | Block #25() 133 | *->Block #22 134 | 135 | Block #26() 136 | *->Block #22 137 | 138 | Protected: 139 | Types: 140 | Functions: 141 | Private: 142 | Types: 143 | isEven => fn(int)(true|false) 144 | Functions: 145 | isEven: 146 | result: (true|false) $83 147 | blocks: 148 | Block #20() 149 | Expr_BinaryOp_Mod: 150 | left: int $79 151 | right: int $80 = 2 152 | result: unknown $81 153 | Expr_BinaryOp_Equals: 154 | left: unknown $81 155 | right: int $82 = 0 156 | result: (true|false) $83 157 | 158 | -------------------------------------------------------------------------------- /examples/06-matching/Prerano::Examples::Matching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ircmaxell/prerano/08acefad9ac7fab8db5c87b0a76b437fbaa0f897/examples/06-matching/Prerano::Examples::Matching.png -------------------------------------------------------------------------------- /examples/06-matching/code.pr: -------------------------------------------------------------------------------- 1 | package Prerano::Examples::Matching; 2 | 3 | 4 | public fn length(any $input) int = match($input) { 5 | string: php::strlen($input); 6 | array: { 7 | php::count($input); 8 | } 9 | int: $input; 10 | else: 0; 11 | }; 12 | 13 | public fn foo(int $input) int = match($input) { 14 | 0: 1; 15 | 1: 2; 16 | else: 3; 17 | }; 18 | 19 | fn isEven(int $i) bool { 20 | $i % 2 == 0; 21 | } 22 | 23 | public fn mod2(int $input) int = match($input) { 24 | isEven($input): 0; 25 | $input == 1: 0; 26 | else: 1; 27 | }; -------------------------------------------------------------------------------- /examples/07-expression-functions/Prerano::Examples::ExpressionFunctions.cfg: -------------------------------------------------------------------------------- 1 | Package: Prerano::Examples::ExpressionFunctions 2 | Public: 3 | Types: 4 | Functions: 5 | Protected: 6 | Types: 7 | Functions: 8 | Private: 9 | Types: 10 | __main__ => fn()none 11 | int->next => fn()int 12 | int->prev => fn()int 13 | int->even => fn()(true|false) 14 | Functions: 15 | __main__: 16 | result: unknown $150 17 | blocks: 18 | Block #34() 19 | Expr_ExpressionCall: 20 | rootType: int 21 | obj: int $149 = 1 22 | name: name 23 | result: unknown $150 24 | 25 | -------------------------------------------------------------------------------- /examples/07-expression-functions/Prerano::Examples::ExpressionFunctions.php: -------------------------------------------------------------------------------- 1 | headers) { 18 | $this->headers = unserialize(base64_decode(self::HEADERS)); 19 | } 20 | return $this->headers; 21 | } 22 | } 23 | final class __PRERANO_CODE__ 24 | { 25 | private static $Prerano܃܃Examples܃܃ExpressionFunctions܃܃instance; 26 | public static function Prerano܃܃Examples܃܃ExpressionFunctions܃܃∫() 27 | { 28 | if (!self::$Prerano܃܃Examples܃܃ExpressionFunctions܃܃instance) { 29 | self::$Prerano܃܃Examples܃܃ExpressionFunctions܃܃instance = new self(); 30 | } 31 | return self::$Prerano܃܃Examples܃܃ExpressionFunctions܃܃instance; 32 | } 33 | /** fn()none */ 34 | public function __construct() 35 | { 36 | $_150 = $this->Prerano܃܃Examples܃܃ExpressionFunctions܃܃next→int(1); 37 | return $_150; 38 | } 39 | /** int->fn()int */ 40 | public function Prerano܃܃Examples܃܃ExpressionFunctions܃܃next→int($_) 41 | { 42 | $_155 = $_ + 1; 43 | return $_155; 44 | } 45 | /** int->fn()int */ 46 | public function Prerano܃܃Examples܃܃ExpressionFunctions܃܃prev→int($_) 47 | { 48 | $_160 = $_ - 1; 49 | return $_160; 50 | } 51 | /** int->fn()(true|false) */ 52 | public function Prerano܃܃Examples܃܃ExpressionFunctions܃܃even→int($_) 53 | { 54 | $_166 = $_ % 2; 55 | $_168 = $_166 === 0; 56 | if ($_168) { 57 | } else { 58 | $_175 = $_ % 2; 59 | $_177 = $_175 === 1; 60 | if ($_177) { 61 | } 62 | } 63 | return $_183; 64 | } 65 | } 66 | __PRERANO_CODE__::Prerano܃܃Examples܃܃ExpressionFunctions܃܃∫(); -------------------------------------------------------------------------------- /examples/07-expression-functions/Prerano::Examples::ExpressionFunctions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ircmaxell/prerano/08acefad9ac7fab8db5c87b0a76b437fbaa0f897/examples/07-expression-functions/Prerano::Examples::ExpressionFunctions.png -------------------------------------------------------------------------------- /examples/07-expression-functions/__main__.pr: -------------------------------------------------------------------------------- 1 | package Prerano::Examples::ExpressionFunctions; 2 | 3 | fn __main__() none { 4 | 1->next(); 5 | } -------------------------------------------------------------------------------- /examples/07-expression-functions/__main__.pr.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::ExpressionFunctions 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | __main__ 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | none 14 | ] 15 | parameters [ 16 | ] 17 | body [ 18 | Expr_MethodCall 19 | obj: 20 | Scalar_LNumber 21 | value(1) 22 | name: 23 | Expr_IdentifierReference 24 | name: 25 | Name 26 | parts [ 27 | next 28 | ] 29 | args [ 30 | ] 31 | ] 32 | -------------------------------------------------------------------------------- /examples/07-expression-functions/__main__.pr.processed.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::ExpressionFunctions 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | __main__ 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | none 14 | ] 15 | parameters [ 16 | ] 17 | body [ 18 | Expr_MethodCall 19 | obj: 20 | Scalar_LNumber 21 | value(1) 22 | name: 23 | Expr_IdentifierReference 24 | name: 25 | Name 26 | parts [ 27 | next 28 | ] 29 | args [ 30 | ] 31 | ] 32 | -------------------------------------------------------------------------------- /examples/07-expression-functions/types.pr: -------------------------------------------------------------------------------- 1 | package Prerano::Examples::ExpressionFunctions; 2 | 3 | on int fn next() int = $_ + 1; 4 | on int fn prev() int = $_ - 1; 5 | 6 | on int fn even() bool = match($_) { 7 | $_ % 2 == 0: true; 8 | $_ % 2 == 1: false; 9 | else: false; 10 | }; -------------------------------------------------------------------------------- /examples/07-expression-functions/types.pr.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::ExpressionFunctions 2 | Stmt_ExprFunction 3 | on: 4 | Expr_Type_Named 5 | name: 6 | Name 7 | parts [ 8 | int 9 | ] 10 | name: 11 | Name 12 | parts [ 13 | next 14 | ] 15 | returnType: 16 | Expr_Type_Named 17 | name: 18 | Name 19 | parts [ 20 | int 21 | ] 22 | parameters [ 23 | ] 24 | body [ 25 | Expr_BinaryOp_Plus 26 | left: 27 | Expr_Variable 28 | name: 29 | Name 30 | parts [ 31 | _ 32 | ] 33 | right: 34 | Scalar_LNumber 35 | value(1) 36 | ] 37 | Stmt_ExprFunction 38 | on: 39 | Expr_Type_Named 40 | name: 41 | Name 42 | parts [ 43 | int 44 | ] 45 | name: 46 | Name 47 | parts [ 48 | prev 49 | ] 50 | returnType: 51 | Expr_Type_Named 52 | name: 53 | Name 54 | parts [ 55 | int 56 | ] 57 | parameters [ 58 | ] 59 | body [ 60 | Expr_BinaryOp_Minus 61 | left: 62 | Expr_Variable 63 | name: 64 | Name 65 | parts [ 66 | _ 67 | ] 68 | right: 69 | Scalar_LNumber 70 | value(1) 71 | ] 72 | Stmt_ExprFunction 73 | on: 74 | Expr_Type_Named 75 | name: 76 | Name 77 | parts [ 78 | int 79 | ] 80 | name: 81 | Name 82 | parts [ 83 | even 84 | ] 85 | returnType: 86 | Expr_Type_Named 87 | name: 88 | Name 89 | parts [ 90 | bool 91 | ] 92 | parameters [ 93 | ] 94 | body [ 95 | Expr_Match 96 | cond: 97 | Expr_Variable 98 | name: 99 | Name 100 | parts [ 101 | _ 102 | ] 103 | entries [ 104 | Expr_MatchEntry 105 | cond: 106 | Expr_BinaryOp_Equals 107 | left: 108 | Expr_BinaryOp_Mod 109 | left: 110 | Expr_Variable 111 | name: 112 | Name 113 | parts [ 114 | _ 115 | ] 116 | right: 117 | Scalar_LNumber 118 | value(2) 119 | right: 120 | Scalar_LNumber 121 | value(0) 122 | stmts [ 123 | Expr_IdentifierReference 124 | name: 125 | Name 126 | parts [ 127 | true 128 | ] 129 | ] 130 | Expr_MatchEntry 131 | cond: 132 | Expr_BinaryOp_Equals 133 | left: 134 | Expr_BinaryOp_Mod 135 | left: 136 | Expr_Variable 137 | name: 138 | Name 139 | parts [ 140 | _ 141 | ] 142 | right: 143 | Scalar_LNumber 144 | value(2) 145 | right: 146 | Scalar_LNumber 147 | value(1) 148 | stmts [ 149 | Expr_IdentifierReference 150 | name: 151 | Name 152 | parts [ 153 | false 154 | ] 155 | ] 156 | Expr_MatchEntry 157 | cond() 158 | stmts [ 159 | Expr_IdentifierReference 160 | name: 161 | Name 162 | parts [ 163 | false 164 | ] 165 | ] 166 | ] 167 | ] 168 | -------------------------------------------------------------------------------- /examples/07-expression-functions/types.pr.processed.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::ExpressionFunctions 2 | Stmt_ExprFunction 3 | on: 4 | Expr_Type_Named 5 | name: 6 | Name 7 | parts [ 8 | int 9 | ] 10 | name: 11 | Name 12 | parts [ 13 | next 14 | ] 15 | returnType: 16 | Expr_Type_Named 17 | name: 18 | Name 19 | parts [ 20 | int 21 | ] 22 | parameters [ 23 | ] 24 | body [ 25 | Expr_BinaryOp_Plus 26 | left: 27 | Expr_Variable 28 | name: 29 | Name 30 | parts [ 31 | _ 32 | ] 33 | right: 34 | Scalar_LNumber 35 | value(1) 36 | ] 37 | Stmt_ExprFunction 38 | on: 39 | Expr_Type_Named 40 | name: 41 | Name 42 | parts [ 43 | int 44 | ] 45 | name: 46 | Name 47 | parts [ 48 | prev 49 | ] 50 | returnType: 51 | Expr_Type_Named 52 | name: 53 | Name 54 | parts [ 55 | int 56 | ] 57 | parameters [ 58 | ] 59 | body [ 60 | Expr_BinaryOp_Minus 61 | left: 62 | Expr_Variable 63 | name: 64 | Name 65 | parts [ 66 | _ 67 | ] 68 | right: 69 | Scalar_LNumber 70 | value(1) 71 | ] 72 | Stmt_ExprFunction 73 | on: 74 | Expr_Type_Named 75 | name: 76 | Name 77 | parts [ 78 | int 79 | ] 80 | name: 81 | Name 82 | parts [ 83 | even 84 | ] 85 | returnType: 86 | Expr_Type_Named 87 | name: 88 | Name 89 | parts [ 90 | bool 91 | ] 92 | parameters [ 93 | ] 94 | body [ 95 | Expr_Match 96 | cond: 97 | Expr_Variable 98 | name: 99 | Name 100 | parts [ 101 | _ 102 | ] 103 | entries [ 104 | Expr_MatchEntry 105 | cond: 106 | Expr_BinaryOp_Equals 107 | left: 108 | Expr_BinaryOp_Mod 109 | left: 110 | Expr_Variable 111 | name: 112 | Name 113 | parts [ 114 | _ 115 | ] 116 | right: 117 | Scalar_LNumber 118 | value(2) 119 | right: 120 | Scalar_LNumber 121 | value(0) 122 | stmts [ 123 | Expr_IdentifierReference 124 | name: 125 | Name 126 | parts [ 127 | true 128 | ] 129 | ] 130 | Expr_MatchEntry 131 | cond: 132 | Expr_BinaryOp_Equals 133 | left: 134 | Expr_BinaryOp_Mod 135 | left: 136 | Expr_Variable 137 | name: 138 | Name 139 | parts [ 140 | _ 141 | ] 142 | right: 143 | Scalar_LNumber 144 | value(2) 145 | right: 146 | Scalar_LNumber 147 | value(1) 148 | stmts [ 149 | Expr_IdentifierReference 150 | name: 151 | Name 152 | parts [ 153 | false 154 | ] 155 | ] 156 | Expr_MatchEntry 157 | cond() 158 | stmts [ 159 | Expr_IdentifierReference 160 | name: 161 | Name 162 | parts [ 163 | false 164 | ] 165 | ] 166 | ] 167 | ] 168 | -------------------------------------------------------------------------------- /examples/08-arrays/Prerano::Examples::Arrays.cfg: -------------------------------------------------------------------------------- 1 | Package: Prerano::Examples::Arrays 2 | Public: 3 | Types: 4 | Functions: 5 | Protected: 6 | Types: 7 | Functions: 8 | Private: 9 | Types: 10 | test => fn()array 11 | array->count => fn()int 12 | array->slice => fn(int,int)array 13 | Functions: 14 | test: 15 | result: unknown $118 16 | blocks: 17 | Block #27() 18 | Expr_ExpressionCall: 19 | rootType: array 20 | obj: array $110 21 | name: name 22 | result: unknown $111 23 | Expr_ExpressionCall: 24 | rootType: array 25 | obj: array $117 26 | name: name 27 | args: [int $112 = 1, int $113 = 2] 28 | args: [int $112 = 1, int $113 = 2] 29 | result: unknown $118 30 | 31 | -------------------------------------------------------------------------------- /examples/08-arrays/Prerano::Examples::Arrays.php: -------------------------------------------------------------------------------- 1 | headers) { 18 | $this->headers = unserialize(base64_decode(self::HEADERS)); 19 | } 20 | return $this->headers; 21 | } 22 | } 23 | final class __PRERANO_CODE__ 24 | { 25 | private static $Prerano܃܃Examples܃܃Arrays܃܃instance; 26 | public static function Prerano܃܃Examples܃܃Arrays܃܃∫() 27 | { 28 | if (!self::$Prerano܃܃Examples܃܃Arrays܃܃instance) { 29 | self::$Prerano܃܃Examples܃܃Arrays܃܃instance = new self(); 30 | } 31 | return self::$Prerano܃܃Examples܃܃Arrays܃܃instance; 32 | } 33 | /** fn()array */ 34 | public function Prerano܃܃Examples܃܃Arrays܃܃test() 35 | { 36 | $_111 = $this->Prerano܃܃Examples܃܃Arrays܃܃count→array≺any≻(array(1, 2, 3)); 37 | $_118 = $this->Prerano܃܃Examples܃܃Arrays܃܃slice→array≺any≻(array(1, 2, 3), 1, 2); 38 | return $_118; 39 | } 40 | /** array->fn()int */ 41 | public function Prerano܃܃Examples܃܃Arrays܃܃count→array≺any≻($_) 42 | { 43 | $_123 = count($_); 44 | return $_123; 45 | } 46 | /** array->fn(int,int)array */ 47 | public function Prerano܃܃Examples܃܃Arrays܃܃slice→array≺any≻($_, $offset, $length) 48 | { 49 | $_132 = array_slice($_, $offset, $length); 50 | return $_132; 51 | } 52 | } 53 | __PRERANO_CODE__::Prerano܃܃Examples܃܃Arrays܃܃∫(); -------------------------------------------------------------------------------- /examples/08-arrays/Prerano::Examples::Arrays.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ircmaxell/prerano/08acefad9ac7fab8db5c87b0a76b437fbaa0f897/examples/08-arrays/Prerano::Examples::Arrays.png -------------------------------------------------------------------------------- /examples/08-arrays/array.pr: -------------------------------------------------------------------------------- 1 | package Prerano::Examples::Arrays; 2 | 3 | fn test() array { 4 | [1, 2, 3]->count(); 5 | [1, 2, 3]->slice(1, 2); 6 | } 7 | 8 | on array fn count() int = php::count($_); 9 | 10 | on array fn slice(int $offset, int $length) array = php::array_slice($_, $offset, $length); 11 | -------------------------------------------------------------------------------- /examples/08-arrays/array.pr.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::Arrays 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | test 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | array 14 | ] 15 | parameters [ 16 | ] 17 | body [ 18 | Expr_MethodCall 19 | obj: 20 | Expr_Array 21 | items [ 22 | Scalar_LNumber 23 | value(1) 24 | Scalar_LNumber 25 | value(2) 26 | Scalar_LNumber 27 | value(3) 28 | ] 29 | name: 30 | Expr_IdentifierReference 31 | name: 32 | Name 33 | parts [ 34 | count 35 | ] 36 | args [ 37 | ] 38 | Expr_MethodCall 39 | obj: 40 | Expr_Array 41 | items [ 42 | Scalar_LNumber 43 | value(1) 44 | Scalar_LNumber 45 | value(2) 46 | Scalar_LNumber 47 | value(3) 48 | ] 49 | name: 50 | Expr_IdentifierReference 51 | name: 52 | Name 53 | parts [ 54 | slice 55 | ] 56 | args [ 57 | Arg 58 | value: 59 | Scalar_LNumber 60 | value(1) 61 | name() 62 | Arg 63 | value: 64 | Scalar_LNumber 65 | value(2) 66 | name() 67 | ] 68 | ] 69 | Stmt_ExprFunction 70 | on: 71 | Expr_Type_Named 72 | name: 73 | Name 74 | parts [ 75 | array 76 | ] 77 | name: 78 | Name 79 | parts [ 80 | count 81 | ] 82 | returnType: 83 | Expr_Type_Named 84 | name: 85 | Name 86 | parts [ 87 | int 88 | ] 89 | parameters [ 90 | ] 91 | body [ 92 | Expr_FuncCall 93 | name: 94 | Expr_IdentifierReference 95 | name: 96 | Name_Qualified 97 | parts [ 98 | php 99 | count 100 | ] 101 | args [ 102 | Arg 103 | value: 104 | Expr_Variable 105 | name: 106 | Name 107 | parts [ 108 | _ 109 | ] 110 | name() 111 | ] 112 | ] 113 | Stmt_ExprFunction 114 | on: 115 | Expr_Type_Named 116 | name: 117 | Name 118 | parts [ 119 | array 120 | ] 121 | name: 122 | Name 123 | parts [ 124 | slice 125 | ] 126 | returnType: 127 | Expr_Type_Named 128 | name: 129 | Name 130 | parts [ 131 | array 132 | ] 133 | parameters [ 134 | Stmt_Parameter 135 | name(offset) 136 | type: 137 | Expr_Type_Named 138 | name: 139 | Name 140 | parts [ 141 | int 142 | ] 143 | default() 144 | Stmt_Parameter 145 | name(length) 146 | type: 147 | Expr_Type_Named 148 | name: 149 | Name 150 | parts [ 151 | int 152 | ] 153 | default() 154 | ] 155 | body [ 156 | Expr_FuncCall 157 | name: 158 | Expr_IdentifierReference 159 | name: 160 | Name_Qualified 161 | parts [ 162 | php 163 | array_slice 164 | ] 165 | args [ 166 | Arg 167 | value: 168 | Expr_Variable 169 | name: 170 | Name 171 | parts [ 172 | _ 173 | ] 174 | name() 175 | Arg 176 | value: 177 | Expr_Variable 178 | name: 179 | Name 180 | parts [ 181 | offset 182 | ] 183 | name() 184 | Arg 185 | value: 186 | Expr_Variable 187 | name: 188 | Name 189 | parts [ 190 | length 191 | ] 192 | name() 193 | ] 194 | ] 195 | -------------------------------------------------------------------------------- /examples/08-arrays/array.pr.processed.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::Arrays 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | test 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | array 14 | ] 15 | parameters [ 16 | ] 17 | body [ 18 | Expr_MethodCall 19 | obj: 20 | Expr_Array 21 | items [ 22 | Scalar_LNumber 23 | value(1) 24 | Scalar_LNumber 25 | value(2) 26 | Scalar_LNumber 27 | value(3) 28 | ] 29 | name: 30 | Expr_IdentifierReference 31 | name: 32 | Name 33 | parts [ 34 | count 35 | ] 36 | args [ 37 | ] 38 | Expr_MethodCall 39 | obj: 40 | Expr_Array 41 | items [ 42 | Scalar_LNumber 43 | value(1) 44 | Scalar_LNumber 45 | value(2) 46 | Scalar_LNumber 47 | value(3) 48 | ] 49 | name: 50 | Expr_IdentifierReference 51 | name: 52 | Name 53 | parts [ 54 | slice 55 | ] 56 | args [ 57 | Arg 58 | value: 59 | Scalar_LNumber 60 | value(1) 61 | name() 62 | Arg 63 | value: 64 | Scalar_LNumber 65 | value(2) 66 | name() 67 | ] 68 | ] 69 | Stmt_ExprFunction 70 | on: 71 | Expr_Type_Named 72 | name: 73 | Name 74 | parts [ 75 | array 76 | ] 77 | name: 78 | Name 79 | parts [ 80 | count 81 | ] 82 | returnType: 83 | Expr_Type_Named 84 | name: 85 | Name 86 | parts [ 87 | int 88 | ] 89 | parameters [ 90 | ] 91 | body [ 92 | Expr_FuncCall 93 | name: 94 | Expr_IdentifierReference 95 | name: 96 | Name_Qualified 97 | parts [ 98 | php 99 | count 100 | ] 101 | args [ 102 | Arg 103 | value: 104 | Expr_Variable 105 | name: 106 | Name 107 | parts [ 108 | _ 109 | ] 110 | name() 111 | ] 112 | ] 113 | Stmt_ExprFunction 114 | on: 115 | Expr_Type_Named 116 | name: 117 | Name 118 | parts [ 119 | array 120 | ] 121 | name: 122 | Name 123 | parts [ 124 | slice 125 | ] 126 | returnType: 127 | Expr_Type_Named 128 | name: 129 | Name 130 | parts [ 131 | array 132 | ] 133 | parameters [ 134 | Stmt_Parameter 135 | name(offset) 136 | type: 137 | Expr_Type_Named 138 | name: 139 | Name 140 | parts [ 141 | int 142 | ] 143 | default() 144 | Stmt_Parameter 145 | name(length) 146 | type: 147 | Expr_Type_Named 148 | name: 149 | Name 150 | parts [ 151 | int 152 | ] 153 | default() 154 | ] 155 | body [ 156 | Expr_FuncCall 157 | name: 158 | Expr_IdentifierReference 159 | name: 160 | Name_Qualified 161 | parts [ 162 | php 163 | array_slice 164 | ] 165 | args [ 166 | Arg 167 | value: 168 | Expr_Variable 169 | name: 170 | Name 171 | parts [ 172 | _ 173 | ] 174 | name() 175 | Arg 176 | value: 177 | Expr_Variable 178 | name: 179 | Name 180 | parts [ 181 | offset 182 | ] 183 | name() 184 | Arg 185 | value: 186 | Expr_Variable 187 | name: 188 | Name 189 | parts [ 190 | length 191 | ] 192 | name() 193 | ] 194 | ] 195 | -------------------------------------------------------------------------------- /examples/09-pipe-operator/Prerano::Examples::PipeOperator.cfg: -------------------------------------------------------------------------------- 1 | Package: Prerano::Examples::PipeOperator 2 | Public: 3 | Types: 4 | Functions: 5 | Protected: 6 | Types: 7 | Functions: 8 | Private: 9 | Types: 10 | add => fn(int,int)int 11 | test => fn()none 12 | Functions: 13 | add: 14 | result: unknown $7 15 | blocks: 16 | Block #2() 17 | Expr_BinaryOp_Plus: 18 | left: int $5 19 | right: int $6 20 | result: unknown $7 21 | 22 | test: 23 | result: unknown $23 24 | blocks: 25 | Block #3() 26 | Expr_FuncCall: 27 | name: add $12 28 | args: [int $10 = 1, int $11 = 2] 29 | args: [int $10 = 1, int $11 = 2] 30 | result: int $13 31 | Expr_FuncCall: 32 | name: add $15 33 | args: [int $13, int $14 = 3] 34 | args: [int $13, int $14 = 3] 35 | result: int $16 36 | Expr_BinaryOp_Plus: 37 | left: int $9 = 1 38 | right: int $16 39 | result: unknown $17 40 | Expr_FuncCall: 41 | name: add $21 42 | args: [int $19 = 1, int $20 = 2] 43 | args: [int $19 = 1, int $20 = 2] 44 | result: int $22 45 | Expr_BinaryOp_Plus: 46 | left: int $18 = 1 47 | right: int $22 48 | result: unknown $23 49 | 50 | -------------------------------------------------------------------------------- /examples/09-pipe-operator/Prerano::Examples::PipeOperator.php: -------------------------------------------------------------------------------- 1 | headers) { 18 | $this->headers = unserialize(base64_decode(self::HEADERS)); 19 | } 20 | return $this->headers; 21 | } 22 | } 23 | final class __PRERANO_CODE__ 24 | { 25 | private static $Prerano܃܃Examples܃܃PipeOperator܃܃instance; 26 | public static function Prerano܃܃Examples܃܃PipeOperator܃܃∫() 27 | { 28 | if (!self::$Prerano܃܃Examples܃܃PipeOperator܃܃instance) { 29 | self::$Prerano܃܃Examples܃܃PipeOperator܃܃instance = new self(); 30 | } 31 | return self::$Prerano܃܃Examples܃܃PipeOperator܃܃instance; 32 | } 33 | /** fn(int,int)int */ 34 | public function Prerano܃܃Examples܃܃PipeOperator܃܃add($a, $b) 35 | { 36 | $_7 = $a + $b; 37 | return $_7; 38 | } 39 | /** fn()none */ 40 | public function Prerano܃܃Examples܃܃PipeOperator܃܃test() 41 | { 42 | $_13 = $this->Prerano܃܃Examples܃܃PipeOperator܃܃add(1, 2); 43 | $_16 = $this->Prerano܃܃Examples܃܃PipeOperator܃܃add($_13, 3); 44 | $_17 = 1 + $_16; 45 | $_22 = $this->Prerano܃܃Examples܃܃PipeOperator܃܃add(1, 2); 46 | $_23 = 1 + $_22; 47 | return $_23; 48 | } 49 | } 50 | __PRERANO_CODE__::Prerano܃܃Examples܃܃PipeOperator܃܃∫(); -------------------------------------------------------------------------------- /examples/09-pipe-operator/Prerano::Examples::PipeOperator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ircmaxell/prerano/08acefad9ac7fab8db5c87b0a76b437fbaa0f897/examples/09-pipe-operator/Prerano::Examples::PipeOperator.png -------------------------------------------------------------------------------- /examples/09-pipe-operator/pipe.pr: -------------------------------------------------------------------------------- 1 | package Prerano::Examples::PipeOperator; 2 | 3 | fn add(int $a, int $b) int = $a + $b; 4 | 5 | 6 | fn test() none { 7 | 1 + 1 |> add(2) |> add(3); 8 | 1 + 1 |> add(2); 9 | } 10 | -------------------------------------------------------------------------------- /examples/09-pipe-operator/pipe.pr.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::PipeOperator 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | add 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | int 14 | ] 15 | parameters [ 16 | Stmt_Parameter 17 | name(a) 18 | type: 19 | Expr_Type_Named 20 | name: 21 | Name 22 | parts [ 23 | int 24 | ] 25 | default() 26 | Stmt_Parameter 27 | name(b) 28 | type: 29 | Expr_Type_Named 30 | name: 31 | Name 32 | parts [ 33 | int 34 | ] 35 | default() 36 | ] 37 | body [ 38 | Expr_BinaryOp_Plus 39 | left: 40 | Expr_Variable 41 | name: 42 | Name 43 | parts [ 44 | a 45 | ] 46 | right: 47 | Expr_Variable 48 | name: 49 | Name 50 | parts [ 51 | b 52 | ] 53 | ] 54 | Stmt_Function 55 | name: 56 | Name 57 | parts [ 58 | test 59 | ] 60 | returnType: 61 | Expr_Type_Named 62 | name: 63 | Name 64 | parts [ 65 | none 66 | ] 67 | parameters [ 68 | ] 69 | body [ 70 | Expr_BinaryOp_Plus 71 | left: 72 | Scalar_LNumber 73 | value(1) 74 | right: 75 | Expr_Pipe 76 | param: 77 | Expr_Pipe 78 | param: 79 | Scalar_LNumber 80 | value(1) 81 | name: 82 | Expr_IdentifierReference 83 | name: 84 | Name 85 | parts [ 86 | add 87 | ] 88 | args [ 89 | Arg 90 | value: 91 | Scalar_LNumber 92 | value(2) 93 | name() 94 | ] 95 | name: 96 | Expr_IdentifierReference 97 | name: 98 | Name 99 | parts [ 100 | add 101 | ] 102 | args [ 103 | Arg 104 | value: 105 | Scalar_LNumber 106 | value(3) 107 | name() 108 | ] 109 | Expr_BinaryOp_Plus 110 | left: 111 | Scalar_LNumber 112 | value(1) 113 | right: 114 | Expr_Pipe 115 | param: 116 | Scalar_LNumber 117 | value(1) 118 | name: 119 | Expr_IdentifierReference 120 | name: 121 | Name 122 | parts [ 123 | add 124 | ] 125 | args [ 126 | Arg 127 | value: 128 | Scalar_LNumber 129 | value(2) 130 | name() 131 | ] 132 | ] 133 | -------------------------------------------------------------------------------- /examples/09-pipe-operator/pipe.pr.processed.ast: -------------------------------------------------------------------------------- 1 | Package Prerano::Examples::PipeOperator 2 | Stmt_Function 3 | name: 4 | Name 5 | parts [ 6 | add 7 | ] 8 | returnType: 9 | Expr_Type_Named 10 | name: 11 | Name 12 | parts [ 13 | int 14 | ] 15 | parameters [ 16 | Stmt_Parameter 17 | name(a) 18 | type: 19 | Expr_Type_Named 20 | name: 21 | Name 22 | parts [ 23 | int 24 | ] 25 | default() 26 | Stmt_Parameter 27 | name(b) 28 | type: 29 | Expr_Type_Named 30 | name: 31 | Name 32 | parts [ 33 | int 34 | ] 35 | default() 36 | ] 37 | body [ 38 | Expr_BinaryOp_Plus 39 | left: 40 | Expr_Variable 41 | name: 42 | Name 43 | parts [ 44 | a 45 | ] 46 | right: 47 | Expr_Variable 48 | name: 49 | Name 50 | parts [ 51 | b 52 | ] 53 | ] 54 | Stmt_Function 55 | name: 56 | Name 57 | parts [ 58 | test 59 | ] 60 | returnType: 61 | Expr_Type_Named 62 | name: 63 | Name 64 | parts [ 65 | none 66 | ] 67 | parameters [ 68 | ] 69 | body [ 70 | Expr_BinaryOp_Plus 71 | left: 72 | Scalar_LNumber 73 | value(1) 74 | right: 75 | Expr_Pipe 76 | param: 77 | Expr_Pipe 78 | param: 79 | Scalar_LNumber 80 | value(1) 81 | name: 82 | Expr_IdentifierReference 83 | name: 84 | Name 85 | parts [ 86 | add 87 | ] 88 | args [ 89 | Arg 90 | value: 91 | Scalar_LNumber 92 | value(2) 93 | name() 94 | ] 95 | name: 96 | Expr_IdentifierReference 97 | name: 98 | Name 99 | parts [ 100 | add 101 | ] 102 | args [ 103 | Arg 104 | value: 105 | Scalar_LNumber 106 | value(3) 107 | name() 108 | ] 109 | Expr_BinaryOp_Plus 110 | left: 111 | Scalar_LNumber 112 | value(1) 113 | right: 114 | Expr_Pipe 115 | param: 116 | Scalar_LNumber 117 | value(1) 118 | name: 119 | Expr_IdentifierReference 120 | name: 121 | Name 122 | parts [ 123 | add 124 | ] 125 | args [ 126 | Arg 127 | value: 128 | Scalar_LNumber 129 | value(2) 130 | name() 131 | ] 132 | ] 133 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | 3 | Each folder contains one or more `*.pr` files which contain Prerano code. 4 | 5 | It also contains several other files which are results of various stages of the compilation process. 6 | 7 | ## out.ast 8 | 9 | This contains the first step of compilation: an abstract syntax tree. Nothing has been modified yet nor any types resolved. 10 | 11 | ## out.cfg 12 | 13 | This contains the primitive CFG (Control Flow Graph). At this point, types are resolved, yet not inferred yet. 14 | 15 | This means that if the result of an expression from declared types is known, then the expression's result will have a type. 16 | 17 | Example: 18 | 19 | int + int -> int 20 | int + string -> error 21 | int + unknown -> unknown 22 | 23 | Additionally, at this point temporary variables are resolved. This means that you'll start to see weird variables like `$1`. These are internal variables that are implied by the structure of the AST. 24 | 25 | ## out.png 26 | 27 | This contains a graphical representation of the CFG (Control Flow Graph). This contains the same information as `out.cfg` but in a graphical form 28 | 29 | ## out.php 30 | 31 | This contains the compiled "PHP" from the original code. 32 | 33 | There are two primary classes in the file: 34 | 35 | * `__PRERANO_METADATA__` - contains methods to access exported types and function bodies (serailized). This is used internally by the compiler to link compiled packages together. 36 | * `__PRERANO_CODE__` - contains compiled functions. Also, `__main__` if it exists is compiled into the constructor of this class (implementation detail). 37 | 38 | Further, any "public" code (value types, functions, etc) are exported into this file as well. It's worth noting that these "public" exports are merely proxies into the internal compiled result. This is to support type assertions and boxing required for interacting safely with compiled code. -------------------------------------------------------------------------------- /examples/rebuild.php: -------------------------------------------------------------------------------- 1 | isDir() || $file->isDot()) { 10 | continue; 11 | } 12 | $dir = $file->getPathname(); 13 | 14 | echo "Building " . $dir . "\n"; 15 | 16 | (new Prerano\Compiler(true))->compile($dir); 17 | } 18 | 19 | -------------------------------------------------------------------------------- /grammar/.gitignore: -------------------------------------------------------------------------------- 1 | *.output -------------------------------------------------------------------------------- /grammar/parser.template.php: -------------------------------------------------------------------------------- 1 | semValue 4 | #semval($,%t) $this->semValue 5 | #semval(%n) $this->stackPos-(%l-%n) 6 | #semval(%n,%t) $this->stackPos-(%l-%n) 7 | 8 | namespace Prerano\Parser; 9 | 10 | use Prerano\Parser\{ 11 | ParserAbstract, 12 | Error 13 | }; 14 | use Prerano\Language; 15 | use Prerano\AST\Node; 16 | use Prerano\AST\Node\{ 17 | Expr, 18 | Name, 19 | Scalar, 20 | Stmt 21 | }; 22 | #include; 23 | 24 | /* This is an automatically GENERATED file, which should not be manually edited. 25 | * Instead edit one of the following: 26 | * * the grammar files grammar/language.y 27 | * * the skeleton file grammar/parser.template.php 28 | * * the preprocessing script grammar/rebuildParsers.php 29 | */ 30 | class Parser extends ParserAbstract 31 | { 32 | protected $tokenToSymbolMapSize = #(YYMAXLEX); 33 | protected $actionTableSize = #(YYLAST); 34 | protected $gotoTableSize = #(YYGLAST); 35 | 36 | protected $invalidSymbol = #(YYBADCH); 37 | protected $errorSymbol = #(YYINTERRTOK); 38 | protected $defaultAction = #(YYDEFAULT); 39 | protected $unexpectedTokenRule = #(YYUNEXPECTED); 40 | 41 | protected $YY2TBLSTATE = #(YY2TBLSTATE); 42 | protected $YYNLSTATES = #(YYNLSTATES); 43 | 44 | protected $symbolToName = array( 45 | #listvar terminals 46 | ); 47 | 48 | protected $tokenToSymbol = array( 49 | #listvar yytranslate 50 | ); 51 | 52 | protected $action = array( 53 | #listvar yyaction 54 | ); 55 | 56 | protected $actionCheck = array( 57 | #listvar yycheck 58 | ); 59 | 60 | protected $actionBase = array( 61 | #listvar yybase 62 | ); 63 | 64 | protected $actionDefault = array( 65 | #listvar yydefault 66 | ); 67 | 68 | protected $goto = array( 69 | #listvar yygoto 70 | ); 71 | 72 | protected $gotoCheck = array( 73 | #listvar yygcheck 74 | ); 75 | 76 | protected $gotoBase = array( 77 | #listvar yygbase 78 | ); 79 | 80 | protected $gotoDefault = array( 81 | #listvar yygdefault 82 | ); 83 | 84 | protected $ruleToNonTerminal = array( 85 | #listvar yylhs 86 | ); 87 | 88 | protected $ruleToLength = array( 89 | #listvar yylen 90 | ); 91 | #if -t 92 | 93 | protected $productions = array( 94 | #production-strings; 95 | ); 96 | #endif 97 | #reduce 98 | 99 | protected function reduceRule%n() 100 | { 101 | %b 102 | } 103 | #noact 104 | 105 | protected function reduceRule%n() 106 | { 107 | $this->semValue = $this->semStack[$this->stackPos]; 108 | } 109 | #endreduce 110 | } 111 | #tailcode; -------------------------------------------------------------------------------- /grammar/tokens.template.php: -------------------------------------------------------------------------------- 1 | semValue 5 | #semval($,%t) $this->semValue 6 | #semval(%n) $this->stackPos-(%l-%n) 7 | #semval(%n,%t) $this->stackPos-(%l-%n) 8 | 9 | namespace Prerano\Parser; 10 | #include; 11 | 12 | /** GENERATED FILE based on grammar/language.y **/ 13 | final class Tokens 14 | { 15 | #tokenval 16 | const %s = %n; 17 | #endtokenval 18 | } 19 | -------------------------------------------------------------------------------- /lib/AST/Node.php: -------------------------------------------------------------------------------- 1 | value = $value; 23 | $this->name = $name; 24 | } 25 | 26 | /** 27 | * Gets the names of the sub nodes. 28 | * 29 | * @return array Names of sub nodes 30 | */ 31 | public function getSubNodeNames() 32 | { 33 | return ['value', 'name']; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr.php: -------------------------------------------------------------------------------- 1 | addItems(...$items); 23 | } 24 | 25 | public function getSubNodeNames() 26 | { 27 | return array('items'); 28 | } 29 | 30 | protected function addItems(Expr ...$items) 31 | { 32 | $this->items = $items; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/Assign.php: -------------------------------------------------------------------------------- 1 | var = $var; 22 | $this->value = $value; 23 | } 24 | 25 | public function getSubNodeNames() 26 | { 27 | return array('var', 'value'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/BinaryOp.php: -------------------------------------------------------------------------------- 1 | left = $left; 22 | $this->right = $right; 23 | } 24 | 25 | public function getSubNodeNames() 26 | { 27 | return array('left', 'right'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/BinaryOp/BooleanOr.php: -------------------------------------------------------------------------------- 1 | name = $name; 24 | $this->setArguments(...$args); 25 | } 26 | 27 | public function getSubNodeNames() 28 | { 29 | return array('name', 'args'); 30 | } 31 | 32 | private function setArguments(Node\Arg ...$args) 33 | { 34 | $this->args = $args; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/IdentifierReference.php: -------------------------------------------------------------------------------- 1 | name = $name; 23 | } 24 | 25 | public function getSubNodeNames() 26 | { 27 | return array('name'); 28 | } 29 | 30 | public function toString(): string 31 | { 32 | return $this->name->toString(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/Is.php: -------------------------------------------------------------------------------- 1 | cond = $cond; 24 | $this->type = $type; 25 | } 26 | 27 | public function getSubNodeNames() 28 | { 29 | return array('cond', 'type'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/Match.php: -------------------------------------------------------------------------------- 1 | cond = $cond; 23 | $this->entries = $this->addEntries(...$entries); 24 | } 25 | 26 | public function getSubNodeNames() 27 | { 28 | return array('cond', 'entries'); 29 | } 30 | 31 | protected function addEntries(MatchEntry ...$match): array 32 | { 33 | return $match; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/MatchEntry.php: -------------------------------------------------------------------------------- 1 | cond = $cond; 24 | $this->stmts = $this->addNodes(...$stmts); 25 | } 26 | 27 | public function getSubNodeNames() 28 | { 29 | return array('cond', 'stmts'); 30 | } 31 | 32 | protected function addNodes(Node\Expr ...$items): array 33 | { 34 | return $items; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/MethodCall.php: -------------------------------------------------------------------------------- 1 | obj = $obj; 24 | $this->name = $name; 25 | $this->setArguments(...$args); 26 | } 27 | 28 | public function getSubNodeNames() 29 | { 30 | return array('obj', 'name', 'args'); 31 | } 32 | 33 | private function setArguments(Node\Arg ...$args) 34 | { 35 | $this->args = $args; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/Pipe.php: -------------------------------------------------------------------------------- 1 | param = $param; 25 | $this->name = $name; 26 | $this->addArgs(...$args); 27 | } 28 | 29 | public function addArgs(Node\Arg ...$args) 30 | { 31 | $this->args = $args; 32 | } 33 | 34 | public function getSubNodeNames() 35 | { 36 | return array('param', 'name', 'args'); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/PointerDereference.php: -------------------------------------------------------------------------------- 1 | expr = $expr; 23 | } 24 | 25 | public function getSubNodeNames() 26 | { 27 | return array('expr'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/Type.php: -------------------------------------------------------------------------------- 1 | addParameters(...$parameters); 23 | $this->result = $result; 24 | } 25 | 26 | public function getSubNodeNames() 27 | { 28 | return array('parameters', 'result'); 29 | } 30 | 31 | protected function addParameters(Type ...$parameters) 32 | { 33 | $this->parameters = $parameters; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/Type/Intersection.php: -------------------------------------------------------------------------------- 1 | left = $left; 23 | $this->right = $right; 24 | } 25 | 26 | public function getSubNodeNames() 27 | { 28 | return array('left', 'right'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/Type/Named.php: -------------------------------------------------------------------------------- 1 | name = $name; 23 | } 24 | 25 | public function getSubNodeNames() 26 | { 27 | return array('name'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/Type/Pointer.php: -------------------------------------------------------------------------------- 1 | type = $type; 22 | } 23 | 24 | public function getSubNodeNames() 25 | { 26 | return array('type'); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/Type/Specification.php: -------------------------------------------------------------------------------- 1 | root = $root; 24 | $this->addSubTypes(...$subTypes); 25 | } 26 | 27 | public function getSubNodeNames() 28 | { 29 | return array('root', 'subTypes'); 30 | } 31 | 32 | private function addSubTypes(Type ...$subTypes) 33 | { 34 | $this->subTypes = $subTypes; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/Type/Union.php: -------------------------------------------------------------------------------- 1 | left = $left; 23 | $this->right = $right; 24 | } 25 | 26 | public function getSubNodeNames() 27 | { 28 | return array('left', 'right'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/Type/Value.php: -------------------------------------------------------------------------------- 1 | value = $value; 23 | } 24 | 25 | public function getSubNodeNames() 26 | { 27 | return array('value'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/AST/Node/Expr/Variable.php: -------------------------------------------------------------------------------- 1 | name = $name; 23 | } 24 | 25 | public function getSubNodeNames() 26 | { 27 | return array('name'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/AST/Node/Name/Qualified.php: -------------------------------------------------------------------------------- 1 | parts, $name->parts), $attributes); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /lib/AST/Node/Scalar.php: -------------------------------------------------------------------------------- 1 | value = $value; 28 | } 29 | 30 | public function getSubNodeNames() 31 | { 32 | return array('value'); 33 | } 34 | 35 | /** 36 | * Constructs an LNumber node from a string number literal. 37 | * 38 | * @param string $str String number literal (decimal, octal, hex or binary) 39 | * @param array $attributes Additional attributes 40 | * @param bool $allowInvalidOctal Whether to allow invalid octal numbers (PHP 5) 41 | * 42 | * @return LNumber The constructed LNumber, including kind attribute 43 | */ 44 | public static function fromString($str, array $attributes = array(), $allowInvalidOctal = false) 45 | { 46 | if ('0' !== $str[0] || '0' === $str) { 47 | $attributes['kind'] = LNumber::KIND_DEC; 48 | return new LNumber((int) $str, $attributes); 49 | } 50 | 51 | if ('x' === $str[1]) { 52 | $attributes['kind'] = LNumber::KIND_HEX; 53 | return new LNumber(hexdec($str), $attributes); 54 | } 55 | 56 | if ('b' === $str[1]) { 57 | $attributes['kind'] = LNumber::KIND_BIN; 58 | return new LNumber(bindec($str), $attributes); 59 | } 60 | 61 | if ('o' === $str[1]) { 62 | $attributes['kind'] = LNumber::KIND_OCT; 63 | return new LNumber(bindec($str), $attributes); 64 | } 65 | 66 | throw new Error('Invalid numeric literal', $attributes); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /lib/AST/Node/Stmt.php: -------------------------------------------------------------------------------- 1 | name = $name; 26 | $this->as = $as; 27 | } 28 | 29 | public function getSubNodeNames() 30 | { 31 | return array('name', 'as'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/AST/Node/Stmt/Class_.php: -------------------------------------------------------------------------------- 1 | name = $name; 26 | $this->visibility = $visibility; 27 | $this->setBody(...$body); 28 | $this->setParents(...$parents); 29 | } 30 | 31 | public function getSubNodeNames() 32 | { 33 | return array('name', 'parents', 'body'); 34 | } 35 | 36 | private function setParents(Node\Name ...$parents) 37 | { 38 | $this->parents = $parents; 39 | } 40 | 41 | private function setBody(Node ...$body) 42 | { 43 | $this->body = $body; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /lib/AST/Node/Stmt/Enum.php: -------------------------------------------------------------------------------- 1 | name = $name; 27 | $this->addSubTypes(...$subTypes); 28 | $this->visibility = $visibility; 29 | } 30 | 31 | public function getSubNodeNames() 32 | { 33 | return array('name', 'subTypes'); 34 | } 35 | 36 | private function addSubTypes(Node\Stmt\Type ...$subTypes) 37 | { 38 | $this->subTypes = $subTypes; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/AST/Node/Stmt/ExprFunction.php: -------------------------------------------------------------------------------- 1 | on = $on; 24 | } 25 | 26 | public function getSubNodeNames() 27 | { 28 | return array('on', 'name', 'returnType', 'parameters', 'body'); 29 | } 30 | 31 | private function setParameters(Parameter ...$parameters) 32 | { 33 | $this->parameters = $parameters; 34 | } 35 | 36 | private function setBody(Node ...$body) 37 | { 38 | $this->body = $body; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /lib/AST/Node/Stmt/Function_.php: -------------------------------------------------------------------------------- 1 | name = $name; 29 | $this->returnType = $returnType; 30 | $this->visibility = $visibility; 31 | $this->setParameters(...$parameters); 32 | $this->setBody(...$body); 33 | } 34 | 35 | public function getSubNodeNames() 36 | { 37 | return array('name', 'returnType', 'parameters', 'body'); 38 | } 39 | 40 | private function setParameters(Parameter ...$parameters) 41 | { 42 | $this->parameters = $parameters; 43 | } 44 | 45 | private function setBody(Node ...$body) 46 | { 47 | $this->body = $body; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/AST/Node/Stmt/Import.php: -------------------------------------------------------------------------------- 1 | name = $name; 23 | } 24 | 25 | public function getSubNodeNames() 26 | { 27 | return array('name'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/AST/Node/Stmt/Match/Entry.php: -------------------------------------------------------------------------------- 1 | cond = $this->addSubNodes(...$cond); 27 | $this->stmts = $this->addSubNodes(...$stmts); 28 | } 29 | 30 | public function getSubNodeNames() 31 | { 32 | return array('cond', 'stmts'); 33 | } 34 | 35 | private function addSubNodes(Node\Expr ...$subNodes): array 36 | { 37 | return $subNodes; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/AST/Node/Stmt/Package.php: -------------------------------------------------------------------------------- 1 | name = $name; 25 | $this->stmts = $stmts; 26 | } 27 | 28 | public function getSubNodeNames() 29 | { 30 | return array('name', 'stmts'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /lib/AST/Node/Stmt/Parameter.php: -------------------------------------------------------------------------------- 1 | name = $name; 27 | $this->type = $type; 28 | $this->default = $default; 29 | } 30 | 31 | public function getSubNodeNames() 32 | { 33 | return array('name', 'type', 'default'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/AST/Node/Stmt/Type.php: -------------------------------------------------------------------------------- 1 | name = $name; 27 | $this->type = $type; 28 | $this->visibility = $visibility; 29 | } 30 | 31 | public function getSubNodeNames() 32 | { 33 | return array('name', 'type'); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /lib/AST/NodeAbstract.php: -------------------------------------------------------------------------------- 1 | attributes = $attributes; 17 | } 18 | 19 | /** 20 | * Gets the type of the node. 21 | * 22 | * @return string Type of the node 23 | */ 24 | public function getName(): string 25 | { 26 | return strtr(substr(rtrim(get_class($this), '_'), strlen(__NAMESPACE__) + 6), '\\', '_'); 27 | } 28 | 29 | /** 30 | * Gets line the node started in. 31 | * 32 | * @return int Line 33 | */ 34 | public function getLine() 35 | { 36 | return $this->getAttribute('startLine', -1); 37 | } 38 | 39 | /** 40 | * Sets line the node started in. 41 | * 42 | * @param int $line Line 43 | * 44 | * @deprecated 45 | */ 46 | public function setLine($line) 47 | { 48 | $this->setAttribute('startLine', (int) $line); 49 | } 50 | 51 | /** 52 | * Gets the doc comment of the node. 53 | * 54 | * The doc comment has to be the last comment associated with the node. 55 | * 56 | * @return null|Comment\Doc Doc comment object or null 57 | */ 58 | public function getDocComment() 59 | { 60 | $comments = $this->getAttribute('comments'); 61 | if (!$comments) { 62 | return null; 63 | } 64 | 65 | $lastComment = $comments[count($comments) - 1]; 66 | if (!$lastComment instanceof Comment\Doc) { 67 | return null; 68 | } 69 | 70 | return $lastComment; 71 | } 72 | 73 | /** 74 | * Sets the doc comment of the node. 75 | * 76 | * This will either replace an existing doc comment or add it to the comments array. 77 | * 78 | * @param Comment\Doc $docComment Doc comment to set 79 | */ 80 | public function setDocComment(Comment\Doc $docComment) 81 | { 82 | $comments = $this->getAttribute('comments', []); 83 | 84 | $numComments = count($comments); 85 | if ($numComments > 0 && $comments[$numComments - 1] instanceof Comment\Doc) { 86 | // Replace existing doc comment 87 | $comments[$numComments - 1] = $docComment; 88 | } else { 89 | // Append new comment 90 | $comments[] = $docComment; 91 | } 92 | 93 | $this->setAttribute('comments', $comments); 94 | } 95 | 96 | public function setAttribute($key, $value) 97 | { 98 | $this->attributes[$key] = $value; 99 | } 100 | 101 | public function hasAttribute($key) 102 | { 103 | return array_key_exists($key, $this->attributes); 104 | } 105 | 106 | public function &getAttribute($key, $default = null) 107 | { 108 | if (!array_key_exists($key, $this->attributes)) { 109 | return $default; 110 | } else { 111 | return $this->attributes[$key]; 112 | } 113 | } 114 | 115 | public function getAttributes() 116 | { 117 | return $this->attributes; 118 | } 119 | 120 | public function jsonSerialize() 121 | { 122 | return ['nodeType' => $this->getType()] + get_object_vars($this); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /lib/AST/Traverser.php: -------------------------------------------------------------------------------- 1 | visitors = array_merge($this->visitors, $visitors); 12 | } 13 | 14 | public function traverse(Node\Stmt\Package $package) 15 | { 16 | foreach ($this->visitors as $visitor) { 17 | $visitor->beforeTraverse($package); 18 | } 19 | $package->stmts = $this->traverseNode(...$package->stmts); 20 | foreach ($this->visitors as $visitor) { 21 | $visitor->afterTraverse($package); 22 | } 23 | } 24 | 25 | protected function traverseNode(Node ...$nodes) 26 | { 27 | $toChange = []; 28 | foreach ($nodes as $key => $node) { 29 | $mode = Visitor::NORMAL; 30 | foreach ($this->visitors as $visitor) { 31 | $mode |= $visitor->enterNode($node); 32 | } 33 | if ($mode & Visitor::SKIP_CHILDREN) { 34 | continue; 35 | } 36 | foreach ($node->getSubNodeNames() as $name) { 37 | $subNode = $node->$name; 38 | if ($subNode instanceof Node) { 39 | $result = $this->traverseNode($subNode); 40 | if ($result) { 41 | $node->$name = $result[0]; 42 | } else { 43 | $node->$name = null; 44 | } 45 | } elseif (self::isNodeArray($subNode)) { 46 | $node->$name = $this->traverseNode(...$subNode); 47 | } 48 | } 49 | foreach ($this->visitors as $visitor) { 50 | $status = $visitor->leaveNode($node); 51 | if ($status instanceof Node) { 52 | $toChange[] = [$key, [$status]]; 53 | } elseif (is_array($status)) { 54 | $toChange[] = [$key, $status]; 55 | } elseif ($status === Visitor::REMOVE_NODE) { 56 | $toChange[] = [$key, []]; 57 | } 58 | } 59 | } 60 | foreach (array_reverse($toChange) as list($key, $new)) { 61 | array_splice($nodes, $key, 1, $new); 62 | } 63 | return $nodes; 64 | } 65 | 66 | protected static function isNodeArray($array): bool 67 | { 68 | if (!is_array($array)) { 69 | return false; 70 | } 71 | foreach ($array as $value) { 72 | if (!$value instanceof Node) { 73 | return false; 74 | } 75 | } 76 | return true; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /lib/AST/Visitor.php: -------------------------------------------------------------------------------- 1 | stmts as $stmt) { 15 | // All imports are root level, find all of them 16 | if ($stmt instanceof Node\Stmt\Alias) { 17 | $asString = $stmt->as->toString(); 18 | if (isset($this->imports[$asString])) { 19 | throw new \RuntimeException("Duplicate import for $asString found"); 20 | } 21 | $this->imports[$asString] = [$stmt->as, $stmt->name]; 22 | } 23 | } 24 | } 25 | 26 | public function leaveNode(Node $node) 27 | { 28 | if (empty($this->imports)) { 29 | return; 30 | } 31 | if ($node instanceof Node\Name) { 32 | foreach ($this->imports as $string => list($as, $name)) { 33 | if ($node->isPrefixedBy($string)) { 34 | // Replace prefix with nothing 35 | $suffix = $node->getSuffix($string); 36 | $return = new Node\Name\Qualified($name, new Node\Name($suffix)); 37 | return $return; 38 | } 39 | } 40 | } elseif ($node instanceof Node\Stmt\Alias) { 41 | return self::REMOVE_NODE; 42 | } 43 | } 44 | 45 | public function afterTraverse(Node\Stmt\Package $package) 46 | { 47 | $this->imports = []; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/AST/Visitor/TypeQualifier.php: -------------------------------------------------------------------------------- 1 | prefix = $package->name; 16 | } 17 | 18 | public function leaveNode(Node $node) 19 | { 20 | if (!$node instanceof Node\Expr\Type\Named) { 21 | return; 22 | } 23 | if ($node->name->isQualified()) { 24 | return; 25 | } 26 | $type = new Type(Type::TYPE_REFERENCE, $node->name->toString()); 27 | if ($type->type === Type::TYPE_REFERENCE) { 28 | $node->name = new Node\Name\Qualified($this->prefix, $node->name); 29 | } 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /lib/AST/VisitorAbstract.php: -------------------------------------------------------------------------------- 1 | var = $var; 24 | $this->expr = $expr; 25 | } 26 | 27 | public function getSubNodeNames(): array 28 | { 29 | return array('var', 'expr'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/CFG/Node/Expr/BinaryOp.php: -------------------------------------------------------------------------------- 1 | left = $left; 25 | $this->right = $right; 26 | $this->result = $result; 27 | } 28 | 29 | public function getSubNodeNames(): array 30 | { 31 | return array('left', 'right', 'result'); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/CFG/Node/Expr/BinaryOp/Div.php: -------------------------------------------------------------------------------- 1 | rootType = $rootType; 29 | $this->obj = $obj; 30 | $this->name = $name; 31 | $this->result = $result; 32 | $this->setArgs(...$args); 33 | } 34 | 35 | public function getSubNodeNames(): array 36 | { 37 | return array('rootType', 'obj', 'name', 'args', 'result'); 38 | } 39 | 40 | private function setArgs(Variable ...$args) 41 | { 42 | $this->args = $args; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/CFG/Node/Expr/FuncCall.php: -------------------------------------------------------------------------------- 1 | name = $name; 26 | $this->result = $result; 27 | $this->setArgs(...$args); 28 | } 29 | 30 | public function getSubNodeNames(): array 31 | { 32 | return array('name', 'args', 'result'); 33 | } 34 | 35 | private function setArgs(Variable ...$args) 36 | { 37 | $this->args = $args; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /lib/CFG/Node/Expr/If_.php: -------------------------------------------------------------------------------- 1 | cond = $cond; 24 | $this->result = $result; 25 | } 26 | 27 | public function getSubNodeNames(): array 28 | { 29 | return array('cond', 'result'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/CFG/Node/Expr/Is.php: -------------------------------------------------------------------------------- 1 | cond = $cond; 26 | $this->type = $type; 27 | $this->result = $result; 28 | } 29 | 30 | public function getSubNodeNames(): array 31 | { 32 | return array('cond', 'type', 'result'); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /lib/CFG/Node/Expr/MethodCall.php: -------------------------------------------------------------------------------- 1 | obj = $obj; 27 | $this->name = $name; 28 | $this->result = $result; 29 | $this->setArgs(...$args); 30 | } 31 | 32 | public function getSubNodeNames(): array 33 | { 34 | return array('obj', 'name', 'args', 'result'); 35 | } 36 | 37 | private function setArgs(Variable ...$args) 38 | { 39 | $this->args = $args; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /lib/CFG/Node/Expr/PointerDereference.php: -------------------------------------------------------------------------------- 1 | expr = $expr; 24 | $this->result = $result; 25 | } 26 | 27 | public function getSubNodeNames(): array 28 | { 29 | return array('expr', 'result'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/CFG/NodeAbstract.php: -------------------------------------------------------------------------------- 1 | attributes = $attributes; 17 | } 18 | 19 | /** 20 | * Gets the type of the node. 21 | * 22 | * @return string Type of the node 23 | */ 24 | public function getName(): string 25 | { 26 | return strtr(substr(rtrim(get_class($this), '_'), strlen(__NAMESPACE__) + 6), '\\', '_'); 27 | } 28 | 29 | /** 30 | * Gets line the node started in. 31 | * 32 | * @return int Line 33 | */ 34 | public function getLine(): int 35 | { 36 | return $this->getAttribute('startLine', -1); 37 | } 38 | 39 | public function setAttribute($key, $value) 40 | { 41 | $this->attributes[$key] = $value; 42 | } 43 | 44 | public function hasAttribute($key) 45 | { 46 | return array_key_exists($key, $this->attributes); 47 | } 48 | 49 | public function &getAttribute($key, $default = null) 50 | { 51 | if (!array_key_exists($key, $this->attributes)) { 52 | return $default; 53 | } else { 54 | return $this->attributes[$key]; 55 | } 56 | } 57 | 58 | public function getAttributes() 59 | { 60 | return $this->attributes; 61 | } 62 | 63 | public function jsonSerialize() 64 | { 65 | return ['nodeType' => $this->getType()] + get_object_vars($this); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /lib/CFG/Package.php: -------------------------------------------------------------------------------- 1 | debug = $debug; 17 | $this->parser = new Parser\Parser(new Parser\Lexer); 18 | $this->traverser = new AST\Traverser; 19 | $this->traverser->addVisitor(new AST\Visitor\AliasResolver); 20 | $this->traverser->addVisitor(new AST\Visitor\TypeQualifier); 21 | $this->generator = new CFG\Generator; 22 | $this->compiler = new Compiler\PHP; 23 | $this->scope = new Scope; 24 | $this->engine = new Inference\Engine($this->scope); 25 | $this->addPHPPackage(); 26 | } 27 | 28 | public function compile(string $file) 29 | { 30 | if (is_file($file) && substr($file, -3) === '.pr') { 31 | $package = $this->compileFile($file); 32 | $target = str_replace('.pr', '.php', $file); 33 | } elseif (is_dir($file)) { 34 | // compile all files 35 | $packages = []; 36 | foreach (new \DirectoryIterator($file) as $sub) { 37 | if (!$sub->isFile() || $sub->getExtension() !== 'pr') { 38 | continue; 39 | } 40 | $filename = $sub->getPathname(); 41 | $package = $this->compileFile($filename); 42 | $this->debugAST($filename, $package); 43 | $this->traverser->traverse($package); 44 | $this->debugAST($filename . '.processed', $package); 45 | $packages[] = $package; 46 | } 47 | $target = $file . '/'; 48 | } else { 49 | throw new \LogicException("Unknown compilation target $file"); 50 | } 51 | 52 | $toCompile = []; 53 | foreach ($packages as $package) { 54 | $cfg = $this->generator->generatePackage($package); 55 | $toCompile[] = $cfg->name; 56 | $this->scope->addPackage($cfg); 57 | } 58 | $toCompile = array_unique($toCompile); 59 | 60 | foreach ($toCompile as $name) { 61 | $package = $this->scope->getPackage($name); 62 | $this->engine->process($package); 63 | $this->debugCFG($target . $name, $package); 64 | $php = $this->compiler->compile($package); 65 | file_put_contents($target . $name . '.php', $php); 66 | } 67 | } 68 | 69 | protected function addPHPPackage() 70 | { 71 | $dir = __DIR__ . '/php'; 72 | $packages = []; 73 | foreach (new \DirectoryIterator($dir) as $sub) { 74 | if (!$sub->isFile() || $sub->getExtension() !== 'pr') { 75 | continue; 76 | } 77 | $filename = $sub->getPathname(); 78 | $packages[] = $tmp = $this->compileFile($filename); 79 | } 80 | foreach ($packages as $package) { 81 | $cfg = $this->generator->generatePackage($package); 82 | $this->scope->addPackage($cfg); 83 | } 84 | } 85 | 86 | protected function compileFile(string $file): Ast\Node\Stmt\Package 87 | { 88 | return $this->parser->parse(file_get_contents($file), $file); 89 | } 90 | 91 | protected function debugAST(string $target, Ast\Node\Stmt\Package $package) 92 | { 93 | if (!$this->debug) { 94 | return; 95 | } 96 | file_put_contents("$target.ast", Debug\ASTDumper::dump($package)); 97 | } 98 | 99 | protected function debugCFG(string $target, Language\Package $cfg) 100 | { 101 | if (!$this->debug) { 102 | return; 103 | } 104 | file_put_contents("$target.cfg", Debug\CFGDumper::dumpPackage($cfg)); 105 | Debug\CFGGrapher::graphPackage($cfg, "$target.png", 'png'); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /lib/Compiler/Compiler.php: -------------------------------------------------------------------------------- 1 | printer = $printer ?: new Standard; 20 | $this->resolver = new Utility\PhiResolver; 21 | } 22 | 23 | public function compile(Package $package): string 24 | { 25 | $this->resolver->resolve($package); 26 | $result = a( 27 | ...$this->compileMetadata($package), 28 | ...[] 29 | ); 30 | 31 | return 'printer->prettyPrint($result); 32 | } 33 | 34 | protected function compileMetadata(Package $package): array 35 | { 36 | return a( 37 | new PhpNode\Stmt\Namespace_(new PhpNode\Name(str_replace('::', '\\', $package->name))), 38 | ...PHP\Metadata::compile($package), 39 | ...PHP\Code::compile($package), 40 | ...PHP\PublicFunctions::compile($package), 41 | ...PHP\PublicValueConstants::compile($package), 42 | ...[] 43 | ); 44 | } 45 | } 46 | 47 | function a(...$any): array 48 | { 49 | return $any; 50 | } 51 | -------------------------------------------------------------------------------- /lib/Compiler/PHP/Metadata.php: -------------------------------------------------------------------------------- 1 | PHP::modifier('final'), 23 | 'stmts' => a( 24 | ...self::properties($package), 25 | ...[self::init($package)], 26 | ...[self::getHeadersFunction($package)] 27 | ), 28 | ] 29 | ) 30 | ); 31 | } 32 | 33 | protected static function init(Package $package): PhpNode 34 | { 35 | return new PhpNode\Stmt\ClassMethod( 36 | 'init', 37 | [ 38 | 'flags' => PHP::modifier('public static'), 39 | 'stmts' => [ 40 | PHP::if( 41 | PHP::not(PHP::staticPropFetch('self', 'instance')), 42 | [PHP::assign( 43 | PHP::staticPropFetch('self', 'instance'), 44 | PHP::new('self') 45 | )] 46 | ), 47 | PHP::return(PHP::staticPropFetch('self', 'instance')), 48 | ], 49 | ] 50 | ); 51 | } 52 | 53 | protected static function getHeadersFunction(Package $package): PhpNode 54 | { 55 | return new PhpNode\Stmt\ClassMethod( 56 | 'headers', 57 | [ 58 | 'flags' => PHP::modifier('public'), 59 | 'stmts' => a( 60 | PHP::if( 61 | PHP::identical(PHP::null(), PHP::propFetch(PHP::var('this'), 'headers')), 62 | a( 63 | PHP::assign( 64 | PHP::propFetch(PHP::var('this'), 'headers'), 65 | PHP::funcCall('unserialize', PHP::funcCall('base64_decode', PHP::classConstFetch('self', 'HEADERS'))) 66 | ) 67 | ) 68 | ), 69 | PHP::return(PHP::propFetch(PHP::var('this'), 'headers')) 70 | ), 71 | ] 72 | ); 73 | } 74 | 75 | protected static function properties(Package $package): array 76 | { 77 | return a( 78 | PHP::classConst('HEADERS', self::functionHeaders($package)), 79 | new PhpNode\Stmt\Property( 80 | PHP::modifier('private static'), 81 | [ 82 | new PhpNode\Stmt\PropertyProperty('instance'), 83 | ] 84 | ), 85 | new PhpNode\Stmt\Property( 86 | PHP::modifier('private'), 87 | [ 88 | new PhpNode\Stmt\PropertyProperty('headers', PHP::null()), 89 | ] 90 | ) 91 | ); 92 | } 93 | protected static function functionHeaders(Package $package): PhpNode 94 | { 95 | $result = []; 96 | foreach (Package::VISIBILITY_MAP as $visibility => $visibilityName) { 97 | $result[$visibilityName] = []; 98 | foreach ($package->functions[$visibility] as $name => $fn) { 99 | $result[$visibilityName][$name] = $fn->getSignature(); 100 | } 101 | } 102 | return PHP::string(base64_encode(serialize($result))); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lib/Compiler/PHP/PublicFunctions.php: -------------------------------------------------------------------------------- 1 | functions[Package::PUBLIC] as $name => $func) { 19 | $params = self::params($func); 20 | $stmts = a( 21 | ...self::guards($name, $func), 22 | ...[PHP::assign(PHP::var('__result__'), PHP::instanceCall(Scope::resolvePackage($package), Scope::resolveLocal($package, $name), ...self::args($func)))], 23 | ...self::postConditions($func) 24 | ); 25 | 26 | $result[] = new PhpNode\Stmt\Function_( 27 | PHP::name($name), 28 | [ 29 | 'stmts' => $stmts, 30 | 'params' => $params, 31 | 'returnType' => PHP::nativeType($func->returnType), 32 | ] 33 | ); 34 | } 35 | return $result; 36 | } 37 | 38 | protected static function guards(string $name, Function_ $function): array 39 | { 40 | // Not Implemented Yet 41 | $results = []; 42 | foreach ($function->parameters as $key => $parameter) { 43 | $key++; 44 | $results[] = PHP::if( 45 | PHP::not(TypeCheck::compileExternalCheck(PHP::var($parameter->name), $parameter->getInferredType())), 46 | [ 47 | PHP::throw("\TypeException", "Function {$name}() expects parameter {$key} to be " . $parameter->getDeclaredType()->toString()) 48 | ] 49 | ); 50 | } 51 | return $results; 52 | ; 53 | } 54 | 55 | protected static function postConditions(Function_ $function): array 56 | { 57 | // Not Implemented Yet 58 | return [ 59 | // Implement a bunch of checks/value maps 60 | 61 | 62 | PHP::return(PHP::var('__result__')), 63 | ]; 64 | } 65 | 66 | protected static function args(Function_ $function): array 67 | { 68 | // Not Implemented Yet 69 | $result = []; 70 | foreach ($function->parameters as $param) { 71 | $result[] = PHP::var($param->name); 72 | } 73 | return $result; 74 | } 75 | 76 | protected static function params(Function_ $function): array 77 | { 78 | $params = []; 79 | foreach ($function->parameters as $parameter) { 80 | if ($parameter->getDeclaredType()->type === Type::POINTER) { 81 | // handle reference 82 | 83 | $params[] = PHP::paramRef($parameter->name); 84 | } else { 85 | $params[] = PHP::param($parameter->name); 86 | } 87 | } 88 | return $params; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /lib/Compiler/PHP/PublicValueConstants.php: -------------------------------------------------------------------------------- 1 | types[Package::PUBLIC] as $name => $type) { 19 | if ($type->value !== null) { 20 | $result[] = PHP::const($name, PHP::scalar($type->value)); 21 | } 22 | } 23 | return $result; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/Compiler/PHP/TypeCheck.php: -------------------------------------------------------------------------------- 1 | value !== null) { 18 | return PHP::identical($var, PHP::scalar($type->value)); 19 | } 20 | switch ($type->type) { 21 | case Type::ANY: return PHP::constFetch('true'); 22 | case Type::INT: return PHP::funcCall('is_int', $var); 23 | case Type::FLOAT: return PHP::or(PHP::funcCall('is_float', $var), PHP::funcCall('is_int', $var)); 24 | case Type::STRING: return PHP::funcCall('is_string', $var); 25 | case Type::UNION: 26 | $types = $type->subTypes; 27 | $node = self::compileExternalCheck($var, array_shift($types)); 28 | for ($i = 0, $n = count($types); $i < $n; $i++) { 29 | $node = PHP::or($node, self::compileExternalCheck($var, $types[$i])); 30 | } 31 | return $node; 32 | case Type::ARRAY: 33 | $root = PHP::funcCall('is_array', $var); 34 | if ($type->subTypes[0]->type === Type::ANY) { 35 | // Skiip 36 | return $root; 37 | } 38 | throw new \LogicException("Arrays with subtypes not implemented yet"); 39 | } 40 | throw new \LogicException("Compilation for external check of " . $type->toString() . " not implemented"); 41 | } 42 | 43 | public static function compileInternalCheck(PhpNode $var, Type $type): PhpNode 44 | { 45 | return self::compileExternalCheck($var, $type); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/Compiler/Utility/PhiResolver.php: -------------------------------------------------------------------------------- 1 | seen = []; 19 | } 20 | 21 | public function resolve(Package $package) 22 | { 23 | $this->reset(); 24 | foreach ($package->functions as $visibility => $functions) { 25 | foreach ($functions as $function) { 26 | $this->findAndResolveBlocks($function->body); 27 | $function->setResult($this->resolveNode($function->result)); 28 | $this->reset(); 29 | } 30 | } 31 | } 32 | 33 | public function findAndResolveBlocks(Block $block) 34 | { 35 | if (isset($this->seen[$block->getId()])) { 36 | return; 37 | } 38 | $this->seen[$block->getId()] = true; 39 | foreach ($block->getNodes() as $node) { 40 | foreach ($node->getSubNodeNames() as $name) { 41 | $node->$name = $this->resolveNode($node->$name); 42 | } 43 | } 44 | foreach ($block->getNextBlocks() as $child) { 45 | $this->findAndResolveBlocks($child); 46 | } 47 | } 48 | 49 | protected function resolveNode($node) 50 | { 51 | if ($node instanceof Variable\Phi) { 52 | return $this->resolveOutPhiNode($node); 53 | } elseif (is_array($node)) { 54 | return array_map(function ($child) { 55 | return $this->resolveNode($child); 56 | }, $node); 57 | } 58 | return $node; 59 | } 60 | 61 | protected function resolveOutPhiNode(Variable\Phi $phi): Variable 62 | { 63 | $newVar = new Variable\Temp($phi->getDeclaredType()); 64 | foreach ($phi->parents as $parent) { 65 | $parent->block->appendNode(new CFG\Expr\Assign($newVar, $parent->var)); 66 | } 67 | return $newVar; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /lib/Debug/ASTDumper.php: -------------------------------------------------------------------------------- 1 | name->toString() . "\n"; 13 | $result .= self::dumpNodes($package->stmts, ' '); 14 | return $result; 15 | } 16 | 17 | public static function dumpNodes(array $nodes, string $indent = ''): string 18 | { 19 | $result = ''; 20 | foreach ($nodes as $node) { 21 | if ($node instanceof $node) { 22 | $result .= self::dumpNode($node, $indent); 23 | } else { 24 | $result .= $indent . $node . "\n"; 25 | } 26 | } 27 | return $result; 28 | } 29 | 30 | public static function dumpNode(Node $node, string $indent): string 31 | { 32 | $result = $indent . $node->getName() . "\n"; 33 | $indent .= " "; 34 | foreach ($node->getSubNodeNames() as $name) { 35 | $subNodes = $node->$name; 36 | if (is_array($subNodes)) { 37 | $result .= $indent . $name . " [\n"; 38 | $result .= self::dumpNodes($subNodes, $indent . ' '); 39 | $result .= $indent . "]\n"; 40 | } elseif ($subNodes instanceof Node) { 41 | $result .= $indent . $name . ":\n"; 42 | $result .= self::dumpNode($subNodes, $indent . ' '); 43 | } else { 44 | $result .= $indent . $name . '(' . $subNodes . ")\n"; 45 | } 46 | } 47 | return $result; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /lib/Inference/Engine.php: -------------------------------------------------------------------------------- 1 | scope = $scope; 17 | $this->addRule( 18 | new Rule\TypeResolver($scope), 19 | new Rule\TypeReconstruction, 20 | new Rule\FunctionCallResolver($scope), 21 | new Rule\ExpressionFunctionResolver($scope) 22 | ); 23 | } 24 | 25 | public function addRule(Rule ...$rule) 26 | { 27 | $this->rules = array_merge($this->rules, $rule); 28 | } 29 | 30 | public function process(Package $package) 31 | { 32 | $this->fire('beforePackage', $package); 33 | 34 | foreach ($package->functions as $functionList) { 35 | foreach ($functionList as $name => $function) { 36 | $this->fire('beforeFunction', $name, $function); 37 | $this->walkBlocks($function); 38 | $this->fire('afterFunction', $name, $function); 39 | } 40 | } 41 | 42 | $this->fire('afterPackage', $package); 43 | } 44 | 45 | protected function fire(string $cmd, ...$args): int 46 | { 47 | $return = 0; 48 | foreach ($this->rules as $rule) { 49 | $return |= $rule->$cmd(...$args); 50 | } 51 | return $return; 52 | } 53 | 54 | protected function walkBlocks(Function_ $function) 55 | { 56 | start: 57 | do { 58 | $seen = []; 59 | $toSee = [$function->body]; 60 | $result = 0; 61 | while (!empty($toSee)) { 62 | $block = array_shift($toSee); 63 | if (isset($seen[$block->getId()])) { 64 | continue; 65 | } 66 | $seen[$block->getId()] = true; 67 | $result |= $this->fire('processBlock', $block); 68 | if ($result & Rule::SKIP_CHILDREN) { 69 | // Clear flag 70 | $result &= ~Rule::SKIP_CHILDREN; 71 | } else { 72 | $toSee = array_merge($toSee, $block->getNextBlocks()); 73 | } 74 | } 75 | } while ($result & Rule::RERUN); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /lib/Inference/Rule.php: -------------------------------------------------------------------------------- 1 | scope = $scope; 22 | } 23 | 24 | public function beforePackage(Package $package): int 25 | { 26 | $this->packageName = $package->name; 27 | $this->package = $package; 28 | return self::NORMAL; 29 | } 30 | 31 | public function processBlock(Block $block): int 32 | { 33 | $result = self::NORMAL; 34 | foreach ($block->getNodes() as $node) { 35 | if ($node->getName() !== 'Expr_MethodCall') { 36 | continue; 37 | } 38 | if ($node->signature) { 39 | continue; 40 | } 41 | // Attempt to look up method call 42 | $type = $node->obj->getInferredType(); 43 | $name = $node->name; 44 | $rootOn = $this->package->lookupExpressionFunction($type, $name); 45 | if ($rootOn) { 46 | $block->replaceNodeWith($node, new ExpressionCall($rootOn, $node->obj, $node->name, $node->args, $node->result, $node->getAttributes())); 47 | $result |= self::RERUN; 48 | } 49 | } 50 | 51 | return $result; 52 | } 53 | 54 | protected function resolveType(string $name) 55 | { 56 | if (strpos($name, '::') !== false) { 57 | return $this->scope->lookup($name, $this->packageName); 58 | } 59 | return $this->scope->lookup($this->packageName . '::' . $name, $this->packageName); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /lib/Inference/Rule/FunctionCallResolver.php: -------------------------------------------------------------------------------- 1 | scope = $scope; 20 | } 21 | 22 | public function beforePackage(Package $package): int 23 | { 24 | $this->packageName = $package->name; 25 | return self::NORMAL; 26 | } 27 | 28 | public function processBlock(Block $block): int 29 | { 30 | foreach ($block->getNodes() as $node) { 31 | if ($node->getName() !== 'Expr_FuncCall') { 32 | continue; 33 | } 34 | if ($node->signature) { 35 | continue; 36 | } 37 | if ($node->name instanceof Variable\IdentifierReference) { 38 | $type = $this->resolveType($node->name->value); 39 | if (!$type) { 40 | if (substr($node->name->value, 0, 5) === 'php::') { 41 | // Do something to handle this 42 | } 43 | throw new \RuntimeException("Unknown function call: {$node->name->value}"); 44 | } else { 45 | $node->signature = $type; 46 | $node->result->setDeclaredType(array_slice($type->subTypes, -1)[0]); 47 | return self::RERUN; 48 | } 49 | } else { 50 | throw new \LogicException("Not implemented: support for " . get_class($node->name)); 51 | } 52 | } 53 | 54 | return self::NORMAL; 55 | } 56 | 57 | protected function resolveType(string $name) 58 | { 59 | if (strpos($name, '::') !== false) { 60 | return $this->scope->lookup($name, $this->packageName); 61 | } 62 | return $this->scope->lookup($this->packageName . '::' . $name, $this->packageName); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /lib/Inference/Rule/TypeReconstruction.php: -------------------------------------------------------------------------------- 1 | getVariables(); 17 | foreach ($block->getEdges() as $destId => $sources) { 18 | $dest = $vars[$destId]; 19 | $origType = $dest->getDeclaredType(); 20 | if ($origType->type !== Type::UNKNOWN) { 21 | continue; 22 | } 23 | if (count($sources) > 1) { 24 | $dest->setDeclaredType($this->union(...$sources)); 25 | } else { 26 | $dest->setDeclaredType($sources[0]->getDeclaredType()); 27 | } 28 | if (!$dest->getDeclaredType()->equals($origType)) { 29 | $return |= self::RERUN; 30 | } 31 | } 32 | 33 | return $return; 34 | } 35 | 36 | protected function union(Variable ...$vars) 37 | { 38 | $subTypes = []; 39 | foreach ($vars as $var) { 40 | $subTypes[] = $var->getDeclaredType(); 41 | } 42 | return (new Type(Type::UNION, null, ...$subTypes))->simplify(); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /lib/Inference/Rule/TypeResolver.php: -------------------------------------------------------------------------------- 1 | scope = $scope; 22 | } 23 | 24 | public function beforePackage(Package $package): int 25 | { 26 | $this->package = $package; 27 | return self::NORMAL; 28 | } 29 | 30 | public function beforeFunction(string $name, Function_ $function): int 31 | { 32 | $return = self::NORMAL; 33 | $return |= $this->resolveVariables($function->parameters); 34 | $return |= $this->resolveVariables([$function->result]); 35 | 36 | return $return; 37 | } 38 | 39 | 40 | public function processBlock(Block $block): int 41 | { 42 | $vars = $block->getVariables(); 43 | return self::resolveVariables($vars); 44 | } 45 | 46 | protected function resolveVariables(array $vars): int 47 | { 48 | $return = self::NORMAL; 49 | foreach ($vars as $var) { 50 | $origType = $var->getInferredType(); 51 | $type = $this->resolveType($origType); 52 | if ($type !== $origType) { 53 | $var->setInferredType($type); 54 | $return |= self::RERUN; 55 | } 56 | } 57 | return $return; 58 | } 59 | 60 | protected function resolveType(Type $type): Type 61 | { 62 | if ($type->type === Type::TYPE_REFERENCE) { 63 | return $this->scope->lookup($type->value, $this->package->name); 64 | } 65 | return $type; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /lib/Inference/RuleAbstract.php: -------------------------------------------------------------------------------- 1 | id = self::$counter++; 24 | } 25 | 26 | public function getId(): int 27 | { 28 | return $this->id; 29 | } 30 | 31 | public function addInboundBlock(Block $inbound) 32 | { 33 | $this->inbound[] = $inbound; 34 | } 35 | 36 | 37 | public function addOutboundBlock(string $when, Block $output) 38 | { 39 | $this->outbound[$when] = $output; 40 | $output->addInboundBlock($this); 41 | } 42 | 43 | public function getNextBlocks(): array 44 | { 45 | return $this->outbound; 46 | } 47 | 48 | public function getNextBlock(string $name): Block 49 | { 50 | if (!isset($this->outbound[$name])) { 51 | throw new \InvalidArgumentException("Unknown next block $name"); 52 | } 53 | return $this->outbound[$name]; 54 | } 55 | 56 | 57 | public function hasNextBlock(string $name): bool 58 | { 59 | return isset($this->outbound[$name]); 60 | } 61 | 62 | public function replaceNodeWith(Node $old, Node $new) 63 | { 64 | $key = array_search($old, $this->nodes, true); 65 | if ($key !== false) { 66 | $this->nodes[$key] = $new; 67 | } else { 68 | throw new \RuntimeException('Could not find node to replace'); 69 | } 70 | } 71 | 72 | public function appendNode(Node ...$nodes) 73 | { 74 | foreach ($nodes as $node) { 75 | $this->nodes[] = $node; 76 | } 77 | } 78 | 79 | public function getPreviousBlocks(): array 80 | { 81 | return $this->inbound; 82 | } 83 | 84 | public function getNodes(): array 85 | { 86 | return $this->nodes; 87 | } 88 | 89 | public function getInput(): array 90 | { 91 | return $this->input; 92 | } 93 | 94 | public function namedVariable(string $name, int $mode): Variable 95 | { 96 | switch ($mode) { 97 | case Block::MODE_RO: 98 | return $this->read($name); 99 | case Block::MODE_WO: 100 | return $this->write(new Variable\Named($name, new Type(Type::UNKNOWN))); 101 | default: 102 | throw new \LogicException("Unsupported mode: $mode"); 103 | } 104 | } 105 | 106 | public function write(Variable $variable, Variable $value = null): Variable 107 | { 108 | $this->addVariable($variable); 109 | if ($value) { 110 | $this->connect($variable, $value); 111 | } 112 | if (!$variable instanceof Variable\Named) { 113 | return $variable; 114 | } 115 | $this->names[$variable->name] = $variable; 116 | return $variable; 117 | } 118 | 119 | public function read(string $name): Variable 120 | { 121 | if (isset($this->variables[$name])) { 122 | return $this->variables[$name]; 123 | } 124 | $variable = new Variable\Named($name, new Type(Type::UNKNOWN)); 125 | $this->addVariable($variable); 126 | if (!isset($this->names[$name])) { 127 | if (!isset($this->input[$name])) { 128 | $this->input[$name] = new Variable\Named($name, new Type(Type::UNKNOWN)); 129 | $this->write($this->input[$name]); 130 | } else { 131 | throw new LogicException("Not possible, since write adds to names"); 132 | } 133 | // Fall through here is fine, since write adds the variable to names 134 | } 135 | $this->connect($variable, $this->names[$name]); 136 | return $variable; 137 | } 138 | 139 | protected function connect(Variable $destination, Variable $source) 140 | { 141 | $destId = $destination->getId(); 142 | if (!isset($this->edges[$destId])) { 143 | $this->edges[$destId] = []; 144 | } elseif ($this->edges[$destId][0]->getId() !== $source->getId() && !$destination instanceof Variable\Phi) { 145 | throw new \LogicException("Non-Phi variable with multiple edges"); 146 | } 147 | $this->edges[$destId][] = $source; 148 | } 149 | 150 | public function getVariables(): array 151 | { 152 | return $this->variables; 153 | } 154 | 155 | public function getEdges(): array 156 | { 157 | return $this->edges; 158 | } 159 | 160 | protected function addVariable(Variable $variable) 161 | { 162 | $this->variables[$variable->getId()] = $variable; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /lib/Language/Function_.php: -------------------------------------------------------------------------------- 1 | setParameters(...$parameters); 15 | $this->returnType = $returnType; 16 | $this->body = $body; 17 | $this->result = $result; 18 | } 19 | 20 | public function __get(string $name) 21 | { 22 | return $this->$name; 23 | } 24 | 25 | public function setResult(Variable $result) 26 | { 27 | $this->result = $result; 28 | } 29 | 30 | public function getSignature(): Type 31 | { 32 | return new Type( 33 | Type::CALLABLE, 34 | null, 35 | ...array_map(function (Variable\Parameter $param) { 36 | return $param->getDeclaredType(); 37 | }, $this->parameters), 38 | ...[$this->returnType] 39 | ); 40 | } 41 | 42 | private function setParameters(Variable\Parameter ...$parameters) 43 | { 44 | $this->parameters = $parameters; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/Language/Package.php: -------------------------------------------------------------------------------- 1 | 'public', 15 | self::PROTECTED => 'protected', 16 | self::PRIVATE => 'private', 17 | ]; 18 | 19 | const FIELDS = [ 20 | "types", 21 | "functions", 22 | "expressionFunctions", 23 | ]; 24 | 25 | protected $types = [ 26 | self::PUBLIC => [], 27 | self::PROTECTED => [], 28 | self::PRIVATE => [], 29 | ]; 30 | 31 | protected $functions = [ 32 | self::PUBLIC => [], 33 | self::PROTECTED => [], 34 | self::PRIVATE => [], 35 | ]; 36 | 37 | protected $expressionFunctions = [ 38 | self::PUBLIC => [], 39 | self::PROTECTED => [], 40 | self::PRIVATE => [], 41 | ]; 42 | 43 | protected $name; 44 | 45 | public function __construct(string $name) 46 | { 47 | $this->name = $name; 48 | } 49 | 50 | public function __get(string $name) 51 | { 52 | return $this->$name; 53 | } 54 | 55 | public function addTypeDeclaration(string $name, Type $type, int $visibility) 56 | { 57 | if (isset($this->types[$visibility][$name])) { 58 | throw new RuntimeException("Invalid type declaration for $name, symbol already defined"); 59 | } 60 | $this->types[$visibility][$name] = $type; 61 | } 62 | 63 | public function addFunctionDeclaration(string $name, Function_ $function, int $visibility) 64 | { 65 | $this->addTypeDeclaration($name, $function->getSignature(), $visibility); 66 | if (isset($this->functions[$visibility][$name])) { 67 | throw new RuntimeException("Invalid function declaration for $name, symbol already defined"); 68 | } 69 | $this->functions[$visibility][$name] = $function; 70 | } 71 | 72 | public function addExpressionFunctionDeclaration(Type $on, string $name, Function_ $function, int $visibility) 73 | { 74 | $onString = $on->toString(); 75 | $this->addTypeDeclaration($onString . '->' . $name, $function->getSignature(), $visibility); 76 | $this->expressionFunctions[$visibility][$name][] = [$on, $function]; 77 | } 78 | 79 | public function lookupExpressionFunction(Type $on, string $name) 80 | { 81 | for ($i = self::PUBLIC; $i <= self::PRIVATE; $i++) { 82 | if (!isset($this->expressionFunctions[$i][$name])) { 83 | continue; 84 | } 85 | foreach ($this->expressionFunctions[$i][$name] as list($rootOn, $function)) { 86 | if ($on->resolves($rootOn)) { 87 | return $rootOn; 88 | } 89 | } 90 | } 91 | } 92 | 93 | public function mergeWith(Package $other): Package 94 | { 95 | if ($this->name !== $other->name) { 96 | throw new \RuntimeException("Atempting to merge unlike packages"); 97 | } 98 | $new = new static($this->name); 99 | $this->addAllTo($new); 100 | $other->addAllTo($new); 101 | return $new; 102 | } 103 | 104 | protected function addAllTo(Package $other) 105 | { 106 | foreach ($this->types as $visibility => $typeMap) { 107 | foreach ($typeMap as $name => $type) { 108 | $other->addTypeDeclaration($name, $type, $visibility); 109 | } 110 | } 111 | foreach ($this->functions as $visibility => $functionMap) { 112 | foreach ($functionMap as $name => $function) { 113 | // bypass addFunctionDeclaration since type is already extracted 114 | $other->functions[$visibility][$name] = $function; 115 | } 116 | } 117 | foreach ($this->expressionFunctions as $visibility => $functionMap) { 118 | foreach ($functionMap as $name => $exprMap) { 119 | foreach ($exprMap as $onSpec) { 120 | $other->expressionFunctions[$visibility][$name][] = $onSpec; 121 | } 122 | } 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /lib/Language/Variable.php: -------------------------------------------------------------------------------- 1 | items = $items; 17 | parent::__construct(new Type(Type::ARRAY, null, new Type(Type::ANY))); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/Language/Variable/IdentifierReference.php: -------------------------------------------------------------------------------- 1 | value = $value; 16 | parent::__construct(new Type(Type::TYPE_REFERENCE, $value)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/Language/Variable/Literal.php: -------------------------------------------------------------------------------- 1 | value = $value; 16 | if (is_int($value)) { 17 | $type = new Type(Type::INT); 18 | } elseif (is_float($value)) { 19 | $type = new Type(Type::FLOAT); 20 | } elseif (is_string($value)) { 21 | $type = new Type(Type::STRING); 22 | } elseif (is_null($value)) { 23 | $type = new Type(Type::NULL); 24 | } elseif ($value === true) { 25 | $type = new Type(Type::TRUE); 26 | } elseif ($value === false) { 27 | $type = new Type(Type::FALSE); 28 | } else { 29 | throw new RuntimException("Unknown literal type provided: " . gettype($value)); 30 | } 31 | parent::__construct($type); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /lib/Language/Variable/Named.php: -------------------------------------------------------------------------------- 1 | name = $name; 15 | parent::__construct($type); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/Language/Variable/Parameter.php: -------------------------------------------------------------------------------- 1 | position = $position; 14 | parent::__construct($name, $type); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/Language/Variable/Phi.php: -------------------------------------------------------------------------------- 1 | parents = $parents; 15 | parent::__construct(new Type(Type::UNKNOWN)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/Language/Variable/Phi/Entry.php: -------------------------------------------------------------------------------- 1 | block = $block; 17 | $this->var = $var; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/Language/Variable/Temp.php: -------------------------------------------------------------------------------- 1 | id = self::$counter++; 15 | $this->declaredType = $declaredType; 16 | } 17 | 18 | public function getId(): int 19 | { 20 | return $this->id; 21 | } 22 | 23 | public function getDeclaredType(): Type 24 | { 25 | return $this->declaredType; 26 | } 27 | 28 | public function setDeclaredType(Type $type = null) 29 | { 30 | $this->declaredType = $type; 31 | } 32 | 33 | public function getInferredType(): Type 34 | { 35 | return $this->inferredType ?? $this->declaredType; 36 | } 37 | 38 | public function setInferredType(Type $type = null) 39 | { 40 | $this->inferredType = $type; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /lib/Parser/Tokens.php: -------------------------------------------------------------------------------- 1 | name; 13 | if (isset($this->packages[$packageName])) { 14 | $this->packages[$packageName] = $this->packages[$packageName]->mergeWith($package); 15 | } else { 16 | $this->packages[$packageName] = $package; 17 | } 18 | foreach ($this->packages[$packageName]->types as $visibility => $types) { 19 | $this->packageMap[$packageName][$visibility] = []; 20 | foreach ($types as $name => $type) { 21 | $this->packageMap[$packageName][$visibility][$name] = $type; 22 | } 23 | } 24 | } 25 | 26 | public function getPackage(string $name): Language\Package 27 | { 28 | if (!isset($this->packages[$name])) { 29 | throw new \RuntimeException("Could not find package $name"); 30 | } 31 | return $this->packages[$name]; 32 | } 33 | 34 | public function lookup(string $name, string $fromName) 35 | { 36 | $parts = explode('::', $name); 37 | $identifier = array_pop($parts); 38 | $package = implode('::', $parts); 39 | 40 | if (!isset($this->packages[$package])) { 41 | return; 42 | } 43 | 44 | $flag = Language\Package::PUBLIC; 45 | if ($package === $fromName) { 46 | $flag = Language\Package::PRIVATE; 47 | } elseif (strpos($fromName, $package . '::') === 0) { 48 | $flag = Language\Package::PROTECTED; 49 | } 50 | 51 | for ($i = Language\Package::PUBLIC; $i <= $flag; $i++) { 52 | if (isset($this->packageMap[$package][$i][$identifier])) { 53 | return $this->packageMap[$package][$i][$identifier]; 54 | } 55 | } 56 | } 57 | 58 | public function addSignatures(array $signatures) 59 | { 60 | var_dump($signatures); 61 | die(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /lib/php/arrays.pr: -------------------------------------------------------------------------------- 1 | package php; 2 | 3 | public type count = fn(array) int 4 | -------------------------------------------------------------------------------- /lib/php/numbers.pr: -------------------------------------------------------------------------------- 1 | package php; 2 | 3 | public type intdiv = fn(int,int) int 4 | 5 | 6 | -------------------------------------------------------------------------------- /lib/php/strings.pr: -------------------------------------------------------------------------------- 1 | package php; 2 | 3 | public type strlen = fn(string) int 4 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 15 | ./lib 16 | 17 | 18 | 19 | 20 | 21 | ./lib/ 22 | 23 | ./lib/ 24 | 25 | 26 | 27 | --------------------------------------------------------------------------------