My favorites | Sign in
Project Logo
                
Code license: MIT License
Labels: php, compiler, language, parser
Feeds:
People details
Project owners:
  stereofrog

PiHiPi is a simple object-oriented scripting language based on and compatible with PHP http://www.php.net. PiHiPi compiler is able to translate most of php code and also adds some new features to the language. The goal of PiHiPi project is to create simpler and more consistent php parser.

usage

PiHiPi compiler is a standalone command line utility that translates PiHiPi into valid php5 code. The resulting code can be executed or deployed directly, no additional libraries or extensions are required.

phicc -o<output_path> source.ph ... source.ph

translates given PiHiPi (.ph) files into one single php script. If -o option is omitted, phicc prints generated code to standard output, so that you can pipe it with php:

phicc source.ph | php

There's also a shell script, called phi, that does essentially the same:

phi source.ph

compiles and then executes source.ph

installation

windows binaries

Download and unzip windows package. Put phicc.exe somewhere in your path, and phrtl.php in your php include_path. Run tests to make sure everything is ok:

php test.php

After running tests, it's safe to remove installation directory, phicc.exe and phrtl.php are only two files you need to use PiHiPi.

building from source

You will need lemon http://www.hwaci.com/sw/lemon and re2c http://re2c.org

svn checkout http://pihipi.googlecode.com/svn/trunk/ pihipi
cd pihipi
make && make test

For Windows MinGW is preferred, .sln file for Microsoft toolchain is included, but not 'officially supported'. ;)

language extensions

With some exceptions, PiHiPi understands any valid php syntax. The following describes features of PiHiPi not found in standard php. For more details and examples look at the files in test and examples directories.

layout

Code is enclosed in <? ... ?>. Like ?>, closing comment symbol */ can be omitted (assumed at the end of file).

<?= ... ?> is not the same as echo, it's translated into the call to the function web::_print(), which defaults to htmlspecialchars(), but can be redefined:

<?
namespace web {
	function _print()
		print arguments->map(str::upper)->join(' ');
}
?>
<?='hi','there'?> (outputs: HI THERE)

primitives

String interpolation is performed for arbitrary complex references starting with $ and for arbitrary expressions enclosed in {}:

echo "hello $foo->bar->baz[10+20]";
echo "hello {10 + someFunc() + $blah}";

There are also two new string delimiters: """ and ''' (triple-double and triple-single quotes).

echo """ double "quotes" are ok  """;
echo ''' single 'quotes' are ok  ''';

Regular expressions are first class primitives. Regexp literals are enclosed in backticks:

$regexp = `[a-z_][a-z0-9_]+`si;

arrays

Added shortcut syntax for array literals:

$ary = [10, 20, 'foo' => 'bar'];

Arrays are objects:

echo [1, 2, 3]->join('|'); // 1|2|3

operators

Added ruby-alike match =~, not match !~ and compare <=> operators.

echo 'ABC' =~ `[A-Z]+`; // true
echo 'ABC' !~ `[0-9]+`; // true
echo 10 <=> 20; // -1

Index operator [] can accept two arguments. This form is only allowed on the right and returns substring/subarray:

echo '012345'[2, 4];  // '234'
echo '012345'[2, -1]; // '2345'

Perl semantics for boolean || and &&:

echo 5 && 25; // 25
echo 0 || 25; // 25

isset and unset are true operators and can be used without parentheses

if(isset $a) echo $a;
unset $b;
echo isset $b;

Added new is and in operators. in tests if the value is in array or is a substring of the argument:

if(10 in [1, 5, 10, 20]) echo "yes!";
if('bar' in 'foobarbaz') echo "yes!";

is acts like a wrapper around php is_a... family of functions:

if($var is number) echo "number";
if($var is string) echo "string";

class Foo {}

if($var is Foo)
	echo "var is an object of class Foo";

assignments

Added support for multiple assignment:

$a,$b    = 10,20;    // a=10,b=20
$a,,$c   = 10,20,30; // a=10,c=30
$a,$b,$c = 10,20;    // a=10,b=20,c=20

expressions

As a general rule, expression is allowed everywhere a variable can be used, e.g.:

echo func()[10];
echo $(get_var_name());
echo $obj->('pro' . 'perty');
echo (new Foo)->bar;
echo ('func' . 'name')($arg);
$a = new (get_class_name())($args);

statements

throw can throw any object or string:

if(!open_foo_bar())
	throw 'panic!';

catch argument can be arbitrary lvalue, even complex:

try { ... }
catch($myObj->myErr) { ... }

Includes are statements and resolved at compile time i.e. include(expression) is not allowed. Resulting script is monolithic.

echo and print are statements, not functions. Also added puts:

puts 'Hello';

functions

Curly brackets can be omitted if function body is a single statement. Added support for named call arguments, the syntax is the same as for array literals:

function velocity($dist, $time) return $dist / $time;

echo velocity(100, 4); // 25
echo velocity('time' => 4, 'dist' => 100); // 25

Along with traditional callbacks (string and array), there's also direct reference form (Class->method or Namespace::method):

echo [1, 2, 3]->map('someFunc'); // as in php
echo [1, 2, 3]->map([$someObj, 'someMethod']); // as in php

class SomeClass {
	function staticFunc($z) return $z * 10;
}

echo [1, 2, 3]->map(SomeClass->staticFunc); // 10,20,30

Function parameters are stored in arguments array:

function baz()
	echo arguments->reverse()->join();

baz('a', 'b', 'c'); // cba

call and call_array invoke given function (like call_user_func...):

function bar() return 'hi';
call('bar');

apply($func, $obj) and apply_array($func, $obj) call a function in context of object $obj, i.e. $obj temporary becomes $this in the function:

class A {
	function info()
		puts '***' . $this->whoami();
	function whoami()
		return "object A";
}

class B {
	var $bar = '123';
	function whoami()
		return "object B, bar={@bar}";
}

$a = new A;
$a->info(); // calls A->whoami

$b = new B;
apply($a->info, $b); // calls B->whoami

namespaces

namespace Foo { body }

Namespace body can contain constant, function and class declarations. Qualified name is looked for in that namespace:

echo Foo::bar();

Unqualified name is looked for in current namespace and then globally. global is a namespace and can be referred as such:

echo global::foo;
import <namespace-name>
import <namespace-name> from <path>

imports another namespace in the scope of current.

classes

@ is a shortcut for $this->

class A {
	function __construct($t) @wow = $t + 1;
}

echo (new A(125))->wow; // 126

In general, -> refers to a class or object, and :: is used for namespaces. For php compatibility, it's also possible to use :: with global classes.

class GlobClass {
	var $foo = 10;
}

echo GlobClass::foo;
echo GlobClass->foo; // the same

namespace Foo {
	class Bar {
		static $prop;
		...
	}
}

echo Foo::Bar->prop;

extends accepts qualified class names:

class Foo extends OtherNamespace::Bar

Constants are resolved at run-time, that is, arbitrary expressions are allowed on the right:

const X = foo() + bar();

Getters and setters:

class Circle {
	var $r;

	function __construct($radius)
		@r = $radius;

	function get area()
		return 3.1459 * @r * @r;
	function set area()
		throw 'cannot set area directly';
}

$c = new Circle(10);
echo $c->area;
$c->area = 111;

__construct can return a value. If a non-null is returned, it will be taken as the value of "new".

class GoodFella {}

class Person {
	function __construct($name) {
		if($name == 'Joe')
			return new GoodFella($name);
	}
}

echo new Person('Tom'); // (object Person)
echo new Person('Joe'); // (object GoodFella)

php interaction

All php functions (system and user) are automatically available to PiHiPi. PiHiPi identifiers take precedence over php ones, to use php function in any case prepend its name with php::

puts htmlspecialchars($var); // call php function

function mysql_connect() {...}

mysql_connect();       // call my function
php::mysql_connect();  // call php function

You can also embed 'raw' php code using 'unparsed input' brackets {< ... >}:

{<
	# php code
	$html = strip_tags($_GET['msg']);
>}

standard library

Some of php standard library functions are rewritten in PiHiPi style: each function group is either moved to its own namespace or becomes object-oriented:

// in php: echo strlen...
echo str::len('ABC');

// in php: preg_replace...
$text = str::replace($html, `<.*?>`, '');

// in php: fopen/fread
$f = new File('foo');
$first_10 = $f->read(10);

// in php: strtotime/date
echo (new Date('+10 days'))->string('d M Y');

Here's a brief example that should give you a better idea on what PiHiPi programming looks like.

<?

// word count example
// http://www.tagarga.com/pihipi/examples/wc.php

const MAX_LEN = 1024;

if(web::SERVER('REQUEST_METHOD') == 'POST')
{
	try
	{
		$text = web::POST('text');

		if($text !~ `\S`)
			throw "text is empty";

		if(str::len($text) > MAX_LEN)
			throw "text is too long";

		echo "<b>text statistics {new Date}</b>";

		$chars = [];
		$words = [];

		foreach(str::split($text) as $chr) {
			if($chr =~ `[A-Z]`i) {
				$chr = str::upper($chr);
				$chars[$chr] = isset $chars[$chr] ? $chars[$chr] + 1 : 1;
			}
		}

		if(!$chars->count())
			throw "no letters in text";

		echo "<br> Letters by frequency: ";
		echo $chars->arsort()->keys()->join();

		foreach(str::match($text, `[A-Z]+`i) as $w) {
			$w = str::upper($w);
			if(isset $words[$w])
				$words[$w][1]++;
			else
				$words[$w] =  [$w, 1];
		}

		function sort_words($a, $b)
			return $b[1] <=> $a[1] || $a[0] <=> $b[0];

		echo "<br> Words by frequency: ";
		foreach($words->sort('sort_words') as $w)
			echo $w->join ('='), ' ';

	} catch($e)
	{
		puts "<b>Error: $e</b>";
	}
}
echo """
	<form action="{web::SERVER('SCRIPT_NAME')}" method="POST">
		<textarea name="text" rows=10 cols=50>I Love You Love Me Love</textarea>
		<input type="submit" value="get text stats">
	</form>
""";
?>

missing php features

going to be implemented:

going to be dropped from the language:









Hosted by Google Code